From c0e068a51cb0406a2063bc27d0095d3e83e178bd Mon Sep 17 00:00:00 2001
From: Albert <Albert.Bruns@mgm-tp.com>
Date: Tue, 4 Feb 2025 14:08:04 +0100
Subject: [PATCH] OZG-7472-7632 ods buttons

---
 .../libs/test-utils/src/lib/jest.helper.ts    |   8 +-
 .../annehmen-button.component.html            |  45 +-
 .../annehmen-button.component.spec.ts         | 122 +++--
 .../bescheiden-button.component.html          |  45 +-
 .../bescheiden-button.component.spec.ts       | 459 +++++++++---------
 .../src/lib/vorgang-detail.module.ts          |   2 +
 6 files changed, 373 insertions(+), 308 deletions(-)

diff --git a/alfa-client/libs/test-utils/src/lib/jest.helper.ts b/alfa-client/libs/test-utils/src/lib/jest.helper.ts
index 1f05a4791c..60df8592af 100644
--- a/alfa-client/libs/test-utils/src/lib/jest.helper.ts
+++ b/alfa-client/libs/test-utils/src/lib/jest.helper.ts
@@ -23,7 +23,8 @@
  */
 import { ComponentFixture } from '@angular/core/testing';
 import { expect } from '@jest/globals';
