diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts index 43af53698b48a680377197bdcd7093c61fdd5911..9caecfb235e5c9364a935d4ce4b5a1d690d3d86e 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts @@ -5,7 +5,7 @@ import { getCypressEnv, interceptWithResponse, waitOfInterceptor } from 'apps/ad import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component'; import { AdminUserE2E, HttpMethodE2E, SnackbarMessagesE2E } from '../../../model/util'; import { contains, notExist } from '../../../support/cypress.util'; -import { loginAsAriane } from '../../../support/user-util'; +import { loginAsAriane, loginByUsernameAndPassword } from '../../../support/user-util'; describe('Benutzer anlegen', () => { const benutzerHelper: E2EBenutzerHelper = new E2EBenutzerHelper(); @@ -13,7 +13,8 @@ describe('Benutzer anlegen', () => { const snackBar: SnackBarE2EComponent = new SnackBarE2EComponent(); - const newUser: AdminUserE2E = { + const newUserPassword: string = 'TestTestTest'; + const newAdminUser: AdminUserE2E = { vorname: 'Theo', nachname: 'Testuser', username: 'testtheo', @@ -23,6 +24,15 @@ describe('Benutzer anlegen', () => { organisationseinheiten: [], }; + const newRegularUser: AdminUserE2E = { + vorname: 'Max', + nachname: 'Mustermann', + username: 'maxmust', + email: 'max.mustermann@ozg-sh.de', + isUser: true, + organisationseinheiten: [], + }; + before(() => { loginAsAriane(); }); @@ -35,7 +45,7 @@ describe('Benutzer anlegen', () => { interceptWithResponse(HttpMethodE2E.POST, url, { errorCode, errorBody }).as(interceptor); benutzerHelper.openNewBenutzerPage(); - benutzerHelper.addBenutzer(newUser); + benutzerHelper.addBenutzer(newAdminUser); benutzerHelper.saveBenutzer(); waitOfInterceptor(interceptor).then(() => { @@ -48,7 +58,7 @@ describe('Benutzer anlegen', () => { it('should show snackbar after save', () => { benutzerHelper.openNewBenutzerPage(); - benutzerHelper.addBenutzer(newUser); + benutzerHelper.addBenutzer(newAdminUser); benutzerHelper.saveBenutzer(); contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_ANGELEGT); @@ -56,12 +66,61 @@ describe('Benutzer anlegen', () => { }); it('should show created user in list', () => { - benutzerVerifier.verifyUserInList(newUser); + benutzerVerifier.verifyUserInList(newAdminUser); }); it('should remove benutzer', () => { - benutzerHelper.deleteBenutzer(newUser.username); - benutzerVerifier.verifyUserNotInList(newUser.username); + benutzerHelper.deleteBenutzer(newAdminUser.username); + benutzerVerifier.verifyUserNotInList(newAdminUser.username); + }); + + describe('newly created admin user', () => { + it('should create new admin user', () => { + benutzerHelper.openNewBenutzerPage(); + + benutzerHelper.addBenutzer(newAdminUser); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(newAdminUser); + }); + + it('should create new regular user', () => { + benutzerHelper.openNewBenutzerPage(); + + benutzerHelper.addBenutzer(newRegularUser); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(newRegularUser); + }); + + it('should modify user', () => { + const userWithChangedFirstName = { ...newRegularUser, vorname: faker.person.firstName() }; + + benutzerHelper.activateUser(newAdminUser.username, newUserPassword).then(() => { + loginByUsernameAndPassword(newAdminUser.username, newUserPassword); + benutzerHelper.openBenutzerPage(newRegularUser.username); + + benutzerHelper.editBenutzer(userWithChangedFirstName); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(userWithChangedFirstName); + }); + }); + + it('should have rights to delete user', () => { + loginByUsernameAndPassword(newAdminUser.username, newUserPassword); + benutzerHelper.openBenutzerListPage(); + + benutzerHelper.deleteBenutzer(newRegularUser.username); + + benutzerVerifier.verifyUserNotInList(newRegularUser.username); + }); + + it('should delete user', () => { + loginAsAriane(); + + benutzerHelper.deleteBenutzer(newAdminUser.username); + }); }); describe('when filling formular', () => { diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts index a30078f194735495908baaf1d5e8e76653663cba..d6a839a2c755d0e43ab6608f1a8dcb60b57855b0 100644 --- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts @@ -1,3 +1,4 @@ +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { BenutzerDeleteDialogE2EComponent, BenutzerE2EComponent, @@ -7,6 +8,7 @@ import { SnackBarE2EComponent } from '../../components/ui/snackbar.e2e.component import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; import { AdminUserE2E } from '../../model/util'; import { exist, notExist } from '../../support/cypress.util'; +import Chainable = Cypress.Chainable; export class E2EBenutzerExecutor { private benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); @@ -74,4 +76,16 @@ export class E2EBenutzerExecutor { this.benutzerDeleteDialog.getDeleteButton().click(); exist(this.benutzerListPage.getList()); } + + public verifyEmail(userId: string): Chainable<Cypress.Response<void>> { + return cy.verifyEmail(userId); + } + + public resetPassword(userId: string, newPassword: string): Chainable<Cypress.Response<void>> { + return cy.resetPassword(userId, newPassword); + } + + public findUser(username: string): Chainable<UserRepresentation> { + return cy.findUser(username); + } } diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts index 72ef2c819e22a7e8fec59378793fed4145a80107..daf08ce5a6fb0869a60531b9a0179e44d4ce4b72 100644 --- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts @@ -1,3 +1,4 @@ +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; import { AdminUserE2E } from '../../model/util'; import { waitForSpinnerToDisappear } from '../../page-objects/main.po'; @@ -6,7 +7,7 @@ import { E2EBenutzerNavigator } from './benutzer.navigator'; export class E2EBenutzerHelper { private navigator: E2EBenutzerNavigator = new E2EBenutzerNavigator(); - private executer: E2EBenutzerExecutor = new E2EBenutzerExecutor(); + private executor: E2EBenutzerExecutor = new E2EBenutzerExecutor(); public openBenutzerListPage(): void { this.navigator.openBenutzerListPage(); @@ -35,54 +36,63 @@ export class E2EBenutzerHelper { } public editVorname(vorname: string): void { - this.executer.modifyVorname(vorname); + this.executor.modifyVorname(vorname); } public editNachname(nachname: string): void { - this.executer.modifyNachname(nachname); + this.executor.modifyNachname(nachname); } public editBenutzername(username: string): void { - this.executer.modifyBenutzername(username); + this.executor.modifyBenutzername(username); } public editEmail(email: string): void { - this.executer.modifyEmail(email); + this.executor.modifyEmail(email); } public addUserRole(): void { - this.executer.checkUserRole(); + this.executor.checkUserRole(); } private modifyBenutzer(user: AdminUserE2E): void { - this.executer.modifyBenutzer(user); + this.executor.modifyBenutzer(user); } private createBenutzer(user: AdminUserE2E): void { - this.executer.createBenutzer(user); + this.executor.createBenutzer(user); } public editOrganisationsEinheitenAndSave(organisationsEinheiten: OrganisationsEinheitE2E[]): void { - this.executer.modifyOrganisationsEinheiten(organisationsEinheiten); + this.executor.modifyOrganisationsEinheiten(organisationsEinheiten); this.saveAndCloseSnackbar(); } private saveAndCloseSnackbar(): void { - this.executer.saveAndCloseSnackbar(); + this.executor.saveAndCloseSnackbar(); } public saveBenutzer(): void { - this.executer.saveBenutzer(); + this.executor.saveBenutzer(); waitForSpinnerToDisappear(); } public deleteBenutzer(userName: string): void { this.openBenutzerPage(userName); - this.executer.deleteBenutzer(); + this.executor.deleteBenutzer(); waitForSpinnerToDisappear(); } public openBenutzerPage(userName: string): void { this.navigator.openBenutzerPage(userName); } + + public activateUser(username: string, newPassword: string): Cypress.Chainable<UserRepresentation> { + return cy + .findUser(username) + .then((userRepresentation: UserRepresentation) => cy.verifyEmail(userRepresentation.id!).then(() => userRepresentation)) + .then((userRepresentation: UserRepresentation) => + cy.resetPassword(userRepresentation.id!, newPassword).then(() => userRepresentation), + ); + } } diff --git a/alfa-client/apps/admin-e2e/src/support/commands.ts b/alfa-client/apps/admin-e2e/src/support/commands.ts index 15e9839f02fc0b236bc23a554de9caa710947cf1..5442317e9972045e9b6be4644c4bbd5621377682 100644 --- a/alfa-client/apps/admin-e2e/src/support/commands.ts +++ b/alfa-client/apps/admin-e2e/src/support/commands.ts @@ -24,8 +24,12 @@ /// <reference types="cypress" /> +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; +import { getCypressEnv } from './cypress-helper'; + enum HttpMethod { POST = 'POST', + PUT = 'PUT', GET = 'GET', } @@ -81,12 +85,57 @@ Cypress.Commands.add('getUserInfo', () => { return cy.request({ method: HttpMethod.GET, url: `${getKeycloakBaseRealmUrl()}/userinfo`, - headers: { - [Header.AUTHORIZATION]: `bearer ${window.sessionStorage.getItem(ACCES_TOKEN)}`, - }, + headers: { ...buildBearerTokenAuthorizationHeader() }, }); }); +Cypress.Commands.add('findUser', (username: string) => + cy + .request<UserRepresentation[]>({ + method: HttpMethod.GET, + url: getUsersApiUrl(), + headers: { ...buildBearerTokenAuthorizationHeader() }, + }) + .then<UserRepresentation>((response: Cypress.Response<UserRepresentation[]>) => { + const users: UserRepresentation[] = response.body; + const found: UserRepresentation | undefined = users.find((u: UserRepresentation) => u.username === username); + if (found) return found; + return Promise.reject(`User with username ${username} not found`); + }), +); + +Cypress.Commands.add('verifyEmail', (userId: string) => + cy.request<void>({ + method: HttpMethod.PUT, + url: getUsersApiUrl() + '/' + userId, + headers: { ...buildBearerTokenAuthorizationHeader() }, + body: { emailVerified: true }, + }), +); + +Cypress.Commands.add('resetPassword', (userId: string, newPassword: string) => + cy.request<void>({ + method: HttpMethod.PUT, + url: getUsersApiUrl() + '/' + userId + '/reset-password', + headers: { ...buildBearerTokenAuthorizationHeader() }, + body: { type: 'password', temporary: false, value: newPassword }, + }), +); + +function buildBearerTokenAuthorizationHeader(): object { + return { + [Header.AUTHORIZATION]: `Bearer ${getAccessToken()}`, + }; +} + +function getAccessToken(): string | null { + return window.sessionStorage.getItem(ACCES_TOKEN); +} + +function getUsersApiUrl(): string { + return getCypressEnv('keycloakUrl') + '/admin/realms/' + getCypressEnv('keycloakRealm') + '/users'; +} + function getKeycloakBaseRealmUrl(): string { return `${Cypress.env(CypressEnv.KEYCLOAK_URL)}realms/${Cypress.env(CypressEnv.KEYCLOAK_REALM)}/protocol/openid-connect`; } @@ -115,6 +164,12 @@ declare global { findElement(selector: string): Chainable<Element>; getUserInfo(): Chainable<void>; + + findUser(username: string): Chainable<UserRepresentation>; + + verifyEmail(userId: string): Chainable<Response<void>>; + + resetPassword(userId: string, password: string): Chainable<Response<void>>; } } } diff --git a/alfa-client/apps/admin-e2e/src/support/user-util.ts b/alfa-client/apps/admin-e2e/src/support/user-util.ts index 989e061babc526985e62ace05e516bdb2d058516..0b8f311d0e9cbb0e5f453ee3e7c1e72a80548529 100644 --- a/alfa-client/apps/admin-e2e/src/support/user-util.ts +++ b/alfa-client/apps/admin-e2e/src/support/user-util.ts @@ -50,15 +50,19 @@ function login(userJson: string): void { // Hinweis: cacheAcrossSpecs: true lässt Tests umfallen export function loginByUi(user: UserE2E): void { + loginByUsernameAndPassword(user.name, user.password); +} + +export function loginByUsernameAndPassword(username: string, password: string): void { cy.session( - user.name, + username, () => { cy.visit('/') .get('#kc-login') .should('exist') .then(() => { - cy.get('#username').type(user.name); - cy.get('#password').type(user.password); + cy.get('#username').type(username); + cy.get('#password').type(password); cy.get('#kc-login').click(); }); }, diff --git a/alfa-client/apps/alfa-e2e/src/components/navigation/navigation.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/navigation/navigation.e2e.component.ts index 7e1a233687f36196443be78c7d3d56c2601cc51e..5f4b16d3b7c03aaf22996fa476bcc6cde954c363 100644 --- a/alfa-client/apps/alfa-e2e/src/components/navigation/navigation.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/navigation/navigation.e2e.component.ts @@ -28,19 +28,19 @@ export class NavigationE2EComponent { private readonly locatorRoot: string = 'navigation'; - public getRoot() { + public getRoot(): Cypress.Chainable<Element> { return cy.getTestElement(this.locatorRoot); } - public getAlleFilter() { + public getAlleFilter(): Cypress.Chainable<Element> { return cy.getTestElement(this.alleFilterToggleButton); } - public getMeineVorgaengeFilter() { + public getMeineVorgaengeFilter(): Cypress.Chainable<Element> { return cy.getTestElement(this.meineVorgaengeToggleButton); } - public getUnassignedFilter() { + public getUnassignedFilter(): Cypress.Chainable<Element> { return cy.getTestElement(this.unassignedToggleButton); } } diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward-formular.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward-formular.e2e.component.ts index a4c4310c17db187a33065e33cb60e21cbff21b47..a550f4adf9a9e0a864640917ce66fcd10a42ed20 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward-formular.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward-formular.e2e.component.ts @@ -50,13 +50,7 @@ export class ForwardFormularE2EComponent { return cy.getTestElement(this.locatorZustaendigeStelleError); } - //TODO Getter draus machen und im Test den click durchführen - public forward() { - return this.getForwardButton().click(); - } - // - - private getForwardButton() { + public getForwardButton() { return cy.getTestElement(this.locatorForwardButton); } } diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward.e2e.component.ts index b6e8c7ca678c84bc16b90780b606e8858406b042..ee138ef9c37dc0daffcefd25286206011b778f2f 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forward.e2e.component.ts @@ -23,7 +23,7 @@ */ import { ForwardFormularE2EComponent } from './vorgang-forward-formular.e2e.component'; -export class VorgangForwardingE2EComponent { +export class ForwardingByEmailE2EComponent { private readonly locatorForwardingSpinner: string = 'forwarding-spinner'; private readonly locatorForwardingSuccessMessage: string = 'forwarding-success-message'; private readonly locatorForwardingErrorMessage: string = 'forwarding-error-message'; @@ -32,8 +32,7 @@ export class VorgangForwardingE2EComponent { private readonly locatorForwardingMarkAsFailButton: string = 'mark-as-fail-button'; private readonly locatorFailedMessage: string = 'failed-message'; - private readonly forwardingFormular: ForwardFormularE2EComponent = - new ForwardFormularE2EComponent(); + private readonly forwardingFormular: ForwardFormularE2EComponent = new ForwardFormularE2EComponent(); private readonly locatorRoot: string = 'forwarding'; diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forwarding-dialog.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forwarding-dialog.e2e.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f5d897628057b0c929c61fd9596ad7de3dad49a --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-forwarding-dialog.e2e.component.ts @@ -0,0 +1,51 @@ +export class ForwardingDialogE2EComponent { + private readonly root: string = 'forwarding-dialog'; + private readonly cancelButton: string = 'cancel-dialog-button'; + private readonly cancelIconButton: string = 'cancel-dialog-icon-button'; + private readonly forwardingButton: string = 'forwarding-dialog-forwarding-button'; + private readonly searchText: string = 'instant_search-text-input'; + private readonly searchEntry: string = 'item-button'; + private readonly forwardingItem: string = 'forwarding-item'; + private readonly changeButton: string = 'forwarding-item-change-button'; + private readonly zufiSearch: string = 'zufi-search'; + + public getRoot() { + return cy.getTestElement(this.root); + } + + public getCancelButton() { + return cy.getTestElement(this.cancelButton); + } + + public getCancelIconButton() { + return cy.getTestElement(this.cancelIconButton); + } + + public getForwardingButton() { + return cy.getTestElement(this.forwardingButton); + } + + public getSearchText() { + return cy.getTestElement(this.searchText); + } + + public search(text: string) { + this.getSearchText().type(text); + } + + public clickSearchEntry(index: number): void { + cy.getTestElement(this.searchEntry).eq(index).click(); + } + + public getForwardingItem() { + return cy.getTestElement(this.forwardingItem); + } + + public getChangeButton() { + return cy.getTestElement(this.changeButton); + } + + public getZufiSearch() { + return cy.getTestElement(this.zufiSearch); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts index 9ada0f2e5a1a3f6a6b52e516037e1040e5948fd0..09585caa4a0cf07a4e271b9c0f071afa5b8052da 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts @@ -23,33 +23,16 @@ */ export class VorgangViewsE2EComponent { private readonly neuViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Neu'); - private readonly angenommenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Angenommen', - ); - private readonly inBearbeitungViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'In_Bearbeitung', - ); - private readonly beschiedenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Beschieden', - ); - private readonly abgeschlossenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Abgeschlossen', - ); - private readonly verworfenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Verworfen', - ); - private readonly zuLoeschenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Zu_Loschen', - ); - private readonly ungelesenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Ungelesen', - ); - private readonly wiedervorlagenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Wiedervorlagen', - ); - private readonly vorgangListViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent( - 'Vorgangsliste', - ); + private readonly angenommenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Angenommen'); + private readonly inBearbeitungViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('In_Bearbeitung'); + private readonly beschiedenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Beschieden'); + private readonly abgeschlossenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Abgeschlossen'); + private readonly weitergeleitetViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Weitergeleitet'); + private readonly verworfenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Verworfen'); + private readonly zuLoeschenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Zu_Loschen'); + private readonly ungelesenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Ungelesen'); + private readonly wiedervorlagenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Wiedervorlagen'); + private readonly vorgangListViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Vorgangsliste'); private readonly searchViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent('Suche'); public getNeu(): VorgangViewE2EComponent { @@ -72,6 +55,10 @@ export class VorgangViewsE2EComponent { return this.abgeschlossenViewItem; } + public getWeitergeleitet(): VorgangViewE2EComponent { + return this.weitergeleitetViewItem; + } + public getVerworfen(): VorgangViewE2EComponent { return this.verworfenViewItem; } @@ -108,15 +95,15 @@ export class VorgangViewE2EComponent { this.rootId = rootId; } - public getRoot() { + public getRoot(): Cypress.Chainable<Element> { return cy.getTestElement(`${this.root}${this.rootId}`); } - public getCount() { + public getCount(): Cypress.Chainable<Element> { return this.getRoot().getTestElement(`${this.count}${this.rootId}`); } - public getButton() { + public getButton(): Cypress.Chainable<Element> { return this.getRoot().findTestElementWithClass(this.button); } } diff --git a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forward-fail.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-fail.cy.ts similarity index 76% rename from alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forward-fail.cy.ts rename to alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-fail.cy.ts index 717b730610c3be2da7d0f12e9c1f2783c553ae97..e90a6964108c52d02bd0503f615268fc50b0da5b 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forward-fail.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-fail.cy.ts @@ -21,7 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { VorgangForwardingE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; +import { ForwardFormularE2EComponent } from '../../../components/vorgang/vorgang-forward-formular.e2e.component'; +import { ForwardingByEmailE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component'; import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; @@ -32,12 +33,12 @@ import { FORWARDING_INVALID_EMAIL } from '../../../support/data.util'; import { loginAsEmil } from '../../../support/user-util'; import { createVorgang, initVorgang } from '../../../support/vorgang-util'; -describe.skip('{TODO: need to fix with a mock} Vorgang forwarding fail', () => { +describe.skip('{TODO: need to fix with a mock} Vorgang forwarding by email fail', () => { const mainPage: MainPage = new MainPage(); const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); const vorgangPage: VorgangPage = new VorgangPage(); - const forwardingContainer: VorgangForwardingE2EComponent = vorgangPage.getForwardingContainer(); + const forwardingByEmailContainer: ForwardingByEmailE2EComponent = vorgangPage.getForwardingByEmailContainer(); const vorgang: VorgangE2E = createVorgang(); @@ -60,20 +61,20 @@ describe.skip('{TODO: need to fix with a mock} Vorgang forwarding fail', () => { exist(vorgangPage.getVorgangDetailHeader().getRoot()); }); - it('should show forwarding', () => { - exist(forwardingContainer.getRoot()); + it('should show forwarding by email', () => { + exist(forwardingByEmailContainer.getRoot()); }); }); describe('fill forward formular', () => { it('should show spinner with text on valid formular', () => { - const forwardForumlar = forwardingContainer.getFormular(); + const forwardForumlar: ForwardFormularE2EComponent = forwardingByEmailContainer.getFormular(); forwardForumlar.getZustaendigeStelle().clear().type(FORWARDING_INVALID_EMAIL); forwardForumlar.getPasswort().clear().type('validespasswort'); - forwardForumlar.forward(); + forwardForumlar.getForwardButton().click(); - exist(forwardingContainer.getSpinner()); + exist(forwardingByEmailContainer.getSpinner()); }); }); @@ -81,22 +82,19 @@ describe.skip('{TODO: need to fix with a mock} Vorgang forwarding fail', () => { it('should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], () => { waitForSpinnerToDisappear(); - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); }); it('should show forward fail text', () => { - exist(forwardingContainer.getForwardingErrorMessage()); + exist(forwardingByEmailContainer.getForwardingErrorMessage()); }); it('should NOT show "mark as success" button', () => { - notExist(forwardingContainer.getMarkAsSuccessButton()); + notExist(forwardingByEmailContainer.getMarkAsSuccessButton()); }); it('should show formular', () => { - exist(forwardingContainer.getFormular().getRoot()); + exist(forwardingByEmailContainer.getFormular().getRoot()); }); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-failed-cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-failed.cy.ts similarity index 80% rename from alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-failed-cy.ts rename to alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-failed.cy.ts index f9b5af08c1bffc8e87594aa775c383a222255876..8a9bc49f7aa34bf2e1f47da5d31419bf891ea3b9 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-failed-cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email-failed.cy.ts @@ -21,7 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { VorgangForwardingE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; +import { ForwardFormularE2EComponent } from '../../../components/vorgang/vorgang-forward-formular.e2e.component'; +import { ForwardingByEmailE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component'; import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; @@ -32,12 +33,12 @@ import { FORWARDING_TEST_EMAIL } from '../../../support/data.util'; import { loginAsEmil } from '../../../support/user-util'; import { createVorgang, initVorgang } from '../../../support/vorgang-util'; -describe('Vorgang forwarding failed', () => { +describe.skip('{TODO: needs fixing} Vorgang forwarding by email failed', () => { const mainPage: MainPage = new MainPage(); const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); const vorgangPage: VorgangPage = new VorgangPage(); - const forwardingContainer: VorgangForwardingE2EComponent = vorgangPage.getForwardingContainer(); + const forwardingContainer: ForwardingByEmailE2EComponent = vorgangPage.getForwardingByEmailContainer(); const vorgang: VorgangE2E = createVorgang(); @@ -69,11 +70,11 @@ describe('Vorgang forwarding failed', () => { describe('fill forward formular', () => { it('should show spinner with text on valid formular', { defaultCommandTimeout: 30000 }, () => { - const formular = forwardingContainer.getFormular(); + const formular: ForwardFormularE2EComponent = forwardingContainer.getFormular(); formular.getZustaendigeStelle().clear().type(FORWARDING_TEST_EMAIL); formular.getPasswort().clear().type('validespasswort'); - formular.forward(); + formular.getForwardButton().click(); exist(forwardingContainer.getSpinner()); }); @@ -83,10 +84,7 @@ describe('Vorgang forwarding failed', () => { it('should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], () => { waitForSpinnerToDisappear(); - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET]); }); it('should show forward success text', () => { @@ -121,17 +119,11 @@ describe('Vorgang forwarding failed', () => { }); describe('switch to list view', () => { - it( - 'should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG] + ' in list', - () => { - vorgangPage.getSubnavigation().getBackButton().click(); - waitForSpinnerToDisappear(); - - haveText( - vorgangList.getListItem(vorgang.name).getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG], - ); - }, - ); + it('should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG] + ' in list', () => { + vorgangPage.getSubnavigation().getBackButton().click(); + waitForSpinnerToDisappear(); + + haveText(vorgangList.getListItem(vorgang.name).getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.IN_BEARBEITUNG]); + }); }); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email.cy.ts index f090dd3185bf81dffdb06b6f8f3dc48fc7f378a2..279337199a74e46b323388ba33ca09b47d7a80d6 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/einheitlicher-ansprechpartner/vorgang-detail/vorgang-forwarding-by-email.cy.ts @@ -21,32 +21,23 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { VorgangForwardingE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; +import { ForwardingByEmailE2EComponent } from '../../../components/vorgang/vorgang-forward.e2e.component'; import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component'; import { VorgangE2E, VorgangStatusE2E, vorgangStatusLabelE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; import { exist, haveText, haveValue, notExist } from '../../../support/cypress.util'; -import { - FORWARDING_INVALID_EMAIL, - FORWARDING_TEST_EMAIL, - VORGANG_ZUSTAENDIGE_STELLE_EMAIL, -} from '../../../support/data.util'; +import { FORWARDING_INVALID_EMAIL, FORWARDING_TEST_EMAIL, VORGANG_ZUSTAENDIGE_STELLE_EMAIL } from '../../../support/data.util'; import { loginAsEmil } from '../../../support/user-util'; -import { - buildVorgang, - createVorgang, - initVorgaenge, - objectIds, -} from '../../../support/vorgang-util'; - -describe.skip('Vorgang forward', () => { +import { buildVorgang, createVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util'; + +describe.skip('Vorgang forwarding by email', () => { const mainPage: MainPage = new MainPage(); const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); const vorgangPage: VorgangPage = new VorgangPage(); - const forwardingContainer: VorgangForwardingE2EComponent = vorgangPage.getForwardingContainer(); + const forwardingContainer: ForwardingByEmailE2EComponent = vorgangPage.getForwardingByEmailContainer(); const vorgang: VorgangE2E = { ...createVorgang(), name: 'TestVorgangRedirectSpinner' }; const vorgangEmpty: VorgangE2E = buildVorgang(objectIds[0], 'TestVorgangRedirectEmpty'); @@ -77,10 +68,7 @@ describe.skip('Vorgang forward', () => { }); it('should be prefilled', () => { - haveValue( - forwardingContainer.getFormular().getZustaendigeStelle(), - VORGANG_ZUSTAENDIGE_STELLE_EMAIL, - ); + haveValue(forwardingContainer.getFormular().getZustaendigeStelle(), VORGANG_ZUSTAENDIGE_STELLE_EMAIL); }); }); @@ -91,7 +79,7 @@ describe.skip('Vorgang forward', () => { forwardFormular.getZustaendigeStelle().clear().type(FORWARDING_INVALID_EMAIL); //TODO create valid email-address without adding it to landesnetzlist forwardFormular.getPasswort().clear().type('zukurz'); - forwardFormular.forward(); + forwardFormular.getForwardButton().click(); waitForSpinnerToDisappear(); exist(forwardFormular.getPasswortError()); @@ -101,7 +89,7 @@ describe.skip('Vorgang forward', () => { const forwardFormular = forwardingContainer.getFormular(); forwardFormular.getZustaendigeStelle().clear().type(FORWARDING_INVALID_EMAIL); - forwardFormular.forward(); + forwardFormular.getForwardButton().click(); waitForSpinnerToDisappear(); exist(forwardFormular.getZustaendigeStelleError()); @@ -114,7 +102,7 @@ describe.skip('Vorgang forward', () => { forwardFormular.getZustaendigeStelle().clear().type(FORWARDING_TEST_EMAIL); forwardFormular.getPasswort().clear(); - forwardFormular.forward(); + forwardFormular.getForwardButton().click(); exist(forwardingContainer.getSpinner()); }); @@ -122,18 +110,11 @@ describe.skip('Vorgang forward', () => { }); describe('success forwarding', () => { - it( - 'should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], - { defaultCommandTimeout: 30000 }, - () => { - waitForSpinnerToDisappear(); + it('should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], { defaultCommandTimeout: 30000 }, () => { + waitForSpinnerToDisappear(); - haveText( - vorgangPage.getVorgangDetailHeader().getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], - ); - }, - ); + haveText(vorgangPage.getVorgangDetailHeader().getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET]); + }); it('should show forward success text', () => { exist(forwardingContainer.getForwardingSuccessMessage()); @@ -156,18 +137,12 @@ describe.skip('Vorgang forward', () => { }); describe('switch to list view', () => { - it( - 'should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET] + ' in list', - () => { - vorgangPage.getSubnavigation().getBackButton().click(); - waitForSpinnerToDisappear(); + it('should have status ' + vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET] + ' in list', () => { + vorgangPage.getSubnavigation().getBackButton().click(); + waitForSpinnerToDisappear(); - haveText( - vorgangList.getListItem(vorgang.name).getStatus(), - vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET], - ); - }, - ); + haveText(vorgangList.getListItem(vorgang.name).getStatus(), vorgangStatusLabelE2E[VorgangStatusE2E.WEITERGELEITET]); + }); }); describe('change to non forwarding vorgang', () => { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts index a254ba3a092baa3b88fa2579ecf0399e5a83029c..c92fb955a61b78ce58d2222f12b3ff8785c04670 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts @@ -161,6 +161,12 @@ describe('VorgangList Page', () => { isKeyboardFocused(views.getAbgeschlossen().getButton()); }); + it('should focus Weitergeleitet view', () => { + pressTab(); + + isKeyboardFocused(views.getWeitergeleitet().getButton()); + }); + it('should focus Verworfen view', () => { pressTab(); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/forwarding/forwarding.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/forwarding/forwarding.cy.ts new file mode 100644 index 0000000000000000000000000000000000000000..38dc17bb68d5b4e430c6ae5c3c3cd5bbc4cb8f4c --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/forwarding/forwarding.cy.ts @@ -0,0 +1,40 @@ +import { registerLocaleData } from '@angular/common'; +import localeDe from '@angular/common/locales/de'; +import localeDeExtra from '@angular/common/locales/extra/de'; +import { E2EAppHelper } from 'apps/alfa-e2e/src/helper/app.helper'; +import { E2EForwardingHelper } from 'apps/alfa-e2e/src/helper/forwarding/forwarding.helper'; +import { E2EOrganisationsEinheit } from 'apps/alfa-e2e/src/model/organisationseinheit'; +import { E2EVorgangVerifier } from '../../../helper/vorgang/vorgang.verifier'; +import { VorgangE2E } from '../../../model/vorgang'; +import { dropCollections } from '../../../support/cypress-helper'; +import { createVorgang, initVorgang } from '../../../support/vorgang-util'; + +registerLocaleData(localeDe, 'de', localeDeExtra); + +describe('Vorgang weiterleiten', () => { + const appHelper: E2EAppHelper = new E2EAppHelper(); + + const vorgangVerifier: E2EVorgangVerifier = new E2EVorgangVerifier(); + + const forwardingHelper: E2EForwardingHelper = new E2EForwardingHelper(); + + const vorgang: VorgangE2E = { ...createVorgang(), name: 'Weiterleitung' }; + + before(() => { + initVorgang(vorgang); + + appHelper.loginAsSabine(); + }); + + after(() => { + dropCollections(); + }); + + it('should disable all functions after successfully forwarding', () => { + forwardingHelper.openForwarding(vorgang.name); + + forwardingHelper.forwardTo(E2EOrganisationsEinheit.HAMBURG_STADTENTWAESSERUNG); + + vorgangVerifier.verifyVorgangIsLocked(); + }); +}); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-forwarding.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-forwarding.cy.ts index 5130483917d42662bd3c4a806555f163d359514b..d91019905c1bc53a44fb0a28e0fb882a416933f3 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-forwarding.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-forwarding.cy.ts @@ -9,20 +9,25 @@ import { VorgangE2E } from '../../../model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po'; import { VorgangPage } from '../../../page-objects/vorgang.po'; import { dropCollections } from '../../../support/cypress-helper'; -import { exist } from '../../../support/cypress.util'; +import { beDisabled, contains, exist, notBeDisabled, notExist } from '../../../support/cypress.util'; import { loginAsPeter, loginAsSabine } from '../../../support/user-util'; import { createVorgang, initVorgaenge } from '../../../support/vorgang-util'; +import { ForwardingDialogE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-forwarding-dialog.e2e.component'; registerLocaleData(localeDe, 'de', localeDeExtra); -describe('Vorgang weiterleiten innerhalb der OzgCloud', () => { +describe('Vorgang weiterleiten', () => { const vorgangNavigator: E2EVorgangNavigator = new E2EVorgangNavigator(); const vorgangVerifier: E2EVorgangVerifier = new E2EVorgangVerifier(); const mainPage: MainPage = new MainPage(); const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList(); + const organisationsEinheitName = 'Landeshauptstadt Kiel - Pries-Friedrichsort Stadtteilamt'; + const organisationsEinheitAddress = 'An der Schanze 45, 24159 Kiel'; + const vorgangPage: VorgangPage = new VorgangPage(); + const forwardingDialog: ForwardingDialogE2EComponent = vorgangPage.getForwardingDialogContainer(); const vorgangFormularButtons: VorgangFormularButtonsE2EComponent = vorgangPage.getFormularButtons(); const vorgangWeiterleiten: VorgangE2E = { ...createVorgang(), name: 'Weiterleitung' }; @@ -48,14 +53,75 @@ describe('Vorgang weiterleiten innerhalb der OzgCloud', () => { vorgangVerifier.verifyForwardingButtonExists(); }); - it('should not display Weiterleiten button in Status Angenommen', () => { + it('should open forwarding dialog on forward button click', () => { + vorgangFormularButtons.getForwardButton().click(); + + exist(forwardingDialog.getRoot()); + }); + + it('should have zufi search', () => { + exist(forwardingDialog.getZufiSearch()); + }); + + it('should have disabled forwarding button', () => { + beDisabled(forwardingDialog.getForwardingButton()); + }); + + it('should close dialog on escape', () => { + forwardingDialog.getRoot().type('{esc}'); + + notExist(forwardingDialog.getRoot()); + }); + + it('should close dialog on abbrechen button', () => { + vorgangFormularButtons.getForwardButton().click(); + forwardingDialog.getCancelButton().click(); + + notExist(forwardingDialog.getRoot()); + }); + + it('should close dialog on x icon', () => { + vorgangFormularButtons.getForwardButton().click(); + forwardingDialog.getCancelIconButton().click(); + + notExist(forwardingDialog.getRoot()); + }); + + it('should show forwarding item on search select', () => { + vorgangFormularButtons.getForwardButton().click(); + forwardingDialog.search(organisationsEinheitName); + forwardingDialog.clickSearchEntry(0); + + exist(forwardingDialog.getForwardingItem()); + contains(forwardingDialog.getForwardingItem(), organisationsEinheitName); + contains(forwardingDialog.getForwardingItem(), organisationsEinheitAddress); + }); + + it('should not show zufi search on search select', () => { + notExist(forwardingDialog.getZufiSearch()); + }); + + it('should not disable forwarding button on search select', () => { + notBeDisabled(forwardingDialog.getForwardingButton()); + }); + + it('should clear forwarding item on change button click', () => { + forwardingDialog.getChangeButton().click(); + + notExist(forwardingDialog.getForwardingItem()); + exist(forwardingDialog.getZufiSearch()); + beDisabled(forwardingDialog.getForwardingButton()); + }); + + it('should not display Weiterleiten button in status Angenommen', () => { + forwardingDialog.getCancelButton().click(); vorgangFormularButtons.getAnnehmenButton().click(); waitForSpinnerToDisappear(); vorgangVerifier.verifyNoForwardingButtonExists(); }); - it('should not display Weiterleiten button in Status In Bearbeitung', () => { + it('should not display Weiterleiten button in status In Bearbeitung', () => { vorgangFormularButtons.getBearbeitenButton().click(); waitForSpinnerToDisappear(); @@ -68,6 +134,9 @@ describe('Vorgang weiterleiten innerhalb der OzgCloud', () => { initVorgaenge([vorgangWeiterleiten]); loginAsPeter(); + + waitForSpinnerToDisappear(); + exist(vorgangList.getRoot()); }); it('should display Weiterleiten button in Status In Neu', () => { diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-pages.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-pages.cy.ts index 1018a1081b39f524092d92c8d3449c9bdeb2d363..45a24946fded8a238f1d92fa39d4c057b28a5573 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-pages.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-pages.cy.ts @@ -30,6 +30,7 @@ import { dropCollections, intercept, scrollToWindowBottom, + scrollToWindowTop, waitOfInterceptor, } from '../../../support/cypress-helper'; import { generateIds } from '../../../support/tech.util'; @@ -72,13 +73,8 @@ describe('VorgangList Pages', () => { it('should show 1 page with 100 vorgaenge NEU', () => { waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangNEU_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangNEU_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangNEU_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangNEU_' + PAGE_SIZE); }); }); }); @@ -95,14 +91,8 @@ describe('VorgangList Pages', () => { waitOfInterceptor(loadNextPageInterceptor).then((interception: Interception) => { assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === - 'VorgangNEUAssigned_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangNEUAssigned_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangNEUAssigned_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangNEUAssigned_' + PAGE_SIZE); }); waitForSpinnerToDisappear(); }); @@ -120,14 +110,8 @@ describe('VorgangList Pages', () => { waitOfInterceptor(loadNextPageInterceptor).then((interception: Interception) => { assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === - 'VorgangANGENOMMEN_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangANGENOMMEN_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangANGENOMMEN_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangANGENOMMEN_' + PAGE_SIZE); }); waitForSpinnerToDisappear(); }); @@ -140,20 +124,18 @@ describe('VorgangList Pages', () => { intercept(HttpMethodE2E.GET, buildVorgangPageLink(4)).as(loadNextPageInterceptor); }); + after(() => { + scrollToWindowTop(); + }); + it('should show 3 page with 100 vorgaenge ANGENOMMEN ASSIGNED on scrolling to bottom', () => { scrollToWindowBottom(); waitOfInterceptor(loadNextPageInterceptor).then((interception: Interception) => { scrollToWindowBottom(); assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === - 'VorgangANGENOMMENAssigned_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangANGENOMMENAssigned_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangANGENOMMENAssigned_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangANGENOMMENAssigned_' + PAGE_SIZE); }); }); }); @@ -176,14 +158,8 @@ describe('VorgangList Pages', () => { waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === - 'VorgangNEUAssigned_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangNEUAssigned_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangNEUAssigned_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangNEUAssigned_' + PAGE_SIZE); }); }); }); @@ -195,19 +171,17 @@ describe('VorgangList Pages', () => { intercept(HttpMethodE2E.GET, buildVorgangPageLink(2)).as(loadNextPageInterceptor); }); + after(() => { + scrollToWindowTop(); + }); + it('should show 2 page with 100 vorgaenge ANGENOMMEN ASSIGNED on scrolling to bottom', () => { scrollToWindowBottom(); waitOfInterceptor(loadNextPageInterceptor).then((interception: Interception) => { assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert( - interception.response.body._embedded.vorgangHeaderList[0].name === - 'VorgangANGENOMMENAssigned_1', - ); - assert( - interception.response.body._embedded.vorgangHeaderList[99].name === - 'VorgangANGENOMMENAssigned_' + PAGE_SIZE, - ); + assert(interception.response.body._embedded.vorgangHeaderList[0].name === 'VorgangANGENOMMENAssigned_1'); + assert(interception.response.body._embedded.vorgangHeaderList[99].name === 'VorgangANGENOMMENAssigned_' + PAGE_SIZE); }); waitForSpinnerToDisappear(); }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-views-pages.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-views-pages.cy.ts index 2a2316dfc645ba0cbb99af05b34b041ce5d7646e..d8374f8aa947247e627e8d5d437f4aca9f61c9a7 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-views-pages.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-views-pages.cy.ts @@ -23,13 +23,22 @@ */ import { NavigationE2EComponent } from 'apps/alfa-e2e/src/components/navigation/navigation.e2e.component'; import { VorgangListE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-list.e2e.component'; -import { VorgangViewsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component'; +import { + VorgangViewE2EComponent, + VorgangViewsE2EComponent, +} from 'apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component'; import { MainPage, waitForSpinnerToDisappear } from 'apps/alfa-e2e/src/page-objects/main.po'; import { exist } from 'apps/alfa-e2e/src/support/cypress.util'; import { Interception } from 'cypress/types/net-stubbing'; import { HttpMethodE2E } from '../../../model/util'; import { VorgangE2E, VorgangStatusE2E } from '../../../model/vorgang'; -import { dropCollections, intercept, scrollToWindowBottom, waitOfInterceptor } from '../../../support/cypress-helper'; +import { + dropCollections, + intercept, + scrollToWindowBottom, + scrollToWindowTop, + waitOfInterceptor, +} from '../../../support/cypress-helper'; import { generateIds } from '../../../support/tech.util'; import { getUserSabineId, initUsermanagerUsers, loginAsSabine } from '../../../support/user-util'; import { buildVorgang, initVorgaenge } from '../../../support/vorgang-util'; @@ -43,6 +52,7 @@ describe('VorgangList View Pages', () => { const views: VorgangViewsE2EComponent = mainPage.getViews(); + const VORGANG_NAME_PREFIX: string = 'Vorgang'; const PAGE_SIZE: number = 100; const assignedTo: string = getUserSabineId(); @@ -57,6 +67,8 @@ describe('VorgangList View Pages', () => { createAssignedVorgaengeWithStatus(VorgangStatusE2E.BESCHIEDEN), createVorgaengeWithStatus(VorgangStatusE2E.ABGESCHLOSSEN), createAssignedVorgaengeWithStatus(VorgangStatusE2E.ABGESCHLOSSEN), + createVorgaengeWithStatus(VorgangStatusE2E.WEITERGELEITET), + createAssignedVorgaengeWithStatus(VorgangStatusE2E.WEITERGELEITET), createVorgaengeWithStatus(VorgangStatusE2E.VERWORFEN), createAssignedVorgaengeWithStatus(VorgangStatusE2E.VERWORFEN), ); @@ -73,914 +85,259 @@ describe('VorgangList View Pages', () => { }); describe('Neu', () => { - const ALLE_NAME_PREFIX: string = 'VorgangNEU_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangNEUAssigned_'; + const STATUS: string = VorgangStatusE2E.NEU; - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangNeuPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge NEU', () => { - views.getNeu().getRoot().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangNeuPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge NEU and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangNeuPageLink(3)).as(loadPageInterceptor); - }); - - it('should show page 3 with 10 vorgaenge NEU ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - function buildVorgangNeuPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=NEU`; - } - }); - - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangNeuAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge NEU', () => { - navigation.getMeineVorgaengeFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangNeuAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge NEU and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangNeuAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=NEU`; - } - }); - - describe('Nicht zugewiesen filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge NEU', () => { - navigation.getUnassignedFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, ALLE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=NEU`; - } - }); + testAlleFilter(STATUS, views.getNeu()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); }); describe('Angenommen', () => { - const ALLE_NAME_PREFIX: string = 'VorgangANGENOMMEN_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangANGENOMMENAssigned_'; - - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - navigation.getAlleFilter().click(); - waitForSpinnerToDisappear(); - intercept(HttpMethodE2E.GET, buildVorgangAngenommenPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge ANGENOMMEN', () => { - views.getAngenommen().getRoot().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge ANGENOMMEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenPageLink(3)).as(loadPageInterceptor); - }); - - it('should show page 3 with 10 vorgaenge ANGENOMMEN ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); + const STATUS: string = VorgangStatusE2E.ANGENOMMEN; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - function buildVorgangAngenommenPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=ANGENOMMEN`; - } - }); - - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge ANGENOMMEN', () => { - navigation.getMeineVorgaengeFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge ANGENOMMEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangAngenommenAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=ANGENOMMEN`; - } - }); - - describe('Nicht zugewiesen filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge ANGENOMMEN', () => { - navigation.getUnassignedFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAngenommenUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, ALLE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangAngenommenUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=ANGENOMMEN`; - } - }); + testAlleFilter(STATUS, views.getAngenommen()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); }); describe('In Bearbeitung', () => { - const ALLE_NAME_PREFIX: string = 'VorgangIN_BEARBEITUNG_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangIN_BEARBEITUNGAssigned_'; + const STATUS: string = VorgangStatusE2E.IN_BEARBEITUNG; - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - navigation.getAlleFilter().click(); - waitForSpinnerToDisappear(); - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge IN_BEARBEITUNG', () => { - views.getInBearbeitung().getRoot().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); + testAlleFilter(STATUS, views.getInBearbeitung()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); + }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + describe('Bescheiden', () => { + const STATUS: string = VorgangStatusE2E.BESCHIEDEN; - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungPageLink(2)).as(loadPageInterceptor); - }); + testAlleFilter(STATUS, views.getBeschieden()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); + }); - it('should show page 2 with 10 vorgaenge IN_BEARBEITUNG and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); + describe('Abgeschlossen', () => { + const STATUS: string = VorgangStatusE2E.ABGESCHLOSSEN; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); + testAlleFilter(STATUS, views.getAbgeschlossen()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); + }); - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; + describe('Weitergeleitet', () => { + const STATUS: string = VorgangStatusE2E.WEITERGELEITET; - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungPageLink(3)).as(loadPageInterceptor); - }); + testAlleFilter(STATUS, views.getWeitergeleitet()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); + }); - it('should show page 3 with 10 vorgaenge IN_BEARBEITUNG ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); + describe('Verworfen', () => { + const STATUS: string = VorgangStatusE2E.VERWORFEN; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); + testAlleFilter(STATUS, views.getVerworfen()); + testMeineVorgaengeFilter(STATUS); + testNichtZugewiesenFilter(STATUS); + }); - function buildVorgangInBearbeitungPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=IN_BEARBEITUNG`; - } + function testAlleFilter(status: string, view: VorgangViewE2EComponent) { + describe('Alle filter', () => { + testAlleFilterPage1(status, view); + testAlleFilterPage2(status); + testAlleFilterPage3(status); }); + } - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge IN_BEARBEITUNG', () => { - navigation.getMeineVorgaengeFilter().click(); + function testAlleFilterPage1(status: string, view: VorgangViewE2EComponent): void { + describe('page 1', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + navigation.getAlleFilter().click(); + waitForSpinnerToDisappear(); + intercept(HttpMethodE2E.GET, buildVorgangStatusPageLink(1, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + it(`should show page 1 with 100 vorgaenge ${status}`, () => { + view.getRoot().click(); - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge IN_BEARBEITUNG and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === PAGE_SIZE); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + status + 1); + assert(getVorgangList(interception)[99].name, VORGANG_NAME_PREFIX + status + PAGE_SIZE); }); }); - - function buildVorgangInBearbeitungAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=IN_BEARBEITUNG`; - } }); + } - describe('Nicht zugewiesen filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge IN_BEARBEITUNG', () => { - navigation.getUnassignedFilter().click(); + function testAlleFilterPage2(status: string): void { + describe('page 2', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangStatusPageLink(2, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + it(`should show page 2 with 10 vorgaenge ${status} and 90 vorgaenge ASSIGNED on scrolling to bottom`, () => { + scrollToWindowBottom(); - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBearbeitungUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, ALLE_NAME_PREFIX + 110); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === PAGE_SIZE); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + 1); + assert(getVorgangList(interception)[99].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + PAGE_SIZE); }); }); - - function buildVorgangInBearbeitungUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=IN_BEARBEITUNG`; - } }); - }); - - describe('Beschieden', () => { - const ALLE_NAME_PREFIX: string = 'VorgangBESCHIEDEN_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangBESCHIEDENAssigned_'; - - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - navigation.getAlleFilter().click(); - waitForSpinnerToDisappear(); - intercept(HttpMethodE2E.GET, buildVorgangBeschiedenPageLink(1)).as(loadPageInterceptor); - }); + } - it('should show page 1 with 100 vorgaenge BESCHIEDEN', () => { - views.getBeschieden().getRoot().click(); + function testAlleFilterPage3(status: string): void { + describe('page 3', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangStatusPageLink(3, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangBeschiedenPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge BESCHIEDEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); + after(() => { + scrollToWindowTop(); }); - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangBeschiedenPageLink(3)).as(loadPageInterceptor); - }); - - it('should show page 3 with 10 vorgaenge BESCHIEDEN ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); + it(`should show page 3 with 10 vorgaenge ${status} ASSIGNED on scrolling to bottom`, () => { + scrollToWindowBottom(); - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === 20); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + 80); + assert(getVorgangList(interception)[19].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + PAGE_SIZE); }); }); - - function buildVorgangBeschiedenPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=BESCHIEDEN`; - } }); + } - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBescheidenAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge BESCHIEDEN', () => { - navigation.getMeineVorgaengeFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBescheidenAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge BESCHIEDEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); - }); - }); + function buildVorgangStatusPageLink(page: number, status: string): string { + return `${buildVorgangPageLink(page)}&status=${status}`; + } - function buildVorgangInBescheidenAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=BESCHIEDEN`; - } + function testMeineVorgaengeFilter(status: string): void { + describe('Meine Vorgänge filter', () => { + testMeineVorgaengePage1(status); + testMeineVorgaengePage2(status); }); + } - describe('Nicht zugewiesen filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBescheidenUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge BESCHIEDEN', () => { - navigation.getUnassignedFilter().click(); + function testMeineVorgaengePage1(status: string): void { + describe('page 1', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangInStatusAssignedPageLink(1, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + it(`should show page 1 with 100 vorgaenge ${status}`, () => { + navigation.getMeineVorgaengeFilter().click(); - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInBescheidenUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, ALLE_NAME_PREFIX + 110); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === PAGE_SIZE); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + 'Assigned_' + 1); + assert(getVorgangList(interception)[99].name, VORGANG_NAME_PREFIX + 'Assigned_' + PAGE_SIZE); }); }); - - function buildVorgangInBescheidenUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=BESCHIEDEN`; - } }); - }); - - describe('Abgeschlossen', () => { - const ALLE_NAME_PREFIX: string = 'VorgangABGESCHLOSSEN_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangABGESCHLOSSENAssigned_'; - - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - navigation.getAlleFilter().click(); - waitForSpinnerToDisappear(); - intercept(HttpMethodE2E.GET, buildVorgangAbgeschlossenPageLink(1)).as(loadPageInterceptor); - }); + } - it('should show page 1 with 100 vorgaenge ABGESCHLOSSEN', () => { - views.getAbgeschlossen().getRoot().click(); + function testMeineVorgaengePage2(status: string): void { + describe('page 2', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangInStatusAssignedPageLink(2, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAbgeschlossenPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge ABGESCHLOSSEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); + after(() => { + scrollToWindowTop(); }); - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangAbgeschlossenPageLink(3)).as(loadPageInterceptor); - }); - - it('should show page 3 with 10 vorgaenge ABGESCHLOSSEN ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); + it(`should show page 2 with 10 vorgaenge ${status} and 90 vorgaenge ASSIGNED on scrolling to bottom`, () => { + scrollToWindowBottom(); - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === 10); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + 'Assigned_' + 101); + assert(getVorgangList(interception)[9].name, VORGANG_NAME_PREFIX + 'Assigned_' + 110); }); }); - - function buildVorgangAbgeschlossenPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=ABGESCHLOSSEN`; - } }); + } - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInAbgeschlossenAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge ABGESCHLOSSEN', () => { - navigation.getMeineVorgaengeFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInAbgeschlossenAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge ABGESCHLOSSEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangInAbgeschlossenAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=ABGESCHLOSSEN`; - } - }); + function buildVorgangInStatusAssignedPageLink(page: number, status: string): string { + return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=${status}`; + } + function testNichtZugewiesenFilter(status: string): void { describe('Nicht zugewiesen filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInAbgeschlossenUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge ABGESCHLOSSEN', () => { - navigation.getUnassignedFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInAbgeschlossenUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); - }); - }); - - function buildVorgangInAbgeschlossenUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=ABGESCHLOSSEN`; - } + testNichtZugewiesenPage1(status); + testNichtZugewiesenPage2(status); }); - }); - - describe('Verworfen', () => { - const ALLE_NAME_PREFIX: string = 'VorgangVERWORFEN_'; - const MEINE_VORGAENGE_NAME_PREFIX: string = 'VorgangVERWORFENAssigned_'; - - describe('Alle filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - navigation.getAlleFilter().click(); - waitForSpinnerToDisappear(); - intercept(HttpMethodE2E.GET, buildVorgangVerworfenPageLink(1)).as(loadPageInterceptor); - }); + } - it('should show page 1 with 100 vorgaenge VERWORFEN', () => { - views.getVerworfen().getRoot().click(); + function testNichtZugewiesenPage1(status: string): void { + describe('page 1', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangInStatusUnassignedPageLink(1, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + it(`should show page 1 with 100 vorgaeng ${status}`, () => { + navigation.getUnassignedFilter().click(); - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangVerworfenPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge VERWORFEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === PAGE_SIZE); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + 1); + assert(getVorgangList(interception)[99].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + PAGE_SIZE); }); }); - - describe('page 3', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangVerworfenPageLink(3)).as(loadPageInterceptor); - }); - - it('should show page 3 with 10 vorgaenge VERWORFEN ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 20); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 80); - assert(interception.response.body._embedded.vorgangHeaderList[19].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - function buildVorgangVerworfenPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&status=VERWORFEN`; - } }); + } - describe('Meine Vorgänge filter', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInVerworfenAssignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge VERWORFEN', () => { - navigation.getMeineVorgaengeFilter().click(); + function testNichtZugewiesenPage2(status: string): void { + describe('page 2', () => { + const loadPageInterceptor: string = 'loadPage'; - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, MEINE_VORGAENGE_NAME_PREFIX + PAGE_SIZE); - }); - }); + beforeEach(() => { + intercept(HttpMethodE2E.GET, buildVorgangInStatusUnassignedPageLink(2, status)).as(loadPageInterceptor); }); - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; + it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { + scrollToWindowBottom(); - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInVerworfenAssignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge VERWORFEN and 90 vorgaenge ASSIGNED on scrolling to bottom', () => { - scrollToWindowBottom(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, MEINE_VORGAENGE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, MEINE_VORGAENGE_NAME_PREFIX + 110); - }); + waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { + assert(getVorgangList(interception).length === 10); + assert(getVorgangList(interception)[0].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + 101); + assert(getVorgangList(interception)[9].name, VORGANG_NAME_PREFIX + status + 'Assigned_' + 110); }); + scrollToWindowTop(); }); - - function buildVorgangInVerworfenAssignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=${assignedTo}&status=VERWORFEN`; - } }); + } - describe('Nicht zugewiesen', () => { - describe('page 1', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInVerworfenUnassignedPageLink(1)).as(loadPageInterceptor); - }); - - it('should show page 1 with 100 vorgaenge VERWORFEN', () => { - navigation.getUnassignedFilter().click(); - - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === PAGE_SIZE); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 1); - assert(interception.response.body._embedded.vorgangHeaderList[99].name, ALLE_NAME_PREFIX + PAGE_SIZE); - }); - }); - }); - - describe('page 2', () => { - const loadPageInterceptor: string = 'loadPage'; - - beforeEach(() => { - intercept(HttpMethodE2E.GET, buildVorgangInVerworfenUnassignedPageLink(2)).as(loadPageInterceptor); - }); - - it('should show page 2 with 10 vorgaenge on scrolling to bottom', () => { - scrollToWindowBottom(); + function buildVorgangInStatusUnassignedPageLink(page: number, status: string): string { + return `${buildVorgangPageLink(page)}&assignedTo=&status=${status}`; + } - waitOfInterceptor(loadPageInterceptor).then((interception: Interception) => { - assert(interception.response.body._embedded.vorgangHeaderList.length === 10); - assert(interception.response.body._embedded.vorgangHeaderList[0].name, ALLE_NAME_PREFIX + 101); - assert(interception.response.body._embedded.vorgangHeaderList[9].name, ALLE_NAME_PREFIX + 110); - }); - }); - }); + function buildVorgangPageLink(page: number): string { + return `vorgangs?page=${page - 1}&limit=100`; + } - function buildVorgangInVerworfenUnassignedPageLink(page: number): string { - return `${buildVorgangPageLink(page)}&assignedTo=&status=VERWORFEN`; - } - }); - }); + function getVorgangList(interception: Interception): VorgangE2E[] { + return interception.response.body._embedded.vorgangHeaderList; + } function createVorgaengeWithStatus(status: VorgangStatusE2E): VorgangE2E[] { let count = 1; return generateIds(110).map((randomId) => { const vorgang: VorgangE2E = { - ...buildVorgang(randomId, 'Vorgang' + status + '_' + count), + ...buildVorgang(randomId, VORGANG_NAME_PREFIX + status + '_' + count), status, }; count++; @@ -992,7 +349,7 @@ describe('VorgangList View Pages', () => { let count = 1; return generateIds(110).map((randomId) => { const vorgang: VorgangE2E = { - ...buildVorgang(randomId, 'Vorgang' + status + 'Assigned_' + count), + ...buildVorgang(randomId, VORGANG_NAME_PREFIX + status + 'Assigned_' + count), status, assignedTo, }; @@ -1000,8 +357,4 @@ describe('VorgangList View Pages', () => { return vorgang; }); } - - function buildVorgangPageLink(page: number): string { - return `vorgangs?page=${page - 1}&limit=100`; - } }); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-view-wiedervorlagen.pages.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-view-wiedervorlagen.pages.cy.ts index c1ffd8afacb43b5f408688fc2da1c2a0bbe849c3..db83669a5bb144828aa67a60d4f89a8271fc8972 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-view-wiedervorlagen.pages.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-view-wiedervorlagen.pages.cy.ts @@ -31,7 +31,13 @@ import { VorgangViewsE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/v import { HttpMethodE2E } from 'apps/alfa-e2e/src/model/util'; import { ClientAttributeNameE2E, VorgangE2E } from 'apps/alfa-e2e/src/model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from 'apps/alfa-e2e/src/page-objects/main.po'; -import { dropCollections, intercept, scrollToWindowBottom, waitOfInterceptor } from 'apps/alfa-e2e/src/support/cypress-helper'; +import { + dropCollections, + intercept, + scrollToWindowBottom, + scrollToWindowTop, + waitOfInterceptor, +} from 'apps/alfa-e2e/src/support/cypress-helper'; import { exist } from 'apps/alfa-e2e/src/support/cypress.util'; import { createDateToday, generateIds } from 'apps/alfa-e2e/src/support/tech.util'; import { getUserSabineId, initUsermanagerUsers, loginAsSabine } from 'apps/alfa-e2e/src/support/user-util'; @@ -161,6 +167,10 @@ describe('VorgangList View Wiedervorlagen', () => { intercept(HttpMethodE2E.GET, buildVorgangWithOpenWiedervorlagenPageLink(3)).as(loadPageInterceptor); }); + after(() => { + scrollToWindowTop(); + }); + it('should show 3 page with 10 vorgaenge with open wiedervorlagen ASSIGNED on scrolling to bottom', () => { scrollToWindowBottom(); @@ -203,6 +213,10 @@ describe('VorgangList View Wiedervorlagen', () => { intercept(HttpMethodE2E.GET, buildVorgangWithOpenWiedervorlagenAssignedPageLink(2)).as(loadPageInterceptor); }); + after(() => { + scrollToWindowTop(); + }); + it('should show 2 page with 10 vorgaenge with open wiedervorlagen and 90 vorgaenge with open wiedervorlagen ASSIGNED on scrolling to bottom', () => { scrollToWindowBottom(); diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-views-filter.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-views-filter.cy.ts index 2547f4523c44b68ebd98dacc223c38f8db94abf0..d2b2f5c137420c986239141c7b60c4dff57868f0 100644 --- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-views-filter.cy.ts +++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-views-filter.cy.ts @@ -66,12 +66,29 @@ describe('Vorgang views and filter', () => { const inBearbeitungView: VorgangViewE2EComponent = views.getInBearbeitung(); const beschiedenView: VorgangViewE2EComponent = views.getBeschieden(); const abgeschlossenView: VorgangViewE2EComponent = views.getAbgeschlossen(); + const weitergeleitetView: VorgangViewE2EComponent = views.getWeitergeleitet(); const verworfenView: VorgangViewE2EComponent = views.getVerworfen(); const zuLoeschenView: VorgangViewE2EComponent = views.getZuLoeschen(); + const ungelesenView: VorgangViewE2EComponent = views.getUngelesen(); const wiedervorlagenView: VorgangViewE2EComponent = views.getWiedervorlagen(); const vorgangListView: VorgangViewE2EComponent = views.getVorgangList(); const sucheView: VorgangViewE2EComponent = views.getSuche(); + const ALL_VIEW_COMPONENTS: VorgangViewE2EComponent[] = [ + neuView, + angenommenView, + inBearbeitungView, + beschiedenView, + abgeschlossenView, + weitergeleitetView, + verworfenView, + zuLoeschenView, + ungelesenView, + wiedervorlagenView, + vorgangListView, + sucheView, + ]; + const navigation: NavigationE2EComponent = mainPage.getNavigation(); const vorgangNeuAssigned: VorgangE2E = { @@ -134,6 +151,16 @@ describe('Vorgang views and filter', () => { status: VorgangStatusE2E.ABGESCHLOSSEN, }; + const vorgangWeitergeleitetAssigned: VorgangE2E = { + ...buildVorgang(objectIds[13], 'VorgangWeitergeleitetAssigned'), + status: VorgangStatusE2E.WEITERGELEITET, + assignedTo: getUserSabineId(), + }; + const vorgangWeitergeleitetUnassigned: VorgangE2E = { + ...buildVorgang(objectIds[14], 'VorgangWeitergeleitetUnassigned'), + status: VorgangStatusE2E.WEITERGELEITET, + }; + const vorgangVerworfenAssigned: VorgangE2E = { ...buildVorgang(objectIds[9], 'VorgangVerworfenAssigned'), status: VorgangStatusE2E.VERWORFEN, @@ -181,6 +208,13 @@ describe('Vorgang views and filter', () => { vorgangAbgeschlossenUnassigned.name, ); + const vorgangWeitergeleitetAssignedInList: VorgangListItemE2EComponent = vorgangList.getListItem( + vorgangWeitergeleitetAssigned.name, + ); + const vorgangWeitergeleitetUnassignedInList: VorgangListItemE2EComponent = vorgangList.getListItem( + vorgangWeitergeleitetUnassigned.name, + ); + const vorgangVerworfenAssignedInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangVerworfenAssigned.name); const vorgangVerworfenUnassignedInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangVerworfenUnassigned.name); @@ -189,7 +223,7 @@ describe('Vorgang views and filter', () => { vorgangZuLoeschenUnassigned.name, ); - const LIST_SIZE: number = 14; + const LIST_SIZE: number = 16; before(() => { const vorgaenge: VorgangE2E[] = [ @@ -203,6 +237,8 @@ describe('Vorgang views and filter', () => { vorgangBeschiedenUnassigned, vorgangAbgeschlossenAssigned, vorgangAbgeschlossenUnassigned, + vorgangWeitergeleitetAssigned, + vorgangWeitergeleitetUnassigned, vorgangVerworfenAssigned, vorgangVerworfenUnassigned, vorgangZuLoeschenAssigned, @@ -214,8 +250,6 @@ describe('Vorgang views and filter', () => { initUsermanagerUsers(); loginAsSabine(); - - waitForSpinnerToDisappear(); }); after(() => { @@ -257,6 +291,7 @@ describe('Vorgang views and filter', () => { isNotSelected(inBearbeitungView.getRoot()); isNotSelected(beschiedenView.getRoot()); isNotSelected(abgeschlossenView.getRoot()); + isNotSelected(weitergeleitetView.getRoot()); isNotSelected(verworfenView.getRoot()); isNotSelected(zuLoeschenView.getRoot()); isNotSelected(sucheView.getRoot()); @@ -283,6 +318,10 @@ describe('Vorgang views and filter', () => { contains(abgeschlossenView.getCount(), '2'); }); + it('weitergeleitet', () => { + contains(abgeschlossenView.getCount(), '2'); + }); + it('verworfen', () => { contains(verworfenView.getCount(), '2'); }); @@ -300,262 +339,82 @@ describe('Vorgang views and filter', () => { describe('Select view', () => { describe('Neu', () => { - it('should set selected after click', () => { - neuView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(neuView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), 2); - exist(vorgangNeuAssignedInList.getRoot()); - exist(vorgangNeuUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(neuView, [vorgangNeuAssignedInList, vorgangNeuUnassignedInList]); }); describe('Angenommen', () => { - it('should set selected after click', () => { - angenommenView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(angenommenView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), 2); - exist(vorgangAngenommenAssignedInList.getRoot()); - exist(vorgangAngenommenUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(angenommenView, [vorgangAngenommenAssignedInList, vorgangAngenommenUnassignedInList]); }); describe('In Bearbeitung', () => { - it('should set selected after click', () => { - inBearbeitungView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(inBearbeitungView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), LIST_SIZE - 12); - exist(vorgangInBearbeitungAssignedInList.getRoot()); - exist(vorgangInBearbeitungUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(inBearbeitungView, [vorgangInBearbeitungAssignedInList, vorgangInBearbeitungUnassignedInList]); }); describe('Beschieden', () => { - it('should set selected after click', () => { - beschiedenView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(beschiedenView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), LIST_SIZE - 12); - exist(vorgangBeschiedenAssignedInList.getRoot()); - exist(vorgangBeschiedenUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(beschiedenView, [vorgangBeschiedenAssignedInList, vorgangBeschiedenUnassignedInList]); }); describe('Abgeschlossen', () => { - it('should set selected after click', () => { - abgeschlossenView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(abgeschlossenView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); + testAlleFilterViewSelection(abgeschlossenView, [vorgangAbgeschlossenAssignedInList, vorgangAbgeschlossenUnassignedInList]); + }); - it('should filter List', () => { - haveLength(vorgangList.getItems(), LIST_SIZE - 12); - exist(vorgangAbgeschlossenAssignedInList.getRoot()); - exist(vorgangAbgeschlossenUnassignedInList.getRoot()); - }); + describe('Weitergeleitet', () => { + testAlleFilterViewSelection(weitergeleitetView, [ + vorgangWeitergeleitetAssignedInList, + vorgangWeitergeleitetUnassignedInList, + ]); }); describe('Verworfen', () => { - it('should set selected after click', () => { - verworfenView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(verworfenView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), LIST_SIZE - 12); - exist(vorgangVerworfenAssignedInList.getRoot()); - exist(vorgangVerworfenUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(verworfenView, [vorgangVerworfenAssignedInList, vorgangVerworfenUnassignedInList]); }); describe('Zu Löschen', () => { - it('should set selected after click', () => { - zuLoeschenView.getRoot().click(); - waitForSpinnerToDisappear(); - - isSelected(zuLoeschenView.getRoot()); - }); - - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); - - it('should filter List', () => { - haveLength(vorgangList.getItems(), LIST_SIZE - 12); - exist(vorgangZuLoeschenAssignedInList.getRoot()); - exist(vorgangZuLoeschenUnassignedInList.getRoot()); - }); + testAlleFilterViewSelection(zuLoeschenView, [vorgangZuLoeschenAssignedInList, vorgangZuLoeschenUnassignedInList]); }); describe('Wiedervorlagen', () => { + testAlleFilterViewSelection(wiedervorlagenView, [vorgangAngenommenUnassignedInList, vorgangAbgeschlossenAssignedInList]); + }); + + function testAlleFilterViewSelection(view: VorgangViewE2EComponent, listItems: VorgangListItemE2EComponent[]): void { + testViewSelection(view); + testOtherViewsAreUnselected(view); + testAlleFilterIsSelected(); + testVorgangListItem(listItems); + } + + function testViewSelection(view: VorgangViewE2EComponent): void { it('should set selected after click', () => { - wiedervorlagenView.getRoot().click(); + view.getRoot().click(); waitForSpinnerToDisappear(); - isSelected(wiedervorlagenView.getRoot()); + isSelected(view.getRoot()); }); + } + function testOtherViewsAreUnselected(selectedView: VorgangViewE2EComponent): void { it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - isNotSelected(sucheView.getRoot()); + ALL_VIEW_COMPONENTS.filter((view: VorgangViewE2EComponent) => view != selectedView).forEach( + (view: VorgangViewE2EComponent) => isNotSelected(view.getRoot()), + ); }); + } + function testAlleFilterIsSelected(): void { it('should keep filter selection', () => { isOdsButtonToggleChecked(navigation.getAlleFilter()); isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); }); + } + function testVorgangListItem(listItems: VorgangListItemE2EComponent[]): void { it('should filter List', () => { - haveLength(vorgangList.getItems(), 2); - - exist(vorgangAngenommenUnassignedInList.getRoot()); - exist(vorgangAbgeschlossenAssignedInList.getRoot()); + haveLength(vorgangList.getItems(), LIST_SIZE - 14); + listItems.forEach((item: VorgangListItemE2EComponent) => exist(item.getRoot())); }); - }); + } describe('VorgangList', () => { it('should set selected after click', () => { @@ -571,6 +430,7 @@ describe('Vorgang views and filter', () => { isNotSelected(inBearbeitungView.getRoot()); isNotSelected(beschiedenView.getRoot()); isNotSelected(abgeschlossenView.getRoot()); + isNotSelected(weitergeleitetView.getRoot()); isNotSelected(zuLoeschenView.getRoot()); isNotSelected(verworfenView.getRoot()); isNotSelected(sucheView.getRoot()); @@ -595,22 +455,8 @@ describe('Vorgang views and filter', () => { isSelected(sucheView.getRoot()); }); - it('should unselect other views', () => { - isNotSelected(neuView.getRoot()); - isNotSelected(angenommenView.getRoot()); - isNotSelected(inBearbeitungView.getRoot()); - isNotSelected(beschiedenView.getRoot()); - isNotSelected(abgeschlossenView.getRoot()); - isNotSelected(zuLoeschenView.getRoot()); - isNotSelected(verworfenView.getRoot()); - isNotSelected(vorgangListView.getRoot()); - }); - - it('should keep filter selection', () => { - isOdsButtonToggleChecked(navigation.getAlleFilter()); - isOdsButtonToggleNotChecked(navigation.getMeineVorgaengeFilter()); - isOdsButtonToggleNotChecked(navigation.getUnassignedFilter()); - }); + testOtherViewsAreUnselected(sucheView); + testAlleFilterIsSelected(); it('should show message', () => { haveText(vorgangList.getEmptySucheMessage(), 'Bitte geben Sie einen Suchbegriff ein.'); @@ -643,6 +489,7 @@ describe('Vorgang views and filter', () => { isNotSelected(inBearbeitungView.getRoot()); isNotSelected(beschiedenView.getRoot()); isNotSelected(abgeschlossenView.getRoot()); + isNotSelected(weitergeleitetView.getRoot()); isNotSelected(verworfenView.getRoot()); isNotSelected(zuLoeschenView.getRoot()); isNotSelected(vorgangListView.getRoot()); @@ -892,11 +739,11 @@ describe('Vorgang views and filter', () => { vorgangSearch.doSearch(searchString); } - function isNotSelected(element) { + function isNotSelected(element: Cypress.Chainable<Element>): void { notContainClass(element, 'selected'); } - function isSelected(element) { + function isSelected(element: Cypress.Chainable<Element>): void { containClass(element, 'selected'); } }); diff --git a/alfa-client/apps/alfa-e2e/src/helper/app.helper.ts b/alfa-client/apps/alfa-e2e/src/helper/app.helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..e264eb98df16537f69c250fa09252c35346c43b8 --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/helper/app.helper.ts @@ -0,0 +1,23 @@ +import { VorgangListE2EComponent } from '../components/vorgang/vorgang-list.e2e.component'; +import { MainPage, waitForSpinnerToDisappear } from '../page-objects/main.po'; +import { exist } from '../support/cypress.util'; +import { loginAsSabine } from '../support/user-util'; + +export class E2EAppHelper { + private readonly mainPage: MainPage = new MainPage(); + private readonly vorgangList: VorgangListE2EComponent = new VorgangListE2EComponent(); + + public loginAsSabine(): void { + loginAsSabine(); + this.waitAfterLogin(); + } + + private waitAfterLogin(): void { + waitForSpinnerToDisappear(); + exist(this.vorgangList.getRoot()); + } + + public navigateToDomain(): void { + this.mainPage.getHeader().getLogo().click(); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.executor.ts b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.executor.ts new file mode 100644 index 0000000000000000000000000000000000000000..22295bb180d00c9d23b787fde72a001bea29cab2 --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.executor.ts @@ -0,0 +1,16 @@ +import { ForwardingDialogE2EComponent } from '../../components/vorgang/vorgang-forwarding-dialog.e2e.component'; +import { waitForSpinnerToDisappear } from '../../page-objects/main.po'; +import { exist } from '../../support/cypress.util'; + +export class E2EForwardingExecutor { + private readonly forwardingDialog = new ForwardingDialogE2EComponent(); + + public fillForwardingDialog(organisationsEinheit: string): void { + this.forwardingDialog.getSearchText().type(organisationsEinheit); + waitForSpinnerToDisappear(); + this.forwardingDialog.clickSearchEntry(0); + exist(this.forwardingDialog.getForwardingItem()); + this.forwardingDialog.getForwardingButton().click(); + waitForSpinnerToDisappear(); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.helper.ts b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..408faf920fba169b3a69908575d7d422e2cf743d --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.helper.ts @@ -0,0 +1,15 @@ +import { E2EForwardingExecutor } from './forwarding.executor'; +import { E2EForwardingNavigator } from './forwarding.navigator'; + +export class E2EForwardingHelper { + private readonly executor: E2EForwardingExecutor = new E2EForwardingExecutor(); + private readonly navigator: E2EForwardingNavigator = new E2EForwardingNavigator(); + + public openForwarding(vorgangName: string): void { + this.navigator.openForwardDialog(vorgangName); + } + + public forwardTo(organisationsEinheit: string): void { + this.executor.fillForwardingDialog(organisationsEinheit); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.navigator.ts b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.navigator.ts new file mode 100644 index 0000000000000000000000000000000000000000..3400d79516d98512531d28f43b8575f583a5d0f4 --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/helper/forwarding/forwarding.navigator.ts @@ -0,0 +1,17 @@ +import { VorgangFormularButtonsE2EComponent } from '../../components/vorgang/vorgang-formular-buttons.e2e.components'; +import { ForwardingDialogE2EComponent } from '../../components/vorgang/vorgang-forwarding-dialog.e2e.component'; +import { exist } from '../../support/cypress.util'; +import { E2EVorgangNavigator } from '../vorgang/vorgang.navigator'; + +export class E2EForwardingNavigator { + private readonly vorgangNavigator: E2EVorgangNavigator = new E2EVorgangNavigator(); + + private readonly formularButtons: VorgangFormularButtonsE2EComponent = new VorgangFormularButtonsE2EComponent(); + private readonly forwardingDialog: ForwardingDialogE2EComponent = new ForwardingDialogE2EComponent(); + + public openForwardDialog(vorgangName: string): void { + this.vorgangNavigator.openVorgangDetailByName(vorgangName); + this.formularButtons.getForwardButton().click(); + exist(this.forwardingDialog.getRoot()); + } +} diff --git a/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.navigator.ts b/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.navigator.ts index 7b4fc54b196ff4dc2c83ffbf029a8b063c6b1054..3225f82b8ac3c2dd7158bbc00e1499f30c0f4c14 100644 --- a/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.navigator.ts +++ b/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.navigator.ts @@ -1,8 +1,12 @@ import { VorgangListE2EComponent } from '../../components/vorgang/vorgang-list.e2e.component'; import { waitForSpinnerToDisappear } from '../../page-objects/main.po'; +import { exist } from '../../support/cypress.util'; +import { E2EAppHelper } from '../app.helper'; import { E2EVorgangVerifier } from './vorgang.verifier'; export class E2EVorgangNavigator { + private readonly appHelper: E2EAppHelper = new E2EAppHelper(); + private readonly verifier: E2EVorgangVerifier = new E2EVorgangVerifier(); private readonly vorgangListPage = new VorgangListE2EComponent(); @@ -12,4 +16,11 @@ export class E2EVorgangNavigator { waitForSpinnerToDisappear(); this.verifier.verifyVorgangDetailOpen(vorgangName); } + + public openVorgang(vorgangName: string): void { + this.appHelper.navigateToDomain(); + waitForSpinnerToDisappear(); + exist(this.vorgangListPage.getRoot()); + this.openVorgangDetailByName(vorgangName); + } } diff --git a/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.verifier.ts b/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.verifier.ts index c42945065f7c18f03c4f74fbcbf2809c9b2a8021..d8e8e39394686a7a4414a6d38564e69c5969f6f0 100644 --- a/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.verifier.ts +++ b/alfa-client/apps/alfa-e2e/src/helper/vorgang/vorgang.verifier.ts @@ -1,8 +1,10 @@ +import { VorgangFormularButtonsE2EComponent } from '../../components/vorgang/vorgang-formular-buttons.e2e.components'; import { VorgangPage } from '../../page-objects/vorgang.po'; import { contains, exist, notExist } from '../../support/cypress.util'; export class E2EVorgangVerifier { private readonly vorgangPage: VorgangPage = new VorgangPage(); + private readonly formularButtons: VorgangFormularButtonsE2EComponent = new VorgangFormularButtonsE2EComponent(); public verifyVorgangDetailOpen(vorgangName: string): void { exist(this.vorgangPage.getVorgangDetailHeader().getRoot()); @@ -16,4 +18,25 @@ export class E2EVorgangVerifier { public verifyNoForwardingButtonExists(): void { notExist(this.vorgangPage.getFormularButtons().getForwardButton()); } + + public verifyVorgangIsLocked(): void { + this.verifyFormularButtonsNotVisible(); + notExist(this.vorgangPage.getWiedervorlagenContainer().getCreateWiedervorlageButton()); + notExist(this.vorgangPage.getKommentarContainer().getHinzufuegenButton()); + notExist(this.vorgangPage.getPostfachMailcontainer().getCreateButtonWithText()); + notExist(this.vorgangPage.getPostfachMailcontainer().getCreateButtonWithoutText()); + } + + private verifyFormularButtonsNotVisible(): void { + notExist(this.formularButtons.getAbschliessenButton()); + notExist(this.formularButtons.getBearbeitenButton()); + notExist(this.formularButtons.getBescheidenButton()); + notExist(this.formularButtons.getEndgueltigLoeschenButton()); + notExist(this.formularButtons.getForwardButton()); + notExist(this.formularButtons.getLoeschAnforderungZuruecknehmenButton()); + notExist(this.formularButtons.getVerwerfenButton()); + notExist(this.formularButtons.getWiedereroeffnenButton()); + notExist(this.formularButtons.getZurueckholenButton()); + notExist(this.formularButtons.getZurueckstellenButton()); + } } diff --git a/alfa-client/apps/alfa-e2e/src/model/organisationseinheit.ts b/alfa-client/apps/alfa-e2e/src/model/organisationseinheit.ts new file mode 100644 index 0000000000000000000000000000000000000000..302f3c401870a6951537a8fceeea96760e239abf --- /dev/null +++ b/alfa-client/apps/alfa-e2e/src/model/organisationseinheit.ts @@ -0,0 +1,3 @@ +export enum E2EOrganisationsEinheit { + HAMBURG_STADTENTWAESSERUNG = 'Wasserwerk - Hamburg Wasser - Hamburger Stadtentwässerung', +} diff --git a/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts b/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts index 6a1d1b397b3e0a9eb91362cd0220230b67a5db14..8a2647fd1d0a8b47aaf41cd8e007177991b1fe1f 100644 --- a/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts +++ b/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts @@ -33,7 +33,8 @@ import { VorgangBescheideE2EComponent } from '../components/vorgang/vorgang-besc import { VorgangDetailHeaderE2EComponent } from '../components/vorgang/vorgang-detail-header.e2e.component'; import { VorgangFormularButtonsE2EComponent } from '../components/vorgang/vorgang-formular-buttons.e2e.components'; import { VorgangFormularDatenE2EComponent } from '../components/vorgang/vorgang-formular.e2e.component'; -import { VorgangForwardingE2EComponent } from '../components/vorgang/vorgang-forward.e2e.component'; +import { ForwardingByEmailE2EComponent } from '../components/vorgang/vorgang-forward.e2e.component'; +import { ForwardingDialogE2EComponent } from '../components/vorgang/vorgang-forwarding-dialog.e2e.component'; import { VorgangMoreMenuE2EComponent } from '../components/vorgang/vorgang-more-menu.e2e.components'; import { VorgangSubnavigationE2EComponent } from '../components/vorgang/vorgang-subnavigation'; import { VorgangZusammenarbeitE2EComponent } from '../components/vorgang/vorgang-zusammenarbeit.e2e.component'; @@ -49,7 +50,8 @@ export class VorgangPage { private readonly bescheidWizard: VorgangBescheidWizardE2EComponent = new VorgangBescheidWizardE2EComponent(); private readonly bescheide: VorgangBescheideE2EComponent = new VorgangBescheideE2EComponent(); private readonly wiedervorlagen: WiedervorlagenInVorgangE2EComponent = new WiedervorlagenInVorgangE2EComponent(); - private readonly forwardingContainer: VorgangForwardingE2EComponent = new VorgangForwardingE2EComponent(); + private readonly forwardingDialogContainer: ForwardingDialogE2EComponent = new ForwardingDialogE2EComponent(); + private readonly forwardingByEmailContainer: ForwardingByEmailE2EComponent = new ForwardingByEmailE2EComponent(); private readonly attachmentContainer: AttachmentContainerE2EComponent = new AttachmentContainerE2EComponent(); private readonly kommentarContainer: KommentarListInVorgangE2EComponent = new KommentarListInVorgangE2EComponent(); private readonly postfachMailContainer: PostfachMailE2EComponent = new PostfachMailE2EComponent(); @@ -66,8 +68,12 @@ export class VorgangPage { return this.kommentarContainer; } - public getForwardingContainer(): VorgangForwardingE2EComponent { - return this.forwardingContainer; + public getForwardingDialogContainer(): ForwardingDialogE2EComponent { + return this.forwardingDialogContainer; + } + + public getForwardingByEmailContainer(): ForwardingByEmailE2EComponent { + return this.forwardingByEmailContainer; } public getSubnavigation(): VorgangSubnavigationE2EComponent { diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress-helper.ts b/alfa-client/apps/alfa-e2e/src/support/cypress-helper.ts index b4f477e2422f3bd0ea391d7d3259c29bd4b2a8a6..9e520f34e3c7641fc9dd0c0b2d6d4ff25ac39ab0 100644 --- a/alfa-client/apps/alfa-e2e/src/support/cypress-helper.ts +++ b/alfa-client/apps/alfa-e2e/src/support/cypress-helper.ts @@ -28,6 +28,7 @@ import { SmockerMocks } from '../model/smocker'; import { UsermanagerUserE2E } from '../model/usermanager'; import { VorgangE2E } from '../model/vorgang'; import { VorgangAttachedItemE2E } from '../model/vorgang-attached-item'; +import { waitForSpinnerToDisappear } from '../page-objects/main.po'; enum CypressTasks { DROP_COLLECTIONS = 'dropCollections', @@ -62,6 +63,7 @@ export function login(userJsonPath: string): void { cy.fixture(userJsonPath).then((user) => { cy.login(user.name, user.password); }); + waitForSpinnerToDisappear(); } export function visitUrl(url: string): void { @@ -170,6 +172,10 @@ export function scrollToWindowBottom(): void { cy.window().scrollTo('bottom'); } +export function scrollToWindowTop(): void { + cy.window().scrollTo('top'); +} + export function intercept(method: string, url: string): Cypress.Chainable<null> { return cy.intercept(method, url); } diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts index 3dbd6155939b778a411f9b2fd18822286feaf958..f62a66e73e504ddd9952afd438ecdd7cf242866a 100644 --- a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts +++ b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts @@ -97,6 +97,14 @@ export function notBeChecked(element: any): void { element.should('not.be.checked'); } +export function beDisabled(element: any): void { + element.should('be.disabled'); +} + +export function notBeDisabled(element: any): void { + element.should('not.be.disabled'); +} + //TODO: "first()" rausnehmen -> im html eine entprechende data-test-id ansprechen?! | trennen in "get" und "verify" export function shouldFirstContains(element: any, containing: string) { element.first().should('exist').contains(containing); diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a2a5d7eabcfd524c1846a53c47f4d31d54f75a1 --- /dev/null +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts @@ -0,0 +1,12 @@ +export const KeycloakDefaults = { + clients: { + realmManagement: { + clientName: 'realm-management', + roles: { + managerUsers: { roleName: 'manage-users' }, + queryGroups: { roleName: 'query-groups' }, + viewClients: { roleName: 'view-clients' }, + }, + }, + }, +}; diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.spec.ts index 329afd1ac13860890e154f28b5eda68a6636a93c..99426f1a908aa57d206ebc0d9880d1d20b08bcd8 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.spec.ts @@ -24,13 +24,14 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; import { cold } from 'jest-marbles'; -import * as ResourceUtil from 'libs/tech-shared/src/lib/resource/resource.util'; import { createEmptyStateResource, createStateResource, StateResource } from 'libs/tech-shared/src/lib/resource/resource.util'; import { createDummy, Dummy } from 'libs/tech-shared/test/dummy'; import { singleCold } from 'libs/tech-shared/test/marbles'; import { Observable, of, throwError } from 'rxjs'; import { KeycloakResourceService } from './keycloak.resource.service'; +import * as ResourceUtil from 'libs/tech-shared/src/lib/resource/resource.util'; + describe('KeycloakResourceService', () => { let service: KeycloakResourceService<unknown>; @@ -39,6 +40,9 @@ describe('KeycloakResourceService', () => { const dummyObject: Dummy = createDummy(); const dummyAction: Observable<Dummy> = of(dummyObject); + const dummyError: Error = new Error('Test error'); + const dummyErrorAction: Observable<Error> = new Observable((observer) => observer.error(dummyError)); + beforeEach(() => { TestBed.configureTestingModule({ providers: [TestResourceService], @@ -51,7 +55,7 @@ describe('KeycloakResourceService', () => { const stateResource: StateResource<unknown> = createStateResource([]); beforeEach(() => { - service.handleChanges = jest.fn().mockReturnValue(singleCold(stateResource)); + service._handleChanges = jest.fn().mockReturnValue(singleCold(stateResource)); }); it('should return stateResource', () => { @@ -63,7 +67,7 @@ describe('KeycloakResourceService', () => { it('should call handleChanges ', fakeAsync(() => { service.getAll().subscribe(); - expect(service.handleChanges).toHaveBeenCalled(); + expect(service._handleChanges).toHaveBeenCalled(); })); }); @@ -75,7 +79,7 @@ describe('KeycloakResourceService', () => { }); it('should call doIfLoadingRequired', () => { - service.handleChanges(emptyStateResource); + service._handleChanges(emptyStateResource); expect(doIfLoadingRequiredSpy).toHaveBeenCalled(); }); @@ -83,7 +87,7 @@ describe('KeycloakResourceService', () => { it('should return stateResource', (done) => { service.stateResource.next(createStateResource([])); - service.handleChanges(emptyStateResource).subscribe((stateResource: StateResource<[]>) => { + service._handleChanges(emptyStateResource).subscribe((stateResource: StateResource<[]>) => { expect(stateResource).toEqual(createStateResource([])); done(); }); @@ -92,18 +96,18 @@ describe('KeycloakResourceService', () => { describe('loadResource', () => { it('should call set loading', () => { - service.setLoading = jest.fn(); + service._setLoading = jest.fn(); - service.loadResource(); + service._loadResource(); - expect(service.setLoading).toHaveBeenCalled(); + expect(service._setLoading).toHaveBeenCalled(); }); it('should update Resource', fakeAsync(() => { const dummyItems = [createDummy(), createDummy()]; jest.spyOn(service, '_getItemsFromKeycloak' as any).mockReturnValue(of(dummyItems)); - service.loadResource(); + service._loadResource(); tick(); expect(service.stateResource.value.resource).toEqual(dummyItems); @@ -114,11 +118,11 @@ describe('KeycloakResourceService', () => { const saveObject: Dummy = createDummy(); it('should call handleLoading', () => { - service.handleLoading = jest.fn(); + service._handleLoading = jest.fn(); service.create(saveObject); - expect(service.handleLoading).toHaveBeenCalled(); + expect(service._handleLoading).toHaveBeenCalled(); }); it('should call createInKeycloak', () => { @@ -132,11 +136,11 @@ describe('KeycloakResourceService', () => { describe('save', () => { it('should call handleLoading', () => { - service.handleLoading = jest.fn(); + service._handleLoading = jest.fn(); service.save(dummyObject); - expect(service.handleLoading).toHaveBeenCalled(); + expect(service._handleLoading).toHaveBeenCalled(); }); it('should call createInKeycloak', () => { @@ -150,11 +154,11 @@ describe('KeycloakResourceService', () => { describe('delete', () => { it('should call handleLoading', () => { - service.handleLoading = jest.fn(); + service._handleLoading = jest.fn(); service.delete(id); - expect(service.handleLoading).toHaveBeenCalled(); + expect(service._handleLoading).toHaveBeenCalled(); }); it('should call createInKeycloak', () => { @@ -168,42 +172,41 @@ describe('KeycloakResourceService', () => { describe('handleLoading', () => { it('should set loading', () => { - service.handleLoading(dummyAction); + service._handleLoading(dummyAction); expect(service.stateResource.value.loading).toBe(true); }); it('should call refreshAfterFirstEmit', () => { - service.refreshAfterFirstEmit = jest.fn().mockReturnValue(dummyAction); + service._refreshAfterEmit = jest.fn().mockReturnValue(dummyAction); - service.handleLoading(dummyAction); + service._handleLoading(dummyAction); - expect(service.refreshAfterFirstEmit).toHaveBeenCalled(); + expect(service._refreshAfterEmit).toHaveBeenCalled(); }); it('should call progress', () => { - service.setLoadingInStateResource = jest.fn().mockReturnValue(dummyAction); + service._setLoadingInStateResource = jest.fn().mockReturnValue(dummyAction); - service.handleLoading(dummyAction); + service._handleLoading(dummyAction); - expect(service.setLoadingInStateResource).toHaveBeenCalled(); + expect(service._setLoadingInStateResource).toHaveBeenCalled(); }); }); - describe('refreshAfterFirstEmit', () => { - it('should call refresh after first emit', fakeAsync(() => { + describe('refreshAfterEmit', () => { + it('should call refresh after first emit', () => { service.refresh = jest.fn(); - service.refreshAfterFirstEmit(dummyAction).subscribe(); - tick(); + service._refreshAfterEmit(dummyAction).subscribe(); expect(service.refresh).toHaveBeenCalled(); - })); + }); it('should call refresh on error', () => { service.refresh = jest.fn(); - service.refreshAfterFirstEmit(throwError(() => new Error('dummy'))).subscribe(); + service._refreshAfterEmit(dummyErrorAction).subscribe(); expect(service.refresh).toHaveBeenCalled(); }); @@ -212,13 +215,21 @@ describe('KeycloakResourceService', () => { const error = new Error('dummy'); service.refresh = jest.fn(); - expect(service.refreshAfterFirstEmit(throwError(() => error))).toBeObservable(cold('#', null, error)); + expect(service._refreshAfterEmit(throwError(() => error))).toBeObservable(cold('#', null, error)); + }); + + it('should throw error refresh on error', () => { + service.refresh = jest.fn(); + + const result: Observable<unknown> = service._refreshAfterEmit(dummyErrorAction); + + expect(result).toBeObservable(cold('#', null, dummyError)); }); }); describe('setLoadingInStateResource', () => { it('should emit emptyState first with loading and then state without loading', () => { - const result: Observable<StateResource<Dummy>> = service.setLoadingInStateResource<Dummy>(cold('--x', { x: dummyObject })); + const result: Observable<StateResource<Dummy>> = service._setLoadingInStateResource<Dummy>(cold('--x', { x: dummyObject })); expect(result).toBeObservable(cold('a-b', { a: createEmptyStateResource(true), b: createStateResource(dummyObject) })); }); @@ -228,7 +239,7 @@ describe('KeycloakResourceService', () => { it('should set loading in state to true without parameter', () => { service.stateResource.value.loading = false; - service.setLoading(); + service._setLoading(); expect(service.stateResource.value.loading).toEqual(true); }); diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.ts index 8bd44d4254e2c76237fcdf1e2cd47f6181790afc..9e8f1f7828f030c702b617414ff8f46ad0de23dc 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.resource.service.ts @@ -30,16 +30,16 @@ export abstract class KeycloakResourceService<T> { public getAll(): Observable<StateResource<T[]>> { return this.stateResource .asObservable() - .pipe(switchMap((stateResource: StateResource<T[]>) => this.handleChanges(stateResource))); + .pipe(switchMap((stateResource: StateResource<T[]>) => this._handleChanges(stateResource))); } - handleChanges(stateResource: StateResource<T[]>): Observable<StateResource<T[]>> { - doIfLoadingRequired(stateResource, (): void => this.loadResource()); + _handleChanges(stateResource: StateResource<T[]>): Observable<StateResource<T[]>> { + doIfLoadingRequired(stateResource, (): void => this._loadResource()); return this.stateResource.asObservable(); } - loadResource(): void { - this.setLoading(); + _loadResource(): void { + this._setLoading(); this._getItemsFromKeycloak() .pipe(first()) .subscribe((items: T[]): void => this.updateResource(items)); @@ -52,47 +52,52 @@ export abstract class KeycloakResourceService<T> { } public create(item: Partial<T>): Observable<StateResource<T>> { - return this.handleLoading<T>(this._createInKeycloak(item)); + return this._handleLoading<T>(this._createInKeycloak(item)); } protected abstract _createInKeycloak(item: Partial<T>): Observable<T>; public save(item: T): Observable<StateResource<T>> { - return this.handleLoading<T>(this._saveInKeycloak(item)); + return this._handleLoading<T>(this._saveInKeycloak(item)); } protected abstract _saveInKeycloak(item: T): Observable<T>; public delete(id: string): Observable<StateResource<void>> { - return this.handleLoading(this._deleteInKeycloak(id)); + return this._handleLoading(this._deleteInKeycloak(id)); } protected abstract _deleteInKeycloak(id: string): Observable<void>; - handleLoading<D>(action: Observable<D>): Observable<StateResource<D>> { - this.setLoading(); - return this.setLoadingInStateResource<D>(this.refreshAfterFirstEmit<D>(action)); + _handleLoading<D>(action: Observable<D>): Observable<StateResource<D>> { + this._setLoading(); + return this._setLoadingInStateResource<D>(this._refreshAfterEmit<D>(action)); } - refreshAfterFirstEmit<D>(action: Observable<D>): Observable<D> { + _refreshAfterEmit<D>(action: Observable<D>): Observable<D> { return action.pipe( first(), tap((): void => this.refresh()), catchError((err) => { this.refresh(); - return throwError(() => err); + return this._handleError(err); }), ); } - setLoadingInStateResource<D>(action: Observable<D>): Observable<StateResource<D>> { + _handleError(err: Error): Observable<never> { + this.refresh(); + return throwError(() => err); + } + + _setLoadingInStateResource<D>(action: Observable<D>): Observable<StateResource<D>> { return action.pipe( map((value: D): StateResource<D> => createStateResource<D>(value)), startWith(createEmptyStateResource<D>(true)), ); } - setLoading(): void { + _setLoading(): void { this.stateResource.next({ ...this.stateResource.value, loading: true }); } diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts index 471464d347e7e7ed589453ce8347f04d7ff52529..8508ad1aad9980fca4502a94f84a2591c77bf814 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts @@ -21,21 +21,24 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { RoleMappings, User } from '@admin-client/user-shared'; +import { AdminRoles, RoleMappings, User } from '@admin-client/user-shared'; import { UserRepository } from '@admin/keycloak-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; +import { expect } from '@jest/globals'; import KcAdminClient from '@keycloak/keycloak-admin-client'; import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation'; +import { RequiredActionAlias } from '@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation'; import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation'; import { Users } from '@keycloak/keycloak-admin-client/lib/resources/users'; import { cold } from 'jest-marbles'; import { omit, times } from 'lodash-es'; import { createUser } from '../../../user-shared/test/user'; import { UserFormService } from '../../../user/src/lib/user-form/user.formservice'; +import { KeycloakDefaults } from './keycloak.model'; describe('UserRepository', () => { let repository: UserRepository; @@ -509,6 +512,50 @@ describe('UserRepository', () => { }); }); + describe('update user roles for admin', () => { + const clientId: string = faker.string.uuid(); + + beforeEach(() => { + repository._updateUserRolesForClient = jest.fn(); + repository._getClientId = jest.fn().mockReturnValue(new Promise((resolve) => resolve(clientId))); + }); + + it('should get client id', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [AdminRoles.ADMIN], + alfa: [], + }); + + expect(repository._getClientId).toHaveBeenCalledWith(KeycloakDefaults.clients.realmManagement.clientName); + }); + + it('should update user roles', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [AdminRoles.ADMIN], + alfa: [], + }); + + expect(repository._updateUserRolesForClient).toHaveBeenCalledWith( + user.id, + [ + KeycloakDefaults.clients.realmManagement.roles.managerUsers.roleName, + KeycloakDefaults.clients.realmManagement.roles.queryGroups.roleName, + KeycloakDefaults.clients.realmManagement.roles.viewClients.roleName, + ], + clientId, + ); + }); + + it('should NOT update user roles for no ADMIN_ADMIN role', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [faker.word.noun()], + alfa: [], + }); + + expect(repository._updateUserRolesForClient).not.toHaveBeenCalled(); + }); + }); + describe('sendActivationMail', () => { it('should call kcAdminClient users executeActionsEmail', () => { const userId: string = faker.string.uuid(); @@ -517,7 +564,7 @@ describe('UserRepository', () => { expect(kcAdminClientUsers.executeActionsEmail).toHaveBeenCalledWith({ id: userId, - actions: ['VERIFY_EMAIL'], + actions: [RequiredActionAlias.VERIFY_EMAIL, RequiredActionAlias.UPDATE_PASSWORD], lifespan: 3600 * 24 * 7, }); }); diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts index cf471180b7b5e4cdd7c479bea0ab325bbab054e5..da9b890518ef470364c4a30953894c255a328e4b 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts @@ -21,18 +21,21 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ClientMapping, ClientRoles, RoleMappings, User } from '@admin-client/user-shared'; +import { AdminRoles, ClientMapping, ClientRoles, RoleMappings, User } from '@admin-client/user-shared'; import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { inject, Injectable } from '@angular/core'; import KcAdminClient from '@keycloak/keycloak-admin-client'; import ClientRepresentation from '@keycloak/keycloak-admin-client/lib/defs/clientRepresentation'; import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation'; +import { RequiredActionAlias } from '@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation'; import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation'; import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; -import * as _ from 'lodash-es'; import { isNil, omit } from 'lodash-es'; import { concatMap, forkJoin, from, map, mergeMap, Observable, tap, throwError } from 'rxjs'; +import { KeycloakDefaults } from './keycloak.model'; + +import * as _ from 'lodash-es'; @Injectable({ providedIn: 'root', @@ -101,6 +104,7 @@ export class UserRepository { async _updateUserRoles(userId: string, clientRoles: ClientRoles): Promise<void> { await this._updateUserRolesForClient(userId, clientRoles.admin, await this._getClientId(UserRepository.ADMIN_CLIENT_NAME)); await this._updateUserRolesForClient(userId, clientRoles.alfa, await this._getClientId(UserRepository.ALFA_CLIENT_NAME)); + await this._updateUserRolesForAdmin(userId, clientRoles); } async _updateUserRolesForClient(userId: string, clientRoles: string[], clientId: string): Promise<void> { @@ -174,10 +178,24 @@ export class UserRepository { }); } + async _updateUserRolesForAdmin(userId: string, clientRoles: ClientRoles): Promise<void> { + if (clientRoles.admin.includes(AdminRoles.ADMIN)) { + await this._updateUserRolesForClient( + userId, + [ + KeycloakDefaults.clients.realmManagement.roles.managerUsers.roleName, + KeycloakDefaults.clients.realmManagement.roles.queryGroups.roleName, + KeycloakDefaults.clients.realmManagement.roles.viewClients.roleName, + ], + await this._getClientId(KeycloakDefaults.clients.realmManagement.clientName), + ); + } + } + _sendActivationMail(userId: string): void { this.kcAdminClient.users.executeActionsEmail({ id: userId, - actions: ['VERIFY_EMAIL'], + actions: [RequiredActionAlias.VERIFY_EMAIL, RequiredActionAlias.UPDATE_PASSWORD], lifespan: 3600 * 24 * 7, }); } diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts index f496e42b8734907ab060fe4872fc91cb29b14c42..45d8e171c2c2b1cde1e96e25d76cac23bcf6e5e2 100644 --- a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts +++ b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts @@ -48,3 +48,7 @@ export interface RoleMappings { newClientRoleMappings: RoleMappingPayload[]; oldClientRoleMappings: RoleMappingPayload[]; } + +export enum AdminRoles { + ADMIN = 'ADMIN_ADMIN', +} diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts index d8d3db22fda04893aa9567a5262370064f8c7b97..caabe30992d06bce0dffefa1c988f2e405a8793a 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts @@ -26,7 +26,12 @@ import { ROUTES } from '@admin-client/shared'; import { User, UserService } from '@admin-client/user-shared'; import { KeycloakErrorMessage, KeycloakFieldName, PatchConfig } from '@admin/keycloak-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createLoadingStateResource, createStateResource, StateResource, } from '@alfa-client/tech-shared'; +import { + createEmptyStateResource, + createLoadingStateResource, + createStateResource, + StateResource, +} from '@alfa-client/tech-shared'; import { Mock, mock, mockWindowError } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts index 20c697d9eb5f8ae99f86ce6030917303419a5090..b0cb7867c9cd8330c274fd9ee944d16f9a5507bb 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts @@ -23,10 +23,25 @@ */ import { AdminOrganisationsEinheit, AdminOrganisationsEinheitService } from '@admin-client/organisations-einheit-shared'; import { ROUTES } from '@admin-client/shared'; -import { User, UserService } from '@admin-client/user-shared'; -import { KeycloakErrorMessage, KeycloakFieldName, KeycloakFormService, KeycloakHttpErrorResponse, PatchConfig, } from '@admin/keycloak-shared'; +import { AdminRoles, User, UserService } from '@admin-client/user-shared'; +import { + KeycloakErrorMessage, + KeycloakFieldName, + KeycloakFormService, + KeycloakHttpErrorResponse, + PatchConfig, +} from '@admin/keycloak-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { checkBoxGroupsEmptyValidator, EMPTY_STRING, fieldEmptyValidator, fieldInvalidValidator, fieldLengthValidator, isLoaded, mapToResource, StateResource, } from '@alfa-client/tech-shared'; +import { + checkBoxGroupsEmptyValidator, + EMPTY_STRING, + fieldEmptyValidator, + fieldInvalidValidator, + fieldLengthValidator, + isLoaded, + mapToResource, + StateResource, +} from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { Injectable, OnDestroy } from '@angular/core'; import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; @@ -43,7 +58,7 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest public static readonly CLIENT_ROLES: string = 'clientRoles'; public static readonly GROUPS: string = 'groups'; public static readonly ADMINISTRATION_GROUP: string = 'admin'; - public static readonly ADMIN: string = 'ADMIN_ADMIN'; + public static readonly ADMIN: string = AdminRoles.ADMIN; public static readonly DATENBEAUFTRAGUNG: string = 'DATENBEAUFTRAGUNG'; public static readonly ALFA_GROUP: string = 'alfa'; public static readonly LOESCHEN: string = 'VERWALTUNG_LOESCHEN'; diff --git a/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts b/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts index 1ea618d47d18ed73a95030929bf0d581d41d3c6c..9d89989e6f5eb294ee5d7215b881a2584f3490db 100644 --- a/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts +++ b/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts @@ -46,6 +46,9 @@ export enum ApiRootLinkRel { ALLE_VORGAENGE_ABGESCHLOSSEN = 'vorgaenge_abgeschlossen_all', MEINE_VORGAENGE_ABGESCHLOSSEN = 'vorgaenge_abgeschlossen_my', UNASSIGNED_ABGESCHLOSSEN = 'vorgaenge_abgeschlossen_unassigned', + ALLE_VORGAENGE_WEITERGELEITET = 'vorgaenge_weitergeleitet_all', + MEINE_VORGAENGE_WEITERGELEITET = 'vorgaenge_weitergeleitet_my', + UNASSIGNED_WEITERGELEITET = 'vorgaenge_weitergeleitet_unassigned', ALLE_VORGAENGE_VERWORFEN = 'vorgaenge_verworfen_all', MEINE_VORGAENGE_VERWORFEN = 'vorgaenge_verworfen_my', UNASSIGNED_VERWORFEN = 'vorgaenge_verworfen_unassigned', diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts index d22faf648e3d30b95e5d957b99673a29579e619b..ae974499af8180747f7915423b75c4e91a4a48a5 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts @@ -21,10 +21,31 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { BinaryFileListLinkRel, BinaryFileListResource, BinaryFileResource, BinaryFileService, } from '@alfa-client/binary-file-shared'; -import { CommandOrder, CommandResource, CommandResourceService, CommandService, CreateCommandProps, getEffectedResourceUrl, } from '@alfa-client/command-shared'; +import { + BinaryFileListLinkRel, + BinaryFileListResource, + BinaryFileResource, + BinaryFileService, +} from '@alfa-client/binary-file-shared'; +import { + CommandOrder, + CommandResource, + CommandResourceService, + CommandService, + CreateCommandProps, + getEffectedResourceUrl, +} from '@alfa-client/command-shared'; import { PostfachService } from '@alfa-client/postfach-shared'; -import { createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_STRING, getEmbeddedResources, ResourceListService, ResourceRepository, StateResource, } from '@alfa-client/tech-shared'; +import { + createEmptyStateResource, + createErrorStateResource, + createStateResource, + EMPTY_STRING, + getEmbeddedResources, + ResourceListService, + ResourceRepository, + StateResource, +} from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { VorgangCommandService, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { TestBed } from '@angular/core/testing'; @@ -35,19 +56,43 @@ import { createProblemDetail } from 'libs/tech-shared/test/error'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { EMPTY, Observable, of } from 'rxjs'; import { createBinaryFileListResource, createBinaryFileResource } from '../../../binary-file-shared/test/binary-file'; -import { createCommandErrorStateResource, createCommandResource, createCommandStateResource, createCreateCommandProps, createSuccessfullyDoneCommandStateResource, } from '../../../command-shared/test/command'; +import { + createCommandErrorStateResource, + createCommandResource, + createCommandStateResource, + createCreateCommandProps, + createSuccessfullyDoneCommandStateResource, +} from '../../../command-shared/test/command'; import { createFile } from '../../../tech-shared/test/file'; import { singleCold, singleColdCompleted } from '../../../tech-shared/test/marbles'; import { createBescheid, createBescheidDocument, createBescheidListResource, createBescheidResource } from '../test/bescheid'; import { createDocumentResource } from '../test/document'; import { BescheidFacade } from './+state/bescheid.facade'; import { BescheidLinkRel } from './bescheid.linkrel'; -import { Bescheid, BESCHEID_UPLOADED_ATTACHMENTS, BescheidDocument, BescheidListResource, BescheidResource, BescheidStatus, BescheidWizardStep, createEmptyBescheidDocument, createEmptyUploadInProgress, createInitialWizard, } from './bescheid.model'; +import { + Bescheid, + BESCHEID_UPLOADED_ATTACHMENTS, + BescheidDocument, + BescheidListResource, + BescheidResource, + BescheidStatus, + BescheidWizardStep, + createEmptyBescheidDocument, + createEmptyUploadInProgress, + createInitialWizard, +} from './bescheid.model'; import { BescheidService } from './bescheid.service'; import { DocumentLinkRel } from './document.linkrel'; import { DocumentResource } from './document.model'; -import { BescheidListResourceService, BescheidResourceService, buildCreateBescheidDocumentFromFileProps, buildUpdateBescheidCommandProps, createBescheidListResourceService, createBescheidResourceService, } from '@alfa-client/bescheid-shared'; +import { + BescheidListResourceService, + BescheidResourceService, + buildCreateBescheidDocumentFromFileProps, + buildUpdateBescheidCommandProps, + createBescheidListResourceService, + createBescheidResourceService, +} from '@alfa-client/bescheid-shared'; import { expect } from '@jest/globals'; import { cold } from 'jest-marbles'; import * as DateUtil from '../../../tech-shared/src/lib/date.util'; @@ -147,7 +192,7 @@ describe('BescheidService', () => { it('should reload postfach list', () => { service.exit(); - expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); + expect(postfachService._setPostfachMailOnReload).toHaveBeenCalled(); }); it('should clear uploaded files', () => { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index f7b1e2f64bac1adb6a924aa1e6719cdbc1028ec5..22107e92d9b6ff28981edc35f13ab3da9b8880b8 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -44,10 +44,34 @@ import { DocumentResource, Wizard, } from '@alfa-client/bescheid-shared'; -import { BinaryFileListLinkRel, BinaryFileListResource, BinaryFileResource, BinaryFileService, } from '@alfa-client/binary-file-shared'; -import { CommandOrder, CommandResource, CommandService, getEffectedResourceUrl, notHasCommandError, tapOnCommandSuccessfullyDone, } from '@alfa-client/command-shared'; +import { + BinaryFileListLinkRel, + BinaryFileListResource, + BinaryFileResource, + BinaryFileService, +} from '@alfa-client/binary-file-shared'; +import { + CommandOrder, + CommandResource, + CommandService, + getEffectedResourceUrl, + notHasCommandError, + tapOnCommandSuccessfullyDone, +} from '@alfa-client/command-shared'; import { PostfachService } from '@alfa-client/postfach-shared'; -import { createEmptyStateResource, createStateResource, filterIsLoadedOrHasError, getEmbeddedResources, hasStateResourceError, isLoaded, isNotEmpty, isNotNil, ResourceRepository, sortByGermanDateStr, StateResource, } from '@alfa-client/tech-shared'; +import { + createEmptyStateResource, + createStateResource, + filterIsLoadedOrHasError, + getEmbeddedResources, + hasStateResourceError, + isLoaded, + isNotEmpty, + isNotNil, + ResourceRepository, + sortByGermanDateStr, + StateResource, +} from '@alfa-client/tech-shared'; import { VorgangCommandService, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { inject, Injectable } from '@angular/core'; import { getUrl, hasLink, LinkRel, Resource, ResourceUri } from '@ngxp/rest'; @@ -65,7 +89,7 @@ export class BescheidService { private readonly resourceRepository = inject(ResourceRepository); private readonly postfachService = inject(PostfachService); private readonly vorgangService = inject(VorgangService); - // The injection of this service and the one below is problematic. + // The injection of this services is problematic. // It must be analysed how to inject BescheidService via providers in BescheidSharedModule. private readonly bescheidResourceService = createBescheidResourceService( this.resourceRepository, @@ -73,7 +97,7 @@ export class BescheidService { this.vorgangService, ); private readonly bescheidListResourceService = createBescheidListResourceService(this.resourceRepository, this.vorgangService); - + // readonly _bescheidDocument$: BehaviorSubject<BescheidDocument> = new BehaviorSubject(createEmptyBescheidDocument()); readonly _wizard$: BehaviorSubject<Wizard> = new BehaviorSubject(createInitialWizard()); @@ -84,7 +108,7 @@ export class BescheidService { public exit(): void { this.bescheidListResourceService.refresh(); - this.postfachService.setPostfachMailOnReload(); + this.postfachService._setPostfachMailOnReload(); this._clearUploadedFiles(); } diff --git a/alfa-client/libs/command-shared/src/lib/command.model.ts b/alfa-client/libs/command-shared/src/lib/command.model.ts index a64cb0dd5f581ff2a55b66d3ab9e56f22223841a..b86ac920fbeab00514c3cf45b7ae0f88e7ff7ce3 100644 --- a/alfa-client/libs/command-shared/src/lib/command.model.ts +++ b/alfa-client/libs/command-shared/src/lib/command.model.ts @@ -73,6 +73,7 @@ export enum CommandOrder { VORGANG_ZURUECKHOLEN = 'VORGANG_ZURUECKHOLEN', VORGANG_BEARBEITEN = 'VORGANG_BEARBEITEN', VORGANG_BESCHEIDEN = 'VORGANG_BESCHEIDEN', + FORWARD_VORGANG = 'FORWARD_VORGANG', VORGANG_ZURUECKSTELLEN = 'VORGANG_ZURUECKSTELLEN', VORGANG_ABSCHLIESSEN = 'VORGANG_ABSCHLIESSEN', VORGANG_WIEDEREROEFFNEN = 'VORGANG_WIEDEREROEFFNEN', @@ -98,3 +99,5 @@ export interface CreateCommandProps { snackBarMessage?: string; snackBarErrorMessage?: string; } + +export type CreateCommandPropsWithoutResource = Omit<CreateCommandProps, 'resource'>; diff --git a/alfa-client/libs/command-shared/test/command.ts b/alfa-client/libs/command-shared/test/command.ts index ff7aae6c8ba99ae02f921c49b9a789c675e404bd..05fec9de4806f6473cf2d4204ee196ed71db5da0 100644 --- a/alfa-client/libs/command-shared/test/command.ts +++ b/alfa-client/libs/command-shared/test/command.ts @@ -35,6 +35,7 @@ import { CommandStatus, CreateCommand, CreateCommandProps, + CreateCommandPropsWithoutResource, } from '../src/lib/command.model'; export function createCommand(): Command { @@ -85,8 +86,11 @@ export function createCreateCommand(order: CommandOrder = CommandOrder.VORGANG_A } export function createCreateCommandProps(): CreateCommandProps { + return { ...createCreateCommandPropsWithoutResource(), resource: createCommandResource() }; +} + +export function createCreateCommandPropsWithoutResource(): CreateCommandPropsWithoutResource { return { - resource: createCommandResource(), linkRel: faker.internet.url(), command: createCreateCommand(), snackBarMessage: faker.word.sample(5), diff --git a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts index 6adabee9688a1af7ac880621d85af1a90e04c326..8a67d24b410454a80ae2d62f7bbbd6a86a08fd9e 100644 --- a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts +++ b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.spec.ts @@ -12,8 +12,8 @@ describe('CancelDialogButtonComponent', () => { let dialogService: Mock<OzgcloudDialogService>; - const cancelDialogButton: string = getDataTestIdOf('cancel-dialog-button'); - const cancelDialogIconButton: string = getDataTestIdOf('cancel-dialog-icon-button'); + const cancelDialogButton: string = getDataTestIdOf('cancel-dialog-button-container'); + const cancelDialogIconButton: string = getDataTestIdOf('cancel-dialog-icon-button-container'); beforeEach(async () => { dialogService = mock(OzgcloudDialogService); diff --git a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts index 7c41c1bbcdc747090c0aa5bfc64185c577c99fe3..df1f5fa4b1732a9b60879f6353ec9f006832cb5f 100644 --- a/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts +++ b/alfa-client/libs/design-component/src/lib/cancel-dialog-button/cancel-dialog-button.component.ts @@ -14,7 +14,7 @@ import { ButtonComponent, CloseIconComponent, TooltipDirective } from '@ods/syst variant="ghost" size="fit" dataTestId="cancel-dialog-icon-button" - data-test-id="cancel-dialog-icon-button" + data-test-id="cancel-dialog-icon-button-container" > <ng-container icon> <ods-close-icon class="fill-primary" /> @@ -26,7 +26,7 @@ import { ButtonComponent, CloseIconComponent, TooltipDirective } from '@ods/syst variant="outline" text="Abbrechen" dataTestId="cancel-dialog-button" - data-test-id="cancel-dialog-button" + data-test-id="cancel-dialog-button-container" /> }`, }) diff --git a/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.spec.ts b/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.spec.ts index 34a7bd065f0c85b3ddc80a39d2fbe195e9c33655..8c472b9da3215b624913bf869c367887ab97c27f 100644 --- a/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.spec.ts +++ b/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.spec.ts @@ -21,8 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { LinkRelationName } from '@alfa-client/tech-shared'; import { mock, useFromMock } from '@alfa-client/test-utils'; import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { faker } from '@faker-js/faker/.'; import { ResourceFactory } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; import { createForwardingListResource } from 'libs/forwarding-shared/test/forwarding'; @@ -45,25 +47,26 @@ describe('ForwardingRepository', () => { describe('getForwardings', () => { const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([VorgangWithEingangLinkRel.FORWARD_BY_EMAIL]); const commandList: ForwardingListResource = createForwardingListResource(); + const linkRel: LinkRelationName = faker.string.alpha(5); beforeEach(() => { resourceWrapper.get.mockReturnValue(hot('a', { a: commandList })); }); it('should call resourceFactory', () => { - repository.getForwardings(vorgang); + repository.getForwardings(vorgang, linkRel); expect(resourceFactory.from).toHaveBeenCalledWith(vorgang); }); it('should call resourceWrapper', () => { - repository.getForwardings(vorgang); + repository.getForwardings(vorgang, linkRel); - expect(resourceWrapper.get).toHaveBeenCalledWith(VorgangWithEingangLinkRel.FORWARD_BY_EMAIL); + expect(resourceWrapper.get).toHaveBeenCalledWith(linkRel); }); it('should return result', () => { - let result = repository.getForwardings(vorgang); + let result = repository.getForwardings(vorgang, linkRel); expect(result).not.toBeNull(); expect(result).toBeObservable(cold('a', { a: commandList })); diff --git a/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.ts b/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.ts index a83ca3536dabe921ff4dc10719dbbdd1f5c74943..acd33b4bc2523a2761e420640d1d422cbdbca088 100644 --- a/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.ts +++ b/alfa-client/libs/forwarding-shared/src/lib/forwarding.repository.ts @@ -21,7 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { LinkRelationName } from '@alfa-client/tech-shared'; +import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Injectable } from '@angular/core'; import { ResourceFactory } from '@ngxp/rest'; import { Observable } from 'rxjs'; @@ -31,7 +32,7 @@ import { ForwardingListResource } from './forwarding.model'; export class ForwardingRepository { constructor(private resourceFactory: ResourceFactory) {} - public getForwardings(vorgang: VorgangWithEingangResource): Observable<ForwardingListResource> { - return this.resourceFactory.from(vorgang).get(VorgangWithEingangLinkRel.FORWARD_BY_EMAIL); + public getForwardings(vorgang: VorgangWithEingangResource, linkRel: LinkRelationName): Observable<ForwardingListResource> { + return this.resourceFactory.from(vorgang).get(linkRel); } } diff --git a/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.spec.ts b/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.spec.ts index afb141693929a6b51c1d096d58510076816fdc0a..f3f631dfbcb316d354a18b2c2fab9299d347cd91 100644 --- a/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.spec.ts +++ b/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.spec.ts @@ -21,9 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared'; +import { CommandOrder, CommandResource, CommandService, CreateCommandPropsWithoutResource } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; import { + EMPTY_STRING, StateResource, createEmptyStateResource, createErrorStateResource, @@ -38,16 +39,19 @@ import { VorgangWithEingangLinkRel, VorgangWithEingangResource, } from '@alfa-client/vorgang-shared'; -import { cold, hot } from 'jest-marbles'; +import { faker } from '@faker-js/faker/.'; +import { ResourceUri } from '@ngxp/rest'; +import { hot } from 'jest-marbles'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createCommandResource, createCreateCommandPropsWithoutResource } from 'libs/command-shared/test/command'; import { createVorgangForwardRequest, createVorgangResource, createVorgangWithEingangResource, } from 'libs/vorgang-shared/test/vorgang'; -import { of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { createApiError } from '../../../tech-shared/test/error'; +import { multipleCold, singleColdCompleted } from '../../../tech-shared/test/marbles'; import { createForwardingListResource, createForwardingResource } from '../../test/forwarding'; import { ForwardingLinkRel } from './forwarding.linkrel'; import { ForwardingListResource, ForwardingResource } from './forwarding.model'; @@ -82,10 +86,9 @@ describe('ForwardingService', () => { expect(service).toBeTruthy(); }); - describe('forward', () => { + describe('forward by email', () => { const vorgang: VorgangResource = createVorgangResource(); - const commandStateResource: StateResource<CommandResource> = - createStateResource(createCommandResource()); + const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { commandService.createCommand.mockReturnValue(of(commandStateResource)); @@ -99,31 +102,27 @@ describe('ForwardingService', () => { body: null, }; - service.forward(vorgang, forwardRequest); + service.forwardByEmail(vorgang, forwardRequest); - expect(commandService.createCommand).toHaveBeenCalledWith( - vorgang, - VorgangWithEingangLinkRel.FORWARD, - command, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(vorgang, VorgangWithEingangLinkRel.FORWARD, command); }); it('should call reloadCurrentVorgang', () => { service.reloadCurrentVorgang = jest.fn(); - service.forward(vorgang, forwardRequest); + service.forwardByEmail(vorgang, forwardRequest); expect(service.reloadCurrentVorgang).toHaveBeenCalled(); }); it('should call setPendingForwardSingleCommandLoading', () => { - service.forward(vorgang, forwardRequest); + service.forwardByEmail(vorgang, forwardRequest); expect(vorgangService.setPendingForwardSingleCommandLoading).toHaveBeenCalled(); }); it('should call setPendingForwardSingleCommand', () => { - service.forward(vorgang, forwardRequest); + service.forwardByEmail(vorgang, forwardRequest); expect(vorgangService.setPendingForwardSingleCommand).toHaveBeenCalled(); }); @@ -169,16 +168,12 @@ describe('ForwardingService', () => { }); it('should call vorgangservice on command is done', () => { - const commandServiceReturnValue = createStateResource( - createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), - ); + const commandServiceReturnValue = createStateResource(createCommandResource([CommandLinkRel.EFFECTED_RESOURCE])); commandService.pollCommand.mockReturnValue(of(commandServiceReturnValue)); service.pollPendingForwardCommand(createStateResource(commandResourceWithUpdateLink)); - expect(vorgangService.setPendingForwardSingleCommand).toHaveBeenCalledWith( - commandServiceReturnValue, - ); + expect(vorgangService.setPendingForwardSingleCommand).toHaveBeenCalledWith(commandServiceReturnValue); }); it('should call not vorgangservice on pending command', () => { @@ -237,7 +232,7 @@ describe('ForwardingService', () => { }); }); - describe('getForwardings', () => { + describe('get forwardings by email', () => { const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource(); const listResource: ForwardingListResource = createForwardingListResource(); @@ -246,17 +241,15 @@ describe('ForwardingService', () => { }); it('should return value', () => { - const result = service.getForwardings(vorgang); + const result: Observable<StateResource<ForwardingListResource>> = service.getForwardingsByEmail(vorgang); - expect(result).toBeObservable( - cold('ab', { a: createEmptyStateResource(true), b: createStateResource(listResource) }), - ); + expect(result).toBeObservable(multipleCold(createEmptyStateResource(true), createStateResource(listResource))); }); it('should call repository', () => { - service.getForwardings(vorgang); + service.getForwardingsByEmail(vorgang); - expect(forwardingRepository.getForwardings).toHaveBeenCalledWith(vorgang); + expect(forwardingRepository.getForwardings).toHaveBeenCalledWith(vorgang, VorgangWithEingangLinkRel.FORWARD_BY_EMAIL); }); }); @@ -273,10 +266,7 @@ describe('ForwardingService', () => { order: CommandOrder.FORWARD_SUCCESSFULL, body: null, }); - - expect(result).toBeObservable( - cold('ab', { a: createEmptyStateResource(true), b: stateResource }), - ); + expect(result).toBeObservable(multipleCold(createEmptyStateResource(true), stateResource)); }); }); @@ -284,11 +274,10 @@ describe('ForwardingService', () => { it('should call command service', () => { service.markAsSuccess(forwading); - expect(commandService.createCommand).toHaveBeenCalledWith( - forwading, - ForwardingLinkRel.MARK_AS_SUCCESS, - { order: CommandOrder.FORWARD_SUCCESSFULL, body: null }, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(forwading, ForwardingLinkRel.MARK_AS_SUCCESS, { + order: CommandOrder.FORWARD_SUCCESSFULL, + body: null, + }); }); it('should update list on valid response', () => { @@ -306,11 +295,10 @@ describe('ForwardingService', () => { it('should call command service', () => { service.markAsFail(forwading); - expect(commandService.createCommand).toHaveBeenCalledWith( - forwading, - ForwardingLinkRel.MARK_AS_FAIL, - { order: CommandOrder.FORWARD_FAILED, body: null }, - ); + expect(commandService.createCommand).toHaveBeenCalledWith(forwading, ForwardingLinkRel.MARK_AS_FAIL, { + order: CommandOrder.FORWARD_FAILED, + body: null, + }); }); it('should update vorgang on valid response', () => { @@ -368,4 +356,60 @@ describe('ForwardingService', () => { expect(service.setList).toHaveBeenCalledWith(list); }); }); + + describe('forward', () => { + const forwardingToUri: ResourceUri = faker.internet.url(); + + const createCommandProps: CreateCommandPropsWithoutResource = createCreateCommandPropsWithoutResource(); + const commandResource: CommandResource = createCommandResource(); + const commandStateResource: StateResource<CommandResource> = createStateResource(commandResource); + + beforeEach(() => { + vorgangService.createCommand.mockReturnValue(of(commandStateResource)); + service._buildForwardCreateCommandProps = jest.fn().mockReturnValue(createCommandProps); + }); + + it('should call build forward create command', () => { + service.forward(forwardingToUri).subscribe(); + + expect(service._buildForwardCreateCommandProps).toHaveBeenCalledWith(forwardingToUri); + }); + + it('should call vorgang service to create command', () => { + service.forward(forwardingToUri).subscribe(); + + expect(vorgangService.createCommand).toHaveBeenCalledWith(createCommandProps, true); + }); + + it('should return response from command service', () => { + const forwardCommand$: Observable<StateResource<CommandResource>> = service.forward(forwardingToUri); + + expect(forwardCommand$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); + + describe('build forward command props', () => { + const forwardingToUri: ResourceUri = faker.internet.url(); + + it('should contains linkrel', () => { + const commandProps: CreateCommandPropsWithoutResource = service._buildForwardCreateCommandProps(forwardingToUri); + + expect(commandProps.linkRel).toBe(VorgangWithEingangLinkRel.FORWARD_BY_OZGCLOUD); + }); + + it('should contains command', () => { + const commandProps: CreateCommandPropsWithoutResource = service._buildForwardCreateCommandProps(forwardingToUri); + + expect(commandProps.command).toEqual({ + order: CommandOrder.FORWARD_VORGANG, + body: { organisationEinheitId: forwardingToUri }, + }); + }); + + it('should contains empty snackbar message', () => { + const commandProps: CreateCommandPropsWithoutResource = service._buildForwardCreateCommandProps(forwardingToUri); + + expect(commandProps.snackBarMessage).toBe(EMPTY_STRING); + }); + }); }); diff --git a/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.ts b/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.ts index 73510b902a2a9408905b9af3124bba1ab81efe47..b84c9d5c0ee51ea7e6464997fd24106a8c91fbf4 100644 --- a/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.ts +++ b/alfa-client/libs/forwarding-shared/src/lib/forwarding.service.ts @@ -21,17 +21,18 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Injectable, OnDestroy } from '@angular/core'; -import { Params } from '@angular/router'; import { + CommandOrder, CommandResource, CommandService, CreateCommand, + CreateCommandPropsWithoutResource, isDone, isPending, } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; import { + EMPTY_STRING, StateResource, createEmptyStateResource, createStateResource, @@ -45,21 +46,22 @@ import { VorgangWithEingangResource, createForwardCommand, } from '@alfa-client/vorgang-shared'; +import { Injectable, OnDestroy } from '@angular/core'; +import { Params } from '@angular/router'; +import { ResourceUri } from '@ngxp/rest'; import { isNil } from 'lodash-es'; import { BehaviorSubject, Observable, Subscription } from 'rxjs'; import { first, map, startWith, tap } from 'rxjs/operators'; import { ForwardingLinkRel } from './forwarding.linkrel'; import { ForwardingListResource, ForwardingResource } from './forwarding.model'; import { ForwardingRepository } from './forwarding.repository'; -import { - createForwardingMarkAsFailCommand, - createForwardingMarkAsSuccessCommand, -} from './forwarding.util'; +import { createForwardingMarkAsFailCommand, createForwardingMarkAsSuccessCommand } from './forwarding.util'; @Injectable({ providedIn: 'root' }) export class ForwardingService implements OnDestroy { - private readonly forwardingList$: BehaviorSubject<StateResource<ForwardingListResource>> = - new BehaviorSubject(createEmptyStateResource<ForwardingListResource>()); + private readonly forwardingList$: BehaviorSubject<StateResource<ForwardingListResource>> = new BehaviorSubject( + createEmptyStateResource<ForwardingListResource>(), + ); private navigationSubscription: Subscription; private subscription: Subscription; @@ -71,15 +73,15 @@ export class ForwardingService implements OnDestroy { private forwardingRepository: ForwardingRepository, ) {} - getForwardings( - vorgang: VorgangWithEingangResource, - ): Observable<StateResource<ForwardingListResource>> { + getForwardingsByEmail(vorgang: VorgangWithEingangResource): Observable<StateResource<ForwardingListResource>> { this.forwardingList$.next(createEmptyStateResource(true)); - const subscription = this.forwardingRepository.getForwardings(vorgang).subscribe((list) => { - this.forwardingList$.next(createStateResource(list)); - subscription.unsubscribe(); - }); + const subscription = this.forwardingRepository + .getForwardings(vorgang, VorgangWithEingangLinkRel.FORWARD_BY_EMAIL) + .subscribe((listResource: ForwardingListResource) => { + this.forwardingList$.next(createStateResource(listResource)); + subscription.unsubscribe(); + }); return this.forwardingList$.asObservable(); } @@ -94,9 +96,7 @@ export class ForwardingService implements OnDestroy { listenToNavigation(): void { this.unsubscribe(); - this.navigationSubscription = this.navigationService - .urlChanged() - .subscribe((params) => this.onNavigation(params)); + this.navigationSubscription = this.navigationService.urlChanged().subscribe((params) => this.onNavigation(params)); } onNavigation(params: Params): void { @@ -105,19 +105,15 @@ export class ForwardingService implements OnDestroy { } } - pollPendingForwardCommand( - command: StateResource<CommandResource>, - ): StateResource<CommandResource> { + pollPendingForwardCommand(command: StateResource<CommandResource>): StateResource<CommandResource> { if (this.shouldPoll(command)) { - this.subscription = this.commandService - .pollCommand(command.resource) - .subscribe((updatedCommand) => { - if (isDone(updatedCommand.resource)) { - this.vorgangService.setPendingForwardSingleCommand(updatedCommand); - this.reloadCurrentVorgang(updatedCommand); - this.subscription.unsubscribe(); - } - }); + this.subscription = this.commandService.pollCommand(command.resource).subscribe((updatedCommand) => { + if (isDone(updatedCommand.resource)) { + this.vorgangService.setPendingForwardSingleCommand(updatedCommand); + this.reloadCurrentVorgang(updatedCommand); + this.subscription.unsubscribe(); + } + }); } return command; } @@ -126,10 +122,7 @@ export class ForwardingService implements OnDestroy { return command.loaded && isPending(command.resource); } - public forward( - vorgang: VorgangResource, - request: ForwardRequest, - ): Observable<StateResource<CommandResource>> { + public forwardByEmail(vorgang: VorgangResource, request: ForwardRequest): Observable<StateResource<CommandResource>> { this.vorgangService.setPendingForwardSingleCommandLoading(); const subscription: Subscription = this.commandService .createCommand(vorgang, VorgangWithEingangLinkRel.FORWARD, createForwardCommand(request)) @@ -142,19 +135,13 @@ export class ForwardingService implements OnDestroy { } markAsSuccess(forward: ForwardingResource): Observable<StateResource<CommandResource>> { - return this.createMarkAsCommand( - forward, - ForwardingLinkRel.MARK_AS_SUCCESS, - createForwardingMarkAsSuccessCommand(), - ).pipe(tap((command) => this.updateForwardingList(command))); + return this.createMarkAsCommand(forward, ForwardingLinkRel.MARK_AS_SUCCESS, createForwardingMarkAsSuccessCommand()).pipe( + tap((command) => this.updateForwardingList(command)), + ); } markAsFail(forward: ForwardingResource): Observable<StateResource<CommandResource>> { - return this.createMarkAsCommand( - forward, - ForwardingLinkRel.MARK_AS_FAIL, - createForwardingMarkAsFailCommand(), - ).pipe( + return this.createMarkAsCommand(forward, ForwardingLinkRel.MARK_AS_FAIL, createForwardingMarkAsFailCommand()).pipe( tap((command) => { if (isDone(command.resource)) this.reloadCurrentVorgang(command); }), @@ -192,6 +179,22 @@ export class ForwardingService implements OnDestroy { this.forwardingList$.next(createStateResource(list)); } + public forward(forwardingToUri: ResourceUri): Observable<StateResource<CommandResource>> { + return this.vorgangService.createCommand(this._buildForwardCreateCommandProps(forwardingToUri), true); + } + + _buildForwardCreateCommandProps(forwardingToUri: ResourceUri): CreateCommandPropsWithoutResource { + return { + linkRel: VorgangWithEingangLinkRel.FORWARD_BY_OZGCLOUD, + command: this.createBuildForwardCommand(forwardingToUri), + snackBarMessage: EMPTY_STRING, + }; + } + + private createBuildForwardCommand(forwardingToUri: ResourceUri): CreateCommand { + return { order: CommandOrder.FORWARD_VORGANG, body: { organisationEinheitId: forwardingToUri } }; + } + ngOnDestroy(): void { this.unsubscribe(); } diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.spec.ts b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.spec.ts index a4dd016d064b1e6d4c377d4f37518d8f9811eb84..b7387f11528fc118117ad6ca0cb51e11850ec1e8 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.spec.ts @@ -120,7 +120,7 @@ describe('ForwardingByEmailContainerComponent', () => { component.getForwardings(); - expect(service.getForwardings).not.toHaveBeenCalled(); + expect(service.getForwardingsByEmail).not.toHaveBeenCalled(); }); it('should call service get forward commands', () => { @@ -129,7 +129,7 @@ describe('ForwardingByEmailContainerComponent', () => { component.getForwardings(); - expect(service.getForwardings).toHaveBeenCalled(); + expect(service.getForwardingsByEmail).toHaveBeenCalled(); }); }); diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.ts b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.ts index f38fe66d56f971eef30db7804b5f8eea516853f1..bfc76dd9bd7bcb57c775bf38f8b60ab924c8f31b 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-container.component.ts @@ -65,7 +65,7 @@ export class ForwardingByEmailContainerComponent implements OnChanges { getForwardings(): void { if (hasLink(this.vorgang, VorgangWithEingangLinkRel.FORWARD_BY_EMAIL)) { - this.forwardingStateResources$ = this.forwardingService.getForwardings(this.vorgang); + this.forwardingStateResources$ = this.forwardingService.getForwardingsByEmail(this.vorgang); } } diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email-form.service.ts b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email-form.service.ts index 9cbe55ce655a5df52ab295788a8879602a7d9bb9..364d7e506e6e6b54ec5a84ecfb01f98ffebb9d9c 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email-form.service.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email-form.service.ts @@ -61,7 +61,7 @@ export class ForwardingByEmailFormService extends AbstractFormService<CommandRes } protected doSubmit(): Observable<StateResource<CommandResource>> { - return this.forwardingService.forward(this.vorgang, this.getFormValue()); + return this.forwardingService.forwardByEmail(this.vorgang, this.getFormValue()); } patchField(fieldName: string, value: string) { diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email.formservice.spec.ts b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email.formservice.spec.ts index a20bed0488696ecb79c97108a03d0c2b5f1a36f8..26483f43dbf893769e87f2c6589ff88744c84461 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email.formservice.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-by-email-container/forwarding-by-email-formular/forwarding-by-email-form/forwarding-by-email.formservice.spec.ts @@ -22,7 +22,7 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { ForwardingService } from '@alfa-client/forwarding-shared'; -import { mock, useFromMock } from '@alfa-client/test-utils'; +import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang'; import { of } from 'rxjs'; @@ -30,7 +30,8 @@ import { ForwardingByEmailFormService } from './forwarding-by-email-form.service describe('ForwardingByEmailFormService', () => { let formService: ForwardingByEmailFormService; - let service; + + let service: Mock<ForwardingService>; const formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); @@ -48,8 +49,7 @@ describe('ForwardingByEmailFormService', () => { const returnValue = {}; beforeEach(() => { - service.forward.mockReturnValue(of(returnValue)); - service.doSubmit = jest.fn(); + service.forwardByEmail.mockReturnValue(of(returnValue)); }); it('should call service', () => { @@ -57,7 +57,7 @@ describe('ForwardingByEmailFormService', () => { formService.submit(); - expect(service.forward).toHaveBeenCalledWith(formService.vorgang, formService.form.value); + expect(service.forwardByEmail).toHaveBeenCalledWith(formService.vorgang, formService.form.value); }); }); diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.html b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.html index ad97972cd9cc4c7e7f135d96b2b755378f953b3e..e6c65fbf4d123859056d2b834c6b45107a620683 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.html +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.html @@ -1 +1,6 @@ -<alfa-forwarding-dialog [selectedSearchResult]="selectedSearchResult$ | async" data-test-id="forwarding-dialog"/> \ No newline at end of file +<alfa-forwarding-dialog + [forwardCommandStateResource]="forwardCommandStateResource$ | async" + [selectedSearchResult]="selectedSearchResult$ | async" + (forward)="forward($event)" + data-test-id="forwarding-dialog" +/> diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.spec.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.spec.ts index 355c614cc694333be2f34a629eac5ad5b527035e..2dbd1a86402ade740cfbef6bc23460542baec559 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.spec.ts @@ -1,9 +1,18 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { mock, Mock } from '@alfa-client/test-utils'; +import { CommandLinkRel, CommandResource } from '@alfa-client/command-shared'; +import { ForwardingService } from '@alfa-client/forwarding-shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { mock, Mock, triggerEvent } from '@alfa-client/test-utils'; +import { OzgcloudDialogService } from '@alfa-client/ui'; import { OrganisationsEinheitService, ZUSTAENDIGE_STELLE_SERVICE } from '@alfa-client/zustaendige-stelle-shared'; import { AsyncPipe } from '@angular/common'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { faker } from '@faker-js/faker/.'; +import { ResourceUri } from '@ngxp/rest'; +import { createCommandStateResource } from 'libs/command-shared/test/command'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { singleColdCompleted } from 'libs/tech-shared/test/marbles'; import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; import { ForwardingDialogContainerComponent } from './forwarding-dialog-container.component'; import { ForwardingDialogComponent } from './forwarding-dialog/forwarding-dialog.component'; @@ -11,14 +20,30 @@ describe('ForwardingDialogContainerComponent', () => { let component: ForwardingDialogContainerComponent; let fixture: ComponentFixture<ForwardingDialogContainerComponent>; + const forwardingDialog: string = getDataTestIdOf('forwarding-dialog'); + + let service: Mock<ForwardingService>; let organisationsEinheitService: Mock<OrganisationsEinheitService>; + let dialogService: Mock<OzgcloudDialogService>; beforeEach(async () => { + service = mock(ForwardingService); organisationsEinheitService = mock(OrganisationsEinheitService); + dialogService = mock(OzgcloudDialogService); await TestBed.configureTestingModule({ imports: [ForwardingDialogContainerComponent, AsyncPipe], declarations: [MockComponent(ForwardingDialogComponent)], + providers: [ + { + provide: ForwardingService, + useValue: service, + }, + { + provide: OzgcloudDialogService, + useValue: dialogService, + }, + ], }) .overrideComponent(ForwardingDialogContainerComponent, { set: { @@ -40,4 +65,45 @@ describe('ForwardingDialogContainerComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + describe('forward button', () => { + const targetUri: ResourceUri = faker.internet.url(); + + it('should call forward on click', () => { + component.forward = jest.fn(); + + triggerEvent({ fixture, elementSelector: forwardingDialog, name: 'forward', data: targetUri }); + + expect(component.forward).toHaveBeenCalledWith(targetUri); + }); + }); + + describe('forward', () => { + const targetUri: ResourceUri = faker.internet.url(); + + const commandStateResource: StateResource<CommandResource> = createCommandStateResource([CommandLinkRel.EFFECTED_RESOURCE]); + + beforeEach(() => { + service.forward.mockReturnValue(of(commandStateResource)); + }); + + it('should call service with uri', () => { + component.forward(targetUri); + + expect(service.forward).toHaveBeenCalledWith(targetUri); + }); + + it('should set service response', () => { + component.forward(targetUri); + + expect(component.forwardCommandStateResource$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + + it('should call dialog service to close all if command is done', () => { + component.forward(targetUri); + component.forwardCommandStateResource$.subscribe(); + + expect(dialogService.closeAll).toHaveBeenCalled(); + }); + }); }); diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.ts index afb2a3d5a97213615dcc22a98195e82fd916ed50..726320a3498c9e9b3ede988f28d84feee3cbcc24 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog-container.component.ts @@ -1,4 +1,7 @@ -import { ResourceRepository } from '@alfa-client/tech-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { ForwardingService } from '@alfa-client/forwarding-shared'; +import { createEmptyStateResource, ResourceRepository, StateResource } from '@alfa-client/tech-shared'; +import { OzgcloudDialogService } from '@alfa-client/ui'; import { VorgangService } from '@alfa-client/vorgang-shared'; import { createOrganisationEinheitService } from '@alfa-client/zustaendige-stelle'; import { @@ -6,15 +9,16 @@ import { OrganisationsEinheitService, ZUSTAENDIGE_STELLE_SERVICE, } from '@alfa-client/zustaendige-stelle-shared'; -import { AsyncPipe } from '@angular/common'; +import { AsyncPipe, CommonModule } from '@angular/common'; import { Component, inject, OnInit } from '@angular/core'; -import { Observable } from 'rxjs'; +import { ResourceUri } from '@ngxp/rest'; +import { Observable, of } from 'rxjs'; import { ForwardingDialogComponent } from './forwarding-dialog/forwarding-dialog.component'; @Component({ selector: 'alfa-forwarding-dialog-container', standalone: true, - imports: [ForwardingDialogComponent, AsyncPipe], + imports: [ForwardingDialogComponent, AsyncPipe, CommonModule], templateUrl: './forwarding-dialog-container.component.html', providers: [ { @@ -26,10 +30,22 @@ import { ForwardingDialogComponent } from './forwarding-dialog/forwarding-dialog }) export class ForwardingDialogContainerComponent implements OnInit { private readonly organisationsEinheitService = inject(ZUSTAENDIGE_STELLE_SERVICE) as OrganisationsEinheitService; + private readonly forwardingService = inject(ForwardingService); + private readonly dialogService = inject(OzgcloudDialogService); public selectedSearchResult$: Observable<OrganisationsEinheitResource>; + public forwardCommandStateResource$: Observable<StateResource<CommandResource>> = + of(createEmptyStateResource<CommandResource>()); ngOnInit(): void { this.selectedSearchResult$ = this.organisationsEinheitService.getSelectedResult(); } + + public forward(targetUri: ResourceUri): void { + this.forwardCommandStateResource$ = this.forwardingService.forward(targetUri).pipe( + tapOnCommandSuccessfullyDone(() => { + this.dialogService.closeAll(); + }), + ); + } } diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.html b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.html index d0dd3c9c055bfc74030ddd0a0c19ddacafa8976b..5bf44a14c8978d8fea1e07d51b0ccc1279935ca4 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.html +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.html @@ -1,3 +1,11 @@ -<ods-button-with-spinner [disabled]="disabled" text="Weiterleiten" variant="outline" dataTestId="forwarding-button"> +<ods-button-with-spinner + [stateResource]="stateResource" + [disabled]="disabled" + (clickEmitter)="clickEmitter.emit()" + text="Weiterleiten" + variant="outline" + dataTestId="forwarding-dialog-forwarding-button" + data-test-id="forwarding-button-container" +> <ods-forward-vorgang-icon icon class="fill-primary" /> -</ods-button-with-spinner> \ No newline at end of file +</ods-button-with-spinner> diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.spec.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.spec.ts index ec3ee8288b888a029f6de545b97636ec3c5aae5d..9e9a9d2118e1a9758f7ba58715f822822ead4cbf 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.spec.ts @@ -1,7 +1,8 @@ +import { dispatchEventFromFixture, MockEvent } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; - import { ButtonWithSpinnerComponent } from '@ods/component'; import { ForwardVorgangIconComponent } from '@ods/system'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; import { ForwardingButtonComponent } from './forwarding-button.component'; @@ -9,6 +10,8 @@ describe('ForwardingButtonComponent', () => { let component: ForwardingButtonComponent; let fixture: ComponentFixture<ForwardingButtonComponent>; + const button: string = getDataTestIdOf('forwarding-button-container'); + beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ForwardingButtonComponent], @@ -23,4 +26,14 @@ describe('ForwardingButtonComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + describe('on button click', () => { + it('should emit', () => { + component.clickEmitter.emit = jest.fn(); + + dispatchEventFromFixture(fixture, button, MockEvent.CLICK); + + expect(component.clickEmitter.emit).toHaveBeenCalled(); + }); + }); }); diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.ts index 63fec70d17fb549ab13163155fe3ca596446209a..767fe5e4ce40e7589725973d37e9a84c12fd0564 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-button/forwarding-button.component.ts @@ -1,4 +1,6 @@ -import { Component, Input } from '@angular/core'; +import { CommandResource } from '@alfa-client/command-shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ButtonWithSpinnerComponent } from '@ods/component'; import { ForwardVorgangIconComponent } from '@ods/system'; @@ -10,4 +12,7 @@ import { ForwardVorgangIconComponent } from '@ods/system'; }) export class ForwardingButtonComponent { @Input() disabled: boolean; + @Input() stateResource: StateResource<CommandResource>; + + @Output() clickEmitter: EventEmitter<void> = new EventEmitter(); } diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.html b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.html index 3d60550c444dcbc34d9f229e91c1133e6a5af9ac..5aaf99a340455262073812254cf8c7d74adf578e 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.html +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.html @@ -1,5 +1,5 @@ <div class="flex w-[620px] max-w-full flex-col gap-4 bg-background-100 p-8"> - <div class="flex items-center justify-between" > + <div class="flex items-center justify-between"> <h1 class="text-xl font-semibold text-primary">Vorgang weiterleiten</h1> <ods-cancel-dialog-button showAsIconButton="true" /> </div> @@ -7,14 +7,16 @@ @if (!selectedSearchResult) { <alfa-search-zustaendige-stelle-form-container cdkFocusInitial focusOnSearchField="true" data-test-id="zufi-search" /> } @else { - <alfa-forwarding-item-in-dialog - [organisationsEinheitResource]="selectedSearchResult" - data-test-id="forwarding-item" - /> + <alfa-forwarding-item-in-dialog [organisationsEinheitResource]="selectedSearchResult" data-test-id="forwarding-item" /> } <div class="flex gap-4"> - <alfa-forwarding-button [disabled]="!selectedSearchResult"/> + <alfa-forwarding-button + [stateResource]="forwardCommandStateResource" + [disabled]="!selectedSearchResult" + (clickEmitter)="onForwarding()" + data-test-id="foward-dialog-forward-button" + /> <ods-cancel-dialog-button /> </div> </div> diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.spec.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.spec.ts index 6d4454c8e37a0bde91a410aeacf6df07087973f6..7e6114236be2ad7d2dddfcdfd309853b32568cdd 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.spec.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.spec.ts @@ -1,14 +1,21 @@ -import { existsAsHtmlElement, getMockComponent, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { + dispatchEventFromFixture, + existsAsHtmlElement, + getMockComponent, + MockEvent, + notExistsAsHtmlElement, +} from '@alfa-client/test-utils'; import { ZustaendigeStelleModule } from '@alfa-client/zustaendige-stelle'; import { OrganisationsEinheitResource } from '@alfa-client/zustaendige-stelle-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { getUrl } from '@ngxp/rest'; import { CancelDialogButtonComponent } from '@ods/component'; import { MockComponent, MockModule } from 'ng-mocks'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; import { createOrganisationsEinheitResource } from '../../../../../zustaendige-stelle-shared/test/organisations-einheit'; import { ForwardingButtonComponent } from './forwarding-button/forwarding-button.component'; -import { ForwardingItemInDialogComponent } from './forwarding-item/forwarding-item.component'; import { ForwardingDialogComponent } from './forwarding-dialog.component'; +import { ForwardingItemInDialogComponent } from './forwarding-item/forwarding-item.component'; describe('ForwardingDialogComponent', () => { let component: ForwardingDialogComponent; @@ -16,6 +23,7 @@ describe('ForwardingDialogComponent', () => { const zufiSearch: string = getDataTestIdOf('zufi-search'); const forwardingItem: string = getDataTestIdOf('forwarding-item'); + const forwardButton: string = getDataTestIdOf('foward-dialog-forward-button'); const organisationsEinheitResource: OrganisationsEinheitResource = createOrganisationsEinheitResource(); beforeEach(async () => { @@ -64,23 +72,21 @@ describe('ForwardingDialogComponent', () => { fixture.detectChanges(); }); - describe('template', () => { - describe('forwarding item', () => { - it('should render if selectedSearchResult is NOT null', () => { - component.selectedSearchResult = organisationsEinheitResource; + describe('forwarding item', () => { + it('should render if selectedSearchResult is NOT null', () => { + component.selectedSearchResult = organisationsEinheitResource; - fixture.detectChanges(); + fixture.detectChanges(); - existsAsHtmlElement(fixture, forwardingItem); - }); + existsAsHtmlElement(fixture, forwardingItem); + }); - it('should NOT render if selectedSearchResult is null', () => { - component.selectedSearchResult = null; + it('should NOT render if selectedSearchResult is null', () => { + component.selectedSearchResult = null; - fixture.detectChanges(); + fixture.detectChanges(); - notExistsAsHtmlElement(fixture, forwardingItem); - }); + notExistsAsHtmlElement(fixture, forwardingItem); }); }); @@ -103,4 +109,15 @@ describe('ForwardingDialogComponent', () => { expect(forwardingButton.disabled).toBeFalsy(); }); }); + + describe('forward button', () => { + it('should emit on click', () => { + component.selectedSearchResult = organisationsEinheitResource; + component.forward.emit = jest.fn(); + + dispatchEventFromFixture(fixture, forwardButton, MockEvent.CLICK); + + expect(component.forward.emit).toHaveBeenCalledWith(getUrl(organisationsEinheitResource)); + }); + }); }); diff --git a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.ts b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.ts index c1695f42a08728b6921b6813694fad2ffb5440fe..178d84465273bc421ee5bd9a49dca84d213cb299 100644 --- a/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.ts +++ b/alfa-client/libs/forwarding/src/lib/forwarding-dialog-container/forwarding-dialog/forwarding-dialog.component.ts @@ -1,8 +1,11 @@ +import { CommandResource } from '@alfa-client/command-shared'; +import { StateResource } from '@alfa-client/tech-shared'; import { ZustaendigeStelleModule } from '@alfa-client/zustaendige-stelle'; import { OrganisationsEinheitResource } from '@alfa-client/zustaendige-stelle-shared'; import { A11yModule } from '@angular/cdk/a11y'; -import { Component, Input } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; +import { getUrl, ResourceUri } from '@ngxp/rest'; import { CancelDialogButtonComponent } from '@ods/component'; import { ForwardingButtonComponent } from './forwarding-button/forwarding-button.component'; import { ForwardingItemInDialogComponent } from './forwarding-item/forwarding-item.component'; @@ -22,4 +25,11 @@ import { ForwardingItemInDialogComponent } from './forwarding-item/forwarding-it }) export class ForwardingDialogComponent { @Input() selectedSearchResult: OrganisationsEinheitResource; + @Input() forwardCommandStateResource: StateResource<CommandResource>; + + @Output() forward: EventEmitter<ResourceUri> = new EventEmitter(); + + public onForwarding(): void { + this.forward.emit(getUrl(this.selectedSearchResult)); + } } diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts index 522ed1f6ce6a4ae086d1226253f1d1236eb3eb9d..5860d364284ddcb2e8a62b90e568bd84ad336ad9 100644 --- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts +++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts @@ -35,7 +35,7 @@ import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandResource } from 'libs/command-shared/test/command'; import { createKommentar, createKommentarListResource, createKommentarResource } from 'libs/kommentar-shared/test/kommentar'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; -import { of } from 'rxjs'; +import { of, Subscription } from 'rxjs'; import { singleCold } from '../../../tech-shared/test/marbles'; import { KommentarLinkRel, KommentarListLinkRel } from './kommentar.linkrel'; import { Kommentar, KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarListResource, KommentarResource } from './kommentar.model'; @@ -51,9 +51,12 @@ describe('KommentarService', () => { let binaryFileService: Mock<BinaryFileService>; const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource(); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(vorgang); + const kommentarList: KommentarListResource = createKommentarListResource(); const kommentar: Kommentar = createKommentar(); const kommentarResource: KommentarResource = createKommentarResource(); + const command: CommandResource = createCommandResource(); const commandStateResource: StateResource<CommandResource> = createStateResource(command); @@ -61,7 +64,10 @@ describe('KommentarService', () => { repository = mock(KommentarRepository); commandService = mock(CommandService); navigationService = mock(NavigationService); - vorgangService = mock(VorgangService); + vorgangService = { + ...mock(VorgangService), + getVorgangWithEingang: jest.fn().mockReturnValue(of(vorgangWithEingangStateResource)), + }; binaryFileService = mock(BinaryFileService); navigationService.urlChanged.mockReturnValue(of({})); @@ -79,14 +85,21 @@ describe('KommentarService', () => { beforeEach(() => { repository.findKommentare.mockReturnValue(of(kommentarList)); - service.setListLoadingTrue = jest.fn(); - service.setKommentarList = jest.fn(); + service._setListLoadingTrue = jest.fn(); + service._setKommentarList = jest.fn(); + service._refreshVorgangSubscription = jest.fn(); + }); + + it('should call refresh vorgang subscription', () => { + service.getKommentareByVorgang(vorgang); + + expect(service._refreshVorgangSubscription).toHaveBeenCalled(); }); it('should set loading to true', () => { service.getKommentareByVorgang(vorgang); - expect(service.setListLoadingTrue).toHaveBeenCalled(); + expect(service._setListLoadingTrue).toHaveBeenCalled(); }); it('should call repository', () => { @@ -98,7 +111,25 @@ describe('KommentarService', () => { it('should set loaded resource', () => { service.getKommentareByVorgang(vorgang); - expect(service.setKommentarList).toHaveBeenCalledWith(kommentarList); + expect(service._setKommentarList).toHaveBeenCalledWith(kommentarList); + }); + }); + + describe('refresh vorgang subscription', () => { + beforeEach(() => { + service.vorgangSubscription = <any>mock(Subscription); + service._listenToVorgangChange = jest.fn(); + }); + + it('should unsubscribe existing subscription', () => { + service._refreshVorgangSubscription(); + + expect(service.vorgangSubscription.unsubscribe).toHaveBeenCalled(); + }); + it('should call listen to vorgang change', () => { + service._refreshVorgangSubscription(); + + expect(service._listenToVorgangChange).toHaveBeenCalled(); }); }); @@ -126,28 +157,28 @@ describe('KommentarService', () => { expect(commandService.createCommand).toHaveBeenCalledWith( service.kommentarList$.value.resource, KommentarListLinkRel.CREATE_KOMMENTAR, - service.createCreateKommentarCommand(kommentar), + service._createCreateKommentarCommand(kommentar), ); }); it('should call getEffectedResource', () => { - service.afterCreateOrEditKommentar = jest.fn(); + service._afterCreateOrEditKommentar = jest.fn(); service.createKommentar(kommentar).subscribe(); - expect(service.afterCreateOrEditKommentar).toHaveBeenCalledWith(commandStateResource); + expect(service._afterCreateOrEditKommentar).toHaveBeenCalledWith(commandStateResource); }); it('should call createCreateKommentarCommand', () => { - service.createCreateKommentarCommand = jest.fn(); + service._createCreateKommentarCommand = jest.fn(); service.createKommentar(kommentar); - expect(service.createCreateKommentarCommand).toHaveBeenCalledWith(kommentar); + expect(service._createCreateKommentarCommand).toHaveBeenCalledWith(kommentar); }); it('should create CreateKommentarCommand', () => { - var command: CreateCommand = service.createCreateKommentarCommand(kommentar); + var command: CreateCommand = service._createCreateKommentarCommand(kommentar); expect(command).toEqual({ order: CommandOrder.CREATE_KOMMENTAR, body: kommentar }); }); @@ -178,28 +209,28 @@ describe('KommentarService', () => { expect(commandService.createCommand).toHaveBeenCalledWith( kommentarResource, KommentarLinkRel.EDIT, - service.createEditKommentarCommand(kommentar), + service._createEditKommentarCommand(kommentar), ); }); it('should call getEffectedResource', () => { - service.afterCreateOrEditKommentar = jest.fn(); + service._afterCreateOrEditKommentar = jest.fn(); service.editKommentar(kommentarResource, kommentar).subscribe(); - expect(service.afterCreateOrEditKommentar).toHaveBeenCalledWith(commandStateResource); + expect(service._afterCreateOrEditKommentar).toHaveBeenCalledWith(commandStateResource); }); it('should call createEditKommentarCommand', () => { - service.createEditKommentarCommand = jest.fn(); + service._createEditKommentarCommand = jest.fn(); service.editKommentar(kommentarResource, kommentar); - expect(service.createEditKommentarCommand).toHaveBeenCalledWith(kommentar); + expect(service._createEditKommentarCommand).toHaveBeenCalledWith(kommentar); }); it('should create CreateKommentarCommand', () => { - var command: CreateCommand = service.createEditKommentarCommand(kommentar); + var command: CreateCommand = service._createEditKommentarCommand(kommentar); expect(command).toEqual({ order: CommandOrder.EDIT_KOMMENTAR, body: kommentar }); }); @@ -217,7 +248,7 @@ describe('KommentarService', () => { it('should hide formular', () => { service.hideFormular = jest.fn(); - service.afterCreateOrEditKommentar({ + service._afterCreateOrEditKommentar({ ...commandStateResource, resource: createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), }); @@ -226,7 +257,7 @@ describe('KommentarService', () => { }); it('should reload vorgang', () => { - service.afterCreateOrEditKommentar({ + service._afterCreateOrEditKommentar({ ...commandStateResource, resource: createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), }); @@ -235,20 +266,20 @@ describe('KommentarService', () => { }); it('should set kommentar list on reload', () => { - service.setKommentarListReload = jest.fn(); + service._setKommentarListReload = jest.fn(); - service.afterCreateOrEditKommentar({ + service._afterCreateOrEditKommentar({ ...commandStateResource, resource: createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), }); - expect(service.setKommentarListReload).toHaveBeenCalled(); + expect(service._setKommentarListReload).toHaveBeenCalled(); }); }); describe('on command is pending', () => { it('should do nothing', () => { - service.afterCreateOrEditKommentar({ + service._afterCreateOrEditKommentar({ ...commandStateResource, resource: createCommandResource([CommandLinkRel.UPDATE]), }); @@ -265,13 +296,13 @@ describe('KommentarService', () => { }); it('should clear uploaded files', () => { - service.onNavigation({}); + service._onNavigation({}); expect(service.clearUploadedFiles).toHaveBeenCalled(); }); it('should hide forumlar', () => { - service.onNavigation({}); + service._onNavigation({}); expect(service.hideFormular).toHaveBeenCalled(); }); @@ -280,7 +311,7 @@ describe('KommentarService', () => { it('should set reload flag of kommentar list', () => { service.kommentarList$.next(createEmptyStateResource()); - service.onNavigation({}); + service._onNavigation({}); expect(service.kommentarList$.value.reload).toEqual(true); }); @@ -290,7 +321,7 @@ describe('KommentarService', () => { it('should set kommentar list to reload', () => { service.kommentarList$.next(createEmptyStateResource()); - service.onNavigation({ vorgangWithEingangUrl: 'X' }); + service._onNavigation({ vorgangWithEingangUrl: 'X' }); expect(service.kommentarList$.value.reload).toEqual(true); }); @@ -300,13 +331,13 @@ describe('KommentarService', () => { describe('attachments', () => { it('should be loaded if link avaible', () => { const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]); - service.getAttachments(kommentarResource); + service._getAttachments(kommentarResource); expect(binaryFileService.getFiles).toHaveBeenCalledWith(kommentarResource, KommentarLinkRel.ATTACHMENTS); }); it('should not be loaded if no link available', () => { - service.getAttachments(kommentarResource); + service._getAttachments(kommentarResource); expect(binaryFileService.getFiles).not.toHaveBeenCalled(); }); @@ -421,4 +452,63 @@ describe('KommentarService', () => { expect(service._currentlyEdited$).toBeObservable(singleCold(resourceUri)); }); }); + + describe('listen to vorgang change', () => { + beforeEach(() => { + service._handleVorgangChange = jest.fn(); + }); + + it('should call vorgang service to get vorgang with eingang', () => { + service._listenToVorgangChange(); + + expect(vorgangService.getVorgangWithEingang).toHaveBeenCalled(); + }); + + it('should call handle vorgang change', () => { + service._listenToVorgangChange(); + + expect(service._handleVorgangChange).toHaveBeenCalledWith(vorgangWithEingangStateResource); + }); + }); + + describe('handle vorgang change', () => { + it('should set reload flag if list is loaded and state resource is loading', () => { + service.shouldReload = false; + service.kommentarList$.next(createStateResource(createKommentarListResource())); + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, loading: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + it('should set reload flag if list is loaded and state resource is reloading', () => { + service.kommentarList$.next(createStateResource(createKommentarListResource())); + service.shouldReload = false; + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, reload: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + describe('on setted reload flag', () => { + beforeEach(() => { + service._setKommentarListReload = jest.fn(); + service.shouldReload = true; + }); + + describe('and loaded vorgang resource', () => { + it('should call set kommentar list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service._setKommentarListReload).toHaveBeenCalled(); + }); + + it('and loaded vorgang resource should call set kommentar list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service.shouldReload).toBeFalsy(); + }); + }); + }); + }); }); diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts index 0055824e34836c3ad1195ce85d01ff4f2b772a35..395872897b9e894a0c4336f50f16a10f7598e878 100644 --- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts +++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts @@ -24,8 +24,17 @@ import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService, CreateCommand, isDone } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, doIfLoadingRequired, EMPTY_STRING, isNotEmpty, StateResource, } from '@alfa-client/tech-shared'; -import { VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; +import { + createEmptyStateResource, + createStateResource, + doIfLoadingRequired, + EMPTY_STRING, + isLoaded, + isNotEmpty, + isNotNull, + StateResource, +} from '@alfa-client/tech-shared'; +import { VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Injectable } from '@angular/core'; import { Params } from '@angular/router'; import { hasLink, Resource, ResourceUri } from '@ngxp/rest'; @@ -46,6 +55,10 @@ export class KommentarService { private navigationSub: Subscription; + vorgangSubscription: Subscription; + + shouldReload: boolean = false; + constructor( private repository: KommentarRepository, private commandService: CommandService, @@ -54,18 +67,19 @@ export class KommentarService { private binaryFileService: BinaryFileService, ) { this.listenToNavigation(); + this._listenToVorgangChange(); } private listenToNavigation(): void { this.unsubscribe(); - this.navigationSub = this.navigationService.urlChanged().subscribe((params: Params) => this.onNavigation(params)); + this.navigationSub = this.navigationService.urlChanged().subscribe((params: Params) => this._onNavigation(params)); } private unsubscribe(): void { if (!isNil(this.navigationSub)) this.navigationSub.unsubscribe(); } - onNavigation(params: Params): void { + _onNavigation(params: Params): void { this.clearUploadedFiles(); this.hideFormular(); if (NavigationService.isVorgangListPage(params)) { @@ -81,28 +95,59 @@ export class KommentarService { } public getKommentareByVorgang(vorgang: VorgangResource): Observable<StateResource<KommentarListResource>> { + this._refreshVorgangSubscription(); doIfLoadingRequired(this.kommentarList$.value, () => this.loadKommentare(vorgang)); return this.kommentarList$.asObservable(); } + _refreshVorgangSubscription(): void { + this.vorgangSubscription.unsubscribe(); + this._listenToVorgangChange(); + } + + _listenToVorgangChange(): void { + this.vorgangSubscription = this.vorgangService + .getVorgangWithEingang() + .subscribe((vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>) => + this._handleVorgangChange(vorgangWithEingangStateResource), + ); + } + + _handleVorgangChange(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): void { + if (this.shouldReloadList(vorgangWithEingangStateResource)) { + this.shouldReload = true; + } + if (isLoaded(vorgangWithEingangStateResource) && this.shouldReload) { + this._setKommentarListReload(); + this.shouldReload = false; + } + } + + private shouldReloadList(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): boolean { + return ( + (vorgangWithEingangStateResource.loading || vorgangWithEingangStateResource.reload) && + isNotNull(this.kommentarList$.value.resource) + ); + } + private loadKommentare(vorgang: VorgangResource): void { - this.setListLoadingTrue(); + this._setListLoadingTrue(); const sub: Subscription = this.repository.findKommentare(vorgang).subscribe((kommentarList: KommentarListResource) => { - this.setKommentarList(kommentarList); + this._setKommentarList(kommentarList); sub.unsubscribe(); }); } - setListLoadingTrue(): void { + _setListLoadingTrue(): void { this.kommentarList$.next({ ...this.kommentarList$.value, loading: true }); } - setKommentarListReload() { + _setKommentarListReload() { this.kommentarList$.next({ ...this.kommentarList$.value, reload: true }); } - setKommentarList(kommentarList: KommentarListResource): void { + _setKommentarList(kommentarList: KommentarListResource): void { this.kommentarList$.next(createStateResource(kommentarList)); } @@ -128,45 +173,45 @@ export class KommentarService { } public createKommentar(kommentar: Kommentar): Observable<StateResource<CommandResource>> { - return this.createKommentarCommand( + return this._createKommentarCommand( this.kommentarList$.value.resource, KommentarListLinkRel.CREATE_KOMMENTAR, - this.createCreateKommentarCommand(kommentar), + this._createCreateKommentarCommand(kommentar), ); } - createCreateKommentarCommand(kommentar: Kommentar): CreateCommand { + _createCreateKommentarCommand(kommentar: Kommentar): CreateCommand { return { order: CommandOrder.CREATE_KOMMENTAR, body: kommentar }; } public editKommentar(kommentar: KommentarResource, toPatch: Kommentar): Observable<StateResource<CommandResource>> { - return this.createKommentarCommand(kommentar, KommentarLinkRel.EDIT, this.createEditKommentarCommand(toPatch)); + return this._createKommentarCommand(kommentar, KommentarLinkRel.EDIT, this._createEditKommentarCommand(toPatch)); } - createEditKommentarCommand(kommentar: Kommentar): CreateCommand { + _createEditKommentarCommand(kommentar: Kommentar): CreateCommand { return { order: CommandOrder.EDIT_KOMMENTAR, body: kommentar }; } - createKommentarCommand( + _createKommentarCommand( resource: Resource, linkRel: string, command: CreateCommand, ): Observable<StateResource<CommandResource>> { return this.commandService.createCommand(resource, linkRel, command).pipe( - tap((createdCommand: StateResource<CommandResource>) => this.afterCreateOrEditKommentar(createdCommand)), + tap((createdCommand: StateResource<CommandResource>) => this._afterCreateOrEditKommentar(createdCommand)), startWith(createEmptyStateResource<CommandResource>(true)), ); } - afterCreateOrEditKommentar(command: StateResource<CommandResource>): void { + _afterCreateOrEditKommentar(command: StateResource<CommandResource>): void { if (isDone(command.resource)) { this.hideFormular(); - this.setKommentarListReload(); + this._setKommentarListReload(); this.vorgangService.reloadCurrentVorgang(); } } - getAttachments(kommentar: KommentarResource): Observable<StateResource<BinaryFileListResource>> { + _getAttachments(kommentar: KommentarResource): Observable<StateResource<BinaryFileListResource>> { if (hasLink(kommentar, KommentarLinkRel.ATTACHMENTS)) { return this.binaryFileService.getFiles(kommentar, KommentarLinkRel.ATTACHMENTS); } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts index 9753cc7fa2dafde144f13618d84c55a24b1bc1a3..4470d7d9b7d85481c65e909ef9e12fef63b59194 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts @@ -102,7 +102,7 @@ describe('KommentarFormComponent', () => { const patchSpy = jest.spyOn(KommentarFormService.prototype, 'patch').mockImplementation(); const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]); component.kommentar = kommentarResource; - kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); + kommentarService._getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); component.ngOnChanges(); @@ -111,7 +111,7 @@ describe('KommentarFormComponent', () => { it('should load attachments', (done) => { component.kommentar = createKommentarResource([KommentarLinkRel.ATTACHMENTS]); - kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); + kommentarService._getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); component.ngOnChanges(); @@ -124,11 +124,11 @@ describe('KommentarFormComponent', () => { it('should call kommentarService', () => { const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]); component.kommentar = kommentarResource; - kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); + kommentarService._getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource()))); component.ngOnChanges(); - expect(kommentarService.getAttachments).toHaveBeenCalledWith(kommentarResource); + expect(kommentarService._getAttachments).toHaveBeenCalledWith(kommentarResource); }); describe('submit', () => { diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts index 0566d0f19efcc3e09aff3d5a726465eae21371d9..851cf4590f31bd8877ee22a935ca569c804c6aa1 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts @@ -23,7 +23,14 @@ */ import { BinaryFileListLinkRel, BinaryFileResource } from '@alfa-client/binary-file-shared'; import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; -import { KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarLinkRel, KommentarListLinkRel, KommentarListResource, KommentarResource, KommentarService, } from '@alfa-client/kommentar-shared'; +import { + KOMMENTAR_UPLOADED_ATTACHMENTS, + KommentarLinkRel, + KommentarListLinkRel, + KommentarListResource, + KommentarResource, + KommentarService, +} from '@alfa-client/kommentar-shared'; import { createEmptyStateResource, getEmbeddedResources, StateResource } from '@alfa-client/tech-shared'; import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { isNil } from 'lodash-es'; @@ -66,7 +73,7 @@ export class KommentarFormComponent implements OnChanges { private updateAttachments() { this.attachments$ = this.kommentarService - .getAttachments(this.kommentar) + ._getAttachments(this.kommentar) .pipe(map((stateResource) => getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST))); } diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts index 1fa11168673776f20130a7be5616abb0ac84380a..e27318f11b1c3ab1c1263586b23781a0f42b5606 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.spec.ts @@ -127,7 +127,7 @@ describe('KommentarListInVorgangContainerComponent', () => { describe('reloadKommentarListOnVorgangReload', () => { beforeEach(() => { - kommentarService.setKommentarListReload.mockClear(); + kommentarService._setKommentarListReload.mockClear(); }); it('should call kommentarService', () => { @@ -138,7 +138,7 @@ describe('KommentarListInVorgangContainerComponent', () => { component.reloadKommentarListOnVorgangReload(); - expect(kommentarService.setKommentarListReload).toHaveBeenCalled(); + expect(kommentarService._setKommentarListReload).toHaveBeenCalled(); }); it('should not call kommentarService', () => { @@ -149,7 +149,7 @@ describe('KommentarListInVorgangContainerComponent', () => { component.reloadKommentarListOnVorgangReload(); - expect(kommentarService.setKommentarListReload).not.toHaveBeenCalled(); + expect(kommentarService._setKommentarListReload).not.toHaveBeenCalled(); }); }); diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts index 21d3159a29496a6927f7076de4734ff03c663f44..78bdbb63fd8a82dc06d7ea412d9967577796b64e 100644 --- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts +++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component.ts @@ -55,7 +55,7 @@ export class KommentarListInVorgangContainerComponent implements OnChanges, OnIn reloadKommentarListOnVorgangReload(): void { if (this.vorgangStateResource.reload) { - this.kommentarService.setKommentarListReload(); + this.kommentarService._setKommentarListReload(); } } diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts index 678219f735fd5882a763a535687688c630bd5045..9149471c8d22327948bb18ae382aeeeb45cafe32 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts @@ -35,7 +35,13 @@ import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandErrorResource, createCommandResource } from 'libs/command-shared/test/command'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BehaviorSubject, of } from 'rxjs'; -import { createPostfachFeatures, createPostfachMail, createPostfachMailListResource, createPostfachMailResource, createPostfachSettings, } from '../../test/postfach'; +import { + createPostfachFeatures, + createPostfachMail, + createPostfachMailListResource, + createPostfachMailResource, + createPostfachSettings, +} from '../../test/postfach'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; import { PostfachMessages } from './postfach.message'; @@ -50,7 +56,7 @@ describe('PostfachService', () => { let repository: Mock<PostfachRepository>; const commandService: Mock<CommandService> = mock(CommandService); const navigationService: Mock<NavigationService> = mock(NavigationService); - const vorgangService: Mock<VorgangService> = mock(VorgangService); + let vorgangService: Mock<VorgangService>; const snackbarService: Mock<SnackBarService> = mock(SnackBarService); const dialog: Mock<MatDialog> = <Mock<MatDialog>>{ closeAll: jest.fn() }; const postfachFacade: Mock<PostfachFacade> = mock(PostfachFacade); @@ -58,7 +64,14 @@ describe('PostfachService', () => { const urlChangedParams = {}; + const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource(); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(vorgang); + beforeEach(() => { + vorgangService = { + ...mock(VorgangService), + getVorgangWithEingang: jest.fn().mockReturnValue(of(vorgangWithEingangStateResource)), + }; navigationService.urlChanged = jest.fn(); navigationService.urlChanged.mockReturnValue(of(urlChangedParams)); @@ -114,7 +127,7 @@ describe('PostfachService', () => { describe('reload postfach list', () => { beforeEach(() => { - service.refreshPostfachMailList = jest.fn(); + service._refreshPostfachMailList = jest.fn(); }); it('should execute on command is done', () => { @@ -125,7 +138,7 @@ describe('PostfachService', () => { service.sendMail(postfachMail); - expect(service.refreshPostfachMailList).toHaveBeenCalledWith(commandStateResource); + expect(service._refreshPostfachMailList).toHaveBeenCalledWith(commandStateResource); }); it('should not execute on pending command', () => { @@ -133,7 +146,7 @@ describe('PostfachService', () => { service.sendMail(postfachMail); - expect(service.refreshPostfachMailList).not.toHaveBeenCalled(); + expect(service._refreshPostfachMailList).not.toHaveBeenCalled(); }); }); }); @@ -145,13 +158,13 @@ describe('PostfachService', () => { const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); it('should call doSendNachricht', () => { - service.doSendNachricht = jest.fn(); + service._doSendNachricht = jest.fn(); commandService.createCommand.mockReturnValue(of(commandStateResource)); vorgangService.getPendingSendPostfachMailCommand.mockReturnValue(of(commandStateResource)); service.sendExistingMail(postfachNachricht, nachricht); - expect(service.doSendNachricht).toHaveBeenCalledWith( + expect(service._doSendNachricht).toHaveBeenCalledWith( postfachNachricht, PostfachMailLinkRel.SEND, createSendPostfachMailCommand(nachricht), @@ -163,7 +176,7 @@ describe('PostfachService', () => { const postfachMailResource: PostfachMailResource = createPostfachMailResource(); beforeEach(() => { - service.handleSendPostfachMailIsDone = jest.fn(); + service._handleSendPostfachMailIsDone = jest.fn(); commandService.createCommand.mockReturnValue(of(createStateResource(createCommandResource()))); vorgangService.getPendingSendPostfachMailCommand.mockReturnValue(of(createStateResource(createCommandResource()))); @@ -191,7 +204,7 @@ describe('PostfachService', () => { commandService.createCommand.mockReturnValue(of(createStateResource(createCommandResource([CommandLinkRel.UPDATE])))); service.resendMail(postfachMailResource); - expect(service.handleSendPostfachMailIsDone).not.toHaveBeenCalled(); + expect(service._handleSendPostfachMailIsDone).not.toHaveBeenCalled(); }); it('should call handleSendPostfachMailIsDone if command is done', () => { @@ -202,7 +215,7 @@ describe('PostfachService', () => { service.resendMail(postfachMailResource); - expect(service.handleSendPostfachMailIsDone).toHaveBeenCalledWith(commandResponse); + expect(service._handleSendPostfachMailIsDone).toHaveBeenCalledWith(commandResponse); }); }); @@ -210,25 +223,25 @@ describe('PostfachService', () => { const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { - service.commandIsDone = jest.fn(); + service._commandIsDone = jest.fn(); }); it('should call vorgang service', () => { - service.handleSendNachrichtCommand(commandStateResource); + service._handleSendNachrichtCommand(commandStateResource); expect(vorgangService.setPendingSendPostfachMailCommand).toHaveBeenCalledWith(commandStateResource); }); it('should call commandIsDone', () => { - service.handleSendNachrichtCommand(commandStateResource); + service._handleSendNachrichtCommand(commandStateResource); - expect(service.commandIsDone).toHaveBeenCalledWith(commandStateResource); + expect(service._commandIsDone).toHaveBeenCalledWith(commandStateResource); }); }); describe('commandIsDone', () => { beforeEach(() => { - service.handleSendPostfachMailIsDone = jest.fn(); + service._handleSendPostfachMailIsDone = jest.fn(); }); it('should call handleSendPostfachMailIsDone', () => { @@ -236,9 +249,9 @@ describe('PostfachService', () => { createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]), ); - service.commandIsDone(commandStateResource); + service._commandIsDone(commandStateResource); - expect(service.handleSendPostfachMailIsDone).toHaveBeenCalledWith(commandStateResource); + expect(service._handleSendPostfachMailIsDone).toHaveBeenCalledWith(commandStateResource); }); describe('on command is done', () => { @@ -248,7 +261,7 @@ describe('PostfachService', () => { errorMessage: null, }); - service.commandIsDone(commandStateResource); + service._commandIsDone(commandStateResource); expect(snackbarService.show).toHaveBeenCalledWith(commandStateResource.resource, PostfachMessages.SEND_SUCCESSFUL); }); @@ -260,7 +273,7 @@ describe('PostfachService', () => { createCommandErrorResource([CommandLinkRel.EFFECTED_RESOURCE]), ); - service.commandIsDone(commandStateResource); + service._commandIsDone(commandStateResource); expect(snackbarService.showError).toHaveBeenCalledWith(PostfachMessages.SEND_FAILED); }); @@ -269,58 +282,58 @@ describe('PostfachService', () => { describe('listenToNavigation', () => { it('should call usnsubcribeToNavigation', () => { - service.listenToNavigation(); + service._listenToNavigation(); expect(navigationService.urlChanged).toHaveBeenCalled(); }); it('should call navigation service', () => { - service.unsubscribeToNavigation = jest.fn(); + service._unsubscribeToNavigation = jest.fn(); - service.listenToNavigation(); + service._listenToNavigation(); - expect(service.unsubscribeToNavigation).toHaveBeenCalled(); + expect(service._unsubscribeToNavigation).toHaveBeenCalled(); }); it('should call onNavigation', () => { - service.onNavigation = jest.fn(); + service._onNavigation = jest.fn(); - service.listenToNavigation(); + service._listenToNavigation(); - expect(service.onNavigation).toHaveBeenCalledWith(urlChangedParams); + expect(service._onNavigation).toHaveBeenCalledWith(urlChangedParams); }); }); describe('onNavigation', () => { describe('to vorgang list', () => { beforeEach(() => { - service.setPollingFalse = jest.fn(); - service.clearPostfachMailList = jest.fn(); - service.unsubscribe = jest.fn(); + service._setPollingFalse = jest.fn(); + service._clearPostfachMailList = jest.fn(); + service._unsubscribe = jest.fn(); }); it('should set polling false', () => { - service.onNavigation({}); + service._onNavigation({}); - expect(service.setPollingFalse).toHaveBeenCalled(); + expect(service._setPollingFalse).toHaveBeenCalled(); }); it('should call clearPostfachMailList', () => { - service.onNavigation({}); + service._onNavigation({}); - expect(service.clearPostfachMailList).toHaveBeenCalled(); + expect(service._clearPostfachMailList).toHaveBeenCalled(); }); it('should call closeOpenDialogs', () => { - service.onNavigation({}); + service._onNavigation({}); expect(dialog.closeAll).toHaveBeenCalled(); }); it('should call unsubscribe', () => { - service.onNavigation({}); + service._onNavigation({}); - expect(service.unsubscribe).toHaveBeenCalled(); + expect(service._unsubscribe).toHaveBeenCalled(); }); }); @@ -328,7 +341,7 @@ describe('PostfachService', () => { it('should set postfach nachrichten list to reload', () => { service.postfachMailList$.next(createEmptyStateResource()); - service.onNavigation({ vorgangWithEingangUrl: 'X' }); + service._onNavigation({ vorgangWithEingangUrl: 'X' }); expect(service.postfachMailList$.value.reload).toEqual(true); }); @@ -336,12 +349,12 @@ describe('PostfachService', () => { describe('to postfach page', () => { beforeEach(() => { - service.resetHasNewPostfachNachrichten = jest.fn(); + service._resetHasNewPostfachNachrichten = jest.fn(); navigationService.isPostfachPage.mockReturnValue(true); }); it('should call navigationService', () => { - service.onNavigation({}); + service._onNavigation({}); expect(navigationService.isPostfachPage).toHaveBeenCalled(); }); @@ -349,17 +362,17 @@ describe('PostfachService', () => { it('should reset hasNewPostfachNachrichten', () => { navigationService.isPostfachPage.mockReturnValue(true); - service.onNavigation({}); + service._onNavigation({}); - expect(service.resetHasNewPostfachNachrichten).toHaveBeenCalled(); + expect(service._resetHasNewPostfachNachrichten).toHaveBeenCalled(); }); }); }); describe('getPendingSendPostfachMailCommand', () => { beforeEach(() => { - service.unsubscribe = jest.fn(); - service.pollSendPostfachMailCommand = jest.fn(); + service._unsubscribe = jest.fn(); + service._pollSendPostfachMailCommand = jest.fn(); commandService.pollCommand.mockReturnValue(of(createStateResource(createCommandResource()))); vorgangService.getPendingSendPostfachMailCommand.mockReturnValue(of(createStateResource(createCommandResource()))); @@ -377,12 +390,12 @@ describe('PostfachService', () => { it('should call doResetHasNewPostfachNachrichten', () => { service.getPostfachMailListByVorgang = jest.fn(); - service.doResetHasNewPostfachNachrichten = jest.fn(); + service._doResetHasNewPostfachNachrichten = jest.fn(); (<any>service.getPostfachMailListByVorgang).mockReturnValue(of(postfachListNachrichtenResource)); - service.resetHasNewPostfachNachrichten(); + service._resetHasNewPostfachNachrichten(); - expect(service.doResetHasNewPostfachNachrichten).toHaveBeenCalled(); + expect(service._doResetHasNewPostfachNachrichten).toHaveBeenCalled(); }); }); @@ -398,7 +411,7 @@ describe('PostfachService', () => { }); it('should call repository if link exists', () => { - service.doResetHasNewPostfachNachrichten(); + service._doResetHasNewPostfachNachrichten(); expect(repository.resetHasNewPostfachNachrichten).toHaveBeenCalledWith(postfachNachrichtenListResource); }); @@ -408,7 +421,7 @@ describe('PostfachService', () => { const postfachNachrichtenListResource: PostfachMailListResource = createPostfachMailListResource(); service.postfachMailList$.next(createStateResource(postfachNachrichtenListResource)); - service.doResetHasNewPostfachNachrichten(); + service._doResetHasNewPostfachNachrichten(); expect(repository.resetHasNewPostfachNachrichten).not.toHaveBeenCalled(); }); @@ -419,16 +432,23 @@ describe('PostfachService', () => { beforeEach(() => { repository.loadPostfachMailList.mockReturnValue(of(postfachMailList)); - service.setPostfachMailListLoading = jest.fn(); - service.setPostfachMailList = jest.fn(); + service._setPostfachMailListLoading = jest.fn(); + service._setPostfachMailList = jest.fn(); vorgangService.getVorgangWithEingang.mockReturnValue(of(createStateResource(createVorgangWithEingangResource()))); service.postfachMailList$.next(createEmptyStateResource()); + service._refreshVorgangSubscription = jest.fn(); + }); + + it('should call refresh vorgang subscription', () => { + service.getPostfachMailListByVorgang(); + + expect(service._refreshVorgangSubscription).toHaveBeenCalled(); }); it('should set loading to true', () => { service.getPostfachMailListByVorgang(); - expect(service.setPostfachMailListLoading).toHaveBeenCalled(); + expect(service._setPostfachMailListLoading).toHaveBeenCalled(); }); it('should call vorgang service', () => { @@ -446,7 +466,7 @@ describe('PostfachService', () => { it('should set loading to false', () => { service.getPostfachMailListByVorgang(); - expect(service.setPostfachMailList).toHaveBeenCalled(); + expect(service._setPostfachMailList).toHaveBeenCalled(); }); }); @@ -454,28 +474,28 @@ describe('PostfachService', () => { const stateResource: StateResource<CommandResource> = createStateResource(createCommandResource()); beforeEach(() => { - service.setPollingFalse = jest.fn(); - service.setPostfachMailList = jest.fn(); + service._setPollingFalse = jest.fn(); + service._setPostfachMailList = jest.fn(); commandService.getEffectedResource.mockReturnValue(of(createCommandResource())); }); it('should call command service to get effected resource', () => { - service.handleSendPostfachMailIsDone(stateResource); + service._handleSendPostfachMailIsDone(stateResource); expect(commandService.getEffectedResource).toHaveBeenCalledWith(stateResource.resource); }); it('should set postfachMailList', () => { - service.handleSendPostfachMailIsDone(stateResource); + service._handleSendPostfachMailIsDone(stateResource); - expect(service.setPostfachMailList).toHaveBeenCalled(); + expect(service._setPostfachMailList).toHaveBeenCalled(); }); it('should set polling to false', () => { - service.handleSendPostfachMailIsDone(stateResource); + service._handleSendPostfachMailIsDone(stateResource); - expect(service.setPollingFalse).toHaveBeenCalled(); + expect(service._setPollingFalse).toHaveBeenCalled(); }); }); @@ -548,9 +568,68 @@ describe('PostfachService', () => { }); it('should clear uploaded files', () => { - service.closeOpenDialogs(); + service._closeOpenDialogs(); expect(service.clearUploadedFiles).toHaveBeenCalled(); }); }); + + describe('listen to vorgang change', () => { + beforeEach(() => { + service._handleVorgangChange = jest.fn(); + }); + + it('should call vorgang service to get vorgang with eingang', () => { + service._listenToVorgangChange(); + + expect(vorgangService.getVorgangWithEingang).toHaveBeenCalled(); + }); + + it('should call handle vorgang change', () => { + service._listenToVorgangChange(); + + expect(service._handleVorgangChange).toHaveBeenCalledWith(vorgangWithEingangStateResource); + }); + }); + + describe('handle vorgang change', () => { + it('should set reload flag if list is loaded and state resource is loading', () => { + service.shouldReload = false; + service.postfachMailList$.next(createStateResource(createPostfachMailListResource())); + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, loading: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + it('should set reload flag if list is loaded and state resource is reloading', () => { + service.postfachMailList$.next(createStateResource(createPostfachMailListResource())); + service.shouldReload = false; + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, reload: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + describe('on setted reload flag', () => { + beforeEach(() => { + service._setPostfachMailOnReload = jest.fn(); + service.shouldReload = true; + }); + + describe('and loaded vorgang resource', () => { + it('should call set kommentar list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service._setPostfachMailOnReload).toHaveBeenCalled(); + }); + + it('and loaded vorgang resource should call set kommentar list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service.shouldReload).toBeFalsy(); + }); + }); + }); + }); }); diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts index e39019766d5f873a246643dec3c951cc4e2efd39..f650edd3f4c598a309482fe95658930794deaae8 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts @@ -23,11 +23,26 @@ */ import { POSTFACH_NACHRICHT_UPLOADED_ATTACHMENTS } from '@admin-client/postfach-shared'; import { BinaryFileService } from '@alfa-client/binary-file-shared'; -import { CommandResource, CommandService, doIfCommandIsDone, hasCommandError, isDone, isPending, } from '@alfa-client/command-shared'; +import { + CommandResource, + CommandService, + doIfCommandIsDone, + hasCommandError, + isDone, + isPending, +} from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, doIfLoadingRequired, isNotNull, isNotUndefined, StateResource, } from '@alfa-client/tech-shared'; +import { + createEmptyStateResource, + createStateResource, + doIfLoadingRequired, + isLoaded, + isNotNull, + isNotUndefined, + StateResource, +} from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; -import { VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; +import { VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { inject, Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { Params } from '@angular/router'; @@ -38,7 +53,14 @@ import { first, map, take, tap } from 'rxjs/operators'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; import { PostfachMessages } from './postfach.message'; -import { CreatePostfachMailCommand, PostfachFeatures, PostfachMail, PostfachMailListResource, PostfachMailResource, PostfachSettings, } from './postfach.model'; +import { + CreatePostfachMailCommand, + PostfachFeatures, + PostfachMail, + PostfachMailListResource, + PostfachMailResource, + PostfachSettings, +} from './postfach.model'; import { PostfachRepository } from './postfach.repository'; import { createResendPostfachMailCommand, createSendPostfachMailCommand } from './postfach.util'; @@ -65,12 +87,17 @@ export class PostfachService { private vorgangSubscription: Subscription; private postfachNachrichtenListSubscription: Subscription; + private vorgangChangeSubscription: Subscription; + + shouldReload: boolean = false; + constructor() { - this.listenToNavigation(); + this._listenToNavigation(); + this._listenToVorgangChange(); } public sendMail(postfachMail: PostfachMail): Observable<StateResource<CommandResource>> { - return this.doSendNachricht( + return this._doSendNachricht( this.postfachMailList$.value.resource, PostfachMailListLinkRel.SEND_POSTFACH_MAIL, createSendPostfachMailCommand(postfachMail), @@ -81,18 +108,18 @@ export class PostfachService { postfachMailResource: PostfachMailResource, postfachMail: PostfachMail, ): Observable<StateResource<CommandResource>> { - return this.doSendNachricht(postfachMailResource, PostfachMailLinkRel.SEND, createSendPostfachMailCommand(postfachMail)); + return this._doSendNachricht(postfachMailResource, PostfachMailLinkRel.SEND, createSendPostfachMailCommand(postfachMail)); } public resendMail(postfachMailResource: PostfachMailResource): Observable<StateResource<CommandResource>> { - return this.doSendNachricht( + return this._doSendNachricht( postfachMailResource, PostfachMailLinkRel.RESEND_POSTFACH_MAIL, createResendPostfachMailCommand(), ); } - doSendNachricht( + _doSendNachricht( resource: Resource, linkRel: string, command: CreatePostfachMailCommand, @@ -102,20 +129,20 @@ export class PostfachService { this.commandService .createCommand(resource, linkRel, command) .pipe(first()) - .subscribe((createdCommand) => this.handleSendNachrichtCommand(createdCommand)); + .subscribe((createdCommand) => this._handleSendNachrichtCommand(createdCommand)); return this.getPendingSendPostfachMailCommand(); } - handleSendNachrichtCommand(commandStateResource: StateResource<CommandResource>): void { + _handleSendNachrichtCommand(commandStateResource: StateResource<CommandResource>): void { this.vorgangService.setPendingSendPostfachMailCommand(commandStateResource); - this.commandIsDone(commandStateResource); + this._commandIsDone(commandStateResource); } - commandIsDone(commandStateResource: StateResource<CommandResource>): void { + _commandIsDone(commandStateResource: StateResource<CommandResource>): void { doIfCommandIsDone(commandStateResource.resource, () => { this.showSnackbar(commandStateResource.resource); - this.handleSendPostfachMailIsDone(commandStateResource); + this._handleSendPostfachMailIsDone(commandStateResource); }); } @@ -130,79 +157,79 @@ export class PostfachService { public getPendingSendPostfachMailCommand(): Observable<StateResource<CommandResource>> { return this.vorgangService .getPendingSendPostfachMailCommand() - .pipe(map((pendingCommand) => this.pollSendPostfachMailCommand(pendingCommand))); + .pipe(map((pendingCommand) => this._pollSendPostfachMailCommand(pendingCommand))); } - listenToNavigation(): void { - this.unsubscribeToNavigation(); - this.navigationSubscription = this.navigationService.urlChanged().subscribe((params) => this.onNavigation(params)); + _listenToNavigation(): void { + this._unsubscribeToNavigation(); + this.navigationSubscription = this.navigationService.urlChanged().subscribe((params) => this._onNavigation(params)); } - unsubscribeToNavigation(): void { + _unsubscribeToNavigation(): void { if (!isNil(this.navigationSubscription)) this.navigationSubscription.unsubscribe(); } - onNavigation(params: Params): void { + _onNavigation(params: Params): void { if (NavigationService.isVorgangListPage(params)) { - this.setPollingFalse(); - this.clearPostfachMailList(); - this.closeOpenDialogs(); - this.unsubscribe(); + this._setPollingFalse(); + this._clearPostfachMailList(); + this._closeOpenDialogs(); + this._unsubscribe(); } if (NavigationService.isVorgangDetailPage(params, VorgangService.VORGANG_WITH_EINGANG_URL)) { - this.setPostfachMailOnReload(); + this._setPostfachMailOnReload(); } if (this.navigationService.isPostfachPage()) { - this.resetHasNewPostfachNachrichten(); + this._resetHasNewPostfachNachrichten(); } } - setPollingFalse(): void { + _setPollingFalse(): void { this.isPollSendPostachMail.next(false); } - clearPostfachMailList(): void { + _clearPostfachMailList(): void { this.postfachMailList$.next(createEmptyStateResource<PostfachMailListResource>()); } - closeOpenDialogs(): void { + _closeOpenDialogs(): void { this.dialog.closeAll(); this.clearUploadedFiles(); } - unsubscribe(): void { + _unsubscribe(): void { if (isNotUndefined(this.sendPostfachMailSubscription)) this.sendPostfachMailSubscription.unsubscribe(); if (isNotUndefined(this.loadPostfachMailSubscription)) this.loadPostfachMailSubscription.unsubscribe(); if (isNotUndefined(this.vorgangSubscription)) this.vorgangSubscription.unsubscribe(); } - setPostfachMailOnReload(): void { + _setPostfachMailOnReload(): void { this.postfachMailList$.next({ ...this.postfachMailList$.value, reload: true }); } - resetHasNewPostfachNachrichten(): void { + _resetHasNewPostfachNachrichten(): void { this.postfachNachrichtenListSubscription = this.getPostfachMailListByVorgang().subscribe((postfachNachrichtenList) => { if (isNotNull(postfachNachrichtenList.resource)) { setTimeout(() => this.postfachNachrichtenListSubscription.unsubscribe(), 0); - this.doResetHasNewPostfachNachrichten(); + this._doResetHasNewPostfachNachrichten(); } }); } - doResetHasNewPostfachNachrichten(): void { + _doResetHasNewPostfachNachrichten(): void { if (hasLink(this.postfachMailList$.value.resource, PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT)) { this.repository.resetHasNewPostfachNachrichten(this.postfachMailList$.value.resource).pipe(take(1)).subscribe(); } } - pollSendPostfachMailCommand(command: StateResource<CommandResource>): StateResource<CommandResource> { + _pollSendPostfachMailCommand(command: StateResource<CommandResource>): StateResource<CommandResource> { if (this.shouldPoll(command)) { - this.setPollingTrue(); + this._setPollingTrue(); this.sendPostfachMailSubscription = this.commandService.pollCommand(command.resource).subscribe((updatedStateResource) => { this.vorgangService.setPendingSendPostfachMailCommand(updatedStateResource); if (isDone(updatedStateResource.resource)) { - this.handleSendPostfachMailIsDone(updatedStateResource); + this._handleSendPostfachMailIsDone(updatedStateResource); setTimeout(() => this.sendPostfachMailSubscription.unsubscribe(), 0); } }); @@ -214,39 +241,40 @@ export class PostfachService { return command.loaded && isPending(command.resource) && !this.isPollSendPostachMail.value; } - setPollingTrue(): void { + _setPollingTrue(): void { this.isPollSendPostachMail.next(true); } - handleSendPostfachMailIsDone(updatedStateResource: StateResource<CommandResource>): void { - this.refreshPostfachMailList(updatedStateResource); - this.setPollingFalse(); + _handleSendPostfachMailIsDone(updatedStateResource: StateResource<CommandResource>): void { + this._refreshPostfachMailList(updatedStateResource); + this._setPollingFalse(); } - refreshPostfachMailList(updatedStateResource: StateResource<CommandResource>): void { - this.setPostfachMailListLoading(); - this.getEffectedResource(updatedStateResource) + _refreshPostfachMailList(updatedStateResource: StateResource<CommandResource>): void { + this._setPostfachMailListLoading(); + this._getEffectedResource(updatedStateResource) .pipe(first()) .subscribe((effectedResource) => { - this.setPostfachMailList(effectedResource); + this._setPostfachMailList(effectedResource); }); } - getEffectedResource(updatedStateResource: StateResource<CommandResource>): Observable<PostfachMailListResource> { + _getEffectedResource(updatedStateResource: StateResource<CommandResource>): Observable<PostfachMailListResource> { return this.commandService.getEffectedResource<PostfachMailListResource>(updatedStateResource.resource); } public getPostfachMailListByGivenVorgang(vorgang: VorgangResource): Observable<StateResource<PostfachMailListResource>> { doIfLoadingRequired(this.postfachMailList$.value, () => { - this.setPostfachMailListLoading(); + this._setPostfachMailListLoading(); this.loadPostfachMailsByVorgang(vorgang); }); return this.postfachMailList$.asObservable(); } public getPostfachMailListByVorgang(): Observable<StateResource<PostfachMailListResource>> { + this._refreshVorgangSubscription(); doIfLoadingRequired(this.postfachMailList$.value, () => { - this.setPostfachMailListLoading(); + this._setPostfachMailListLoading(); this.vorgangSubscription = this.vorgangService.getVorgangWithEingang().subscribe((vorgangWithEingangStateResource) => { if (vorgangWithEingangStateResource.resource) { this.loadPostfachMailsByVorgang(vorgangWithEingangStateResource.resource); @@ -257,20 +285,50 @@ export class PostfachService { return this.postfachMailList$.asObservable(); } - setPostfachMailListLoading(): void { + _refreshVorgangSubscription(): void { + this.vorgangChangeSubscription.unsubscribe(); + this._listenToVorgangChange(); + } + + _listenToVorgangChange(): void { + this.vorgangChangeSubscription = this.vorgangService + .getVorgangWithEingang() + .subscribe((vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>) => + this._handleVorgangChange(vorgangWithEingangStateResource), + ); + } + + _handleVorgangChange(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): void { + if (this.shouldReloadList(vorgangWithEingangStateResource)) { + this.shouldReload = true; + } + if (isLoaded(vorgangWithEingangStateResource) && this.shouldReload) { + this._setPostfachMailOnReload(); + this.shouldReload = false; + } + } + + private shouldReloadList(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): boolean { + return ( + (vorgangWithEingangStateResource.loading || vorgangWithEingangStateResource.reload) && + isNotNull(this.postfachMailList$.value.resource) + ); + } + + _setPostfachMailListLoading(): void { this.postfachMailList$.next({ ...this.postfachMailList$.value, loading: true }); } public loadPostfachMailsByVorgang(vorgang: VorgangResource): void { this.loadPostfachMailSubscription = this.repository.loadPostfachMailList(vorgang).subscribe((postfachMaiList) => { if (!isNull(postfachMaiList)) { - this.setPostfachMailList(postfachMaiList); + this._setPostfachMailList(postfachMaiList); setTimeout(() => this.loadPostfachMailSubscription.unsubscribe(), 0); } }); } - setPostfachMailList(postfachMailList: PostfachMailListResource): void { + _setPostfachMailList(postfachMailList: PostfachMailListResource): void { this.postfachMailList$.next(createStateResource(postfachMailList)); } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts index f2b47f34a70349440a1b12df07830044472fc724..62804bcc27411f45fac774d32995f4267b2162f7 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.spec.ts @@ -82,7 +82,7 @@ describe('PostfachMailListContainerComponent', () => { describe('reloadPostfachMailListOnVorgangReload', () => { beforeEach(() => { - postfachService.setPostfachMailOnReload.mockClear(); + postfachService._setPostfachMailOnReload.mockClear(); }); it('should call postfachService', () => { @@ -93,7 +93,7 @@ describe('PostfachMailListContainerComponent', () => { component.reloadPostfachMailListOnVorgangReload(); - expect(postfachService.setPostfachMailOnReload).toHaveBeenCalled(); + expect(postfachService._setPostfachMailOnReload).toHaveBeenCalled(); }); it('should not call postfachService', () => { @@ -104,7 +104,7 @@ describe('PostfachMailListContainerComponent', () => { component.reloadPostfachMailListOnVorgangReload(); - expect(postfachService.setPostfachMailOnReload).not.toHaveBeenCalled(); + expect(postfachService._setPostfachMailOnReload).not.toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts index 70ae1c3856ad88ebe07b61aaf03b800b79d5fd7a..14c858585f1b747ec7175b1d717c13f23e44d547 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list-container.component.ts @@ -21,10 +21,10 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnChanges } from '@angular/core'; import { ON_PAGE, PostfachMailListResource, PostfachService } from '@alfa-client/postfach-shared'; import { isNotNull, StateResource } from '@alfa-client/tech-shared'; import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { Component, Input, OnChanges } from '@angular/core'; import { Observable } from 'rxjs'; @Component({ @@ -51,7 +51,7 @@ export class PostfachMailListContainerComponent implements OnChanges { reloadPostfachMailListOnVorgangReload(): void { if (this.vorgangStateResource.reload) { - this.postfachService.setPostfachMailOnReload(); + this.postfachService._setPostfachMailOnReload(); } } } diff --git a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts index c3358acb510534afa4df0bca712d8b2ff8161bb5..c2e342d93cc22a74bd18be0d1c135b5e51606c50 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts @@ -1054,6 +1054,12 @@ describe('Vorgang Reducer', () => { expect(vorgangStatistic.resource.byStatus.verworfen).toBeNull(); }); + it('should have null as weitergeleitet', () => { + const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic; + + expect(vorgangStatistic.resource.byStatus.weitergeleitet).toBeNull(); + }); + it('should have null as zuLoeschen', () => { const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic; diff --git a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts index 0f200a551da43386ab80c67938d561a277bed11d..2601e8b7044b3d484d2556d1e418d1642dffa17f 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts @@ -126,6 +126,7 @@ function createEmptyVorgangStatistic(): VorgangStatistic { inBearbeitung: null, beschieden: null, verworfen: null, + weitergeleitet: null, zuLoeschen: null, }, wiedervorlagen: null, diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.spec.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.spec.ts index 76c2de5b4f697f184580a6ec74c0ebaaaf1705be..c522a0f4fcc3a6dfb8ee4d11c373ad4030d1717a 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.spec.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.spec.ts @@ -21,11 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { UrlSegment } from '@angular/router'; -import { faker } from '@faker-js/faker'; import { ApiRootLinkRel } from '@alfa-client/api-root-shared'; import { RouteData } from '@alfa-client/navigation-shared'; import { EMPTY_STRING } from '@alfa-client/tech-shared'; +import { UrlSegment } from '@angular/router'; +import { faker } from '@faker-js/faker'; import { createRouteData } from 'libs/navigation-shared/test/navigation-test-factory'; import { initialState, VorgangState } from './+state/vorgang.reducer'; import { @@ -130,9 +130,7 @@ describe('Vorgang Navigation Util', () => { it('should return value on uebersichtsSeite', () => { jest.spyOn(VorgangNavigationUtil, 'isUebersichtsSeite').mockReturnValue(true); - const vorgangFilter: VorgangFilter = getVorgangFilter( - buildWithRouteParam(VorgangFilter.ALLE), - ); + const vorgangFilter: VorgangFilter = getVorgangFilter(buildWithRouteParam(VorgangFilter.ALLE)); expect(vorgangFilter).toBe(VorgangFilter.ALLE); }); @@ -152,10 +150,7 @@ describe('Vorgang Navigation Util', () => { const vorgangView: VorgangView = VorgangView.ANGENOMMEN; jest.spyOn(VorgangNavigationUtil, 'getVorgangView').mockReturnValue(vorgangView); - const isSelected: boolean = VorgangNavigationUtil.isViewSelected( - createRouteData(), - vorgangView, - ); + const isSelected: boolean = VorgangNavigationUtil.isViewSelected(createRouteData(), vorgangView); expect(isSelected).toBeTruthy(); }); @@ -164,10 +159,7 @@ describe('Vorgang Navigation Util', () => { const vorgangView: VorgangView = VorgangView.ANGENOMMEN; jest.spyOn(VorgangNavigationUtil, 'getVorgangView').mockReturnValue(VorgangView.NEU); - const isSelected: boolean = VorgangNavigationUtil.isViewSelected( - createRouteData(), - vorgangView, - ); + const isSelected: boolean = VorgangNavigationUtil.isViewSelected(createRouteData(), vorgangView); expect(isSelected).toBeFalsy(); }); @@ -198,7 +190,7 @@ describe('Vorgang Navigation Util', () => { const vorgangView: VorgangView = VorgangNavigationUtil.getVorgangView(routeData); - expect(vorgangView).toBe(6); + expect(vorgangView).toBe(VorgangView.VORGANG_LIST); }); it('should return VorgangView.NEU if routeData contains this view', () => { @@ -261,9 +253,7 @@ describe('Vorgang Navigation Util', () => { }); it('should build by given filter and view', () => { - jest - .spyOn(Storage, 'getViewFromLocalStorage') - .mockReturnValue(ROUTE_PARAM_BY_VORGANG_VIEW[VorgangView.ANGENOMMEN]); + jest.spyOn(Storage, 'getViewFromLocalStorage').mockReturnValue(ROUTE_PARAM_BY_VORGANG_VIEW[VorgangView.ANGENOMMEN]); jest .spyOn(Storage, 'getFilterFromLocalStorage') .mockReturnValue(ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.MEINE_VORGAENGE]); @@ -340,10 +330,7 @@ describe('Vorgang Navigation Util', () => { it('should build by meine vorgänge filter and view', () => { const state: VorgangState = { ...initialState, vorgangView: VorgangView.NEU }; - const routePath: string = buildVorgangListRouteWithVorgangFilter( - state, - VorgangFilter.MEINE_VORGAENGE, - ); + const routePath: string = buildVorgangListRouteWithVorgangFilter(state, VorgangFilter.MEINE_VORGAENGE); expect(routePath).toEqual('/meine/neu'); }); @@ -354,10 +341,7 @@ describe('Vorgang Navigation Util', () => { vorgangView: VorgangView.SEARCH, searchString: 'testSearchString', }; - const routePath: string = buildVorgangListRouteWithVorgangFilter( - state, - VorgangFilter.MEINE_VORGAENGE, - ); + const routePath: string = buildVorgangListRouteWithVorgangFilter(state, VorgangFilter.MEINE_VORGAENGE); expect(routePath).toEqual('/meine/search/testSearchString'); }); @@ -368,10 +352,7 @@ describe('Vorgang Navigation Util', () => { vorgangView: VorgangView.ANGENOMMEN, searchString: 'testSearchString', }; - const routePath: string = buildVorgangListRouteWithVorgangFilter( - state, - VorgangFilter.MEINE_VORGAENGE, - ); + const routePath: string = buildVorgangListRouteWithVorgangFilter(state, VorgangFilter.MEINE_VORGAENGE); expect(routePath).toEqual('/meine/angenommen'); }); @@ -406,19 +387,13 @@ describe('Vorgang Navigation Util', () => { }); it('return linkRel for Meine Vorgänge Filter', () => { - const linkRel: string = buildLinkRel( - VorgangFilter.MEINE_VORGAENGE, - VorgangView.VORGANG_LIST, - ); + const linkRel: string = buildLinkRel(VorgangFilter.MEINE_VORGAENGE, VorgangView.VORGANG_LIST); expect(linkRel).toBe('vorgaenge_my'); }); it('return linkRel for Nicht Zugewiesen Filter', () => { - const linkRel: string = buildLinkRel( - VorgangFilter.NICHT_ZUGEWIESEN, - VorgangView.VORGANG_LIST, - ); + const linkRel: string = buildLinkRel(VorgangFilter.NICHT_ZUGEWIESEN, VorgangView.VORGANG_LIST); expect(linkRel).toBe('vorgaenge_unassigned'); }); @@ -456,21 +431,13 @@ describe('Vorgang Navigation Util', () => { const vorgangView: VorgangView = VorgangView.NEU; it('should return routePath of view and filter', () => { - const routePath: string = buildVorgangFilterViewRoutePath( - vorgangFilter, - vorgangView, - EMPTY_STRING, - ); + const routePath: string = buildVorgangFilterViewRoutePath(vorgangFilter, vorgangView, EMPTY_STRING); expect(routePath).toBe('/alle/neu'); }); it('should return routePath of view and filter and searchString', () => { - const routePath: string = buildVorgangFilterViewRoutePath( - vorgangFilter, - vorgangView, - 'searchString', - ); + const routePath: string = buildVorgangFilterViewRoutePath(vorgangFilter, vorgangView, 'searchString'); expect(routePath).toBe('/alle/neu/searchString'); }); diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts index d525cd4e9a1614ee19f2db106387e0ed2937fe5b..053d9eb1c84a2b396d86b45fbf8908b4790f76a9 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang-navigation.util.ts @@ -40,6 +40,7 @@ export const ANGENOMMEN_ROUTE_PARAM: string = 'angenommen'; export const IN_BEARBEITUNG_ROUTE_PARAM: string = 'in_bearbeitung'; export const BESCHIEDEN_ROUTE_PARAM: string = 'beschieden'; export const ABGESCHLOSSEN_ROUTE_PARAM: string = 'abgeschlossen'; +export const WEITERGELEITET_ROUTE_PARAM: string = 'weitergeleitet'; export const VERWORFEN_ROUTE_PARAM: string = 'verworfen'; export const WIEDERVORLAGEN_ROUTE_PARAM: string = 'wiedervorlagen'; export const UNGELESENE_NACHRICHTEN_ROUTE_PARAM: string = 'ungelesene_nachrichten'; @@ -54,6 +55,7 @@ export const ROUTE_PARAM_BY_VORGANG_VIEW: { [view: string]: string } = { [VorgangView.IN_BEARBEITUNG]: IN_BEARBEITUNG_ROUTE_PARAM, [VorgangView.BESCHIEDEN]: BESCHIEDEN_ROUTE_PARAM, [VorgangView.ABGESCHLOSSEN]: ABGESCHLOSSEN_ROUTE_PARAM, + [VorgangView.WEITERGELEITET]: WEITERGELEITET_ROUTE_PARAM, [VorgangView.VERWORFEN]: VERWORFEN_ROUTE_PARAM, [VorgangView.VORGANG_LIST]: EMPTY_STRING, [VorgangView.WIEDERVORLAGEN]: WIEDERVORLAGEN_ROUTE_PARAM, @@ -68,6 +70,7 @@ export const VORGANG_VIEW_BY_ROUTE_PARAM: { [routeParam: string]: VorgangView } [IN_BEARBEITUNG_ROUTE_PARAM]: VorgangView.IN_BEARBEITUNG, [BESCHIEDEN_ROUTE_PARAM]: VorgangView.BESCHIEDEN, [ABGESCHLOSSEN_ROUTE_PARAM]: VorgangView.ABGESCHLOSSEN, + [WEITERGELEITET_ROUTE_PARAM]: VorgangView.WEITERGELEITET, [VERWORFEN_ROUTE_PARAM]: VorgangView.VERWORFEN, [WIEDERVORLAGEN_ROUTE_PARAM]: VorgangView.WIEDERVORLAGEN, [UNGELESENE_NACHRICHTEN_ROUTE_PARAM]: VorgangView.UNGELESENE_NACHRICHTEN, @@ -115,9 +118,7 @@ export function isViewSelected(routeData: RouteData, vorgangView: VorgangView): export function getVorgangView(routeData: RouteData): VorgangView { const vorgangViewValue: string = VorgangNavigationUtil.getRouteUrlSegment(routeData, 1); if (VorgangNavigationUtil.isUebersichtsSeite(routeData)) { - return isNotUndefined(vorgangViewValue) ? - VORGANG_VIEW_BY_ROUTE_PARAM[vorgangViewValue] - : VorgangView.VORGANG_LIST; + return isNotUndefined(vorgangViewValue) ? VORGANG_VIEW_BY_ROUTE_PARAM[vorgangViewValue] : VorgangView.VORGANG_LIST; } return undefined; } @@ -133,9 +134,7 @@ export function isUebersichtsSeite(routeData: RouteData): boolean { } export function getRouteUrlSegment(routeData: RouteData, num: number): string { - return routeData.urlSegments.length > num ? - routeData.urlSegments[num].path.toString() - : undefined; + return routeData.urlSegments.length > num ? routeData.urlSegments[num].path.toString() : undefined; } export function buildBackButtonUrl(state: VorgangState): string { @@ -153,17 +152,11 @@ export function isStateEqualLocalStorage(state: VorgangState): boolean { ); } -export function buildVorgangListRoutePathWithFilter( - state: VorgangState, - filter: VorgangFilter, -): string { +export function buildVorgangListRoutePathWithFilter(state: VorgangState, filter: VorgangFilter): string { return VorgangNavigationUtil.buildVorgangListRouteWithVorgangFilter(state, filter); } -export function buildVorgangListRouteWithVorgangFilter( - state: VorgangState, - filter: VorgangFilter, -): string { +export function buildVorgangListRouteWithVorgangFilter(state: VorgangState, filter: VorgangFilter): string { let route = '/' + ROUTE_PARAM_BY_VORGANG_FILTER[filter]; if (state.vorgangView !== VorgangView.VORGANG_LIST) { @@ -198,9 +191,7 @@ export function buildLinkRelFromPathSegments(pathSegments: string[]): string { } const vorgangView: VorgangView = - isEmpty(pathSegments[1]) ? - VorgangView.VORGANG_LIST - : VORGANG_VIEW_BY_ROUTE_PARAM[pathSegments[1]]; + isEmpty(pathSegments[1]) ? VorgangView.VORGANG_LIST : VORGANG_VIEW_BY_ROUTE_PARAM[pathSegments[1]]; return buildLinkRel(vorgangFilter, vorgangView); } @@ -210,11 +201,7 @@ export function buildVorgangFilterViewRoutePath( vorgangView: VorgangView, searchString: string, ): string { - let baseRoutePath: string = - '/' + - ROUTE_PARAM_BY_VORGANG_FILTER[vorgangFilter] + - '/' + - ROUTE_PARAM_BY_VORGANG_VIEW[vorgangView]; + let baseRoutePath: string = '/' + ROUTE_PARAM_BY_VORGANG_FILTER[vorgangFilter] + '/' + ROUTE_PARAM_BY_VORGANG_VIEW[vorgangView]; if (isNotEmpty(searchString)) { return baseRoutePath + '/' + searchString; } diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.model.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.model.ts index 8417137108330ec18fd817f11a55d134e9e47f24..956adad470e23174c4cd6360ab7853420a9e5cc9 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.model.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.model.ts @@ -118,6 +118,7 @@ export interface ByStatus { beschieden: number; abgeschlossen: number; verworfen: number; + weitergeleitet: number; zuLoeschen: number; } @@ -160,6 +161,7 @@ export enum VorgangView { ABGESCHLOSSEN, VERWORFEN, VORGANG_LIST, + WEITERGELEITET, WIEDERVORLAGEN, SEARCH, ZU_LOESCHEN, diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.spec.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.spec.ts index 0aa3ead988609bc5416e593f13cfdf6e44bd8a6e..5e9995262ed38703521d02d10ee078a330163cbd 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.spec.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.spec.ts @@ -23,27 +23,33 @@ */ import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared'; import { BinaryFileListResource } from '@alfa-client/binary-file-shared'; -import { CommandOrder, CommandResource, CommandService, CreateCommandProps } from '@alfa-client/command-shared'; +import { + CommandOrder, + CommandResource, + CommandService, + CreateCommandProps, + CreateCommandPropsWithoutResource, +} from '@alfa-client/command-shared'; import { Environment } from '@alfa-client/environment-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; import { EMPTY_STRING, StateResource, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { HttpErrorResponse } from '@angular/common/http'; +import { faker } from '@faker-js/faker'; import { ResourceUri, getUrl } from '@ngxp/rest'; import { cold, hot } from 'jest-marbles'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { createBinaryFileListResource } from 'libs/binary-file-shared/test/binary-file'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; -import { createCommandResource } from 'libs/command-shared/test/command'; +import { createCommandResource, createCreateCommandPropsWithoutResource } from 'libs/command-shared/test/command'; +import { singleColdCompleted } from 'libs/tech-shared/test/marbles'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { Observable, of } from 'rxjs'; import { VorgangFacade } from './+state/vorgang.facade'; import { VorgangWithEingangLinkRel } from './vorgang.linkrel'; -import { AdditionalActions, VorgangWithEingangResource } from './vorgang.model'; +import { AdditionalActions, VorgangResource, VorgangWithEingangResource } from './vorgang.model'; import { VorgangService } from './vorgang.service'; -import { faker } from '@faker-js/faker'; - import * as VorgangNavigationUtil from './vorgang-navigation.util'; describe('VorgangService', () => { @@ -515,4 +521,64 @@ describe('VorgangService', () => { }); }); }); + + describe('select vorgang with eingang', () => { + const vorgangStateResource: StateResource<VorgangResource> = createStateResource(createVorgangWithEingangResource()); + + beforeEach(() => { + facade.getVorgangWithEingang.mockReturnValue(of(vorgangStateResource)); + }); + + it('should call facade to get vorgang with eingang', () => { + service.selectVorgangWithEingang(); + + expect(facade.getVorgangWithEingang).toHaveBeenCalled(); + }); + + it('should return value', () => { + const vorgangWithEingangStateResource$: Observable<StateResource<VorgangWithEingangResource>> = + service.selectVorgangWithEingang(); + + expect(vorgangWithEingangStateResource$).toBeObservable(singleColdCompleted(vorgangStateResource)); + }); + }); + + describe('create command', () => { + const vorgangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + + const createCommandProps: CreateCommandPropsWithoutResource = createCreateCommandPropsWithoutResource(); + const commandResource: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); + const commandStateResource: StateResource<CommandResource> = createStateResource(commandResource); + + beforeEach(() => { + facade.getVorgangWithEingang.mockReturnValue(of(createStateResource(vorgangResource))); + commandService.createCommandByProps.mockReturnValue(of(commandStateResource)); + }); + + it('should call facade to get vorgang with eingang', () => { + service.createCommand(createCommandProps).subscribe(); + + expect(facade.getVorgangWithEingang).toHaveBeenCalled(); + }); + + it('should call command service to create command', () => { + service.createCommand(createCommandProps).subscribe(); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ ...createCommandProps, resource: vorgangResource }); + }); + + it('should return response from command service', () => { + const forwardCommand$: Observable<StateResource<CommandResource>> = service.createCommand(createCommandProps); + + expect(forwardCommand$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + + it('should call reload if command is done and reload flag is true', () => { + service.reloadVorgang = jest.fn(); + + service.createCommand(createCommandProps, true).subscribe(); + + expect(service.reloadVorgang).toHaveBeenCalled(); + }); + }); }); diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.ts index 1af6e12ff7877e9e221d05730199423689663082..7e43262e9757d58e030c4bbe2900aae791255e96 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.service.ts @@ -28,15 +28,17 @@ import { CommandResource, CommandService, CreateCommandProps, + CreateCommandPropsWithoutResource, getEffectedResourceUrl, + tapOnCommandSuccessfullyDone, } from '@alfa-client/command-shared'; import { ENVIRONMENT_CONFIG, Environment } from '@alfa-client/environment-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { StateResource, createEmptyStateResource, doIfLoadingRequired, isNotNull } from '@alfa-client/tech-shared'; +import { StateResource, createEmptyStateResource, doIfLoadingRequired, isNotNull, mapToResource } from '@alfa-client/tech-shared'; import { Inject, Injectable } from '@angular/core'; import { ResourceUri, hasLink } from '@ngxp/rest'; import { Observable, combineLatest } from 'rxjs'; -import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators'; +import { filter, first, map, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators'; import { VorgangFacade } from './+state/vorgang.facade'; import { buildLinkRelFromPathSegments } from './vorgang-navigation.util'; import { VorgangWithEingangLinkRel } from './vorgang.linkrel'; @@ -142,10 +144,6 @@ export class VorgangService { return this.facade.getAssignUserCommand(); } - public reloadVorgang(commandResource: CommandResource): void { - this.facade.loadVorgangWithEingang(getEffectedResourceUrl(commandResource)); - } - public getBackButtonUrl(): Observable<string> { return this.facade.getBackButtonUrl(); } @@ -198,4 +196,28 @@ export class VorgangService { const createCommand = { order: CommandOrder.SET_AKTENZEICHEN, body: { aktenzeichen } }; return this.commandService.createCommand(vorgang, VorgangWithEingangLinkRel.SET_AKTENZEICHEN, createCommand); } + + public createCommand( + createCommandProps: CreateCommandPropsWithoutResource, + reloadResource: boolean = false, + ): Observable<StateResource<CommandResource>> { + return this.selectVorgangWithEingang().pipe( + first(), + mapToResource(), + switchMap((vorgang: VorgangWithEingangResource) => + this.commandService.createCommandByProps({ ...createCommandProps, resource: vorgang }), + ), + tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => { + if (reloadResource) this.reloadVorgang(commandStateResource.resource); + }), + ); + } + + public selectVorgangWithEingang(): Observable<StateResource<VorgangWithEingangResource>> { + return this.facade.getVorgangWithEingang(); + } + + public reloadVorgang(commandResource: CommandResource): void { + this.facade.loadVorgangWithEingang(getEffectedResourceUrl(commandResource)); + } } diff --git a/alfa-client/libs/vorgang-shared/test/vorgang.ts b/alfa-client/libs/vorgang-shared/test/vorgang.ts index 9eadf4c36b6fbb1e06bab1d81880a2d386db0246..0a98811ad59a31a8c735fa90e1efe5a296f6aceb 100644 --- a/alfa-client/libs/vorgang-shared/test/vorgang.ts +++ b/alfa-client/libs/vorgang-shared/test/vorgang.ts @@ -160,6 +160,7 @@ function createByStatus(): ByStatus { beschieden: faker.number.int(), abgeschlossen: faker.number.int(), verworfen: faker.number.int(), + weitergeleitet: faker.number.int(), zuLoeschen: faker.number.int(), }; } diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/_vorgang-views-menu.theme.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/_vorgang-views-menu.theme.scss index 01889d5e0d21fe759a533c2415fe3ccfac84c804..b29f62b51b0da42f61a47a11583e6e11445e272e 100644 --- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/_vorgang-views-menu.theme.scss +++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/_vorgang-views-menu.theme.scss @@ -90,22 +90,15 @@ alfa-vorgang-view-item { border-color: #155ab4; } - &.angenommen { - background-color: #f6ebce; - border-color: #f1c14e; - } - + &.angenommen, &.in_bearbeitung { background-color: #f6ebce; border-color: #f1c14e; } - &.beschieden { - background-color: #d9eec5; - border-color: #7ccb2b; - } - - &.abgeschlossen { + &.beschieden, + &.abgeschlossen, + &.weitergeleitet { background-color: #d9eec5; border-color: #7ccb2b; } diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html index 21f2c7272fe3695da90ec1ffd5685265b2a0e4be..fde89f0449a26cb2ab766ff0c4eef29de14fd154 100644 --- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html +++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html @@ -28,10 +28,7 @@ <alfa-vorgang-view-item-container *ngIf=" apiRootResource - | hasAnyLink - : apiRootLinkRel.ALLE_VORGAENGE_NEU - : apiRootLinkRel.MEINE_VORGAENGE_NEU - : apiRootLinkRel.UNASSIGNED_NEU + | hasAnyLink: apiRootLinkRel.ALLE_VORGAENGE_NEU : apiRootLinkRel.MEINE_VORGAENGE_NEU : apiRootLinkRel.UNASSIGNED_NEU " data-test-id="vorgang-neu-view" label="Neu" @@ -100,6 +97,22 @@ > <div class="dot abgeschlossen"></div> </alfa-vorgang-view-item-container> + @if ( + apiRootResource + | hasAnyLink + : apiRootLinkRel.ALLE_VORGAENGE_WEITERGELEITET + : apiRootLinkRel.MEINE_VORGAENGE_WEITERGELEITET + : apiRootLinkRel.UNASSIGNED_WEITERGELEITET + ) { + <alfa-vorgang-view-item-container + data-test-id="vorgang-weitergeleitet-view" + label="Weitergeleitet" + [view]="vorgangView.WEITERGELEITET" + [count]="statistic.byStatus.weitergeleitet" + > + <div class="dot weitergeleitet"></div> + </alfa-vorgang-view-item-container> + } <alfa-vorgang-view-item-container *ngIf=" apiRootResource @@ -159,17 +172,11 @@ [view]="vorgangView.WIEDERVORLAGEN" [count]="statistic.wiedervorlagen" > - <alfa-wiedervorlage-icon - [isOverdue]="statistic.existsWiedervorlageOverdue" - ></alfa-wiedervorlage-icon> + <alfa-wiedervorlage-icon [isOverdue]="statistic.existsWiedervorlageOverdue"></alfa-wiedervorlage-icon> </alfa-vorgang-view-item-container> <alfa-vorgang-view-item-container *ngIf=" - apiRootResource - | hasAnyLink - : apiRootLinkRel.ALLE_VORGAENGE - : apiRootLinkRel.MEINE_VORGAENGE - : apiRootLinkRel.UNASSIGNED + apiRootResource | hasAnyLink: apiRootLinkRel.ALLE_VORGAENGE : apiRootLinkRel.MEINE_VORGAENGE : apiRootLinkRel.UNASSIGNED " data-test-id="vorgang-vorgang-list-view" label="Vorgangsliste" @@ -180,11 +187,7 @@ </alfa-vorgang-view-item-container> <alfa-vorgang-search-view-item-container *ngIf=" - apiRootResource - | hasAnyLink - : apiRootLinkRel.SEARCH_ALLE - : apiRootLinkRel.SEARCH_MEINE - : apiRootLinkRel.SEARCH_UNASSIGNED + apiRootResource | hasAnyLink: apiRootLinkRel.SEARCH_ALLE : apiRootLinkRel.SEARCH_MEINE : apiRootLinkRel.SEARCH_UNASSIGNED " data-test-id="vorgang-search-view" class="top-border" diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.spec.ts index 002788d2e9ecf9fc8c9f0e23f9797b125c7edc8d..d7cd88c0faf1e5ca2ec114a6908733f27df88fe8 100644 --- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.spec.ts +++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.spec.ts @@ -24,11 +24,7 @@ import { ApiRootLinkRel } from '@alfa-client/api-root-shared'; import { HasLinkPipe, createStateResource } from '@alfa-client/tech-shared'; import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils'; -import { - OzgcloudIconComponent, - OzgcloudSvgIconComponent, - PostfachIconComponent, -} from '@alfa-client/ui'; +import { OzgcloudIconComponent, OzgcloudSvgIconComponent, PostfachIconComponent } from '@alfa-client/ui'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { HasAnyLinkPipe } from 'libs/tech-shared/src/lib/pipe/has-any-link.pipe'; @@ -50,6 +46,7 @@ describe('VorgangViewsMenuComponent', () => { const inBearbeitungView: string = getDataTestIdOf('vorgang-in-bearbeitung-view'); const beschiedenView: string = getDataTestIdOf('vorgang-beschieden-view'); const abgeschlossenView: string = getDataTestIdOf('vorgang-abgeschlossen-view'); + const weitergeleitetView: string = getDataTestIdOf('vorgang-weitergeleitet-view'); const verworfenView: string = getDataTestIdOf('vorgang-verworfen-view'); const wiedervorlagenView: string = getDataTestIdOf('vorgang-wiedervorlagen-view'); const ungeleseneNachrichtenView: string = getDataTestIdOf('vorgang-ungelesene-nachrichten-view'); @@ -83,16 +80,15 @@ describe('VorgangViewsMenuComponent', () => { }); describe('neu view', () => { - it.each([ - ApiRootLinkRel.ALLE_VORGAENGE_NEU, - ApiRootLinkRel.MEINE_VORGAENGE_NEU, - ApiRootLinkRel.UNASSIGNED_NEU, - ])('should show if %s link exists', (linkRel: string) => { - component.apiRootResource = createApiRootResource([linkRel]); - fixture.detectChanges(); + it.each([ApiRootLinkRel.ALLE_VORGAENGE_NEU, ApiRootLinkRel.MEINE_VORGAENGE_NEU, ApiRootLinkRel.UNASSIGNED_NEU])( + 'should show if %s link exists', + (linkRel: string) => { + component.apiRootResource = createApiRootResource([linkRel]); + fixture.detectChanges(); - existsAsHtmlElement(fixture, neuView); - }); + existsAsHtmlElement(fixture, neuView); + }, + ); it('should hide if both links not exists', () => { component.apiRootResource = createApiRootResource(); @@ -182,6 +178,26 @@ describe('VorgangViewsMenuComponent', () => { }); }); + describe('weitergeleitet view', () => { + it.each([ + ApiRootLinkRel.ALLE_VORGAENGE_WEITERGELEITET, + ApiRootLinkRel.MEINE_VORGAENGE_WEITERGELEITET, + ApiRootLinkRel.UNASSIGNED_WEITERGELEITET, + ])('should show if %s link exists', (linkRel: string) => { + component.apiRootResource = createApiRootResource([linkRel]); + fixture.detectChanges(); + + existsAsHtmlElement(fixture, weitergeleitetView); + }); + + it('should hide if both links not exists', () => { + component.apiRootResource = createApiRootResource(); + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, beschiedenView); + }); + }); + describe('verworfen view', () => { it.each([ ApiRootLinkRel.ALLE_VORGAENGE_VERWORFEN, @@ -203,16 +219,15 @@ describe('VorgangViewsMenuComponent', () => { }); describe('wiedervorlagen view', () => { - it.each([ - ApiRootLinkRel.ALL_WIEDERVORLAGEN, - ApiRootLinkRel.MY_WIEDERVORLAGEN, - ApiRootLinkRel.UNASSIGNED_WIEDERVORLAGEN, - ])('should show if %s link exists', (linkRel: string) => { - component.apiRootResource = createApiRootResource([linkRel]); - fixture.detectChanges(); + it.each([ApiRootLinkRel.ALL_WIEDERVORLAGEN, ApiRootLinkRel.MY_WIEDERVORLAGEN, ApiRootLinkRel.UNASSIGNED_WIEDERVORLAGEN])( + 'should show if %s link exists', + (linkRel: string) => { + component.apiRootResource = createApiRootResource([linkRel]); + fixture.detectChanges(); - existsAsHtmlElement(fixture, wiedervorlagenView); - }); + existsAsHtmlElement(fixture, wiedervorlagenView); + }, + ); it('should hide if link not exists', () => { component.apiRootResource = createApiRootResource(); @@ -243,16 +258,15 @@ describe('VorgangViewsMenuComponent', () => { }); describe('vorgangList view', () => { - it.each([ - ApiRootLinkRel.ALLE_VORGAENGE, - ApiRootLinkRel.MEINE_VORGAENGE, - ApiRootLinkRel.UNASSIGNED, - ])('should show if %s link exists', (linkRel: string) => { - component.apiRootResource = createApiRootResource([linkRel]); - fixture.detectChanges(); + it.each([ApiRootLinkRel.ALLE_VORGAENGE, ApiRootLinkRel.MEINE_VORGAENGE, ApiRootLinkRel.UNASSIGNED])( + 'should show if %s link exists', + (linkRel: string) => { + component.apiRootResource = createApiRootResource([linkRel]); + fixture.detectChanges(); - existsAsHtmlElement(fixture, vorgangListView); - }); + existsAsHtmlElement(fixture, vorgangListView); + }, + ); it('should hide if link not exists', () => { component.apiRootResource = createApiRootResource(); @@ -263,16 +277,15 @@ describe('VorgangViewsMenuComponent', () => { }); describe('search view', () => { - it.each([ - ApiRootLinkRel.SEARCH_ALLE, - ApiRootLinkRel.SEARCH_MEINE, - ApiRootLinkRel.SEARCH_UNASSIGNED, - ])('should show if %s link exists', (linkRel: string) => { - component.apiRootResource = createApiRootResource([linkRel]); - fixture.detectChanges(); - - existsAsHtmlElement(fixture, searchView); - }); + it.each([ApiRootLinkRel.SEARCH_ALLE, ApiRootLinkRel.SEARCH_MEINE, ApiRootLinkRel.SEARCH_UNASSIGNED])( + 'should show if %s link exists', + (linkRel: string) => { + component.apiRootResource = createApiRootResource([linkRel]); + fixture.detectChanges(); + + existsAsHtmlElement(fixture, searchView); + }, + ); it('should hide if no link not exists', () => { component.apiRootResource = createApiRootResource(); diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts index 4d6c0e5ba0bca3a14b4e33d989d737fa379552ff..13e5fcd714c9800fd2dbd9b8fdacc3135037bd58 100644 --- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts +++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts @@ -24,7 +24,6 @@ import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import * as TechShared from '@alfa-client/tech-shared'; import { createEmptyStateResource, createStateResource, decodeUrlFromEmbedding, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; @@ -35,14 +34,25 @@ import { cold, hot } from 'jest-marbles'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createCommandResource } from 'libs/command-shared/test/command'; import { createVorgangResource, createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; -import { createWiedervorlage, createWiedervorlageListResource, createWiedervorlageResource, } from 'libs/wiedervorlage-shared/test/wiedervorlage'; -import { of } from 'rxjs'; +import { + createWiedervorlage, + createWiedervorlageListResource, + createWiedervorlageResource, +} from 'libs/wiedervorlage-shared/test/wiedervorlage'; +import { of, Subscription } from 'rxjs'; import { WiedervorlageLinkRel, WiedervorlageListLinkRel } from './wiedervorlage.linkrel'; import { WiedervorlageMessages } from './wiedervorlage.message'; -import { Wiedervorlage, WIEDERVORLAGE_UPLOADED_ATTACHMENTS, WiedervorlageListResource, WiedervorlageResource, } from './wiedervorlage.model'; +import { + Wiedervorlage, + WIEDERVORLAGE_UPLOADED_ATTACHMENTS, + WiedervorlageListResource, + WiedervorlageResource, +} from './wiedervorlage.model'; import { WiedervorlageRepository } from './wiedervorlage.repository'; import { WiedervorlageService } from './wiedervorlage.service'; +import * as TechShared from '@alfa-client/tech-shared'; + jest.mock('@alfa-client/tech-shared', () => mockAsEsModule('@alfa-client/tech-shared')); function mockAsEsModule(module: string) { @@ -59,11 +69,14 @@ describe('WiedervorlageService', () => { let commandService: Mock<CommandService>; let snackbarService: Mock<SnackBarService>; let binaryFileService: Mock<BinaryFileService>; - let vorgangService: Mock<VorgangService> = mock(VorgangService); + let vorgangService: Mock<VorgangService>; const vorgangResource: VorgangWithEingangResource = createVorgangWithEingangResource(); + const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(vorgangResource); + const wiedervorlageResource: WiedervorlageResource = createWiedervorlageResource(); const wiedervorlage: Wiedervorlage = createWiedervorlage(); + const commandResource: CommandResource = createCommandResource(); const commandResourceWithEffectedResourceLink: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); @@ -73,7 +86,10 @@ describe('WiedervorlageService', () => { commandService = mock(CommandService); snackbarService = mock(SnackBarService); binaryFileService = mock(BinaryFileService); - vorgangService = mock(VorgangService); + vorgangService = { + ...mock(VorgangService), + getVorgangWithEingang: jest.fn().mockReturnValue(of(vorgangWithEingangStateResource)), + }; navigationService.urlChanged.mockReturnValue(of({})); @@ -93,10 +109,6 @@ describe('WiedervorlageService', () => { const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> = createStateResource(vorgangResource); - beforeEach(() => { - vorgangService.getVorgangWithEingang.mockReturnValue(of(vorgangWithEingangStateResource)); - }); - it('should call vorgangFacade getVorgangWithEingang', () => { service.getWiedervorlageList(); @@ -113,11 +125,11 @@ describe('WiedervorlageService', () => { }); it.skip('should call loadWiedervorlagenByVorgang if required', (done) => { - service.loadWiedervorlagenByVorgang = jest.fn(); + service._loadWiedervorlagenByVorgang = jest.fn(); // service.wiedervorlageList$.next({ ...wiedervorlageListStateResource, reload: true }); service.getWiedervorlageList().subscribe((list) => { - expect(service.loadWiedervorlagenByVorgang).toHaveBeenCalled(); + expect(service._loadWiedervorlagenByVorgang).toHaveBeenCalled(); done(); }); // expect(service.loadWiedervorlagenByVorgang).toHaveBeenCalled(); @@ -127,12 +139,12 @@ describe('WiedervorlageService', () => { }); it('should NOT call loadWiedervorlagenByVorgang if already loaded', () => { - service.loadWiedervorlagenByVorgang = jest.fn(); + service._loadWiedervorlagenByVorgang = jest.fn(); service.wiedervorlageList$.asObservable = jest.fn().mockReturnValue(of(wiedervorlageListStateResource)); service.getWiedervorlageList(); - expect(service.loadWiedervorlagenByVorgang).not.toHaveBeenCalled(); + expect(service._loadWiedervorlagenByVorgang).not.toHaveBeenCalled(); }); }); @@ -142,6 +154,16 @@ describe('WiedervorlageService', () => { const wiedervorlageListStateResource: StateResource<WiedervorlageListResource> = createStateResource(wiedervorlageListResource); + beforeEach(() => { + service._refreshVorgangSubscription = jest.fn(); + }); + + it('should call refresh vorgang subscription', () => { + service.getWiedervorlageListByGivenVorgang(vorgang); + + expect(service._refreshVorgangSubscription).toHaveBeenCalled(); + }); + it('should return initial value', () => { service.wiedervorlageList$.asObservable = jest.fn().mockReturnValue(hot('-a', { a: wiedervorlageListResource })); @@ -151,21 +173,39 @@ describe('WiedervorlageService', () => { }); it('should load wiedervorlagen by vorgang if required', () => { - service.loadWiedervorlagenByVorgang = jest.fn(); + service._loadWiedervorlagenByVorgang = jest.fn(); service.wiedervorlageList$.next(createEmptyStateResource()); service.getWiedervorlageListByGivenVorgang(vorgang).subscribe(); - expect(service.loadWiedervorlagenByVorgang).toHaveBeenCalledWith(vorgang); + expect(service._loadWiedervorlagenByVorgang).toHaveBeenCalledWith(vorgang); }); it('should NOT load wiedervorlagen by vorgang if already loaded', () => { - service.loadWiedervorlagenByVorgang = jest.fn(); + service._loadWiedervorlagenByVorgang = jest.fn(); service.wiedervorlageList$.next(wiedervorlageListStateResource); service.getWiedervorlageListByGivenVorgang(vorgang).subscribe(); - expect(service.loadWiedervorlagenByVorgang).not.toHaveBeenCalled(); + expect(service._loadWiedervorlagenByVorgang).not.toHaveBeenCalled(); + }); + }); + + describe('refresh vorgang subscription', () => { + beforeEach(() => { + service.vorgangSubscription = <any>mock(Subscription); + service._listenToVorgangChange = jest.fn(); + }); + + it('should unsubscribe existing subscription', () => { + service._refreshVorgangSubscription(); + + expect(service.vorgangSubscription.unsubscribe).toHaveBeenCalled(); + }); + it('should call listen to vorgang change', () => { + service._refreshVorgangSubscription(); + + expect(service._listenToVorgangChange).toHaveBeenCalled(); }); }); @@ -187,11 +227,11 @@ describe('WiedervorlageService', () => { }); it('should set loading to true', () => { - service.setWiedervorlageLoading = jest.fn(); + service._setWiedervorlageLoading = jest.fn(); service.getWiedervorlage().subscribe(); - expect(service.setWiedervorlageLoading).toHaveBeenCalled(); + expect(service._setWiedervorlageLoading).toHaveBeenCalled(); }); it('should call navigationService', () => { @@ -251,12 +291,12 @@ describe('WiedervorlageService', () => { }); it('should call proceedAfterRecieveCommand', () => { - service.proceedAfterReceiveCommand = jest.fn(); + service._proceedAfterReceiveCommand = jest.fn(); service.saveWiedervorlage(wiedervorlageResource, wiedervorlage).subscribe(); const expectedMessage = WiedervorlageMessages.SAVED.replace('{betreff}', wiedervorlage.betreff); - expect(service.proceedAfterReceiveCommand).toHaveBeenCalledWith( + expect(service._proceedAfterReceiveCommand).toHaveBeenCalledWith( createStateResource(commandResourceWithEffectedResourceLink), expectedMessage, ); @@ -296,12 +336,12 @@ describe('WiedervorlageService', () => { }); it('should call proceedAfterReceiveCommand', () => { - service.proceedAfterReceiveCommand = jest.fn(); + service._proceedAfterReceiveCommand = jest.fn(); service.createWiedervorlage(wiedervorlage).subscribe(); const expectedMessage = WiedervorlageMessages.CREATED.replace('{betreff}', wiedervorlage.betreff); - expect(service.proceedAfterReceiveCommand).toHaveBeenCalledWith(createStateResource(commandResource), expectedMessage); + expect(service._proceedAfterReceiveCommand).toHaveBeenCalledWith(createStateResource(commandResource), expectedMessage); }); }); @@ -311,13 +351,13 @@ describe('WiedervorlageService', () => { }); it('should set reload on wiedervorlageList', () => { - service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); + service._proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); expect(service.wiedervorlageList$.value.reload).toBe(true); }); it('should do nothing on apiError', () => { - service.proceedAfterReceiveCommand(createEmptyStateResource(), null); + service._proceedAfterReceiveCommand(createEmptyStateResource(), null); expect(service.wiedervorlageList$.value.reload).toBe(false); }); @@ -326,13 +366,13 @@ describe('WiedervorlageService', () => { snackbarService.show = jest.fn(); const snackbarMessage: string = 'XX wurde XX'; - service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), snackbarMessage); + service._proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), snackbarMessage); expect(snackbarService.show).toHaveBeenCalledWith(commandResourceWithEffectedResourceLink, snackbarMessage); }); it('should clear uploaded files', () => { - service.proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); + service._proceedAfterReceiveCommand(createStateResource(commandResourceWithEffectedResourceLink), null); expect(service.clearUploadedFiles).toHaveBeenCalled(); }); @@ -421,7 +461,7 @@ describe('WiedervorlageService', () => { it('should call service if command is done', () => { const commandResource: CommandResource = createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]); - service.showSnackBar(commandResource, message); + service._showSnackBar(commandResource, message); expect(snackbarService.show).toHaveBeenCalledWith(commandResource, message); }); @@ -429,7 +469,7 @@ describe('WiedervorlageService', () => { it('should NOT call service if command is pending', () => { const commandResource: CommandResource = createCommandResource(); - service.showSnackBar(commandResource, message); + service._showSnackBar(commandResource, message); expect(snackbarService.show).not.toHaveBeenCalled(); }); @@ -439,14 +479,14 @@ describe('WiedervorlageService', () => { beforeEach(() => { (<any>service).navigateToVorgangDetailPage = jest.fn(); - service.setWiedervorlageListReload = jest.fn(); + service._setWiedervorlageListReload = jest.fn(); (<any>service).forceWiedervorlageReload = jest.fn(); - service.clearWiedervorlagenList = jest.fn(); + service._clearWiedervorlagenList = jest.fn(); service.clearUploadedFiles = jest.fn(); }); it('should clear uploaded files', () => { - service.onNavigation({}); + service._onNavigation({}); expect(service.clearUploadedFiles).toHaveBeenCalled(); }); @@ -457,13 +497,13 @@ describe('WiedervorlageService', () => { }); it('should set wiedervorlage list on reload', () => { - service.onNavigation({}); + service._onNavigation({}); - expect(service.setWiedervorlageListReload).toHaveBeenCalled(); + expect(service._setWiedervorlageListReload).toHaveBeenCalled(); }); it('should set wiedervorlage on reload', () => { - service.onNavigation({}); + service._onNavigation({}); expect((<any>service).forceWiedervorlageReload).toHaveBeenCalled(); }); @@ -471,9 +511,9 @@ describe('WiedervorlageService', () => { describe('to vorgang list', () => { it('should clear list', () => { - service.onNavigation({}); + service._onNavigation({}); - expect(service.clearWiedervorlagenList).toHaveBeenCalled(); + expect(service._clearWiedervorlagenList).toHaveBeenCalled(); }); }); }); @@ -534,4 +574,63 @@ describe('WiedervorlageService', () => { expect(binaryFileService.clearUploadedFiles).toHaveBeenCalledWith(WIEDERVORLAGE_UPLOADED_ATTACHMENTS); }); }); + + describe('listen to vorgang change', () => { + beforeEach(() => { + service._handleVorgangChange = jest.fn(); + }); + + it('should call vorgang service to get vorgang with eingang', () => { + service._listenToVorgangChange(); + + expect(vorgangService.getVorgangWithEingang).toHaveBeenCalled(); + }); + + it('should call handle vorgang change', () => { + service._listenToVorgangChange(); + + expect(service._handleVorgangChange).toHaveBeenCalledWith(vorgangWithEingangStateResource); + }); + }); + + describe('handle vorgang change', () => { + it('should set reload flag if list is loaded and state resource is loading', () => { + service.shouldReload = false; + service.wiedervorlageList$.next(createStateResource(createWiedervorlageListResource())); + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, loading: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + it('should set reload flag if list is loaded and state resource is reloading', () => { + service.wiedervorlageList$.next(createStateResource(createWiedervorlageListResource())); + service.shouldReload = false; + + service._handleVorgangChange({ ...vorgangWithEingangStateResource, reload: true }); + + expect(service.shouldReload).toBeTruthy(); + }); + + describe('on setted reload flag', () => { + beforeEach(() => { + service._setWiedervorlageListReload = jest.fn(); + service.shouldReload = true; + }); + + describe('and loaded vorgang resource', () => { + it('should call set wiedervorlage list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service._setWiedervorlageListReload).toHaveBeenCalled(); + }); + + it('and loaded vorgang resource should call set wiedervorlage list reload', () => { + service._handleVorgangChange(vorgangWithEingangStateResource); + + expect(service.shouldReload).toBeFalsy(); + }); + }); + }); + }); }); diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts index 208bf667e34a682bf13a4022276667409c9f4831..6590ff67384d09ef8d8f46a867bfdfb9536648a3 100644 --- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts +++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts @@ -24,9 +24,20 @@ import { BinaryFileService } from '@alfa-client/binary-file-shared'; import { CommandOrder, CommandResource, CommandService, CreateCommand, isDone } from '@alfa-client/command-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { createEmptyStateResource, createStateResource, decodeUrlFromEmbedding, doIfLoadingRequired, hasStateResourceError, isNotNull, isNotUndefined, replacePlaceholder, StateResource, } from '@alfa-client/tech-shared'; +import { + createEmptyStateResource, + createStateResource, + decodeUrlFromEmbedding, + doIfLoadingRequired, + hasStateResourceError, + isLoaded, + isNotNull, + isNotUndefined, + replacePlaceholder, + StateResource, +} from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; -import { VorgangHeaderLinkRel, VorgangResource, VorgangService } from '@alfa-client/vorgang-shared'; +import { VorgangHeaderLinkRel, VorgangResource, VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; import { Injectable, OnDestroy } from '@angular/core'; import { Params } from '@angular/router'; import { hasLink, ResourceUri } from '@ngxp/rest'; @@ -35,7 +46,12 @@ import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { filter, map, startWith, tap } from 'rxjs/operators'; import { WiedervorlageLinkRel, WiedervorlageListLinkRel } from './wiedervorlage.linkrel'; import { WiedervorlageMessages } from './wiedervorlage.message'; -import { Wiedervorlage, WIEDERVORLAGE_UPLOADED_ATTACHMENTS, WiedervorlageListResource, WiedervorlageResource, } from './wiedervorlage.model'; +import { + Wiedervorlage, + WIEDERVORLAGE_UPLOADED_ATTACHMENTS, + WiedervorlageListResource, + WiedervorlageResource, +} from './wiedervorlage.model'; import { WiedervorlageRepository } from './wiedervorlage.repository'; import { WiedervorlageRoutes } from './wiedervorlage.route'; import { createErledigenCommand, createWiedereroeffnenCommand } from './wiedervorlage.util'; @@ -62,7 +78,10 @@ export class WiedervorlageService implements OnDestroy { StateResource<CommandResource> >(createEmptyStateResource<CommandResource>()); + shouldReload: boolean = false; + private subscription: Subscription; + vorgangSubscription: Subscription; constructor( private repository: WiedervorlageRepository, @@ -73,13 +92,14 @@ export class WiedervorlageService implements OnDestroy { private vorgangService: VorgangService, ) { this.listenToNavigation(); + this._listenToVorgangChange(); } public getWiedervorlageList(): Observable<StateResource<WiedervorlageListResource>> { return combineLatest([this.wiedervorlageList$.asObservable(), this.vorgangService.getVorgangWithEingang()]).pipe( tap(([wiedervorlageList, vorgangResource]) => { if (isNotNull(vorgangResource.resource)) { - doIfLoadingRequired(wiedervorlageList, () => this.loadWiedervorlagenByVorgang(vorgangResource.resource)); + doIfLoadingRequired(wiedervorlageList, () => this._loadWiedervorlagenByVorgang(vorgangResource.resource)); } }), map(([wiedervorlageList]) => wiedervorlageList), @@ -90,20 +110,51 @@ export class WiedervorlageService implements OnDestroy { public getWiedervorlageListByGivenVorgang( vorgangResource: VorgangResource, ): Observable<StateResource<WiedervorlageListResource>> { - doIfLoadingRequired(this.wiedervorlageList$.value, () => this.loadWiedervorlagenByVorgang(vorgangResource)); + this._refreshVorgangSubscription(); + doIfLoadingRequired(this.wiedervorlageList$.value, () => this._loadWiedervorlagenByVorgang(vorgangResource)); return this.wiedervorlageList$.asObservable(); } - loadWiedervorlagenByVorgang(vorgangResource: VorgangResource): void { + _refreshVorgangSubscription(): void { + this.vorgangSubscription.unsubscribe(); + this._listenToVorgangChange(); + } + + _listenToVorgangChange(): void { + this.vorgangSubscription = this.vorgangService + .getVorgangWithEingang() + .subscribe((vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>) => + this._handleVorgangChange(vorgangWithEingangStateResource), + ); + } + + _handleVorgangChange(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): void { + if (this.shouldReloadList(vorgangWithEingangStateResource)) { + this.shouldReload = true; + } + if (isLoaded(vorgangWithEingangStateResource) && this.shouldReload) { + this._setWiedervorlageListReload(); + this.shouldReload = false; + } + } + + private shouldReloadList(vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource>): boolean { + return ( + (vorgangWithEingangStateResource.loading || vorgangWithEingangStateResource.reload) && + isNotNull(this.wiedervorlageList$.value.resource) + ); + } + + _loadWiedervorlagenByVorgang(vorgangResource: VorgangResource): void { if (hasLink(vorgangResource, VorgangHeaderLinkRel.WIEDERVORLAGEN)) { const subscription: Subscription = this.repository.getWiedervorlageList(vorgangResource).subscribe((wiedervorlagenList) => { if (!isNull(wiedervorlagenList)) { - this.setWiedervorlagenList(wiedervorlagenList); + this._setWiedervorlagenList(wiedervorlagenList); subscription.unsubscribe(); } }); } else { - this.clearWiedervorlagenList(); + this._clearWiedervorlagenList(); } } @@ -116,7 +167,7 @@ export class WiedervorlageService implements OnDestroy { ); } - setWiedervorlagenList(wiedervorlagenList: WiedervorlageListResource): void { + _setWiedervorlagenList(wiedervorlagenList: WiedervorlageListResource): void { this.wiedervorlageList$.next(createStateResource(wiedervorlagenList)); } @@ -128,13 +179,13 @@ export class WiedervorlageService implements OnDestroy { } private updateWiedervorlage(): void { - this.setWiedervorlageLoading(); + this._setWiedervorlageLoading(); this.loadAndSetWiedervorlageByUrl(this.getWiedervorlageUri()); } private loadAndSetWiedervorlageByUrl(url: ResourceUri): void { - this.setWiedervorlageLoading(); + this._setWiedervorlageLoading(); const subscription: Subscription = this.repository.getWiedervorlage(url).subscribe((wiedervorlage) => { this.wiedervorlage$.next(createStateResource(wiedervorlage)); @@ -148,23 +199,23 @@ export class WiedervorlageService implements OnDestroy { private listenToNavigation(): void { this.unsubscribe(); - this.subscription = this.navigationService.urlChanged().subscribe((params) => this.onNavigation(params)); + this.subscription = this.navigationService.urlChanged().subscribe((params) => this._onNavigation(params)); } - onNavigation(params: Params): void { + _onNavigation(params: Params): void { this.clearUploadedFiles(); if (this.navigateToVorgangDetailPage(params)) { - this.setWiedervorlageListReload(); + this._setWiedervorlageListReload(); this.forceWiedervorlageReload(); this.submitInProgress$.next(createEmptyStateResource<CommandResource>()); } if (NavigationService.isVorgangListPage(params)) { - this.clearWiedervorlagenList(); + this._clearWiedervorlagenList(); this.submitInProgress$.next(createEmptyStateResource<CommandResource>()); } } - clearWiedervorlagenList(): void { + _clearWiedervorlagenList(): void { this.wiedervorlageList$.next(createEmptyStateResource<WiedervorlageListResource>()); } @@ -183,23 +234,23 @@ export class WiedervorlageService implements OnDestroy { return this.navigationService.getDecodedParam(WiedervorlageService.encodedWiedervorlageUriParam); } - setWiedervorlageLoading(): void { + _setWiedervorlageLoading(): void { this.wiedervorlage$.next({ ...this.wiedervorlage$.value, loading: true }); } public createWiedervorlage(wiedervorlage: Wiedervorlage): Observable<StateResource<CommandResource>> { this.setSubmitInProgressLoading(); - return this.createCreateWiedervorlageCommand(this.wiedervorlageList$.value.resource, wiedervorlage).pipe( + return this._createCreateWiedervorlageCommand(this.wiedervorlageList$.value.resource, wiedervorlage).pipe( filter((commandStateResource) => !commandStateResource.loading), tap((commandStateResource) => - this.proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.CREATED, wiedervorlage)), + this._proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.CREATED, wiedervorlage)), ), startWith(createEmptyStateResource<CommandResource>(true)), ); } - createCreateWiedervorlageCommand( + _createCreateWiedervorlageCommand( wiedervorlageListResource: WiedervorlageListResource, wiedervorlage: Wiedervorlage, ): Observable<StateResource<CommandResource>> { @@ -220,10 +271,10 @@ export class WiedervorlageService implements OnDestroy { ): Observable<StateResource<CommandResource>> { this.setSubmitInProgressLoading(); - return this.createSaveWiedervorlageCommand(wiedervorlageResource, wiedervorlage).pipe( + return this._createSaveWiedervorlageCommand(wiedervorlageResource, wiedervorlage).pipe( filter((commandStateResource) => !commandStateResource.loading), tap((commandStateResource) => - this.proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.SAVED, wiedervorlage)), + this._proceedAfterReceiveCommand(commandStateResource, this.buildMessage(WiedervorlageMessages.SAVED, wiedervorlage)), ), startWith(createEmptyStateResource<CommandResource>(true)), ); @@ -233,7 +284,7 @@ export class WiedervorlageService implements OnDestroy { this.submitInProgress$.next({ ...this.submitInProgress$.value, loading: true }); } - createSaveWiedervorlageCommand( + _createSaveWiedervorlageCommand( wiedervorlageResource: WiedervorlageResource, wiedervorlage: Wiedervorlage, ): Observable<StateResource<CommandResource>> { @@ -248,7 +299,7 @@ export class WiedervorlageService implements OnDestroy { return { order: CommandOrder.EDIT_WIEDERVORLAGE, body: wiedervorlage }; } - proceedAfterReceiveCommand(commandStateResource: StateResource<CommandResource>, message: string): void { + _proceedAfterReceiveCommand(commandStateResource: StateResource<CommandResource>, message: string): void { this.submitInProgress$.next({ ...this.submitInProgress$.value, resource: commandStateResource.resource, @@ -256,14 +307,14 @@ export class WiedervorlageService implements OnDestroy { if (isDone(commandStateResource.resource)) { this.submitInProgress$.next(createStateResource(commandStateResource.resource)); this.snackbarService.show(commandStateResource.resource, message); - this.setWiedervorlageListReload(); + this._setWiedervorlageListReload(); this.clearUploadedFiles(); } else if (hasStateResourceError(commandStateResource)) { this.submitInProgress$.next(createStateResource(commandStateResource.resource)); } } - setWiedervorlageListReload(): void { + _setWiedervorlageListReload(): void { this.wiedervorlageList$.next({ ...this.wiedervorlageList$.value, reload: true }); } @@ -298,7 +349,7 @@ export class WiedervorlageService implements OnDestroy { .subscribe((commandStateResource) => { if (isDone(commandStateResource.resource)) { this.handleSource(commandStateResource.resource); - this.showSnackBar( + this._showSnackBar( commandStateResource.resource, this.buildMessage(snackBarMessage, this.wiedervorlage$.value.resource), ); @@ -321,7 +372,7 @@ export class WiedervorlageService implements OnDestroy { return replacePlaceholder(message, 'betreff', wiedervorlage.betreff); } - showSnackBar(commandResource: CommandResource, message: string) { + _showSnackBar(commandResource: CommandResource, message: string) { if (isDone(commandResource)) { this.snackbarService.show(commandResource, message); } diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.spec.ts index 305ae85a3562debef815c485cc0820e6971e9139..533f48ef565166aac55ae5fcf355ed99f86a81ce 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.spec.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.spec.ts @@ -86,7 +86,7 @@ describe('WiedervorlageListInVorgangContainerComponent', () => { describe('reloadWiedervorlageListOnVorgangReload', () => { beforeEach(() => { - wiedervorlageService.setWiedervorlageListReload.mockClear(); + wiedervorlageService._setWiedervorlageListReload.mockClear(); }); it('should call wiedervorlageService', () => { @@ -97,7 +97,7 @@ describe('WiedervorlageListInVorgangContainerComponent', () => { component.reloadWiedervorlageListOnVorgangReload(); - expect(wiedervorlageService.setWiedervorlageListReload).toHaveBeenCalled(); + expect(wiedervorlageService._setWiedervorlageListReload).toHaveBeenCalled(); }); it('should not call wiedervorlageService', () => { @@ -108,7 +108,7 @@ describe('WiedervorlageListInVorgangContainerComponent', () => { component.reloadWiedervorlageListOnVorgangReload(); - expect(wiedervorlageService.setWiedervorlageListReload).not.toHaveBeenCalled(); + expect(wiedervorlageService._setWiedervorlageListReload).not.toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.ts index 6a99467e90164b63414677a0e80f4f9ea2470759..4313ee4c1f9ee06cd1515686c8985ec0806fa068 100644 --- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.ts +++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang-container.component.ts @@ -21,11 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, Input, OnChanges } from '@angular/core'; -import { StateResource } from '@alfa-client/tech-shared'; +import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared'; import { VorgangHeaderLinkRel, VorgangResource } from '@alfa-client/vorgang-shared'; import { WiedervorlageListResource, WiedervorlageService } from '@alfa-client/wiedervorlage-shared'; -import { Observable } from 'rxjs'; +import { Component, Input, OnChanges } from '@angular/core'; +import { Observable, of } from 'rxjs'; @Component({ selector: 'alfa-wiedervorlage-list-in-vorgang-container', @@ -35,7 +35,8 @@ import { Observable } from 'rxjs'; export class WiedervorlageListInVorgangContainerComponent implements OnChanges { @Input() vorgangStateResource: StateResource<VorgangResource>; - wiedervorlagenStateResource$: Observable<StateResource<WiedervorlageListResource>>; + wiedervorlagenStateResource$: Observable<StateResource<WiedervorlageListResource>> = + of(createEmptyStateResource<WiedervorlageListResource>()); readonly vorgangLinkRel = VorgangHeaderLinkRel; @@ -43,15 +44,14 @@ export class WiedervorlageListInVorgangContainerComponent implements OnChanges { ngOnChanges(): void { this.reloadWiedervorlageListOnVorgangReload(); - this.wiedervorlagenStateResource$ = - this.wiedervorlageService.getWiedervorlageListByGivenVorgang( - this.vorgangStateResource.resource, - ); + this.wiedervorlagenStateResource$ = this.wiedervorlageService.getWiedervorlageListByGivenVorgang( + this.vorgangStateResource.resource, + ); } reloadWiedervorlageListOnVorgangReload(): void { if (this.vorgangStateResource.reload) { - this.wiedervorlageService.setWiedervorlageListReload(); + this.wiedervorlageService._setWiedervorlageListReload(); } } }