-import { getElementFromFixture } from './helper';
+import { TooltipDirective } from '@ods/system';
+import { getDebugElementFromFixtureByCss, getElementFromFixture } from './helper';
 
 export function notExistsAsHtmlElement(fixture: ComponentFixture<any>, domElement: string): void {
   expect(getElementFromFixture(fixture, domElement)).not.toBeInstanceOf(HTMLElement);
@@ -32,3 +33,8 @@ export function notExistsAsHtmlElement(fixture: ComponentFixture<any>, domElemen
 export function existsAsHtmlElement(fixture: ComponentFixture<any>, domElement: string): void {
   expect(getElementFromFixture(fixture, domElement)).toBeInstanceOf(HTMLElement);
 }
+
+export function tooltipExistsWithText(fixture: ComponentFixture<any>, domElement: string, tooltipText: string) {
+  const tooltipInstance = getDebugElementFromFixtureByCss(fixture, domElement).injector.get(TooltipDirective);
+  expect(tooltipInstance.componentRef.instance.text).toBe(tooltipText);
+}
diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.html b/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.html
index 97c685caf7..b93172bd7e 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.html
@@ -23,24 +23,27 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ng-container *ngIf="vorgang | hasLink: linkRel.ANNEHMEN">
-  <ozgcloud-stroked-button-with-spinner
-    *ngIf="!showAsIconButton"
-    data-test-id="annehmen-button"
-    text="Annehmen"
-    icon="check_circle_outline"
-    [stateResource]="commandStateResource$ | async"
-    (clickEmitter)="annehmen()"
-  >
-  </ozgcloud-stroked-button-with-spinner>
-
-  <ozgcloud-icon-button-with-spinner
-    *ngIf="showAsIconButton"
-    data-test-id="annehmen-icon-button"
-    icon="check_circle_outline"
-    toolTip="Vorgang annehmen"
-    [stateResource]="commandStateResource$ | async"
-    (clickEmitter)="annehmen()"
-  >
-  </ozgcloud-icon-button-with-spinner>
-</ng-container>
+@if(vorgang | hasLink: linkRel.ANNEHMEN){
+  @if(showAsIconButton){
+    <ods-button-with-spinner
+      [stateResource]="commandStateResource$ | async"
+      (clickEmitter)="annehmen()"
+      toolTip="Vorgang annehmen"
+      variant="icon"
+      size="fit"
+      data-test-id="annehmen-icon-button"
+    >
+      <ods-check-icon icon class="fill-primary"/>
+    </ods-button-with-spinner>
+  } @else {
+    <ods-button-with-spinner
+      [stateResource]="commandStateResource$ | async"
+      (clickEmitter)="annehmen()"
+      toolTip="Vorgang annehmen"
+      variant="outline"
+      data-test-id="annehmen-button"
+    >
+      <ods-check-icon icon class="fill-primary"/>
+    </ods-button-with-spinner>
+  }
+}
\ No newline at end of file
diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.spec.ts
index 43b5fa53e7..9d201f9cc3 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/annehmen-button/annehmen-button.component.spec.ts
@@ -21,14 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { HasLinkPipe, createStateResource } from '@alfa-client/tech-shared';
-import { mock } from '@alfa-client/test-utils';
-import {
-  IconButtonWithSpinnerComponent,
-  OzgcloudStrokedButtonWithSpinnerComponent,
-} from '@alfa-client/ui';
+import { CommandResource } from '@alfa-client/command-shared';
+import { createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared';
+import { getElementComponentFromFixtureByCss, mock, notExistsAsHtmlElement, triggerEvent } from '@alfa-client/test-utils';
 import { VorgangCommandService, VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ButtonWithSpinnerComponent } from '@ods/component';
+import { CheckIconComponent, TooltipDirective } from '@ods/system';
 import { createCommandResource } from 'libs/command-shared/test/command';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
@@ -52,9 +51,10 @@ describe('AnnehmenButtonComponent', () => {
     await TestBed.configureTestingModule({
       declarations: [
         AnnehmenButtonComponent,
-        MockComponent(OzgcloudStrokedButtonWithSpinnerComponent),
-        MockComponent(IconButtonWithSpinnerComponent),
         HasLinkPipe,
+        TooltipDirective,
+        MockComponent(ButtonWithSpinnerComponent),
+        MockComponent(CheckIconComponent),
       ],
       providers: [
         {
@@ -75,69 +75,95 @@ describe('AnnehmenButtonComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('ngOnInit', () => {
-    it('should call service', () => {
-      component.ngOnInit();
+  describe('component', () => {
+    describe('ngOnInit', () => {
+      it('should call service', () => {
+        component.ngOnInit();
 
-      expect(vorgangCommandService.getAnnehmenCommand).toHaveBeenCalled();
+        expect(vorgangCommandService.getAnnehmenCommand).toHaveBeenCalled();
+      });
     });
-  });
 
-  describe('annehmen', () => {
-    it('should call vorgang service', () => {
-      component.annehmen();
+    describe('annehmen', () => {
+      it('should call vorgang service', () => {
+        component.annehmen();
 
-      expect(vorgangCommandService.annehmen).toHaveBeenCalled();
+        expect(vorgangCommandService.annehmen).toHaveBeenCalled();
+      });
     });
   });
 
-  describe('annehmen button', () => {
+  describe('template', () => {
+    const state: StateResource<CommandResource> = createStateResource(createCommandResource());
+
     beforeEach(() => {
-      component.showAsIconButton = false;
+      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.ANNEHMEN]);
+      component.commandStateResource$ = of(state);
       fixture.detectChanges();
     });
 
-    it('should be hidden', () => {
-      component.vorgang = createVorgangWithEingangResource();
+    describe('annehmen button', () => {
+      beforeEach(() => {
+        component.showAsIconButton = false;
+        fixture.detectChanges();
+      });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(annehmenButton);
+      it('should not exist', () => {
+        component.vorgang = createVorgangWithEingangResource();
 
-      expect(buttonElement).not.toBeInstanceOf(HTMLElement);
-    });
+        fixture.detectChanges();
 
-    it('should be visible', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.ANNEHMEN]);
+        notExistsAsHtmlElement(fixture, annehmenButton);
+      });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(annehmenButton);
+      it('should exist with input', () => {
+        fixture.detectChanges();
 
-      expect(buttonElement).toBeInstanceOf(HTMLElement);
-    });
-  });
+        const button: ButtonWithSpinnerComponent = getElementComponentFromFixtureByCss(fixture, annehmenButton);
 
-  describe('annehmen icon button', () => {
-    beforeEach(() => {
-      component.showAsIconButton = true;
-      fixture.detectChanges();
-    });
+        expect(button).toBeTruthy();
+        expect(button.stateResource).toBe(state);
+      });
 
-    it('should be hidden', () => {
-      component.vorgang = createVorgangWithEingangResource();
+      it('should call annehmen on click', () => {
+        component.annehmen = jest.fn();
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(annehmenIconButton);
+        triggerEvent({ fixture, name: 'clickEmitter', elementSelector: annehmenButton });
 
-      expect(buttonElement).not.toBeInstanceOf(HTMLElement);
+        expect(component.annehmen).toHaveBeenCalled();
+      });
     });
 
-    it('should be visible', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.ANNEHMEN]);
+    describe('annehmen icon button', () => {
+      beforeEach(() => {
+        component.showAsIconButton = true;
+        fixture.detectChanges();
+      });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(annehmenIconButton);
+      it('should not exist', () => {
+        component.vorgang = createVorgangWithEingangResource();
+
+        fixture.detectChanges();
+
+        notExistsAsHtmlElement(fixture, annehmenIconButton);
+      });
+
+      it('should exist with input', () => {
+        fixture.detectChanges();
+
+        const button: ButtonWithSpinnerComponent = getElementComponentFromFixtureByCss(fixture, annehmenIconButton);
+
+        expect(button).toBeTruthy();
+        expect(button.stateResource).toBe(state);
+      });
+
+      it('should call annehmen on click', () => {
+        component.annehmen = jest.fn();
+
+        triggerEvent({ fixture, name: 'clickEmitter', elementSelector: annehmenIconButton });
 
-      expect(buttonElement).toBeInstanceOf(HTMLElement);
+        expect(component.annehmen).toHaveBeenCalled();
+      });
     });
   });
 });
diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.html b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.html
index fa3f6f038d..287fe3e8e1 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.html
@@ -23,24 +23,27 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ng-container *ngIf="vorgang | hasLink: linkRel.BESCHEIDEN">
-  <ozgcloud-stroked-button-with-spinner
-    *ngIf="!showAsIconButton"
-    data-test-id="bescheiden-button"
-    [text]="buttonText"
-    svgIcon="stamp"
-    [stateResource]="commandStateResource$ | async"
-    (clickEmitter)="bescheiden()"
-  >
-  </ozgcloud-stroked-button-with-spinner>
-
-  <ozgcloud-icon-button-with-spinner
-    *ngIf="showAsIconButton"
-    data-test-id="bescheiden-icon-button"
-    svgIcon="stamp"
-    [toolTip]="toolTipText"
-    [stateResource]="commandStateResource$ | async"
-    (clickEmitter)="bescheiden()"
-  >
-  </ozgcloud-icon-button-with-spinner>
-</ng-container>
+@if (vorgang | hasLink: linkRel.BESCHEIDEN) {
+  @if (showAsIconButton) {
+    <ods-button-with-spinner
+      [stateResource]="commandStateResource$ | async"
+      (clickEmitter)="bescheiden()"
+      [tooltip]="toolTipText"
+      variant="icon"
+      size="fit"
+      data-test-id="bescheiden-icon-button"
+    >
+      <ods-stamp-icon icon class="fill-black" size="medium" />
+    </ods-button-with-spinner>
+  } @else {
+    <ods-button-with-spinner
+      [stateResource]="commandStateResource$ | async"
+      (clickEmitter)="bescheiden()"
+      [text]="buttonText"
+      variant="outline"
+      data-test-id="bescheiden-button"
+    >
+      <ods-stamp-icon icon class="fill-primary" size="medium" />
+    </ods-button-with-spinner>
+  }
+}
diff --git a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts
index 01fc62566a..4587f44e18 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/buttons/bescheiden-button/bescheiden-button.component.spec.ts
@@ -24,12 +24,16 @@
 import { BescheidResource, BescheidService, BescheidWizardDialogResult } from '@alfa-client/bescheid-shared';
 import { CommandResource } from '@alfa-client/command-shared';
 import { createEmptyStateResource, createStateResource, HasLinkPipe, StateResource } from '@alfa-client/tech-shared';
-import { Mock, mock } from '@alfa-client/test-utils';
 import {
-  IconButtonWithSpinnerComponent,
-  OzgcloudDialogService,
-  OzgcloudStrokedButtonWithSpinnerComponent,
-} from '@alfa-client/ui';
+  getElementComponentFromFixtureByCss,
+  getMockComponent,
+  Mock,
+  mock,
+  notExistsAsHtmlElement,
+  tooltipExistsWithText,
+  triggerEvent,
+} from '@alfa-client/test-utils';
+import { OzgcloudDialogService } from '@alfa-client/ui';
 import { BescheidenDialogData } from '@alfa-client/vorgang-detail';
 import {
   VorgangCommandService,
@@ -39,6 +43,8 @@ import {
 } from '@alfa-client/vorgang-shared';
 import { DialogRef } from '@angular/cdk/dialog';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ButtonWithSpinnerComponent } from '@ods/component';
+import { StampIconComponent, TooltipDirective } from '@ods/system';
 import { createCommandResource } from 'libs/command-shared/test/command';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
@@ -74,8 +80,9 @@ describe('BescheidenButtonComponent', () => {
       declarations: [
         BescheidenButtonComponent,
         HasLinkPipe,
-        MockComponent(OzgcloudStrokedButtonWithSpinnerComponent),
-        MockComponent(IconButtonWithSpinnerComponent),
+        TooltipDirective,
+        MockComponent(ButtonWithSpinnerComponent),
+        MockComponent(StampIconComponent),
       ],
       providers: [
         {
@@ -107,300 +114,318 @@ describe('BescheidenButtonComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('ngOnInit', () => {
-    it('should call service', () => {
-      component.ngOnInit();
+  describe('component', () => {
+    describe('ngOnInit', () => {
+      it('should call service', () => {
+        component.ngOnInit();
 
-      expect(vorgangCommandService.getBeschiedenCommand).toHaveBeenCalled();
+        expect(vorgangCommandService.getBeschiedenCommand).toHaveBeenCalled();
+      });
     });
-  });
 
-  describe('bescheiden button', () => {
-    beforeEach(() => {
-      component.showAsIconButton = false;
-      fixture.detectChanges();
-    });
+    describe('bescheiden', () => {
+      describe('should open bescheid wizard', () => {
+        beforeEach(() => {
+          component.openBescheidenWizard = jest.fn();
+          component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT]);
+        });
 
-    it('should be hidden', () => {
-      component.vorgang = createVorgangWithEingangResource();
+        it('should open bescheid wizard when create bescheid draft link exists', () => {
+          component.bescheiden();
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(bescheidenButton);
+          expect(component.openBescheidenWizard).toHaveBeenCalled();
+        });
 
-      expect(buttonElement).not.toBeInstanceOf(HTMLElement);
-    });
+        it('should open bescheid wizard when bescheid draft exists', () => {
+          component.bescheiden();
 
-    it('should be visible', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]);
+          expect(component.openBescheidenWizard).toHaveBeenCalled();
+        });
+      });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(bescheidenButton);
+      describe('should do bescheiden', () => {
+        const command: CommandResource = createCommandResource();
+        const comandStateResource$: Observable<StateResource<CommandResource>> = of(createStateResource(command));
 
-      expect(buttonElement).toBeInstanceOf(HTMLElement);
-    });
+        beforeEach(() => {
+          vorgangCommandService.bescheiden.mockReturnValue(comandStateResource$);
+        });
 
-    it('should get "Bescheid" text', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]);
+        it('should call vorgangCommandService.bescheiden', () => {
+          component.bescheiden();
+
+          expect(vorgangCommandService.bescheiden).toHaveBeenCalled();
+        });
+
+        it('should assign response', () => {
+          component.commandStateResource$ = of(createEmptyStateResource<CommandResource>());
 
-      const buttonText: string = component.buttonText;
+          component.bescheiden();
 
-      expect(buttonText).toBe('Bescheiden');
+          expect(component.commandStateResource$).toBe(comandStateResource$);
+        });
+      });
     });
 
-    it('should get "Bescheiden fortsetzen" text', () => {
-      component.vorgang = createVorgangWithEingangResource([
-        VorgangWithEingangLinkRel.BESCHEIDEN,
-        VorgangWithEingangLinkRel.BESCHEID_DRAFT,
-      ]);
+    // TODO: Use this version after completed Bescheid refactoring and delete the other version below.
+    // describe('openBescheidenWizard', () => {
+    //   let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>;
+    //
+    //   beforeEach(() => {
+    //     dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>();
+    //     ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock);
+    //   });
+    //
+    //   it('should open wizard dialog', () => {
+    //     const vorgang = createVorgangWithEingangResource();
+    //     component.vorgang = vorgang;
+    //
+    //     component.openBescheidenWizard();
+    //
+    //     expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, {
+    //       vorgangWithEingangResource: vorgang,
+    //     });
+    //   });
+    //
+    //   it('should handleBescheidWizardClosed', () => {
+    //     component.handleBescheidWizardClosed = jest.fn();
+    //     const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true };
+    //     dialogRefMock.closed = of(dialogResult);
+    //
+    //     component.openBescheidenWizard();
+    //
+    //     expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult);
+    //   });
+    // });
+
+    describe('openBescheidenWizard', () => {
+      it('should init', () => {
+        component.openBescheidenWizard();
+
+        expect(bescheidService.init).toBeCalled();
+      });
 
-      const buttonText: string = component.buttonText;
+      it('should open bescheiden dialog with existing draft', () => {
+        component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]);
+        component.openBescheidenDialogWithExistingDraft = jest.fn();
 
-      expect(buttonText).toBe('Bescheiden fortsetzen');
-    });
-  });
+        component.openBescheidenWizard();
 
-  describe('tool tip', () => {
-    it('should get "Vorgang bescheiden" text', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]);
+        expect(component.openBescheidenDialogWithExistingDraft).toHaveBeenCalled();
+      });
 
-      const toolTipText: string = component.toolTipText;
+      it('should open bescheiden dialog with new draft', () => {
+        component.vorgang = createVorgangWithEingangResource();
+        component.openBescheidDialogWithNewDraft = jest.fn();
 
-      expect(toolTipText).toBe('Vorgang bescheiden');
+        component.openBescheidenWizard();
+
+        expect(component.openBescheidDialogWithNewDraft).toHaveBeenCalled();
+      });
     });
 
-    it('should get "Vorgang bescheiden fortsetzen" text', () => {
-      component.vorgang = createVorgangWithEingangResource([
-        VorgangWithEingangLinkRel.BESCHEIDEN,
-        VorgangWithEingangLinkRel.BESCHEID_DRAFT,
-      ]);
+    describe('openBescheidDialogWithNewDraft', () => {
+      it('should open wizard', () => {
+        component.vorgang = createVorgangWithEingangResource();
+        component.openDialog = jest.fn();
 
-      const toolTipText: string = component.toolTipText;
+        component.openBescheidDialogWithNewDraft();
 
-      expect(toolTipText).toBe('Vorgang bescheiden fortsetzen');
+        expect(component.openDialog).toHaveBeenCalledWith({
+          vorgangWithEingangResource: component.vorgang,
+          bescheidDraftResource: null,
+        });
+      });
     });
-  });
 
-  describe('bescheiden', () => {
-    describe('should open bescheid wizard', () => {
+    describe('openBescheidenDialogWithExistingDraft', () => {
+      const bescheidDraftResource: BescheidResource = createBescheidResource();
+      const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraftResource);
+      const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource([
+        VorgangWithEingangLinkRel.BESCHEID_DRAFT,
+      ]);
+
       beforeEach(() => {
-        component.openBescheidenWizard = jest.fn();
-        component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT]);
+        component.vorgang = vorgangWithEingangResource;
+        bescheidService.getBescheidDraftIfExists.mockReturnValue(of(bescheidDraftStateResource));
       });
 
-      it('should open bescheid wizard when create bescheid draft link exists', () => {
-        component.bescheiden();
+      it('should open wizard if bescheid draft loaded', () => {
+        component.openBescheidenDialogWithExistingDraft();
 
-        expect(component.openBescheidenWizard).toHaveBeenCalled();
+        expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(VorgangDetailBescheidenComponent, {
+          bescheidDraftResource,
+          vorgangWithEingangResource,
+        });
       });
 
-      it('should open bescheid wizard when bescheid draft exists', () => {
-        component.bescheiden();
-
-        expect(component.openBescheidenWizard).toHaveBeenCalled();
-      });
-    });
+      it('should not open wizard if bescheid draft not loaded', () => {
+        bescheidService.getBescheidDraftIfExists.mockReturnValue(of(createEmptyStateResource()));
 
-    describe('should do bescheiden', () => {
-      const command: CommandResource = createCommandResource();
-      const comandStateResource$: Observable<StateResource<CommandResource>> = of(createStateResource(command));
+        component.openBescheidenDialogWithExistingDraft();
 
-      beforeEach(() => {
-        vorgangCommandService.bescheiden.mockReturnValue(comandStateResource$);
+        expect(ozgcloudDialogService.openWizard).not.toHaveBeenCalled();
       });
 
-      it('should call vorgangCommandService.bescheiden', () => {
-        component.bescheiden();
+      it('should not open wizard on loading bescheid draft', () => {
+        bescheidService.getBescheidDraftIfExists.mockReturnValue(
+          of({ ...createStateResource(createBescheidResource()), loading: true }),
+        );
+
+        component.openBescheidenDialogWithExistingDraft();
 
-        expect(vorgangCommandService.bescheiden).toHaveBeenCalled();
+        expect(ozgcloudDialogService.openWizard).not.toHaveBeenCalled();
       });
+    });
 
-      it('should assign response', () => {
-        component.commandStateResource$ = of(createEmptyStateResource<CommandResource>());
+    describe('openDialog', () => {
+      const bescheidDraftResource: BescheidResource = createBescheidResource();
+      const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraftResource);
+      const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource([
+        VorgangWithEingangLinkRel.BESCHEID_DRAFT,
+      ]);
 
-        component.bescheiden();
+      const dialogData: BescheidenDialogData = {
+        bescheidDraftResource: bescheidDraftResource,
+        vorgangWithEingangResource: vorgangWithEingangResource,
+      };
 
-        expect(component.commandStateResource$).toBe(comandStateResource$);
+      beforeEach(() => {
+        component.vorgang = vorgangWithEingangResource;
+        bescheidService.getBescheidDraftIfExists.mockReturnValue(of(bescheidDraftStateResource));
       });
-    });
-  });
 
-  describe('bescheiden icon button', () => {
-    beforeEach(() => {
-      component.showAsIconButton = true;
-      fixture.detectChanges();
+      it('should call ozgcloudDialogService.openWizard', () => {
+        component.openDialog(dialogData);
+
+        expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(VorgangDetailBescheidenComponent, dialogData);
+      });
     });
 
-    it('should be hidden', () => {
-      component.vorgang = createVorgangWithEingangResource();
+    describe('handleBescheidWizardClosed', () => {
+      it('should reload current vorgang', () => {
+        component.handleBescheidWizardClosed({ reloadVorgang: true });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton);
+        expect(vorgangService.reloadCurrentVorgang).toHaveBeenCalled();
+      });
 
-      expect(buttonElement).not.toBeInstanceOf(HTMLElement);
-    });
+      it('should not reload current vorgang', () => {
+        component.handleBescheidWizardClosed({ reloadVorgang: false });
 
-    it('should be visible', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]);
+        expect(vorgangService.reloadCurrentVorgang).not.toHaveBeenCalled();
+      });
 
-      fixture.detectChanges();
-      const buttonElement = fixture.nativeElement.querySelector(bescheidenIconButton);
+      it.each([null, undefined])(
+        'should not reload current vorgang if result nil',
+        (dialogResult: BescheidWizardDialogResult) => {
+          component.handleBescheidWizardClosed(dialogResult);
 
-      expect(buttonElement).toBeInstanceOf(HTMLElement);
+          expect(vorgangService.reloadCurrentVorgang).not.toHaveBeenCalled();
+        },
+      );
     });
   });
 
-  // TODO: Use this version after completed Bescheid refactoring and delete the other version below.
-  // describe('openBescheidenWizard', () => {
-  //   let dialogRefMock: DialogRefMock<BescheidWizardDialogResult>;
-  //
-  //   beforeEach(() => {
-  //     dialogRefMock = createDialogRefMock<BescheidWizardDialogResult>();
-  //     ozgcloudDialogService.openWizard.mockReturnValue(dialogRefMock);
-  //   });
-  //
-  //   it('should open wizard dialog', () => {
-  //     const vorgang = createVorgangWithEingangResource();
-  //     component.vorgang = vorgang;
-  //
-  //     component.openBescheidenWizard();
-  //
-  //     expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(BescheidWizardContainerComponent, {
-  //       vorgangWithEingangResource: vorgang,
-  //     });
-  //   });
-  //
-  //   it('should handleBescheidWizardClosed', () => {
-  //     component.handleBescheidWizardClosed = jest.fn();
-  //     const dialogResult: BescheidWizardDialogResult = { reloadVorgang: true };
-  //     dialogRefMock.closed = of(dialogResult);
-  //
-  //     component.openBescheidenWizard();
-  //
-  //     expect(component.handleBescheidWizardClosed).toHaveBeenCalledWith(dialogResult);
-  //   });
-  // });
-
-  describe('openBescheidenWizard', () => {
-    it('should init', () => {
-      component.openBescheidenWizard();
-
-      expect(bescheidService.init).toBeCalled();
-    });
-
-    it('should open bescheiden dialog with existing draft', () => {
-      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEID_DRAFT]);
-      component.openBescheidenDialogWithExistingDraft = jest.fn();
+  describe('template', () => {
+    const state: StateResource<CommandResource> = createStateResource(createCommandResource());
 
-      component.openBescheidenWizard();
+    beforeEach(() => {
+      component.vorgang = createVorgangWithEingangResource([VorgangWithEingangLinkRel.BESCHEIDEN]);
+      component.commandStateResource$ = of(state);
 
-      expect(component.openBescheidenDialogWithExistingDraft).toHaveBeenCalled();
+      fixture.detectChanges();
     });
 
-    it('should open bescheiden dialog with new draft', () => {
-      component.vorgang = createVorgangWithEingangResource();
-      component.openBescheidDialogWithNewDraft = jest.fn();
+    describe('bescheiden button', () => {
+      beforeEach(() => {
+        component.showAsIconButton = false;
+        fixture.detectChanges();
+      });
 
-      component.openBescheidenWizard();
+      it('should not exits', () => {
+        component.vorgang = createVorgangWithEingangResource();
 
-      expect(component.openBescheidDialogWithNewDraft).toHaveBeenCalled();
-    });
-  });
+        fixture.detectChanges();
 
-  describe('openBescheidDialogWithNewDraft', () => {
-    it('should open wizard', () => {
-      component.vorgang = createVorgangWithEingangResource();
-      component.openDialog = jest.fn();
+        notExistsAsHtmlElement(fixture, bescheidenButton);
+      });
 
-      component.openBescheidDialogWithNewDraft();
+      it('should exist with input', () => {
+        const button: ButtonWithSpinnerComponent = getElementComponentFromFixtureByCss(fixture, bescheidenButton);
 
-      expect(component.openDialog).toHaveBeenCalledWith({
-        vorgangWithEingangResource: component.vorgang,
-        bescheidDraftResource: null,
+        expect(button).toBeTruthy();
+        expect(button.stateResource).toBe(state);
       });
-    });
-  });
 
-  describe('openBescheidenDialogWithExistingDraft', () => {
-    const bescheidDraftResource: BescheidResource = createBescheidResource();
-    const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraftResource);
-    const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource([
-      VorgangWithEingangLinkRel.BESCHEID_DRAFT,
-    ]);
+      it('should get "Bescheid" text', () => {
+        const button: ButtonWithSpinnerComponent = getMockComponent(fixture, ButtonWithSpinnerComponent);
+        expect(button.text).toBe('Bescheiden');
+      });
 
-    beforeEach(() => {
-      component.vorgang = vorgangWithEingangResource;
-      bescheidService.getBescheidDraftIfExists.mockReturnValue(of(bescheidDraftStateResource));
-    });
+      it('should get "Bescheiden fortsetzen" text', () => {
+        component.vorgang = createVorgangWithEingangResource([
+          VorgangWithEingangLinkRel.BESCHEIDEN,
+          VorgangWithEingangLinkRel.BESCHEID_DRAFT,
+        ]);
 
-    it('should open wizard if bescheid draft loaded', () => {
-      component.openBescheidenDialogWithExistingDraft();
+        fixture.detectChanges();
 
-      expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(VorgangDetailBescheidenComponent, {
-        bescheidDraftResource,
-        vorgangWithEingangResource,
+        const button: ButtonWithSpinnerComponent = getMockComponent(fixture, ButtonWithSpinnerComponent);
+        expect(button.text).toBe('Bescheiden fortsetzen');
       });
-    });
 
-    it('should not open wizard if bescheid draft not loaded', () => {
-      bescheidService.getBescheidDraftIfExists.mockReturnValue(of(createEmptyStateResource()));
+      it('should call bescheiden on click', () => {
+        component.bescheiden = jest.fn();
 
-      component.openBescheidenDialogWithExistingDraft();
+        triggerEvent({ fixture, name: 'clickEmitter', elementSelector: bescheidenButton });
 
-      expect(ozgcloudDialogService.openWizard).not.toHaveBeenCalled();
+        expect(component.bescheiden).toHaveBeenCalled();
+      });
     });
 
-    it('should not open wizard on loading bescheid draft', () => {
-      bescheidService.getBescheidDraftIfExists.mockReturnValue(
-        of({ ...createStateResource(createBescheidResource()), loading: true }),
-      );
-
-      component.openBescheidenDialogWithExistingDraft();
+    describe('bescheiden icon button', () => {
+      beforeEach(() => {
+        component.showAsIconButton = true;
+        fixture.detectChanges();
+      });
 
-      expect(ozgcloudDialogService.openWizard).not.toHaveBeenCalled();
-    });
-  });
+      it('should not exist', () => {
+        component.vorgang = createVorgangWithEingangResource();
 
-  describe('openDialog', () => {
-    const bescheidDraftResource: BescheidResource = createBescheidResource();
-    const bescheidDraftStateResource: StateResource<BescheidResource> = createStateResource(bescheidDraftResource);
-    const vorgangWithEingangResource: VorgangWithEingangResource = createVorgangWithEingangResource([
-      VorgangWithEingangLinkRel.BESCHEID_DRAFT,
-    ]);
+        fixture.detectChanges();
 
-    const dialogData: BescheidenDialogData = {
-      bescheidDraftResource: bescheidDraftResource,
-      vorgangWithEingangResource: vorgangWithEingangResource,
-    };
+        notExistsAsHtmlElement(fixture, bescheidenIconButton);
+      });
 
-    beforeEach(() => {
-      component.vorgang = vorgangWithEingangResource;
-      bescheidService.getBescheidDraftIfExists.mockReturnValue(of(bescheidDraftStateResource));
-    });
+      it('should exist with input', () => {
+        const button: ButtonWithSpinnerComponent = getElementComponentFromFixtureByCss(fixture, bescheidenIconButton);
 
-    it('should call ozgcloudDialogService.openWizard', () => {
-      component.openDialog(dialogData);
+        expect(button).toBeTruthy();
+        expect(button.stateResource).toBe(state);
+      });
 
-      expect(ozgcloudDialogService.openWizard).toHaveBeenCalledWith(VorgangDetailBescheidenComponent, dialogData);
-    });
-  });
+      it('should have "Vorgang bescheiden" tooltip', () => {
+        tooltipExistsWithText(fixture, bescheidenIconButton, 'Vorgang bescheiden');
+      });
 
-  describe('handleBescheidWizardClosed', () => {
-    it('should reload current vorgang', () => {
-      component.handleBescheidWizardClosed({ reloadVorgang: true });
+      it('should have "Vorgang bescheiden fortsetzen" tooltip', () => {
+        component.vorgang = createVorgangWithEingangResource([
+          VorgangWithEingangLinkRel.BESCHEIDEN,
+          VorgangWithEingangLinkRel.BESCHEID_DRAFT,
+        ]);
 
-      expect(vorgangService.reloadCurrentVorgang).toHaveBeenCalled();
-    });
+        fixture.detectChanges();
 
-    it('should not reload current vorgang', () => {
-      component.handleBescheidWizardClosed({ reloadVorgang: false });
+        tooltipExistsWithText(fixture, bescheidenIconButton, 'Vorgang bescheiden fortsetzen');
+      });
 
-      expect(vorgangService.reloadCurrentVorgang).not.toHaveBeenCalled();
-    });
+      it('should call bescheiden on click', () => {
+        component.bescheiden = jest.fn();
 
-    it.each([null, undefined])('should not reload current vorgang if result nil', (dialogResult: BescheidWizardDialogResult) => {
-      component.handleBescheidWizardClosed(dialogResult);
+        triggerEvent({ fixture, name: 'clickEmitter', elementSelector: bescheidenIconButton });
 
-      expect(vorgangService.reloadCurrentVorgang).not.toHaveBeenCalled();
+        expect(component.bescheiden).toHaveBeenCalled();
+      });
     });
   });
 });
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
index 579b092e9c..269d972319 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
@@ -70,6 +70,7 @@ import {
   SendIconComponent,
   SpinnerIconComponent,
   StampIconComponent,
+  TooltipDirective,
 } from '@ods/system';
 import { AktenzeichenEditDialogComponent } from './aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component';
 import { AktenzeichenEditableComponent } from './aktenzeichen-editable/aktenzeichen-editable.component';
@@ -179,6 +180,7 @@ const routes: Routes = [
     MoreIconComponent,
     FileIconComponent,
     ForwardByOzgcloudButtonContainerComponent,
+    TooltipDirective,
   ],
   declarations: [
     VorgangDetailPageComponent,
-- 
GitLab