From 83766ca03d021f778afa47a4415d02457fc8c9a5 Mon Sep 17 00:00:00 2001 From: Yanick Minder Date: Thu, 19 Dec 2024 10:33:50 +0100 Subject: [PATCH 1/6] run frontend formatter --- frontend/.prettierrc | 8 +- frontend/README.md | 21 +- frontend/cypress.config.ts | 6 +- frontend/cypress/e2e/check-in.cy.ts | 56 ++- .../cypress/e2e/duplicate-objective.cy.ts | 56 ++- frontend/cypress/e2e/key-result.cy.ts | 197 +++++--- frontend/cypress/e2e/login.cy.ts | 35 +- frontend/cypress/e2e/objective-backlog.cy.ts | 115 +++-- frontend/cypress/e2e/objective-crud.cy.ts | 77 ++- frontend/cypress/e2e/objective.cy.ts | 138 ++++-- frontend/cypress/e2e/overview.cy.ts | 35 +- frontend/cypress/e2e/routing.cy.ts | 18 +- frontend/cypress/e2e/scoring.cy.ts | 54 ++- frontend/cypress/e2e/tab.cy.ts | 117 +++-- frontend/cypress/e2e/team.cy.ts | 61 ++- frontend/cypress/e2e/teammanagement.cy.ts | 437 +++++++++++------ frontend/cypress/support/commands.ts | 81 ++-- frontend/cypress/support/e2e.ts | 32 +- .../helper/dom-helper/angularSearchBox.ts | 25 +- .../dom-helper/dialogs/checkInDialog.ts | 37 +- .../dialogs/checkInHistoryDialog.ts | 22 +- .../dom-helper/dialogs/confirmDialog.ts | 24 +- .../helper/dom-helper/dialogs/dialog.ts | 28 +- .../dom-helper/dialogs/inviteMembersDialog.ts | 32 +- .../dom-helper/dialogs/keyResultDialog.ts | 50 +- .../dom-helper/dialogs/objectiveDialog.ts | 36 +- .../helper/dom-helper/dialogs/teamDialog.ts | 14 +- .../support/helper/dom-helper/filterHelper.ts | 24 +- .../helper/dom-helper/pageObjectMapperBase.ts | 27 +- .../dom-helper/pages/keyResultDetailPage.ts | 45 +- .../helper/dom-helper/pages/overviewPage.ts | 160 +++--- .../support/helper/dom-helper/pages/page.ts | 13 +- .../dom-helper/pages/teammanagementPage.ts | 63 ++- .../cypress/support/helper/keyResultHelper.ts | 7 +- .../cypress/support/helper/objectiveHelper.ts | 12 +- .../cypress/support/helper/scoringSupport.ts | 54 ++- frontend/cypress/support/helper/utils.ts | 40 +- frontend/src/app/app-routing.module.ts | 44 +- frontend/src/app/app.component.spec.ts | 43 +- frontend/src/app/app.component.ts | 21 +- frontend/src/app/app.module.ts | 54 ++- .../action-plan/action-plan.component.html | 6 +- .../action-plan/action-plan.component.spec.ts | 92 +++- .../action-plan/action-plan.component.ts | 63 +-- .../application-banner.component.html | 7 +- .../application-banner.component.scss | 2 +- .../application-banner.component.spec.ts | 78 +-- .../application-banner.component.ts | 29 +- .../application-top-bar.component.html | 46 +- .../application-top-bar.component.scss | 2 +- .../application-top-bar.component.spec.ts | 51 +- .../application-top-bar.component.ts | 31 +- .../check-in-history-dialog.component.html | 18 +- .../check-in-history-dialog.component.spec.ts | 31 +- .../check-in-history-dialog.component.ts | 36 +- .../check-in-form-metric.component.spec.ts | 43 +- .../check-in-form-metric.component.ts | 19 +- .../metric-check-in-directive.spec.ts | 24 +- .../metric-check-in-directive.ts | 30 +- .../check-in-form-ordinal.component.html | 30 +- .../check-in-form-ordinal.component.scss | 2 +- .../check-in-form-ordinal.component.spec.ts | 29 +- .../check-in-form-ordinal.component.ts | 5 +- .../check-in-form.component.html | 22 +- .../check-in-form.component.spec.ts | 122 ++--- .../check-in-form/check-in-form.component.ts | 64 ++- .../confidence/confidence.component.html | 12 +- .../confidence/confidence.component.spec.ts | 31 +- .../confidence/confidence.component.ts | 16 +- .../key-result-form.component.spec.ts | 125 +++-- .../key-result-form.component.ts | 97 ++-- .../keyresult-detail.component.html | 28 +- .../keyresult-detail.component.scss | 4 +- .../keyresult-detail.component.spec.ts | 76 +-- .../keyresult-detail.component.ts | 78 +-- .../keyresult-dialog.component.html | 14 +- .../keyresult-dialog.component.spec.ts | 437 +++++++++-------- .../keyresult-dialog.component.ts | 56 ++- .../keyresult-type.component.scss | 2 +- .../keyresult-type.component.spec.ts | 217 +++++---- .../keyresult-type.component.ts | 65 +-- .../keyresult/keyresult.component.html | 6 +- .../keyresult/keyresult.component.scss | 2 +- .../keyresult/keyresult.component.spec.ts | 12 +- .../keyresult/keyresult.component.ts | 12 +- .../objective-detail.component.html | 17 +- .../objective-detail.component.scss | 2 +- .../objective-detail.component.spec.ts | 46 +- .../objective-detail.component.ts | 33 +- .../objective-filter.component.html | 6 +- .../objective-filter.component.spec.ts | 74 +-- .../objective-filter.component.ts | 33 +- .../objective/ObjectiveMenuActions.ts | 70 +-- .../objective/ObjectiveMenuAfterActions.ts | 86 ++-- .../objective/objective.component.html | 12 +- .../objective/objective.component.scss | 2 +- .../objective/objective.component.spec.ts | 72 ++- .../objective/objective.component.ts | 35 +- .../overview/overview.component.html | 18 +- .../overview/overview.component.spec.ts | 122 +++-- .../components/overview/overview.component.ts | 51 +- .../quarter-filter.component.spec.ts | 94 ++-- .../quarter-filter.component.ts | 55 ++- .../team-filter/team-filter.component.spec.ts | 270 ++++++++--- .../team-filter/team-filter.component.ts | 79 +-- .../app/components/team/team.component.html | 5 +- .../components/team/team.component.spec.ts | 83 ++-- .../src/app/components/team/team.component.ts | 47 +- frontend/src/app/guards/auth.guard.spec.ts | 76 +-- frontend/src/app/guards/auth.guard.ts | 29 +- .../interceptors/error-interceptor.service.ts | 66 ++- .../interceptors/error.interceptor.spec.ts | 341 +++++++++---- .../interceptors/oauth.interceptor.spec.ts | 21 +- .../src/app/interceptors/oauth.interceptor.ts | 39 +- .../src/app/services/action.service.spec.ts | 5 +- frontend/src/app/services/action.service.ts | 8 +- .../src/app/services/check-in.service.spec.ts | 22 +- frontend/src/app/services/check-in.service.ts | 8 +- frontend/src/app/services/completed.servce.ts | 8 +- .../app/services/completed.service.spec.ts | 5 +- .../src/app/services/config.service.spec.ts | 5 +- frontend/src/app/services/config.service.ts | 7 +- .../services/customization.service.spec.ts | 135 ++++-- .../src/app/services/customization.service.ts | 42 +- .../src/app/services/dialog.service.spec.ts | 195 +++++--- frontend/src/app/services/dialog.service.ts | 25 +- .../app/services/keyresult.service.spec.ts | 3 +- .../src/app/services/keyresult.service.ts | 17 +- .../objective-menu-actions.service.spec.ts | 56 ++- .../objective-menu-actions.service.ts | 38 +- .../app/services/objective.service.spec.ts | 5 +- .../src/app/services/objective.service.ts | 21 +- .../src/app/services/overview.service.spec.ts | 26 +- frontend/src/app/services/overview.service.ts | 15 +- .../src/app/services/quarter.service.spec.ts | 5 +- frontend/src/app/services/quarter.service.ts | 16 +- .../app/services/refresh-data.service.spec.ts | 3 +- .../src/app/services/refresh-data.service.ts | 10 +- .../src/app/services/team.service.spec.ts | 5 +- frontend/src/app/services/team.service.ts | 52 +- .../src/app/services/toaster.service.spec.ts | 33 +- frontend/src/app/services/toaster.service.ts | 12 +- .../src/app/services/user.service.spec.ts | 51 +- frontend/src/app/services/user.service.ts | 52 +- frontend/src/app/shared/common.spec.ts | 459 ++++++++++++------ frontend/src/app/shared/common.ts | 70 +-- frontend/src/app/shared/constantLibary.ts | 78 ++- .../dialog-template-core.component.html | 6 +- .../dialog-template-core.component.scss | 2 +- .../dialog-template-core.component.ts | 7 +- .../okr-tangram/okr-tangram.component.html | 8 +- .../okr-tangram/okr-tangram.component.ts | 9 +- .../puzzle-icon-button.component.html | 13 +- .../puzzle-icon-button.component.ts | 9 +- .../puzzle-icon/puzzle-icon.component.html | 7 +- .../puzzle-icon/puzzle-icon.component.ts | 4 +- .../custom/scoring/scoring.component.html | 23 +- .../custom/scoring/scoring.component.scss | 4 +- .../custom/scoring/scoring.component.spec.ts | 155 +++--- .../custom/scoring/scoring.component.ts | 66 ++- .../custom/spinner/spinner.component.html | 6 +- .../custom/spinner/spinner.component.ts | 2 +- frontend/src/app/shared/customRouter.ts | 7 +- .../complete-dialog.component.html | 7 +- .../complete-dialog.component.spec.ts | 105 ++-- .../complete-dialog.component.ts | 27 +- .../confirm-dialog.component.spec.ts | 31 +- .../confirm-dialog.component.ts | 32 +- .../example-dialog.component.html | 6 +- .../example-dialog.component.spec.ts | 183 ++++--- .../example-dialog.component.ts | 32 +- .../objective-form.component.html | 15 +- .../objective-form.component.spec.ts | 373 ++++++++------ .../objective-form.component.ts | 143 +++--- .../unit-transformation.pipe.spec.ts | 30 +- .../unit-transformation.pipe.ts | 13 +- frontend/src/app/shared/routeUtils.spec.ts | 15 +- frontend/src/app/shared/shared.module.ts | 8 +- .../shared/sidepanel/sidepanel.component.scss | 2 +- .../shared/sidepanel/sidepanel.component.ts | 41 +- frontend/src/app/shared/testData.ts | 200 ++++---- .../src/app/shared/types/enums/ButtonState.ts | 2 +- .../src/app/shared/types/enums/CloseState.ts | 2 +- .../src/app/shared/types/enums/HttpType.ts | 2 +- frontend/src/app/shared/types/enums/State.ts | 2 +- .../src/app/shared/types/enums/ToasterType.ts | 2 +- frontend/src/app/shared/types/enums/Unit.ts | 2 +- .../src/app/shared/types/enums/UserRole.ts | 2 +- frontend/src/app/shared/types/enums/Zone.ts | 2 +- .../app/shared/types/model/ClientConfig.ts | 4 +- .../src/app/shared/types/model/Quarter.ts | 11 +- .../app/shared/types/model/UserTableEntry.ts | 2 +- frontend/src/app/shared/validators.ts | 23 +- .../add-edit-team-dialog.component.html | 7 +- .../add-edit-team-dialog.component.scss | 2 +- .../add-edit-team-dialog.component.spec.ts | 56 ++- .../add-edit-team-dialog.component.ts | 62 ++- .../add-member-to-team-dialog.component.html | 13 +- ...dd-member-to-team-dialog.component.spec.ts | 86 ++-- .../add-member-to-team-dialog.component.ts | 73 +-- .../add-user-team.component.html | 16 +- .../add-user-team.component.spec.ts | 71 ++- .../add-user-team/add-user-team.component.ts | 53 +- .../delete-user/delete-user.component.html | 6 +- .../delete-user/delete-user.component.spec.ts | 161 +++--- .../delete-user/delete-user.component.ts | 104 ++-- .../edit-okr-champion.component.html | 46 +- .../edit-okr-champion.component.scss | 2 +- .../edit-okr-champion.component.ts | 21 +- .../invite-user-dialog.component.html | 45 +- .../invite-user-dialog.component.spec.ts | 73 ++- .../invite-user-dialog.component.ts | 32 +- .../member-detail.component.html | 35 +- .../member-detail.component.spec.ts | 93 ++-- .../member-detail/member-detail.component.ts | 90 ++-- .../member-list-mobile.component.html | 30 +- .../member-list-mobile.component.scss | 2 +- .../member-list-mobile.component.spec.ts | 20 +- .../member-list-mobile.component.ts | 9 +- .../member-list-table.component.html | 12 +- .../member-list-table.component.scss | 2 +- .../member-list-table.component.spec.ts | 102 ++-- .../member-list-table.component.ts | 77 +-- .../member-list/member-list.component.html | 18 +- .../member-list/member-list.component.scss | 2 +- .../member-list/member-list.component.spec.ts | 225 +++++---- .../member-list/member-list.component.ts | 67 +-- .../new-user/new-user.component.html | 18 +- .../new-user/new-user.component.spec.ts | 21 +- .../new-user/new-user.component.ts | 17 +- .../new-user/unique-mail.directive.spec.ts | 17 +- .../new-user/unique-mail.validator.ts | 10 +- .../team-management/okr-champion.pipe.spec.ts | 11 +- .../app/team-management/okr-champion.pipe.ts | 6 +- .../src/app/team-management/roles.pipe.ts | 9 +- .../search-team-management.component.html | 12 +- .../search-team-management.component.spec.ts | 148 +++--- .../search-team-management.component.ts | 78 +-- .../show-edit-role.component.html | 5 +- .../show-edit-role.component.spec.ts | 16 +- .../show-edit-role.component.ts | 24 +- .../team-list/team-list.component.html | 4 +- .../team-list/team-list.component.scss | 2 +- .../team-list/team-list.component.spec.ts | 29 +- .../team-list/team-list.component.ts | 23 +- .../team-management-banner.component.html | 13 +- .../team-management-banner.component.scss | 2 +- .../team-management-banner.component.spec.ts | 30 +- .../team-management-banner.component.ts | 13 +- ...am-management-mobile-filter.component.html | 6 +- ...management-mobile-filter.component.spec.ts | 58 ++- ...team-management-mobile-filter.component.ts | 23 +- .../team-management-routing.module.ts | 44 +- .../team-management.component.spec.ts | 27 +- .../team-management.component.ts | 2 +- .../team-management/team-management.module.ts | 6 +- .../team-role-dropdown.component.html | 4 +- .../team-role-dropdown.component.spec.ts | 31 +- .../team-role-dropdown.component.ts | 6 +- .../app/team-management/teams.pipe.spec.ts | 22 +- .../src/app/team-management/teams.pipe.ts | 13 +- frontend/src/environments/environment.prod.ts | 4 +- frontend/src/environments/environment.ts | 12 +- frontend/src/global.ts | 3 +- frontend/src/index.html | 13 +- .../src/style/custom_angular.components.scss | 4 +- frontend/src/style/custom_angular.scss | 6 +- frontend/src/style/custom_bootstrap.scss | 14 +- frontend/src/style/styles.scss | 78 +-- 269 files changed, 7461 insertions(+), 4750 deletions(-) diff --git a/frontend/.prettierrc b/frontend/.prettierrc index cc9131084c..fa51da29e7 100644 --- a/frontend/.prettierrc +++ b/frontend/.prettierrc @@ -1,6 +1,6 @@ { - "trailingComma": "es5", - "tabWidth": 2, - "semi": false, - "singleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "semi": false, + "singleQuote": true } diff --git a/frontend/README.md b/frontend/README.md index 79ee611146..5c0712d9b5 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -30,7 +30,6 @@ Build: ## Formatting - We use **EsLint** and a variety of plugins to format html and ts files: https://eslint.org/ @@ -48,16 +47,16 @@ Open the html file in browser and you get a beautiful overview ## Cypress Tests - local setup - - start local Docker `docker-compose up` - - start local Server: `OkrApplication-E2E` - - start local Client: `npm run start` + - start local Docker `docker-compose up` + - start local Server: `OkrApplication-E2E` + - start local Client: `npm run start` - run selected Tests - - npm run `npm run cypress:open` - - in Cypress App, select `E2E Testing` and `Chrome` as Browser + - npm run `npm run cypress:open` + - in Cypress App, select `E2E Testing` and `Chrome` as Browser - run all tests - - npm run `npm run cypress:run` - - in Cypress App, select `E2E Testing` and `Chrome` as Browser + - npm run `npm run cypress:run` + - in Cypress App, select `E2E Testing` and `Chrome` as Browser - in case of failing Tests: - - stop and restart local Server - - stop and restart local Client - - re-run Cypress Tests + - stop and restart local Server + - stop and restart local Client + - re-run Cypress Tests diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts index b188ef99ec..47f5248cf0 100644 --- a/frontend/cypress.config.ts +++ b/frontend/cypress.config.ts @@ -6,9 +6,9 @@ export default defineConfig({ experimentalMemoryManagement: true, testIsolation: true, viewportWidth: 1920, - viewportHeight: 1080, + viewportHeight: 1080 }, env: { - login_url: 'http://localhost:8544', - }, + login_url: 'http://localhost:8544' + } }); diff --git a/frontend/cypress/e2e/check-in.cy.ts b/frontend/cypress/e2e/check-in.cy.ts index f1ff021f7c..04b68b877f 100644 --- a/frontend/cypress/e2e/check-in.cy.ts +++ b/frontend/cypress/e2e/check-in.cy.ts @@ -160,14 +160,18 @@ describe('OKR Check-in e2e tests', () => { keyresultDetailPage.showAllCheckins(); cy.contains('Check-in History'); cy.contains('Wert: 30 CHF'); - CheckInHistoryDialog.do().editLatestCheckIn(); + CheckInHistoryDialog.do() + .editLatestCheckIn(); cy.contains('Here we edit a metric checkin'); cy.contains('30 CHF'); cy.contains('Confidence um Target Zone (213 CHF) zu erreichen'); cy.contains('5/10'); cy.contains('Here we are'); cy.contains('A cat would be great'); - CheckInDialog.do().fillMetricCheckInValue('200').fillCheckInCommentary('We bought a new sheep').submit(); + CheckInDialog.do() + .fillMetricCheckInValue('200') + .fillCheckInCommentary('We bought a new sheep') + .submit(); cy.contains('200 CHF'); cy.contains('We bought a new sheep'); }); @@ -191,7 +195,8 @@ describe('OKR Check-in e2e tests', () => { keyresultDetailPage.showAllCheckins(); cy.contains('Check-in History'); cy.contains('Wert: 30 EUR'); - CheckInHistoryDialog.do().close(); + CheckInHistoryDialog.do() + .close(); keyresultDetailPage.close(); overviewPage @@ -229,20 +234,27 @@ describe('OKR Check-in e2e tests', () => { .fillCheckInCommentary('There is a new car') .fillCheckInInitiatives('Buy now a new pool') .submit(); - keyresultDetailPage.showAllCheckins().editLatestCheckIn(); + keyresultDetailPage.showAllCheckins() + .editLatestCheckIn(); cy.contains('For editing ordinal checkin'); cy.contains('Confidence um Target Zone zu erreichen'); cy.contains('6/10'); cy.contains('There is a new car'); cy.contains('Buy now a new pool'); - CheckInDialog.do().selectOrdinalCheckInZone('stretch').fillCheckInCommentary('We bought a new dog').submit(); + CheckInDialog.do() + .selectOrdinalCheckInZone('stretch') + .fillCheckInCommentary('We bought a new dog') + .submit(); cy.contains('We bought a new dog'); cy.contains('Buy now a new pool'); cy.contains('STRETCH'); }); it(`Should display confirm dialog when creating checkin on draft objective`, () => { - overviewPage.addObjective().fillObjectiveTitle('draft objective title').selectQuarter('3').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('draft objective title') + .selectQuarter('3') + .submitDraftObjective(); overviewPage.visitNextQuarter(); overviewPage .addKeyResult(undefined, 'draft objective title') @@ -251,17 +263,21 @@ describe('OKR Check-in e2e tests', () => { .fillKeyResultDescription('This is my description') .submit(); keyresultDetailPage.visit('I am a metric keyresult for testing'); - keyresultDetailPage.elements.addCheckin().click(); - ConfirmDialog.do().checkTitle('Check-in im Draft-Status'); - ConfirmDialog.do().checkDescription( - 'Dein Objective befindet sich noch im DRAFT Status. Möchtest du das Check-in trotzdem erfassen?', - ); + keyresultDetailPage.elements.addCheckin() + .click(); + ConfirmDialog.do() + .checkTitle('Check-in im Draft-Status'); + ConfirmDialog.do() + .checkDescription('Dein Objective befindet sich noch im DRAFT Status. Möchtest du das Check-in trotzdem erfassen?'); }); it(`Should only display last value div if last checkin is present`, () => { const objectiveName = uniqueSuffix('new objective'); - overviewPage.addObjective().fillObjectiveTitle(objectiveName).selectQuarter('3').submit(); + overviewPage.addObjective() + .fillObjectiveTitle(objectiveName) + .selectQuarter('3') + .submit(); overviewPage.visitNextQuarter(); overviewPage .addKeyResult(undefined, objectiveName) @@ -269,8 +285,10 @@ describe('OKR Check-in e2e tests', () => { .withMetricValues(Unit.PERCENT, '45', '60') .fillKeyResultDescription('Description') .submit(); - keyresultDetailPage.visit('I am a keyresult metric').createCheckIn(); - cy.getByTestId('old-checkin-value').should('not.exist'); + keyresultDetailPage.visit('I am a keyresult metric') + .createCheckIn(); + cy.getByTestId('old-checkin-value') + .should('not.exist'); CheckInDialog.do() .fillMetricCheckInValue('10') .setCheckInConfidence(0) @@ -279,16 +297,18 @@ describe('OKR Check-in e2e tests', () => { .submit(); cy.contains(`Letztes Check-in (${getCurrentDate()})`); keyresultDetailPage.createCheckIn(); - cy.contains('Letzter Wert').siblings('div').contains('10%'); + cy.contains('Letzter Wert') + .siblings('div') + .contains('10%'); }); }); }); -function getCurrentDate() { +function getCurrentDate () { const today = new Date(); const yyyy = today.getFullYear(); - let mm = today.getMonth() + 1; // Months start at 0! - let dd = today.getDate(); + const mm = today.getMonth() + 1; // Months start at 0! + const dd = today.getDate(); let dd_str = '' + dd; let mm_str = '' + mm; diff --git a/frontend/cypress/e2e/duplicate-objective.cy.ts b/frontend/cypress/e2e/duplicate-objective.cy.ts index 97f996078d..896c841339 100644 --- a/frontend/cypress/e2e/duplicate-objective.cy.ts +++ b/frontend/cypress/e2e/duplicate-objective.cy.ts @@ -24,9 +24,12 @@ describe('Functionality of duplicating objectives and their belonging keyResults .submit(); cy.contains(duplicatedTitle); - overviewPage.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName).should('exist'); - overviewPage.getKeyResultOfObjective(duplicatedTitle, secondKeyResultName).should('exist'); - overviewPage.getKeyResultOfObjective(duplicatedTitle, thirdKeyResultName).should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName) + .should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, secondKeyResultName) + .should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, thirdKeyResultName) + .should('exist'); }); it('Should be able to duplicate a objective into this quarter, only including one keyResult', () => { @@ -35,7 +38,8 @@ describe('Functionality of duplicating objectives and their belonging keyResults overviewPage .duplicateObjective('Build a company culture that kills the competition.') .fillObjectiveTitle(duplicatedTitle) - .excludeKeyResults([secondKeyResultName, thirdKeyResultName]) + .excludeKeyResults([secondKeyResultName, + thirdKeyResultName]) .submit(); overviewPage.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName); @@ -49,13 +53,15 @@ describe('Functionality of duplicating objectives and their belonging keyResults it('Should not show option to select keyResults when objective with no keyResults is being duplicated', () => { const duplicatedTitle = 'This is a duplicated objective without any keyResults'; - overviewPage.duplicateObjective( - 'should not appear on staging, no sea takimata sanctus est Lorem ipsum dolor sit amet.', - ); - cy.contains('Key Results:').should('not.exist'); - ObjectiveDialog.do().fillObjectiveTitle(duplicatedTitle).submit(); + overviewPage.duplicateObjective('should not appear on staging, no sea takimata sanctus est Lorem ipsum dolor sit amet.'); + cy.contains('Key Results:') + .should('not.exist'); + ObjectiveDialog.do() + .fillObjectiveTitle(duplicatedTitle) + .submit(); - overviewPage.getObjectiveByName(duplicatedTitle).should('exist'); + overviewPage.getObjectiveByName(duplicatedTitle) + .should('exist'); }); it('Should be able to duplicate a objective into the next quarter, including all keyResults', () => { @@ -70,9 +76,12 @@ describe('Functionality of duplicating objectives and their belonging keyResults overviewPage.visitNextQuarter(); cy.contains(duplicatedTitle); - overviewPage.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName).should('exist'); - overviewPage.getKeyResultOfObjective(duplicatedTitle, secondKeyResultName).should('exist'); - overviewPage.getKeyResultOfObjective(duplicatedTitle, thirdKeyResultName).should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName) + .should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, secondKeyResultName) + .should('exist'); + overviewPage.getKeyResultOfObjective(duplicatedTitle, thirdKeyResultName) + .should('exist'); }); it('Should not duplicate objective when cancel button is clicked', () => { @@ -84,12 +93,13 @@ describe('Functionality of duplicating objectives and their belonging keyResults .fillObjectiveDescription('Wow this is a very nice description!') .cancel(); - cy.contains(duplicatedTitle).should('not.exist'); + cy.contains(duplicatedTitle) + .should('not.exist'); }); }); describe('Verify functionality of scoring adjustment on duplicated objectives', () => { - let keyresultDetailPage = new KeyResultDetailPage(); + const keyresultDetailPage = new KeyResultDetailPage(); it('Duplicate ordinal checkin and validate value of scoring component', () => { overviewPage @@ -108,7 +118,8 @@ describe('Verify functionality of scoring adjustment on duplicated objectives', .fillCheckInInitiatives('Testmassnahmen') .submit(); - cy.intercept('GET', '**/overview?*').as('indexPage'); + cy.intercept('GET', '**/overview?*') + .as('indexPage'); keyresultDetailPage.close(); cy.wait('@indexPage'); @@ -128,11 +139,12 @@ describe('Verify functionality of scoring adjustment on duplicated objectives', .findByTestId('fail') .as('fail-area'); - cy.get('@fail-area').should(($fail) => { - expect($fail).not.to.have.css('score-red'); - expect($fail).not.to.have.css('score-yellow'); - expect($fail).not.to.have.css('score-green'); - expect($fail).not.to.have.css('score-stretch'); - }); + cy.get('@fail-area') + .should(($fail) => { + expect($fail).not.to.have.css('score-red'); + expect($fail).not.to.have.css('score-yellow'); + expect($fail).not.to.have.css('score-green'); + expect($fail).not.to.have.css('score-stretch'); + }); }); }); diff --git a/frontend/cypress/e2e/key-result.cy.ts b/frontend/cypress/e2e/key-result.cy.ts index 5a2597cf54..45d45af130 100644 --- a/frontend/cypress/e2e/key-result.cy.ts +++ b/frontend/cypress/e2e/key-result.cy.ts @@ -76,7 +76,8 @@ describe('OKR Overview', () => { .fillKeyResultDescription('This is my description when creating and then open a new') .saveAndNew(); cy.contains('Jaya Norris'); - KeyResultDialog.do().checkForDialogTextMetric(); + KeyResultDialog.do() + .checkForDialogTextMetric(); }); it('Create and edit KeyResult with Action Plan', () => { @@ -103,7 +104,8 @@ describe('OKR Overview', () => { cy.contains('A new company'); keyResultDetailPage.editKeyResult(); - cy.getByTestId('actionInput').should('have.length', 3); + cy.getByTestId('actionInput') + .should('have.length', 3); }); it('Edit a KeyResult without type change', () => { @@ -114,16 +116,24 @@ describe('OKR Overview', () => { .checkForDialogTextOrdinal() .fillKeyResultDescription('This is my description') .submit(); - keyResultDetailPage.visit('We want not to change keyresult title').editKeyResult(); + keyResultDetailPage.visit('We want not to change keyresult title') + .editKeyResult(); - cy.getByTestId('submit').should('not.be.disabled'); + cy.getByTestId('submit') + .should('not.be.disabled'); cy.contains('Key Result bearbeiten'); - cy.getByTestId('titleInput').should('have.value', 'We want not to change keyresult title'); - cy.getByTestId('commitZone').should('have.value', 'My commit zone'); - cy.getByTestId('targetZone').should('have.value', 'My target zone'); - cy.getByTestId('stretchZone').should('have.value', 'My stretch goal'); - cy.getByTestId('ownerInput').should('have.value', 'Jaya Norris'); - cy.getByTestId('descriptionInput').should('have.value', 'This is my description'); + cy.getByTestId('titleInput') + .should('have.value', 'We want not to change keyresult title'); + cy.getByTestId('commitZone') + .should('have.value', 'My commit zone'); + cy.getByTestId('targetZone') + .should('have.value', 'My target zone'); + cy.getByTestId('stretchZone') + .should('have.value', 'My stretch goal'); + cy.getByTestId('ownerInput') + .should('have.value', 'Jaya Norris'); + cy.getByTestId('descriptionInput') + .should('have.value', 'This is my description'); KeyResultDialog.do() .fillKeyResultTitle('This is the new title') @@ -149,16 +159,24 @@ describe('OKR Overview', () => { .addActionPlanElement('Action 1') .addActionPlanElement('Action 2') .submit(); - keyResultDetailPage.visit('Here we want to change keyresult title').editKeyResult(); + keyResultDetailPage.visit('Here we want to change keyresult title') + .editKeyResult(); - cy.getByTestId('submit').should('not.be.disabled'); + cy.getByTestId('submit') + .should('not.be.disabled'); cy.contains('Key Result bearbeiten'); - cy.getByTestId('titleInput').should('have.value', 'Here we want to change keyresult title'); - cy.getByTestId('commitZone').should('have.value', 'My commit zone'); - cy.getByTestId('targetZone').should('have.value', 'My target zone'); - cy.getByTestId('stretchZone').should('have.value', 'My stretch goal'); - cy.getByTestId('ownerInput').should('have.value', 'Jaya Norris'); - cy.getByTestId('descriptionInput').should('have.value', 'This is my description'); + cy.getByTestId('titleInput') + .should('have.value', 'Here we want to change keyresult title'); + cy.getByTestId('commitZone') + .should('have.value', 'My commit zone'); + cy.getByTestId('targetZone') + .should('have.value', 'My target zone'); + cy.getByTestId('stretchZone') + .should('have.value', 'My stretch goal'); + cy.getByTestId('ownerInput') + .should('have.value', 'Jaya Norris'); + cy.getByTestId('descriptionInput') + .should('have.value', 'This is my description'); KeyResultDialog.do() .fillKeyResultTitle('This is my new title for the new metric keyresult') @@ -196,82 +214,126 @@ describe('OKR Overview', () => { keyResultDetailPage.close(); - keyResultDetailPage.visit('Here we want to create a checkin').editKeyResult(); + keyResultDetailPage.visit('Here we want to create a checkin') + .editKeyResult(); - cy.getByTestId('metricTab').should('have.class', 'non-active'); + cy.getByTestId('metricTab') + .should('have.class', 'non-active'); }); it('Check validation in keyresult dialog', () => { - overviewPage.addKeyResult().checkForDialogTextMetric(); - cy.getByTestId('submit').should('be.disabled'); + overviewPage.addKeyResult() + .checkForDialogTextMetric(); + cy.getByTestId('submit') + .should('be.disabled'); KeyResultDialog.do() .fillKeyResultTitle('I am a metric keyresult') .withMetricValues(Unit.PERCENT, '21', '52') .fillKeyResultDescription('This is my description'); - cy.getByTestId('submit').should('not.be.disabled'); + cy.getByTestId('submit') + .should('not.be.disabled'); - cy.getByTestId('titleInput').clear(); - cy.getByTestId('submit').should('be.disabled'); + cy.getByTestId('titleInput') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Titel muss folgende Länge haben: 2-250 Zeichen'); - KeyResultDialog.do().fillKeyResultTitle('My title'); - cy.getByTestId('submit').should('not.be.disabled'); - cy.getByTestId('baseline').clear(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .fillKeyResultTitle('My title'); + cy.getByTestId('submit') + .should('not.be.disabled'); + cy.getByTestId('baseline') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Baseline muss eine Zahl sein'); - KeyResultDialog.do().withMetricValues(Unit.PERCENT, 'abc', '52'); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withMetricValues(Unit.PERCENT, 'abc', '52'); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Baseline muss eine Zahl sein'); - KeyResultDialog.do().withMetricValues(Unit.PERCENT, '45', '52'); - cy.getByTestId('submit').should('not.be.disabled'); - cy.getByTestId('stretchGoal').clear(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withMetricValues(Unit.PERCENT, '45', '52'); + cy.getByTestId('submit') + .should('not.be.disabled'); + cy.getByTestId('stretchGoal') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Stretch Goal muss eine Zahl sein'); - KeyResultDialog.do().withMetricValues(Unit.PERCENT, '45', 'abc'); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withMetricValues(Unit.PERCENT, '45', 'abc'); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Stretch Goal muss eine Zahl sein'); - KeyResultDialog.do().withMetricValues(Unit.PERCENT, '45', '83'); - cy.getByTestId('submit').should('not.be.disabled'); - cy.getByTestId('ownerInput').clear(); - cy.getByTestId('submit').should('be.disabled'); - - cy.getByTestId('ownerInput').type('abc'); - cy.getByTestId('titleInput').type('Hello'); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withMetricValues(Unit.PERCENT, '45', '83'); + cy.getByTestId('submit') + .should('not.be.disabled'); + cy.getByTestId('ownerInput') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); + + cy.getByTestId('ownerInput') + .type('abc'); + cy.getByTestId('titleInput') + .type('Hello'); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Owner muss ausgewählt sein'); - KeyResultDialog.do().fillOwner('Bob Baumeister'); - cy.getByTestId('submit').should('not.be.disabled'); - - cy.getByTestId('ordinalTab').click(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .fillOwner('Bob Baumeister'); + cy.getByTestId('submit') + .should('not.be.disabled'); - KeyResultDialog.do().withOrdinalValues('Commit', 'Target', 'Stretch'); - cy.getByTestId('submit').should('not.be.disabled'); + cy.getByTestId('ordinalTab') + .click(); + cy.getByTestId('submit') + .should('be.disabled'); - cy.getByTestId('commitZone').clear(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withOrdinalValues('Commit', 'Target', 'Stretch'); + cy.getByTestId('submit') + .should('not.be.disabled'); + + cy.getByTestId('commitZone') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Commit Zone muss folgende Länge haben: 1-400 Zeichen'); - KeyResultDialog.do().withOrdinalValues('Commit', 'Target', 'Stretch'); - cy.getByTestId('submit').should('not.be.disabled'); - cy.getByTestId('targetZone').clear(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withOrdinalValues('Commit', 'Target', 'Stretch'); + cy.getByTestId('submit') + .should('not.be.disabled'); + cy.getByTestId('targetZone') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Target Zone muss folgende Länge haben: 1-400 Zeichen'); - KeyResultDialog.do().withOrdinalValues('Commit', 'Target', 'Stretch'); - cy.getByTestId('submit').should('not.be.disabled'); - cy.getByTestId('stretchZone').clear(); - cy.getByTestId('submit').should('be.disabled'); + KeyResultDialog.do() + .withOrdinalValues('Commit', 'Target', 'Stretch'); + cy.getByTestId('submit') + .should('not.be.disabled'); + cy.getByTestId('stretchZone') + .clear(); + cy.getByTestId('submit') + .should('be.disabled'); cy.contains('Stretch Zone muss folgende Länge haben: 1-400 Zeichen'); - KeyResultDialog.do().withOrdinalValues('Commit', 'Target', 'Stretch'); - cy.getByTestId('submit').should('not.be.disabled'); + KeyResultDialog.do() + .withOrdinalValues('Commit', 'Target', 'Stretch'); + cy.getByTestId('submit') + .should('not.be.disabled'); }); it('Delete existing keyresult', () => { @@ -287,12 +349,11 @@ describe('OKR Overview', () => { .editKeyResult() .deleteKeyResult() .checkTitle('Key Result löschen') - .checkDescription( - 'Möchtest du dieses Key Result wirklich löschen? Zugehörige Check-ins werden dadurch ebenfalls gelöscht!', - ) + .checkDescription('Möchtest du dieses Key Result wirklich löschen? Zugehörige Check-ins werden dadurch ebenfalls gelöscht!') .submit(); cy.contains('Puzzle ITC'); - cy.get('A keyresult to delete').should('not.exist'); + cy.get('A keyresult to delete') + .should('not.exist'); }); }); diff --git a/frontend/cypress/e2e/login.cy.ts b/frontend/cypress/e2e/login.cy.ts index d7730d355b..2ab584f05c 100644 --- a/frontend/cypress/e2e/login.cy.ts +++ b/frontend/cypress/e2e/login.cy.ts @@ -6,26 +6,37 @@ describe('OKR Login', () => { }); it('Login and check correct name is displayed', () => { - cy.title().should('equal', 'Puzzle OKR'); - cy.getByTestId('user-name').contains(users.gl.name); + cy.title() + .should('equal', 'Puzzle OKR'); + cy.getByTestId('user-name') + .contains(users.gl.name); }); it('Login and logout', () => { - cy.title().should('equal', 'Puzzle OKR'); - cy.getByTestId('user-options').click(); - cy.getByTestId('logout').click(); + cy.title() + .should('equal', 'Puzzle OKR'); + cy.getByTestId('user-options') + .click(); + cy.getByTestId('logout') + .click(); cy.origin(Cypress.env('login_url'), () => { - cy.url().should('include', Cypress.env('login_url')); - cy.get('#kc-page-title').contains('Sign in to your account'); + cy.url() + .should('include', Cypress.env('login_url')); + cy.get('#kc-page-title') + .contains('Sign in to your account'); }); }); it('Click on the Hilfe button should open a new tab with the correct URL', () => { - cy.window().then((win) => { - cy.stub(win, 'open').as('openWindow'); - }); + cy.window() + .then((win) => { + cy.stub(win, 'open') + .as('openWindow'); + }); - cy.get('#hilfeButton').click(); - cy.get('@openWindow').should('be.calledWith', 'https://wiki.puzzle.ch/Puzzle/OKRs'); + cy.get('#hilfeButton') + .click(); + cy.get('@openWindow') + .should('be.calledWith', 'https://wiki.puzzle.ch/Puzzle/OKRs'); }); }); diff --git a/frontend/cypress/e2e/objective-backlog.cy.ts b/frontend/cypress/e2e/objective-backlog.cy.ts index b9d58ff14b..f14d53ba52 100644 --- a/frontend/cypress/e2e/objective-backlog.cy.ts +++ b/frontend/cypress/e2e/objective-backlog.cy.ts @@ -15,18 +15,22 @@ describe('OKR Objective Backlog e2e tests', () => { .addObjective() .fillObjectiveTitle('Objective in quarter backlog') .selectQuarter('Backlog') - .run(cy.contains('Speichern').should('not.exist')) + .run(cy.contains('Speichern') + .should('not.exist')) .run(cy.contains('Als Draft speichern')) .submitDraftObjective(); - cy.contains('Objective in quarter backlog').should('not.exist'); + cy.contains('Objective in quarter backlog') + .should('not.exist'); overviewPage.visitBacklogQuarter(); cy.contains('Objective in quarter backlog'); }); it(`Edit Objective and move to backlog`, () => { - overviewPage.addObjective().fillObjectiveTitle('Move to another quarter on edit').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('Move to another quarter on edit') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('Move to another quarter on edit', 'draft') @@ -34,16 +38,22 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - ObjectiveDialog.do().fillObjectiveTitle('This goes now to backlog').selectQuarter('Backlog').submit(); + ObjectiveDialog.do() + .fillObjectiveTitle('This goes now to backlog') + .selectQuarter('Backlog') + .submit(); - cy.contains('This goes now to backlog').should('not.exist'); + cy.contains('This goes now to backlog') + .should('not.exist'); overviewPage.visitBacklogQuarter(); cy.contains('This goes now to backlog'); }); it(`Edit ongoing Objective can not choose backlog in quarter select`, () => { - overviewPage.addObjective().fillObjectiveTitle('We can not move this to backlog').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('We can not move this to backlog') + .submit(); overviewPage .getObjectiveByNameAndState('We can not move this to backlog', 'ongoing') @@ -51,30 +61,45 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - cy.get('select#quarter').should('contain', 'GJ ForTests'); - cy.get('select#quarter').should('not.contain', 'Backlog'); + cy.get('select#quarter') + .should('contain', 'GJ ForTests'); + cy.get('select#quarter') + .should('not.contain', 'Backlog'); }); it(`Can release Objective to another quarter from backlog`, () => { overviewPage.visitBacklogQuarter(); - overviewPage.addObjective().fillObjectiveTitle('We can not release this').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('We can not release this') + .submitDraftObjective(); - overviewPage.getObjectiveByNameAndState('We can not release this', 'draft').findByTestId('three-dot-menu').click(); + overviewPage.getObjectiveByNameAndState('We can not release this', 'draft') + .findByTestId('three-dot-menu') + .click(); overviewPage.selectFromThreeDotMenu('Objective veröffentlichen'); cy.contains('Objective veröffentlichen'); - cy.getByTestId('title').first().as('title'); - cy.get('@title').clear(); - cy.get('@title').type('This is our first released objective'); - - cy.get('select#quarter').should('not.contain', 'Backlog'); - cy.get('select#quarter').select('GJ ForTests'); - - cy.contains('Als Draft speichern').should('not.exist'); + cy.getByTestId('title') + .first() + .as('title'); + cy.get('@title') + .clear(); + cy.get('@title') + .type('This is our first released objective'); + + cy.get('select#quarter') + .should('not.contain', 'Backlog'); + cy.get('select#quarter') + .select('GJ ForTests'); + + cy.contains('Als Draft speichern') + .should('not.exist'); cy.contains('Speichern'); - cy.getByTestId('save').click(); + cy.getByTestId('save') + .click(); - cy.contains('This is our first released objective').should('not.exist'); + cy.contains('This is our first released objective') + .should('not.exist'); overviewPage.visitGJForTests(); cy.contains('This is our first released objective'); @@ -82,7 +107,9 @@ describe('OKR Objective Backlog e2e tests', () => { it(`Can edit Objective title in backlog`, () => { overviewPage.visitBacklogQuarter(); - overviewPage.addObjective().fillObjectiveTitle('This is possible for edit').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('This is possible for edit') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('This is possible for edit', 'draft') @@ -90,14 +117,18 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - ObjectiveDialog.do().fillObjectiveTitle('My new title').submit(); + ObjectiveDialog.do() + .fillObjectiveTitle('My new title') + .submit(); overviewPage.getObjectiveByNameAndState('My new title', 'draft'); }); it(`Can edit Objective in backlog and change quarter`, () => { overviewPage.visitBacklogQuarter(); - overviewPage.addObjective().fillObjectiveTitle('This goes to other quarter later').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('This goes to other quarter later') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('This goes to other quarter later', 'draft') @@ -105,7 +136,9 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - ObjectiveDialog.do().selectQuarter('GJ ForTests').submit(); + ObjectiveDialog.do() + .selectQuarter('GJ ForTests') + .submit(); overviewPage.visitGJForTests(); overviewPage.getObjectiveByNameAndState('This goes to other quarter later', 'draft'); @@ -113,7 +146,9 @@ describe('OKR Objective Backlog e2e tests', () => { it(`Can duplicate in backlog`, () => { overviewPage.visitBacklogQuarter(); - overviewPage.addObjective().fillObjectiveTitle('Ready for duplicate in backlog').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('Ready for duplicate in backlog') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('Ready for duplicate in backlog', 'draft') @@ -121,7 +156,9 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective duplizieren'); - ObjectiveDialog.do().fillObjectiveTitle('This is a new duplication in backlog').submit(); + ObjectiveDialog.do() + .fillObjectiveTitle('This is a new duplication in backlog') + .submit(); overviewPage.getObjectiveByNameAndState('Ready for duplicate in backlog', 'draft'); overviewPage.getObjectiveByNameAndState('This is a new duplication in backlog', 'draft'); @@ -129,23 +166,33 @@ describe('OKR Objective Backlog e2e tests', () => { it('should duplicate from backlog', () => { overviewPage.visitBacklogQuarter(); - overviewPage.addObjective().fillObjectiveTitle('Ready for duplicate to another quarter').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('Ready for duplicate to another quarter') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('Ready for duplicate to another quarter', 'draft') .findByTestId('three-dot-menu') .click(); overviewPage.selectFromThreeDotMenu('Objective duplizieren'); - ObjectiveDialog.do().fillObjectiveTitle('New duplication from backlog').selectQuarter('GJ ForTests').submit(); + ObjectiveDialog.do() + .fillObjectiveTitle('New duplication from backlog') + .selectQuarter('GJ ForTests') + .submit(); - overviewPage.getObjectiveByNameAndState('Ready for duplicate to another quarter', 'draft').should('exist'); - cy.contains('New duplication from backlog').should('not.exist'); + overviewPage.getObjectiveByNameAndState('Ready for duplicate to another quarter', 'draft') + .should('exist'); + cy.contains('New duplication from backlog') + .should('not.exist'); overviewPage.visitGJForTests(); - overviewPage.getObjectiveByNameAndState('New duplication from backlog', 'draft').should('exist'); + overviewPage.getObjectiveByNameAndState('New duplication from backlog', 'draft') + .should('exist'); }); it(`Can duplicate ongoing Objective to backlog`, () => { - overviewPage.addObjective().fillObjectiveTitle('Possible to duplicate into backlog').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('Possible to duplicate into backlog') + .submit(); overviewPage .getObjectiveByNameAndState('Possible to duplicate into backlog', 'ongoing') @@ -153,7 +200,9 @@ describe('OKR Objective Backlog e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective duplizieren'); - ObjectiveDialog.do().selectQuarter('Backlog').submit(); + ObjectiveDialog.do() + .selectQuarter('Backlog') + .submit(); overviewPage.visitBacklogQuarter(); cy.contains('Possible to duplicate into backlog'); diff --git a/frontend/cypress/e2e/objective-crud.cy.ts b/frontend/cypress/e2e/objective-crud.cy.ts index 06a7545d03..c2af9c5754 100644 --- a/frontend/cypress/e2e/objective-crud.cy.ts +++ b/frontend/cypress/e2e/objective-crud.cy.ts @@ -10,13 +10,20 @@ describe('CRUD operations', () => { cy.loginAsUser(users.gl); }); - [ - ['ongoing objective title', 'save', 'ongoing-icon.svg'], - ['draft objective title', 'save-draft', 'draft-icon.svg'], - ].forEach(([objectiveTitle, buttonTestId, icon]) => { + [['ongoing objective title', + 'save', + 'ongoing-icon.svg'], + ['draft objective title', + 'save-draft', + 'draft-icon.svg']].forEach(([objectiveTitle, + buttonTestId, + icon]) => { it(`Create objective, no keyresults`, () => { - overviewPage.addObjective().fillObjectiveTitle(objectiveTitle).selectQuarter('3'); - cy.getByTestId(buttonTestId).click(); + overviewPage.addObjective() + .fillObjectiveTitle(objectiveTitle) + .selectQuarter('3'); + cy.getByTestId(buttonTestId) + .click(); overviewPage.visitNextQuarter(); overviewPage .getObjectiveByName(objectiveTitle) @@ -27,50 +34,72 @@ describe('CRUD operations', () => { it(`Create objective, should display error message`, () => { overviewPage.addObjective(); - cy.getByTestId('title').first().type('title').clear(); + cy.getByTestId('title') + .first() + .type('title') + .clear(); cy.contains('Titel muss folgende Länge haben: 2-250 Zeichen'); - cy.getByTestId('save').should('be.disabled'); - cy.getByTestId('save-draft').should('be.disabled'); - cy.getByTestId('cancel').should('not.be.disabled'); + cy.getByTestId('save') + .should('be.disabled'); + cy.getByTestId('save-draft') + .should('be.disabled'); + cy.getByTestId('cancel') + .should('not.be.disabled'); }); it(`Create objective, cancel`, () => { const objectiveTitle = 'this is a canceled objective'; - overviewPage.addObjective().selectQuarter('3').cancel(); + overviewPage.addObjective() + .selectQuarter('3') + .cancel(); overviewPage.visitNextQuarter(); - cy.contains(objectiveTitle).should('not.exist'); + cy.contains(objectiveTitle) + .should('not.exist'); }); it(`Delete existing objective`, () => { - overviewPage.getFirstObjective().findByTestId('three-dot-menu').click(); + overviewPage.getFirstObjective() + .findByTestId('three-dot-menu') + .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); ObjectiveDialog.do() .deleteObjective() .checkTitle('Objective löschen') - .checkDescription( - 'Möchtest du dieses Objective wirklich löschen? Zugehörige Key Results werden dadurch ebenfalls gelöscht!', - ) + .checkDescription('Möchtest du dieses Objective wirklich löschen? Zugehörige Key Results werden dadurch ebenfalls gelöscht!') .submit(); }); it(`Open objective aside via click`, () => { - overviewPage.getFirstObjective().find('.title').click(); - cy.url().should('include', 'objective'); + overviewPage.getFirstObjective() + .find('.title') + .click(); + cy.url() + .should('include', 'objective'); }); it(`update objective`, () => { const updatedTitle = 'This is an updated title'; - overviewPage.getFirstObjective().findByTestId('three-dot-menu').click(); + overviewPage.getFirstObjective() + .findByTestId('three-dot-menu') + .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - ObjectiveDialog.do().fillObjectiveTitle(updatedTitle).submit(); - cy.contains(updatedTitle).should('exist'); + ObjectiveDialog.do() + .fillObjectiveTitle(updatedTitle) + .submit(); + cy.contains(updatedTitle) + .should('exist'); }); it(`Duplicate objective`, () => { const duplicatedTitle = 'This is a duplicated objective'; - overviewPage.getFirstObjective().findByTestId('three-dot-menu').click(); + overviewPage.getFirstObjective() + .findByTestId('three-dot-menu') + .click(); overviewPage.selectFromThreeDotMenu('Objective duplizieren'); - ObjectiveDialog.do().fillObjectiveTitle(duplicatedTitle).submit(); - cy.contains(duplicatedTitle).should('exist'); + ObjectiveDialog.do() + .fillObjectiveTitle(duplicatedTitle) + .submit(); + cy.contains(duplicatedTitle) + .should('exist'); }); }); diff --git a/frontend/cypress/e2e/objective.cy.ts b/frontend/cypress/e2e/objective.cy.ts index ebe6a41af5..b7dec8295e 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -12,7 +12,9 @@ describe('OKR Objective e2e tests', () => { describe('tests via click', () => { it(`Release Objective from Draft to Ongoing`, () => { - overviewPage.addObjective().fillObjectiveTitle('A objective in state draft').submitDraftObjective(); + overviewPage.addObjective() + .fillObjectiveTitle('A objective in state draft') + .submitDraftObjective(); overviewPage .getObjectiveByNameAndState('A objective in state draft', 'draft') @@ -25,11 +27,14 @@ describe('OKR Objective e2e tests', () => { .checkDescription('Soll dieses Objective veröffentlicht werden?') .submit(); - overviewPage.getObjectiveByNameAndState('A objective in state draft', 'ongoing').should('exist'); + overviewPage.getObjectiveByNameAndState('A objective in state draft', 'ongoing') + .should('exist'); }); it(`Complete Objective with Successful`, () => { - overviewPage.addObjective().fillObjectiveTitle('We want to complete this successful').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('We want to complete this successful') + .submit(); overviewPage .getObjectiveByNameAndState('We want to complete this successful', 'ongoing') @@ -45,14 +50,18 @@ describe('OKR Objective e2e tests', () => { cy.contains('Objective abschliessen'); cy.contains('Abbrechen'); - cy.getByTestId('successful').click(); - cy.getByTestId('submit').click(); + cy.getByTestId('successful') + .click(); + cy.getByTestId('submit') + .click(); overviewPage.getObjectiveByNameAndState('We want to complete this successful', 'successful'); }); it(`Complete Objective with Not-Successful`, () => { - overviewPage.addObjective().fillObjectiveTitle('A not successful objective').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('A not successful objective') + .submit(); overviewPage .getObjectiveByNameAndState('A not successful objective', 'ongoing') @@ -67,14 +76,18 @@ describe('OKR Objective e2e tests', () => { cy.contains('Objective abschliessen'); cy.contains('Abbrechen'); - cy.getByTestId('not-successful').click(); - cy.getByTestId('submit').click(); + cy.getByTestId('not-successful') + .click(); + cy.getByTestId('submit') + .click(); overviewPage.getObjectiveByNameAndState('A not successful objective', 'not-successful'); }); it(`Reopen Successful Objective`, () => { - overviewPage.addObjective().fillObjectiveTitle('This objective will be reopened after').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('This objective will be reopened after') + .submit(); overviewPage .getObjectiveByNameAndState('This objective will be reopened after', 'ongoing') @@ -83,8 +96,10 @@ describe('OKR Objective e2e tests', () => { overviewPage.selectFromThreeDotMenu('Objective abschliessen'); - cy.getByTestId('successful').click(); - cy.getByTestId('submit').click(); + cy.getByTestId('successful') + .click(); + cy.getByTestId('submit') + .click(); cy.wait(500); @@ -100,11 +115,14 @@ describe('OKR Objective e2e tests', () => { .checkDescription('Soll dieses Objective wiedereröffnet werden?') .submit(); - overviewPage.getObjectiveByNameAndState('This objective will be reopened after', 'ongoing').should('exist'); + overviewPage.getObjectiveByNameAndState('This objective will be reopened after', 'ongoing') + .should('exist'); }); it(`Cancel Reopen Successful Objective`, () => { - overviewPage.addObjective().fillObjectiveTitle('The reopening of this objective will be canceled').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('The reopening of this objective will be canceled') + .submit(); overviewPage .getObjectiveByNameAndState('The reopening of this objective will be canceled', 'ongoing') @@ -113,8 +131,10 @@ describe('OKR Objective e2e tests', () => { overviewPage.selectFromThreeDotMenu('Objective abschliessen'); - cy.getByTestId('successful').click(); - cy.getByTestId('submit').click(); + cy.getByTestId('successful') + .click(); + cy.getByTestId('submit') + .click(); cy.wait(500); @@ -136,7 +156,9 @@ describe('OKR Objective e2e tests', () => { }); it('Cancel Ongoing objective back to draft state', () => { - overviewPage.addObjective().fillObjectiveTitle('This objective will be returned to draft state').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('This objective will be returned to draft state') + .submit(); overviewPage .getObjectiveByNameAndState('This objective will be returned to draft state', 'ongoing') @@ -177,9 +199,13 @@ describe('OKR Objective e2e tests', () => { }); it(`Search for Objective`, () => { - overviewPage.addObjective().fillObjectiveTitle('Search after this objective').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('Search after this objective') + .submit(); - overviewPage.addObjective().fillObjectiveTitle('We dont want to search for this').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('We dont want to search for this') + .submit(); cy.contains('Search after this objective'); cy.contains('We dont want to search for this'); @@ -187,35 +213,59 @@ describe('OKR Objective e2e tests', () => { cy.scrollTo(0, 0); cy.wait(500); - cy.getByTestId('objectiveSearch').first().click(); - cy.getByTestId('objectiveSearch').first().type('Search after').wait(350); + cy.getByTestId('objectiveSearch') + .first() + .click(); + cy.getByTestId('objectiveSearch') + .first() + .type('Search after') + .wait(350); cy.contains('Search after this objective'); - cy.contains('We dont want to search for this').should('not.exist'); + cy.contains('We dont want to search for this') + .should('not.exist'); - cy.getByTestId('objectiveSearch').first().as('objective-search').clear(); - cy.get('@objective-search').type('this').wait(350); + cy.getByTestId('objectiveSearch') + .first() + .as('objective-search') + .clear(); + cy.get('@objective-search') + .type('this') + .wait(350); cy.contains('Search after this objective'); cy.contains('We dont want to search for this'); - cy.get('@objective-search').clear(); - cy.get('@objective-search').type('dont want to').wait(350); + cy.get('@objective-search') + .clear(); + cy.get('@objective-search') + .type('dont want to') + .wait(350); cy.contains('We dont want to search for this'); - cy.contains('Search after this objective').should('not.exist'); - - cy.get('@objective-search').clear(); - cy.get('@objective-search').type('there is no objective').wait(350); - - cy.contains('We dont want to search for this').should('not.exist'); - cy.contains('Search after this objective').should('not.exist'); + cy.contains('Search after this objective') + .should('not.exist'); + + cy.get('@objective-search') + .clear(); + cy.get('@objective-search') + .type('there is no objective') + .wait(350); + + cy.contains('We dont want to search for this') + .should('not.exist'); + cy.contains('Search after this objective') + .should('not.exist'); }); it(`Create Objective in other quarter`, () => { - overviewPage.addObjective().fillObjectiveTitle('Objective in quarter 3').selectQuarter('3').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('Objective in quarter 3') + .selectQuarter('3') + .submit(); - cy.contains('Objective in quarter 3').should('not.exist'); + cy.contains('Objective in quarter 3') + .should('not.exist'); overviewPage.visitNextQuarter(); @@ -223,7 +273,9 @@ describe('OKR Objective e2e tests', () => { }); it(`Edit Objective and move to other quarter`, () => { - overviewPage.addObjective().fillObjectiveTitle('Move to another quarter on edit').submit(); + overviewPage.addObjective() + .fillObjectiveTitle('Move to another quarter on edit') + .submit(); overviewPage .getObjectiveByNameAndState('Move to another quarter on edit', 'ongoing') @@ -231,9 +283,12 @@ describe('OKR Objective e2e tests', () => { .click(); overviewPage.selectFromThreeDotMenu('Objective bearbeiten'); - ObjectiveDialog.do().selectQuarter('3').submit(); + ObjectiveDialog.do() + .selectQuarter('3') + .submit(); - cy.contains('Move to another quarter on edit').should('not.exist'); + cy.contains('Move to another quarter on edit') + .should('not.exist'); overviewPage.visitNextQuarter(); cy.contains('Move to another quarter on edit'); @@ -242,9 +297,14 @@ describe('OKR Objective e2e tests', () => { describe('tests via keyboard', () => { it(`Open objective aside via enter`, () => { - cy.getByTestId('objective').first().find('[tabindex]').first().focus(); + cy.getByTestId('objective') + .first() + .find('[tabindex]') + .first() + .focus(); cy.realPress('Enter'); - cy.url().should('include', 'objective'); + cy.url() + .should('include', 'objective'); }); }); }); diff --git a/frontend/cypress/e2e/overview.cy.ts b/frontend/cypress/e2e/overview.cy.ts index a1aafc86ab..770428a26e 100644 --- a/frontend/cypress/e2e/overview.cy.ts +++ b/frontend/cypress/e2e/overview.cy.ts @@ -7,21 +7,38 @@ describe('OKR Overview', () => { }); it('should have the current quarter with label Aktuell', () => { - cy.getByTestId('quarterFilter').contains('Aktuell'); + cy.getByTestId('quarterFilter') + .contains('Aktuell'); }); it('Check order of teams', () => { - FilterHelper.do().optionShouldNotBeSelected('Alle').toggleOption('Alle'); - const textsExpectedOrder = ['LoremIpsum', 'Puzzle ITC', '/BBT', 'we are cube.³']; + FilterHelper.do() + .optionShouldNotBeSelected('Alle') + .toggleOption('Alle'); + const textsExpectedOrder = [ + 'LoremIpsum', + 'Puzzle ITC', + '/BBT', + 'we are cube.³' + ]; cy.get('.team-title:contains("we are cube.³")'); - cy.get('.team-title').then((elements) => { - const texts: string[] = elements.map((_, el) => Cypress.$(el).text()).get(); - expect(texts).to.deep.equal(textsExpectedOrder); - }); + cy.get('.team-title') + .then((elements) => { + const texts: string[] = elements.map((_, el) => Cypress.$(el) + .text()) + .get(); + expect(texts).to.deep.equal(textsExpectedOrder); + }); }); it('Check font ', () => { - cy.get('.team-title').first().invoke('css', 'font-family').should('eq', 'Roboto, "sans-serif"'); - cy.get('.team-title').first().invoke('css', 'font-variation-settings').should('eq', '"wght" 600'); + cy.get('.team-title') + .first() + .invoke('css', 'font-family') + .should('eq', 'Roboto, "sans-serif"'); + cy.get('.team-title') + .first() + .invoke('css', 'font-variation-settings') + .should('eq', '"wght" 600'); }); }); diff --git a/frontend/cypress/e2e/routing.cy.ts b/frontend/cypress/e2e/routing.cy.ts index 58f80ef982..e08fb94367 100644 --- a/frontend/cypress/e2e/routing.cy.ts +++ b/frontend/cypress/e2e/routing.cy.ts @@ -10,24 +10,32 @@ describe('Routing', () => { describe('Route via url', () => { it('should route to overview', () => { // Visit autocalls the validatePage method - CyOverviewPage.do().visitViaURL(); + CyOverviewPage.do() + .visitViaURL(); }); it('should route to teammanagement', () => { // Visit autocalls the validatePage method - TeammanagementPage.do().visitViaURL(); + TeammanagementPage.do() + .visitViaURL(); }); it('should route from overview to team management ', () => { - CyOverviewPage.do().visitViaURL().visitTeammanagement(); + CyOverviewPage.do() + .visitViaURL() + .visitTeammanagement(); }); it('should route from team management to Overview via back button', () => { - TeammanagementPage.do().visitViaURL().backToOverview(); + TeammanagementPage.do() + .visitViaURL() + .backToOverview(); }); it('should route from team management to Overview via logo', () => { - TeammanagementPage.do().visitViaURL().visitOverview(); + TeammanagementPage.do() + .visitViaURL() + .visitOverview(); }); }); }); diff --git a/frontend/cypress/e2e/scoring.cy.ts b/frontend/cypress/e2e/scoring.cy.ts index e86da67685..0501c3e60c 100644 --- a/frontend/cypress/e2e/scoring.cy.ts +++ b/frontend/cypress/e2e/scoring.cy.ts @@ -15,13 +15,25 @@ describe('Scoring component e2e tests', () => { }); [ - [0, 100, 10], - [0, 100, 31], - [0, 100, 71], - [0, 100, 100], - ].forEach(([baseline, stretchgoal, value]) => { + [0, + 100, + 10], + [0, + 100, + 31], + [0, + 100, + 71], + [0, + 100, + 100] + ].forEach(([baseline, + stretchgoal, + value]) => { it('Create metric checkin and validate value of scoring component', () => { - setupMetricKR(`Metric kr with check-in value ${value}`, baseline, stretchgoal, value); + setupMetricKR( + `Metric kr with check-in value ${value}`, baseline, stretchgoal, value + ); const percentage = getPercentageMetric(baseline, stretchgoal, value); cy.validateScoring(false, percentage); cy.get('.keyResult-detail-attribute-show') @@ -40,12 +52,18 @@ describe('Scoring component e2e tests', () => { }); }); - [ - [0, 100, -1], - [200, 100, 250], - ].forEach(([baseline, stretchgoal, value]) => { + [[0, + 100, + -1], + [200, + 100, + 250]].forEach(([baseline, + stretchgoal, + value]) => { it('show indicator that value is negative', () => { - setupMetricKR(`Check indicator with value ${value}`, baseline, stretchgoal, value); + setupMetricKR( + `Check indicator with value ${value}`, baseline, stretchgoal, value + ); cy.validateScoring(false, 0); cy.get('.keyResult-detail-attribute-show') .contains('Aktuell') @@ -57,11 +75,17 @@ describe('Scoring component e2e tests', () => { keyresultDetailPage.close(); cy.validateScoring(true, 0); - overviewPage.getKeyResultByName(`Check indicator with value ${value}`).get('.scoring-error-badge'); + overviewPage.getKeyResultByName(`Check indicator with value ${value}`) + .get('.scoring-error-badge'); }); }); - [['fail'], ['commit'], ['target'], ['stretch']].forEach(([zoneName]) => { + [ + ['fail'], + ['commit'], + ['target'], + ['stretch'] + ].forEach(([zoneName]) => { it('Create ordinal checkin and validate value of scoring component', () => { overviewPage .addKeyResult() @@ -87,7 +111,9 @@ describe('Scoring component e2e tests', () => { }); }); -function setupMetricKR(name: string, baseline: number, stretchgoal: number, value: number) { +function setupMetricKR ( + name: string, baseline: number, stretchgoal: number, value: number +) { CyOverviewPage.do() .addKeyResult() .fillKeyResultTitle(name) diff --git a/frontend/cypress/e2e/tab.cy.ts b/frontend/cypress/e2e/tab.cy.ts index 3a6a685159..01a6485273 100644 --- a/frontend/cypress/e2e/tab.cy.ts +++ b/frontend/cypress/e2e/tab.cy.ts @@ -8,18 +8,22 @@ describe('Tab workflow tests', () => { beforeEach(() => { cy.loginAsUser(users.gl); overviewPage = new CyOverviewPage(); - overviewPage.elements.logo().parent().focus(); + overviewPage.elements.logo() + .parent() + .focus(); }); - function focusedShouldHaveTestId(testId: string) { - cy.focused().should('have.attr', 'data-testId', testId); + function focusedShouldHaveTestId (testId: string) { + cy.focused() + .should('have.attr', 'data-testId', testId); } - function tabAndCheck(testId: string, text?: string) { + function tabAndCheck (testId: string, text?: string) { cy.tabForwardUntil(`[data-testId="${testId}"]`); focusedShouldHaveTestId(testId); if (text) { - cy.focused().contains(text); + cy.focused() + .contains(text); } } @@ -40,7 +44,8 @@ describe('Tab workflow tests', () => { .should('have.attr', 'src') .and('match', /search-icon.svg/); cy.tabForward(); - cy.focused().contains('Alle'); + cy.focused() + .contains('Alle'); }); it('should be able to tab to overview items', () => { @@ -68,7 +73,8 @@ describe('Tab workflow tests', () => { }); it('should focus three dot menu after edit objective', () => { - overviewPage.getObjectiveByState('ongoing').focus(); + overviewPage.getObjectiveByState('ongoing') + .focus(); tabAndCheck('three-dot-menu'); cy.realPress('Enter'); tabToThreeDotMenuOption('Objective bearbeiten'); @@ -85,17 +91,20 @@ describe('Tab workflow tests', () => { }); it('should be able to complete and reopen objective', () => { - overviewPage.getObjectiveByState('ongoing').focus(); + overviewPage.getObjectiveByState('ongoing') + .focus(); tabAndCheck('three-dot-menu'); cy.realPress('Enter'); tabToThreeDotMenuOption('Objective abschliessen'); cy.contains('h2', 'Objective abschliessen '); focusedShouldHaveTestId('close-dialog'); cy.tabForward(); - cy.focused().contains('Objective erreicht'); + cy.focused() + .contains('Objective erreicht'); cy.realPress('Enter'); cy.tabForward(); - cy.focused().contains('Objective nicht erreicht'); + cy.focused() + .contains('Objective nicht erreicht'); tabAndCheck('completeComment'); tabAndCheck('cancel', 'Abbrechen'); tabAndCheck('submit', 'Objective abschliessen'); @@ -115,7 +124,8 @@ describe('Tab workflow tests', () => { }); it('should be able to set objective to draft and publish it', () => { - overviewPage.getObjectiveByState('ongoing').focus(); + overviewPage.getObjectiveByState('ongoing') + .focus(); tabAndCheck('three-dot-menu'); cy.realPress('Enter'); tabToThreeDotMenuOption('Objective als Draft speichern'); @@ -140,8 +150,10 @@ describe('Tab workflow tests', () => { }); it('should be able to open objective detail view', () => { - overviewPage.getObjectiveByState('ongoing').focus(); - cy.realPress('Enter').tabForward(); + overviewPage.getObjectiveByState('ongoing') + .focus(); + cy.realPress('Enter') + .tabForward(); focusedShouldHaveTestId('closeDrawer'); tabAndCheck('add-keyResult-objective-detail', 'Key Result hinzufügen'); tabAndCheck('edit-objective', 'Objective bearbeiten'); @@ -154,7 +166,8 @@ describe('Tab workflow tests', () => { cy.realPress('Enter'); focusedShouldHaveTestId('close-dialog'); tabAndCheck('titleInput'); - cy.focused().type('Title'); + cy.focused() + .type('Title'); tabAndCheck('unit'); tabAndCheck('baseline'); tabAndCheck('stretchGoal'); @@ -165,19 +178,26 @@ describe('Tab workflow tests', () => { tabAndCheck('ordinalTab', 'Ordinal'); cy.realPress('Enter'); tabAndCheck('commitZone'); - cy.focused().type('Commit'); + cy.focused() + .type('Commit'); tabAndCheck('targetZone'); - cy.focused().type('Target'); + cy.focused() + .type('Target'); tabAndCheck('stretchZone'); - cy.focused().type('Stretch'); + cy.focused() + .type('Stretch'); tabAndCheck('submit', 'Speichern'); tabAndCheck('saveAndNew', 'Speichern & Neu'); tabAndCheck('cancel', 'Abbrechen'); }); it('Should tab keyresult detail view', () => { - overviewPage.getObjectiveByState('ongoing').findByTestId('key-result').first().focus(); - cy.realPress('Enter').tabForward(); + overviewPage.getObjectiveByState('ongoing') + .findByTestId('key-result') + .first() + .focus(); + cy.realPress('Enter') + .tabForward(); focusedShouldHaveTestId('close-drawer'); tabAndCheck('show-all-checkins', 'Alle Check-ins anzeigen'); cy.realPress('Enter'); @@ -196,14 +216,16 @@ describe('Tab workflow tests', () => { .fillKeyResultTitle('A metric Keyresult for tabbing tests') .withMetricValues(Unit.CHF, '10', '100') .submit(); - KeyResultDetailPage.do().visit('A metric Keyresult for tabbing tests'); + KeyResultDetailPage.do() + .visit('A metric Keyresult for tabbing tests'); tabAndCheck('add-check-in', 'Check-in erfassen'); cy.realPress('Enter'); cy.contains('Check-in erfassen'); focusedShouldHaveTestId('close-dialog'); tabAndCheck('changeInfo'); tabAndCheck('check-in-metric-value'); - cy.focused().type('20'); + cy.focused() + .type('20'); tabAndCheck('initiatives'); cy.contains('5/10'); cy.tabForward(); @@ -219,20 +241,29 @@ describe('Tab workflow tests', () => { .fillKeyResultTitle('A ordinal Keyresult for tabbing tests') .withOrdinalValues('Commit', 'Target', 'Stretch') .submit(); - KeyResultDetailPage.do().visit('A ordinal Keyresult for tabbing tests'); + KeyResultDetailPage.do() + .visit('A ordinal Keyresult for tabbing tests'); tabAndCheck('add-check-in', 'Check-in erfassen'); cy.realPress('Enter'); cy.contains('Check-in erfassen'); focusedShouldHaveTestId('close-dialog'); tabAndCheck('changeInfo'); cy.tabForward(); - cy.focused().closest('mat-radio-button').should('have.attr', 'data-testId', 'fail-radio'); + cy.focused() + .closest('mat-radio-button') + .should('have.attr', 'data-testId', 'fail-radio'); cy.realPress('ArrowDown'); - cy.focused().closest('mat-radio-button').should('have.attr', 'data-testId', 'commit-radio'); + cy.focused() + .closest('mat-radio-button') + .should('have.attr', 'data-testId', 'commit-radio'); cy.realPress('ArrowDown'); - cy.focused().closest('mat-radio-button').should('have.attr', 'data-testId', 'target-radio'); + cy.focused() + .closest('mat-radio-button') + .should('have.attr', 'data-testId', 'target-radio'); cy.realPress('ArrowDown'); - cy.focused().closest('mat-radio-button').should('have.attr', 'data-testId', 'stretch-radio'); + cy.focused() + .closest('mat-radio-button') + .should('have.attr', 'data-testId', 'stretch-radio'); tabAndCheck('initiatives'); cy.contains('5/10'); cy.tabForward(); @@ -254,18 +285,21 @@ describe('Tab workflow tests', () => { tabAndCheck('invite-member', 'Member registrieren'); }); it('Should tab create team', () => { - cy.getByTestId('team-management').click(); + cy.getByTestId('team-management') + .click(); tabAndCheck('add-team'); cy.realPress('Enter'); cy.contains('Team erfassen'); focusedShouldHaveTestId('close-dialog'); tabAndCheck('add-team-name'); - cy.focused().type('Name of new team'); + cy.focused() + .type('Name of new team'); tabAndCheck('save', 'Speichern'); tabAndCheck('cancel', 'Abbrechen'); }); it('Should tab register member', () => { - cy.getByTestId('team-management').click(); + cy.getByTestId('team-management') + .click(); tabAndCheck('invite-member'); cy.realPress('Enter'); cy.contains('Member registrieren'); @@ -274,13 +308,16 @@ describe('Tab workflow tests', () => { tabAndCheck('new-member-last-name'); tabAndCheck('email-col_0'); cy.tabForward(); - cy.focused().closest('app-puzzle-icon-button').should('have.attr', 'icon', 'delete-icon.svg'); + cy.focused() + .closest('app-puzzle-icon-button') + .should('have.attr', 'icon', 'delete-icon.svg'); tabAndCheck('new-member-add-row', 'Weiterer Member hinzufügen'); tabAndCheck('invite', 'Einladen'); tabAndCheck('new-member-cancel', 'Abbrechen'); }); it('Should tab edit member', () => { - cy.getByTestId('team-management').click(); + cy.getByTestId('team-management') + .click(); cy.pressUntilContains('Alice Wunderland', 'Tab'); cy.tabForward(); cy.realPress('Enter'); @@ -289,23 +326,31 @@ describe('Tab workflow tests', () => { // Field to toggle if user is OKR-Champion cy.tabForward(); - cy.focused().closest('app-puzzle-icon-button').should('have.attr', 'icon', 'edit.svg'); + cy.focused() + .closest('app-puzzle-icon-button') + .should('have.attr', 'icon', 'edit.svg'); cy.realPress('Enter'); cy.tabForward(); tabAndCheck('close-drawer'); cy.tabForward(); - cy.focused().closest('mat-checkbox').should('have.attr', 'data-testId', 'edit-okr-champion-checkbox'); + cy.focused() + .closest('mat-checkbox') + .should('have.attr', 'data-testId', 'edit-okr-champion-checkbox'); // Field to edit role of assigned team cy.tabForward(); - cy.focused().closest('app-puzzle-icon-button').should('have.attr', 'icon', 'edit.svg'); + cy.focused() + .closest('app-puzzle-icon-button') + .should('have.attr', 'icon', 'edit.svg'); cy.realPress('Enter'); cy.tabForward(); tabAndCheck('select-team-role', 'Team-Member'); // Button to delete assigned team cy.tabForward(); - cy.focused().closest('app-puzzle-icon-button').should('have.attr', 'icon', 'delete-icon.svg'); + cy.focused() + .closest('app-puzzle-icon-button') + .should('have.attr', 'icon', 'delete-icon.svg'); // Button to add user to another team tabAndCheck('add-user'); @@ -319,7 +364,7 @@ describe('Tab workflow tests', () => { }); }); -function tabToThreeDotMenuOption(name: string) { +function tabToThreeDotMenuOption (name: string) { cy.pressUntilContains(name, 'ArrowDown'); cy.realPress('Enter'); } diff --git a/frontend/cypress/e2e/team.cy.ts b/frontend/cypress/e2e/team.cy.ts index 405eb2c993..50a88bc4a0 100644 --- a/frontend/cypress/e2e/team.cy.ts +++ b/frontend/cypress/e2e/team.cy.ts @@ -7,7 +7,8 @@ describe('OKR team e2e tests', () => { describe('tests via click', () => { beforeEach(() => { cy.loginAsUser(users.gl); - CyOverviewPage.do().visitCurrentQuarter(); + CyOverviewPage.do() + .visitCurrentQuarter(); }); it('Should select teams from teamfilter', () => { @@ -51,7 +52,8 @@ describe('OKR team e2e tests', () => { .optionShouldNotBeSelected('/BBT') .optionShouldNotBeSelected('we are cube'); - filterHelper.toggleOption('Puzzle ITC').toggleOption('LoremIpsum'); + filterHelper.toggleOption('Puzzle ITC') + .toggleOption('LoremIpsum'); cy.contains('Kein Team ausgewählt'); }); @@ -64,15 +66,23 @@ describe('OKR team e2e tests', () => { .optionShouldNotBeSelected('/BBT') .optionShouldNotBeSelected('we are cube'); - filterHelper.validateUrlParameter('teams', ['5', '6']); - - filterHelper.toggleOption('/BBT').validateUrlParameter('teams', ['4', '5', '6']); - filterHelper.toggleOption('Puzzle ITC').toggleOption('LoremIpsum').toggleOption('/BBT'); - cy.url().should('not.include', 'teams='); + filterHelper.validateUrlParameter('teams', ['5', + '6']); + + filterHelper.toggleOption('/BBT') + .validateUrlParameter('teams', ['4', + '5', + '6']); + filterHelper.toggleOption('Puzzle ITC') + .toggleOption('LoremIpsum') + .toggleOption('/BBT'); + cy.url() + .should('not.include', 'teams='); }); it('Select teams by url', () => { - cy.url().should('not.include', 'teams'); + cy.url() + .should('not.include', 'teams'); cy.visit('/?quarter=2&teams=4,5,8'); FilterHelper.do() @@ -84,16 +94,24 @@ describe('OKR team e2e tests', () => { }); it('should display less button on mobile header', () => { - let teammanagementPage = TeammanagementPage.do().visitViaURL(); - cy.intercept('POST', '**/teams').as('addTeam'); - - teammanagementPage.addTeam().fillName('X-Team').submit(); + const teammanagementPage = TeammanagementPage.do() + .visitViaURL(); + cy.intercept('POST', '**/teams') + .as('addTeam'); + + teammanagementPage.addTeam() + .fillName('X-Team') + .submit(); cy.wait('@addTeam'); cy.contains('X-Team'); - teammanagementPage.addTeam().fillName('Y-Team').submit(); + teammanagementPage.addTeam() + .fillName('Y-Team') + .submit(); cy.wait('@addTeam'); cy.contains('Y-Team'); - teammanagementPage.addTeam().fillName('Z-Team').submit(); + teammanagementPage.addTeam() + .fillName('Z-Team') + .submit(); cy.wait('@addTeam'); cy.contains('Z-Team'); @@ -102,22 +120,27 @@ describe('OKR team e2e tests', () => { // set viewport to < 768 to trigger mobile header cy.viewport(767, 1200); - cy.getByTestId('expansion-panel-header').click(); + cy.getByTestId('expansion-panel-header') + .click(); cy.contains('Weniger'); // reset viewport cy.viewport(Cypress.config('viewportWidth'), Cypress.config('viewportHeight')); cy.visit(`${teammanagementPage.getURL()}`); - cy.intercept('DELETE', '**/teams/*').as('deleteTeam'); + cy.intercept('DELETE', '**/teams/*') + .as('deleteTeam'); - teammanagementPage.deleteTeam('X-Team').submit(); + teammanagementPage.deleteTeam('X-Team') + .submit(); cy.wait('@deleteTeam'); - teammanagementPage.deleteTeam('Y-Team').submit(); + teammanagementPage.deleteTeam('Y-Team') + .submit(); cy.wait('@deleteTeam'); - teammanagementPage.deleteTeam('Z-Team').submit(); + teammanagementPage.deleteTeam('Z-Team') + .submit(); cy.wait('@deleteTeam'); }); }); diff --git a/frontend/cypress/e2e/teammanagement.cy.ts b/frontend/cypress/e2e/teammanagement.cy.ts index 5603e88143..19b154a3bf 100644 --- a/frontend/cypress/e2e/teammanagement.cy.ts +++ b/frontend/cypress/e2e/teammanagement.cy.ts @@ -16,20 +16,29 @@ describe('Team management tests', () => { }); it('should preserve team filter', () => { - CyOverviewPage.do().visitViaURL(); - FilterHelper.do().toggleOption('/BBT').toggleOption('Puzzle ITC'); + CyOverviewPage.do() + .visitViaURL(); + FilterHelper.do() + .toggleOption('/BBT') + .toggleOption('Puzzle ITC'); checkTeamsSelected(); - CyOverviewPage.do().visitTeammanagement(); + CyOverviewPage.do() + .visitTeammanagement(); checkTeamsSelected(); - TeammanagementPage.do().backToOverview(); + TeammanagementPage.do() + .backToOverview(); checkTeamsSelected(); - CyOverviewPage.do().visitTeammanagement(); - TeammanagementPage.do().visitOverview(); + CyOverviewPage.do() + .visitTeammanagement(); + TeammanagementPage.do() + .visitOverview(); checkTeamsSelected(); }); - function checkTeamsSelected() { - FilterHelper.do().optionShouldBeSelected('LoremIpsum').optionShouldBeSelected('/BBT'); + function checkTeamsSelected () { + FilterHelper.do() + .optionShouldBeSelected('LoremIpsum') + .optionShouldBeSelected('/BBT'); } }); @@ -38,29 +47,40 @@ describe('Team management tests', () => { before(() => { // login as bl to ensure this user exists in database cy.loginAsUser(users.bl); - cy.getByTestId('user-name').click(); - cy.getByTestId('logout').click(); + cy.getByTestId('user-name') + .click(); + cy.getByTestId('logout') + .click(); }); beforeEach(() => { cy.loginAsUser(users.gl); - teammanagementPage = TeammanagementPage.do().visitViaURL(); + teammanagementPage = TeammanagementPage.do() + .visitViaURL(); }); it('Create team', () => { - cy.intercept('POST', '**/teams').as('addTeam'); + cy.intercept('POST', '**/teams') + .as('addTeam'); - teammanagementPage.addTeam().fillName(teamName).submit(); + teammanagementPage.addTeam() + .fillName(teamName) + .submit(); cy.wait('@addTeam'); cy.contains(teamName); }); it('Try to remove last admin of team should not work', () => { - cy.intercept('PUT', '**/removeuser').as('removeUser'); + cy.intercept('PUT', '**/removeuser') + .as('removeUser'); - cy.get('app-team-list .mat-mdc-list-item').contains(teamName).click(); - cy.getByTestId('member-list-more').click(); - cy.getByTestId('remove-from-member-list').click(); + cy.get('app-team-list .mat-mdc-list-item') + .contains(teamName) + .click(); + cy.getByTestId('member-list-more') + .click(); + cy.getByTestId('remove-from-member-list') + .click(); ConfirmDialog.do() .checkTitle('Mitglied entfernen') @@ -69,15 +89,21 @@ describe('Team management tests', () => { cy.wait('@removeUser'); - cy.contains('Der letzte Administrator eines Teams kann nicht entfernt werden').should('exist'); + cy.contains('Der letzte Administrator eines Teams kann nicht entfernt werden') + .should('exist'); }); it('clicking cancel in dialog when removing user should not remove user', () => { - cy.intercept('PUT', '**/removeuser').as('removeUser'); + cy.intercept('PUT', '**/removeuser') + .as('removeUser'); - cy.get('app-team-list .mat-mdc-list-item').contains(teamName).click(); - cy.getByTestId('member-list-more').click(); - cy.getByTestId('remove-from-member-list').click(); + cy.get('app-team-list .mat-mdc-list-item') + .contains(teamName) + .click(); + cy.getByTestId('member-list-more') + .click(); + cy.getByTestId('remove-from-member-list') + .click(); // cancel dialog ConfirmDialog.do() @@ -85,34 +111,46 @@ describe('Team management tests', () => { .checkDescription(`Möchtest du Jaya Norris wirklich aus dem Team '${teamName}' entfernen?`) .cancel(); - cy.get('@removeUser.all').then((interceptions) => { - expect(interceptions).to.have.length(0); - }); + cy.get('@removeUser.all') + .then((interceptions) => { + expect(interceptions).to.have.length(0); + }); }); it('Edit team', () => { - cy.intercept('GET', '**/users').as('getUsers'); - cy.intercept('GET', '**/teams').as('getTeams'); + cy.intercept('GET', '**/users') + .as('getUsers'); + cy.intercept('GET', '**/teams') + .as('getTeams'); - cy.get('app-team-list .mat-mdc-list-item').contains('LoremIpsum').click(); + cy.get('app-team-list .mat-mdc-list-item') + .contains('LoremIpsum') + .click(); editTeamNameAndTest('IpsumLorem'); cy.visit('team-management'); - cy.wait(['@getUsers', '@getTeams']); + cy.wait(['@getUsers', + '@getTeams']); - cy.contains('LoremIpsum').should('not.exist'); - cy.contains('IpsumLorem').should('exist'); + cy.contains('LoremIpsum') + .should('not.exist'); + cy.contains('IpsumLorem') + .should('exist'); // set old team name again - cy.get('app-team-list .mat-mdc-list-item').contains('IpsumLorem').click(); + cy.get('app-team-list .mat-mdc-list-item') + .contains('IpsumLorem') + .click(); editTeamNameAndTest('LoremIpsum'); }); it('Delete team', () => { - //Click delete button and cancel - teammanagementPage.deleteTeam(teamName).cancel(); + // Click delete button and cancel + teammanagementPage.deleteTeam(teamName) + .cancel(); // try again and confirm dialog - teammanagementPage.deleteTeam(teamName).submit(); + teammanagementPage.deleteTeam(teamName) + .submit(); }); describe('Search', () => { @@ -128,7 +166,9 @@ describe('Team management tests', () => { }); it('Search team', () => { - teammanagementPage.elements.teamSearch().fill('we are').selectOption('we are cube.³'); + teammanagementPage.elements.teamSearch() + .fill('we are') + .selectOption('we are cube.³'); cy.contains('app-member-list h2', 'we are cube.³'); }); @@ -148,7 +188,8 @@ describe('Team management tests', () => { describe('invite members', () => { it('invite two members', () => { - teammanagementPage.elements.registerMember().click(); + teammanagementPage.elements.registerMember() + .click(); const firstNames = InviteMembersDialog.do() .enterUser('Claudia', 'Meier', 'claudia.meier@test.ch') .addAnotherUser() @@ -158,56 +199,86 @@ describe('Team management tests', () => { // test error messages fillOutNewUser('Robin', '', 'papierer'); - cy.getByTestId('invite').click(); + cy.getByTestId('invite') + .click(); cy.contains('Angabe benötigt'); cy.contains('E-Mail ungültig'); - cy.getByTestId('email-col_2').focus(); + cy.getByTestId('email-col_2') + .focus(); cy.realType('@puzzle.ch'); - cy.contains('E-Mail ungültig').should('not.exist'); + cy.contains('E-Mail ungültig') + .should('not.exist'); cy.contains('E-Mail existiert bereits'); cy.tabBackward(); cy.realType('Papirer'); - cy.contains('Angabe benötigt').should('not.exist'); + cy.contains('Angabe benötigt') + .should('not.exist'); // delete last entry cy.tabForward(); cy.tabForward(); cy.realPress('Enter'); - cy.contains('papiererr@puzzle.ch').should('not.exist'); + cy.contains('papiererr@puzzle.ch') + .should('not.exist'); // save - cy.getByTestId('invite').click(); + cy.getByTestId('invite') + .click(); cy.contains('Die Members wurden erfolgreich registriert'); firstNames.forEach((email) => cy.contains(email)); }); }); it('Navigate to Bobs profile and add him to BBT and LoremIpsum', () => { - cy.intercept('PUT', '**/updateaddteammembership/*').as('updateEsha'); + cy.intercept('PUT', '**/updateaddteammembership/*') + .as('updateEsha'); navigateToUser(nameEsha); // add to team bbt as admin - cy.get('app-member-detail').findByTestId('add-user').click(); - cy.get('app-member-detail').findByTestId('select-team-dropdown').click(); - cy.getByTestId('select-team-dropdown-option').contains('/BBT').click(); - cy.get('app-member-detail').findByTestId('select-team-role').click(); - cy.getByTestId('select-team-role-admin').click(); - cy.get('app-member-detail').findByTestId('add-user-to-team-save').click(); + cy.get('app-member-detail') + .findByTestId('add-user') + .click(); + cy.get('app-member-detail') + .findByTestId('select-team-dropdown') + .click(); + cy.getByTestId('select-team-dropdown-option') + .contains('/BBT') + .click(); + cy.get('app-member-detail') + .findByTestId('select-team-role') + .click(); + cy.getByTestId('select-team-role-admin') + .click(); + cy.get('app-member-detail') + .findByTestId('add-user-to-team-save') + .click(); cy.wait('@updateEsha'); // add to team loremipsum as member - cy.get('app-member-detail').findByTestId('add-user').click(); - cy.get('app-member-detail').findByTestId('select-team-dropdown').click(); + cy.get('app-member-detail') + .findByTestId('add-user') + .click(); + cy.get('app-member-detail') + .findByTestId('select-team-dropdown') + .click(); // team BBT should not be in list anymore - cy.getByTestId('select-team-dropdown-option').should('not.contain', '/BBT'); + cy.getByTestId('select-team-dropdown-option') + .should('not.contain', '/BBT'); - cy.getByTestId('select-team-dropdown-option').contains('LoremIpsum').click(); - cy.get('app-member-detail').findByTestId('select-team-role').click(); - cy.getByTestId('select-team-role-member').click(); - cy.get('app-member-detail').findByTestId('add-user-to-team-save').click(); + cy.getByTestId('select-team-dropdown-option') + .contains('LoremIpsum') + .click(); + cy.get('app-member-detail') + .findByTestId('select-team-role') + .click(); + cy.getByTestId('select-team-role-member') + .click(); + cy.get('app-member-detail') + .findByTestId('add-user-to-team-save') + .click(); cy.wait('@updateEsha'); // check table @@ -218,13 +289,16 @@ describe('Team management tests', () => { let foundEsha = false; cy.get('app-member-list tbody tr') .each(($row) => { - let usernameCell = $row.find('td:nth-child(2)'); - if (usernameCell.text().trim() === nameEsha) { + const usernameCell = $row.find('td:nth-child(2)'); + if (usernameCell.text() + .trim() === nameEsha) { foundEsha = true; - let roleCell = $row.find('td:nth-child(3)'); - let teamsCell = $row.find('td:nth-child(4)'); - expect(roleCell.text().trim()).to.equal('Team-Admin, Team-Member'); - expect(teamsCell.text().trim()).to.equal('/BBT, LoremIpsum'); + const roleCell = $row.find('td:nth-child(3)'); + const teamsCell = $row.find('td:nth-child(4)'); + expect(roleCell.text() + .trim()).to.equal('Team-Admin, Team-Member'); + expect(teamsCell.text() + .trim()).to.equal('/BBT, LoremIpsum'); return false; } return true; @@ -236,39 +310,59 @@ describe('Team management tests', () => { it('Navigate to user Esha and set as okr champion', () => { navigateToUser(nameEsha); - cy.getByTestId('edit-okr-champion-readonly').contains('OKR Champion:'); - cy.getByTestId('edit-okr-champion-readonly').contains('Nein'); - cy.getByTestId('edit-okr-champion-edit').click(); - cy.getByTestId('edit-okr-champion-readonly').should('not.exist'); - cy.getByTestId('edit-okr-champion-checkbox').click(); - cy.getByTestId('edit-okr-champion-readonly').contains('OKR Champion:'); - cy.getByTestId('edit-okr-champion-readonly').contains('Ja'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('OKR Champion:'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('Nein'); + cy.getByTestId('edit-okr-champion-edit') + .click(); + cy.getByTestId('edit-okr-champion-readonly') + .should('not.exist'); + cy.getByTestId('edit-okr-champion-checkbox') + .click(); + cy.getByTestId('edit-okr-champion-readonly') + .contains('OKR Champion:'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('Ja'); cy.contains('Der Member wurde erfolgreich aktualisiert.'); // reset okr champion to false - cy.getByTestId('edit-okr-champion-edit').click(); - cy.getByTestId('edit-okr-champion-checkbox').click(); - cy.getByTestId('edit-okr-champion-readonly').contains('OKR Champion:'); - cy.getByTestId('edit-okr-champion-readonly').contains('Nein'); + cy.getByTestId('edit-okr-champion-edit') + .click(); + cy.getByTestId('edit-okr-champion-checkbox') + .click(); + cy.getByTestId('edit-okr-champion-readonly') + .contains('OKR Champion:'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('Nein'); // test click outside of element - cy.getByTestId('edit-okr-champion-edit').click(); - cy.get('app-member-detail').find('h2').click(); + cy.getByTestId('edit-okr-champion-edit') + .click(); + cy.get('app-member-detail') + .find('h2') + .click(); // checkbox should hide again - cy.getByTestId('edit-okr-champion-readonly').contains('OKR Champion:'); - cy.getByTestId('edit-okr-champion-readonly').contains('Nein'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('OKR Champion:'); + cy.getByTestId('edit-okr-champion-readonly') + .contains('Nein'); }); }); describe('As BL', () => { beforeEach(() => { cy.loginAsUser(users.bl); - cy.getByTestId('team-management').click(); - cy.intercept('GET', '**/users/*').as('getEsha'); + cy.getByTestId('team-management') + .click(); + cy.intercept('GET', '**/users/*') + .as('getEsha'); }); it('should check if correct roles for BL are set', () => { - cy.get('td').contains(nameEsha).click(); + cy.get('td') + .contains(nameEsha) + .click(); cy.wait('@getEsha'); checkRolesForEsha(); @@ -276,70 +370,108 @@ describe('Team management tests', () => { }); it('should check if team loremIpsum cannot be edited', () => { - cy.get('app-team-management').contains('LoremIpsum').click(); - cy.getByTestId('teamMoreButton').should('not.exist'); - cy.getByTestId('editTeamButton').should('not.exist'); - cy.getByTestId('member-list-more').should('not.exist'); - cy.getByTestId('edit-role').should('not.exist'); + cy.get('app-team-management') + .contains('LoremIpsum') + .click(); + cy.getByTestId('teamMoreButton') + .should('not.exist'); + cy.getByTestId('editTeamButton') + .should('not.exist'); + cy.getByTestId('member-list-more') + .should('not.exist'); + cy.getByTestId('edit-role') + .should('not.exist'); }); it('should check if team /BBT can be edited and edit name', () => { - cy.get('app-team-management').contains('/BBT').click(); - cy.getByTestId('teamMoreButton').should('exist'); + cy.get('app-team-management') + .contains('/BBT') + .click(); + cy.getByTestId('teamMoreButton') + .should('exist'); editTeamNameAndTest('/BBT_edit'); // restore old name editTeamNameAndTest('/BBT'); }); it('should add members to team /BBT', () => { - cy.get('app-team-management').contains('/BBT').click(); - cy.getByTestId('add-team-member').click(); - cy.getByTestId('search-member-to-add').click(); + cy.get('app-team-management') + .contains('/BBT') + .click(); + cy.getByTestId('add-team-member') + .click(); + cy.getByTestId('search-member-to-add') + .click(); // esha should not exist (is already member of team) const matOption = '.cdk-overlay-container mat-option'; - cy.get(matOption).contains(nameEsha).should('not.exist'); + cy.get(matOption) + .contains(nameEsha) + .should('not.exist'); // add findus peterson - cy.getByTestId('search-member-to-add').as('member-search').click(); - cy.get('@member-search').type('Find'); - cy.contains(matOption, 'Findus Peterson').click(); + cy.getByTestId('search-member-to-add') + .as('member-search') + .click(); + cy.get('@member-search') + .type('Find'); + cy.contains(matOption, 'Findus Peterson') + .click(); // add robin papierer - cy.getByTestId('search-member-to-add').click(); - cy.get(matOption).contains('Findus Peterson').should('not.exist'); - cy.get(matOption).contains('Robin Papierer').click(); + cy.getByTestId('search-member-to-add') + .click(); + cy.get(matOption) + .contains('Findus Peterson') + .should('not.exist'); + cy.get(matOption) + .contains('Robin Papierer') + .click(); // check if Findus and Robin exists in table const allMemberTableTr = '#all-member-table tbody tr'; - cy.get(allMemberTableTr).eq(0).should('contain', 'Findus Peterson'); - cy.get(allMemberTableTr).eq(1).should('contain', 'Robin Papierer'); + cy.get(allMemberTableTr) + .eq(0) + .should('contain', 'Findus Peterson'); + cy.get(allMemberTableTr) + .eq(1) + .should('contain', 'Robin Papierer'); // remove robin papierer from list cy.get(allMemberTableTr + ' button') .eq(1) .click(); - cy.get(allMemberTableTr).eq(1).should('not.exist'); + cy.get(allMemberTableTr) + .eq(1) + .should('not.exist'); - cy.getByTestId('save').click(); + cy.getByTestId('save') + .click(); }); it('should change role of Findus Peterson to Team Admin', () => { - cy.get('app-team-management').contains('/BBT').click(); + cy.get('app-team-management') + .contains('/BBT') + .click(); cy.get('app-member-list tbody tr') .each(($row) => { - let usernameCell = $row.find('td:nth-child(2)'); - if (usernameCell.text().trim() !== 'Findus Peterson') { + const usernameCell = $row.find('td:nth-child(2)'); + if (usernameCell.text() + .trim() !== 'Findus Peterson') { return; } - $row.find(`[data-testId='edit-role']`).click(); + $row.find(`[data-testId='edit-role']`) + .click(); cy.wait(500); // wait for dialog to open }) .then(() => { - cy.getByTestId('select-team-role').click(); - cy.getByTestId('select-team-role-admin').click(); - cy.getByTestId('select-team-role').should('not.exist'); + cy.getByTestId('select-team-role') + .click(); + cy.getByTestId('select-team-role-admin') + .click(); + cy.getByTestId('select-team-role') + .should('not.exist'); cy.contains('Das Team wurde erfolgreich aktualisiert.'); }); }); @@ -347,28 +479,38 @@ describe('Team management tests', () => { it('should test that Findus Peterson cannot be added to further teams', () => { navigateToUser('Findus Peterson'); - // current user BL (Esha Harris) is only admin in /BBT team. - // That's why 'add-team-member' should be disabled - cy.get('app-member-detail').getByTestId('add-user').should('be.disabled'); + /* + * current user BL (Esha Harris) is only admin in /BBT team. + * That's why 'add-team-member' should be disabled + */ + cy.get('app-member-detail') + .getByTestId('add-user') + .should('be.disabled'); }); it('should remove BBT membership of findus', () => { navigateToUser('Findus Peterson'); - cy.getByTestId('delete-team-member').click(); + cy.getByTestId('delete-team-member') + .click(); ConfirmDialog.do() .checkTitle('Mitglied entfernen') .checkDescription(`Möchtest du Findus Peterson wirklich aus dem Team '/BBT' entfernen?`) .submit(); - cy.get('app-member-detail').contains('/BBT').should('not.exist'); + cy.get('app-member-detail') + .contains('/BBT') + .should('not.exist'); }); it('should remove added memberships from esha', () => { - cy.intercept('PUT', '**/removeuser').as('removeUser'); + cy.intercept('PUT', '**/removeuser') + .as('removeUser'); navigateToUser(nameEsha); - cy.getByTestId('delete-team-member').eq(0).click(); + cy.getByTestId('delete-team-member') + .eq(0) + .click(); ConfirmDialog.do() .checkTitle('Mitglied entfernen') @@ -377,51 +519,74 @@ describe('Team management tests', () => { cy.wait('@removeUser'); - cy.getByTestId('delete-team-member').eq(0).click(); + cy.getByTestId('delete-team-member') + .eq(0) + .click(); ConfirmDialog.do() .checkTitle('Mitglied entfernen') .checkDescription(`Möchtest du ${nameEsha} wirklich aus dem Team 'LoremIpsum' entfernen?`) .submit(); - cy.get('app-member-detail').should('not.contain', '/BBT').and('not.contain', 'LoremIpsum'); + cy.get('app-member-detail') + .should('not.contain', '/BBT') + .and('not.contain', 'LoremIpsum'); }); it('Navigate to user Esha and check if okr champion is not editable', () => { navigateToUser(nameEsha); - cy.getByTestId('edit-okr-champion-readonly').should('exist'); - cy.getByTestId('edit-okr-champion-edit').should('not.exist'); + cy.getByTestId('edit-okr-champion-readonly') + .should('exist'); + cy.getByTestId('edit-okr-champion-edit') + .should('not.exist'); }); }); }); -function closeOverlay() { - cy.get('.cdk-overlay-backdrop').click(-50, -50, { force: true }); +function closeOverlay () { + cy.get('.cdk-overlay-backdrop') + .click(-50, -50, { force: true }); } -function checkRolesForEsha() { - cy.get('app-member-detail tbody tr').eq(0).should('contain', '/BBT').and('contain', 'Team-Admin'); - cy.get('app-member-detail tbody tr').eq(1).should('contain', 'LoremIpsum').and('contain', 'Team-Member'); +function checkRolesForEsha () { + cy.get('app-member-detail tbody tr') + .eq(0) + .should('contain', '/BBT') + .and('contain', 'Team-Admin'); + cy.get('app-member-detail tbody tr') + .eq(1) + .should('contain', 'LoremIpsum') + .and('contain', 'Team-Member'); } -function editTeamNameAndTest(teamName: string) { - cy.intercept('PUT', '**/teams/*').as('saveTeam'); - cy.getByTestId('editTeamButton').click(); - cy.getByTestId('add-team-name').as('team-name').click(); - cy.get('@team-name').clear(); - cy.get('@team-name').type(teamName); - cy.getByTestId('save').click(); +function editTeamNameAndTest (teamName: string) { + cy.intercept('PUT', '**/teams/*') + .as('saveTeam'); + cy.getByTestId('editTeamButton') + .click(); + cy.getByTestId('add-team-name') + .as('team-name') + .click(); + cy.get('@team-name') + .clear(); + cy.get('@team-name') + .type(teamName); + cy.getByTestId('save') + .click(); cy.wait('@saveTeam'); cy.contains(teamName); } -function navigateToUser(userName: string) { - cy.intercept('GET', '**/users/*').as('getUser'); - cy.get('td').contains(userName).click(); +function navigateToUser (userName: string) { + cy.intercept('GET', '**/users/*') + .as('getUser'); + cy.get('td') + .contains(userName) + .click(); cy.wait('@getUser'); } -function fillOutNewUser(firstname: string, lastname: string, email: string) { +function fillOutNewUser (firstname: string, lastname: string, email: string) { cy.realType(firstname); cy.tabForward(); cy.realType(lastname); diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index ac14a493d4..d69d44e2d6 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -12,24 +12,26 @@ Cypress.Commands.add('getByTestId', (testId: string, text?: string): Chainable = const selector = `[data-testId=${testId}]`; if (text) { - return cy.get(selector).contains(text); + return cy.get(selector) + .contains(text); } else { return cy.get(selector); } }); -Cypress.Commands.add( - 'findByTestId', +Cypress.Commands.add('findByTestId', { prevSubject: true }, (subject: JQuery, testId: string, text?: string): Chainable => { const selector = `[data-testId=${testId}]`; if (text) { - return cy.wrap(subject).find(selector).contains(text); + return cy.wrap(subject) + .find(selector) + .contains(text); } else { - return cy.wrap(subject).find(selector); + return cy.wrap(subject) + .find(selector); } - }, -); + }); Cypress.Commands.add('pressUntilContains', (text: string, key: keyof typeof keyCodeDefinitions) => { pressUntilContains(text, key); @@ -40,7 +42,8 @@ Cypress.Commands.add('tabForward', () => { }); Cypress.Commands.add('tabBackward', () => { - cy.realPress(['Shift', 'Tab']); + cy.realPress(['Shift', + 'Tab']); }); Cypress.Commands.add('tabForwardUntil', (selector: string, limit?: number) => { @@ -59,35 +62,45 @@ Cypress.Commands.add('validateScoring', (isOverview: boolean, percentage: number validateScoring(isOverview, percentage); }); -function loginWithCredentials(username: string, password: string) { +function loginWithCredentials (username: string, password: string) { cy.visit('/'); - cy.intercept('GET', '**/users/current').as('getCurrentUser'); - cy.origin(Cypress.env('login_url'), { args: { username, password } }, ({ username, password }) => { - cy.get('input[name="username"]').type(username); - cy.get('input[name="password"]').type(password); - cy.get('button[type="submit"]').click(); + cy.intercept('GET', '**/users/current') + .as('getCurrentUser'); + cy.origin(Cypress.env('login_url'), { args: { username, + password } }, ({ username, password }) => { + cy.get('input[name="username"]') + .type(username); + cy.get('input[name="password"]') + .type(password); + cy.get('button[type="submit"]') + .click(); cy.wait('@getCurrentUser', { responseTimeout: 10000 }); }); - cy.url().then((url) => { - const currentUrl = new URL(url); - const baseURL = new URL(Cypress.config().baseUrl!); - expect(currentUrl.pathname).equal(baseURL.pathname); - }); + cy.url() + .then((url) => { + const currentUrl = new URL(url); + const baseURL = new URL(Cypress.config().baseUrl!); + expect(currentUrl.pathname) + .equal(baseURL.pathname); + }); } -const overviewIsLoaded = () => cy.get('mat-chip').should('have.length.at.least', 2); +const overviewIsLoaded = () => cy.get('mat-chip') + .should('have.length.at.least', 2); -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +/* + * -- This is a parent command -- + * Cypress.Commands.add("login", (email, password) => { ... }) + * + * + * -- This is a child command -- + * Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) + * + * + * -- This is a dual command -- + * Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) + * + * + * -- This will overwrite an existing command -- + * Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + */ diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts index 31baa58435..3628b50adf 100644 --- a/frontend/cypress/support/e2e.ts +++ b/frontend/cypress/support/e2e.ts @@ -1,24 +1,26 @@ -// *********************************************************** -// This example support/e2e.ts is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** +/* + * *********************************************************** + * This example support/e2e.ts is processed and + * loaded automatically before your test files. + * + * This is a great place to put global configuration and + * behavior that modifies Cypress. + * + * You can change the location of this file or turn off + * automatically serving support files with the + * 'supportFile' configuration option. + * + * You can read more here: + * https://on.cypress.io/configuration + * *********************************************************** + */ import './commands'; import 'cypress-real-events'; import { onlyOn } from '@cypress/skip-test'; Cypress.Keyboard.defaults({ - keystrokeDelay: 0, + keystrokeDelay: 0 }); beforeEach(() => { diff --git a/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts b/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts index f1966bc9ce..c9fe560037 100644 --- a/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts +++ b/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts @@ -3,42 +3,45 @@ import { PageObjectMapperBase } from './pageObjectMapperBase'; export default class AngularSearchBox extends PageObjectMapperBase { selector: string; - constructor(selector: string) { + constructor (selector: string) { super(); this.selector = selector; this.validatePage(); } - fill(value: string) { - const input = cy.get('input').first(); + fill (value: string) { + const input = cy.get('input') + .first(); input.clear(); input.type(value); return this; } - shouldHaveOption(option: string) { + shouldHaveOption (option: string) { cy.contains('.mat-mdc-autocomplete-panel mat-option', option); return this; } - shouldHaveLabel(label: string) { + shouldHaveLabel (label: string) { cy.contains('.mat-mdc-autocomplete-panel .mat-mdc-optgroup-label', label); return this; } - selectOption(option: string) { - cy.contains('.mat-mdc-autocomplete-panel mat-option', option).click(); + selectOption (option: string) { + cy.contains('.mat-mdc-autocomplete-panel mat-option', option) + .click(); } - getPage() { + getPage () { return cy.get(this.selector); } - static from(selector: string): AngularSearchBox { + static from (selector: string): AngularSearchBox { return new this(selector); } - validatePage(): void { - this.getPage().should('exist'); + validatePage (): void { + this.getPage() + .should('exist'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts index 55ef5aab4f..4aec8b5a1c 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts @@ -2,41 +2,47 @@ import Dialog from './dialog'; import Chainable = Cypress.Chainable; export default class CheckInDialog extends Dialog { - fillCheckInCommentary(commentary: string) { + fillCheckInCommentary (commentary: string) { this.fillInputByTestId('changeInfo', commentary); return this; } - fillMetricCheckInValue(value: string) { + fillMetricCheckInValue (value: string) { this.fillInputByTestId('check-in-metric-value', value); return this; } - selectOrdinalCheckInZone(zone: 'fail' | 'commit' | 'target' | 'stretch') { + selectOrdinalCheckInZone (zone: 'fail' | 'commit' | 'target' | 'stretch') { switch (zone) { case 'fail': - cy.getByTestId('fail-radio').click(); + cy.getByTestId('fail-radio') + .click(); break; case 'commit': - cy.getByTestId('commit-radio').click(); + cy.getByTestId('commit-radio') + .click(); break; case 'target': - cy.getByTestId('target-radio').click(); + cy.getByTestId('target-radio') + .click(); break; case 'stretch': - cy.getByTestId('stretch-radio').click(); + cy.getByTestId('stretch-radio') + .click(); break; } return this; } - fillCheckInInitiatives(value: string) { + fillCheckInInitiatives (value: string) { this.fillInputByTestId('initiatives', value); return this; } - setCheckInConfidence(confidence: number) { - cy.getByTestId('confidence-slider').find('input').focus(); + setCheckInConfidence (confidence: number) { + cy.getByTestId('confidence-slider') + .find('input') + .focus(); for (let i = 0; i < 10; i++) { cy.realPress('ArrowLeft'); } @@ -46,7 +52,7 @@ export default class CheckInDialog extends Dialog { return this; } - checkForDialogTextMetric() { + checkForDialogTextMetric () { cy.contains('Very important keyresult'); cy.contains('Check-in erfassen'); cy.contains('Key Result'); @@ -56,7 +62,7 @@ export default class CheckInDialog extends Dialog { return this; } - checkForDialogTextOrdinal() { + checkForDialogTextOrdinal () { cy.contains('A new ordinal keyresult for our company'); cy.contains('Check-in erfassen'); cy.contains('Key Result'); @@ -73,11 +79,12 @@ export default class CheckInDialog extends Dialog { return this; } - override submit() { - cy.getByTestId('submit-check-in').click(); + override submit () { + cy.getByTestId('submit-check-in') + .click(); } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-check-in-form'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts index d984f8b7a5..f97cc858aa 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts @@ -3,25 +3,31 @@ import CheckInDialog from './checkInDialog'; import Chainable = Cypress.Chainable; export default class CheckInHistoryDialog extends Dialog { - override submit() { + override submit () { throw new Error('This dialog doesnt have a submit button'); } - override cancel() { - cy.getByTestId('closeButton').click(); + override cancel () { + cy.getByTestId('closeButton') + .click(); } - editLatestCheckIn() { - cy.getByTestId('edit-check-in').first().click(); + editLatestCheckIn () { + cy.getByTestId('edit-check-in') + .first() + .click(); return new CheckInDialog(); } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-check-in-history-dialog'); } - checkForAttribute(title: string, value: string) { - cy.get('mat-dialog-container').contains(value).parent().should('contain', title); + checkForAttribute (title: string, value: string) { + cy.get('mat-dialog-container') + .contains(value) + .parent() + .should('contain', title); return this; } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/confirmDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/confirmDialog.ts index 688d4fb0eb..7c6eb3d945 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/confirmDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/confirmDialog.ts @@ -2,25 +2,31 @@ import Dialog from './dialog'; import Chainable = Cypress.Chainable; export default class ConfirmDialog extends Dialog { - checkTitle(title: string) { - this.getPage().contains(title).should('exist'); + checkTitle (title: string) { + this.getPage() + .contains(title) + .should('exist'); return this; } - checkDescription(title: string) { - this.getPage().contains(title).should('exist'); + checkDescription (title: string) { + this.getPage() + .contains(title) + .should('exist'); return this; } - override submit() { - cy.getByTestId('confirm-yes').click(); + override submit () { + cy.getByTestId('confirm-yes') + .click(); } - override cancel() { - cy.getByTestId('confirm-no').click(); + override cancel () { + cy.getByTestId('confirm-no') + .click(); } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-confirm-dialog'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts index e2d90e61a4..44cbe75cd6 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts @@ -2,36 +2,40 @@ import { PageObjectMapperBase } from '../pageObjectMapperBase'; import Chainable = Cypress.Chainable; export default abstract class Dialog extends PageObjectMapperBase { - constructor() { + constructor () { super(); this.validatePage(); } - override validatePage() { - this.getPage().should('exist'); + override validatePage () { + this.getPage() + .should('exist'); } - submit() { - cy.getByTestId('save').click(); + submit () { + cy.getByTestId('save') + .click(); } - cancel() { - cy.getByTestId('cancel').click(); + cancel () { + cy.getByTestId('cancel') + .click(); } - close() { - cy.getByTestId('close-dialog').click(); + close () { + cy.getByTestId('close-dialog') + .click(); } - protected fillInputByTestId(testId: string, value: string) { + protected fillInputByTestId (testId: string, value: string) { const elem = cy.getByTestId(testId); this.fillInput(elem, value); } - protected fillInput(elem: Cypress.Chainable>, value: string) { + protected fillInput (elem: Cypress.Chainable>, value: string) { elem.clear(); elem.type(value); } - abstract getPage(): Chainable; + abstract getPage (): Chainable; } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts index f1c493bb32..929e614bc9 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts @@ -5,38 +5,46 @@ import Chainable = Cypress.Chainable; export default class InviteMembersDialog extends Dialog { private readonly firstnames: string[] = []; - override validatePage() { + override validatePage () { super.validatePage(); - this.getPage().contains('Members registrieren').should('exist'); + this.getPage() + .contains('Members registrieren') + .should('exist'); } - enterUser(firstName: string, lastName: string, email: string) { + enterUser (firstName: string, lastName: string, email: string) { firstName = uniqueSuffix(firstName); email = uniqueSuffix(email); this.firstnames.push(firstName); - const firstNameInput = cy.get('[formcontrolname="firstname"]').last(); - const lastNameInput = cy.get('[formcontrolname="lastname"]').last(); - const emailInput = cy.get('[formcontrolname="email"]').last(); + const firstNameInput = cy.get('[formcontrolname="firstname"]') + .last(); + const lastNameInput = cy.get('[formcontrolname="lastname"]') + .last(); + const emailInput = cy.get('[formcontrolname="email"]') + .last(); this.fillInput(firstNameInput, firstName); this.fillInput(lastNameInput, lastName); this.fillInput(emailInput, email); return this; } - addAnotherUser() { - cy.contains('Weiterer Member hinzufügen').click(); + addAnotherUser () { + cy.contains('Weiterer Member hinzufügen') + .click(); return this; } - getFirstNames() { + + getFirstNames () { return this.firstnames; } - override submit() { - cy.getByTestId('invite').click(); + override submit () { + cy.getByTestId('invite') + .click(); return this.firstnames; } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-invite-user-dialog'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts index 3225f4859b..7f6da4a841 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts @@ -4,40 +4,45 @@ import ConfirmDialog from './confirmDialog'; import Chainable = Cypress.Chainable; export default class KeyResultDialog extends Dialog { - fillKeyResultTitle(title: string) { + fillKeyResultTitle (title: string) { this.fillInputByTestId('titleInput', title); return this; } - fillKeyResultDescription(description: string) { + fillKeyResultDescription (description: string) { this.fillInputByTestId('descriptionInput', description); return this; } - withMetricValues(unit: Unit, baseline: string, stretchGoal: string) { - cy.getByTestId('metricTab').click(); - cy.getByTestId('unit').select(unit); + withMetricValues (unit: Unit, baseline: string, stretchGoal: string) { + cy.getByTestId('metricTab') + .click(); + cy.getByTestId('unit') + .select(unit); this.fillInputByTestId('baseline', baseline); this.fillInputByTestId('stretchGoal', stretchGoal); return this; } - withOrdinalValues(commitZone: string, targetZone: string, stretchGoal: string) { - cy.getByTestId('ordinalTab').click(); + withOrdinalValues (commitZone: string, targetZone: string, stretchGoal: string) { + cy.getByTestId('ordinalTab') + .click(); this.fillInputByTestId('commitZone', commitZone); this.fillInputByTestId('targetZone', targetZone); this.fillInputByTestId('stretchZone', stretchGoal); return this; } - fillOwner(owner: string) { + fillOwner (owner: string) { this.fillInputByTestId('ownerInput', owner); - cy.realPress('ArrowDown').realPress('Enter'); + cy.realPress('ArrowDown') + .realPress('Enter'); return this; } - addActionPlanElement(action: string) { - cy.getByTestId('add-action-plan-line').click(); + addActionPlanElement (action: string) { + cy.getByTestId('add-action-plan-line') + .click(); cy.getByTestId('actionInput') .filter((k, el) => { return (el as HTMLInputElement).value.trim() === ''; @@ -47,12 +52,13 @@ export default class KeyResultDialog extends Dialog { return this; } - deleteKeyResult() { - cy.getByTestId('delete-keyResult').click(); + deleteKeyResult () { + cy.getByTestId('delete-keyResult') + .click(); return new ConfirmDialog(); } - checkForDialogTextMetric() { + checkForDialogTextMetric () { cy.contains('Einheit'); cy.contains('Baseline'); cy.contains('Stretch Goal'); @@ -60,7 +66,7 @@ export default class KeyResultDialog extends Dialog { return this; } - checkForDialogTextOrdinal() { + checkForDialogTextOrdinal () { cy.contains('Commit Zone'); cy.contains('Target Zone'); cy.contains('Stretch Goal'); @@ -68,7 +74,7 @@ export default class KeyResultDialog extends Dialog { return this; } - private checkForDialogText() { + private checkForDialogText () { cy.contains('Key Result erfassen'); cy.contains('Titel'); cy.contains('Metrisch'); @@ -82,15 +88,17 @@ export default class KeyResultDialog extends Dialog { cy.contains('Abbrechen'); } - override submit() { - cy.getByTestId('submit').click(); + override submit () { + cy.getByTestId('submit') + .click(); } - saveAndNew() { - cy.getByTestId('saveAndNew').click(); + saveAndNew () { + cy.getByTestId('saveAndNew') + .click(); } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-key-result-form'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts index d6de2ed5ea..5a7accd349 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts @@ -3,43 +3,51 @@ import ConfirmDialog from './confirmDialog'; import Chainable = Cypress.Chainable; export default class ObjectiveDialog extends Dialog { - fillObjectiveTitle(title: string) { + fillObjectiveTitle (title: string) { this.fillInputByTestId('title', title); return this; } - fillObjectiveDescription(description: string) { + fillObjectiveDescription (description: string) { this.fillInputByTestId('description', description); return this; } - selectQuarter(quarter: string) { - cy.get('select#quarter').select(quarter); + selectQuarter (quarter: string) { + cy.get('select#quarter') + .select(quarter); return this; } - toggleCreateKeyResults() { - cy.getByTestId('keyResult-checkbox').find("[type='checkbox']").check(); + toggleCreateKeyResults () { + cy.getByTestId('keyResult-checkbox') + .find("[type='checkbox']") + .check(); return this; } - deleteObjective() { - cy.getByTestId('delete').click(); + deleteObjective () { + cy.getByTestId('delete') + .click(); return new ConfirmDialog(); } - submitDraftObjective() { - cy.getByTestId('save-draft').click(); + submitDraftObjective () { + cy.getByTestId('save-draft') + .click(); } - excludeKeyResults(keyResults: string[]) { + excludeKeyResults (keyResults: string[]) { keyResults.forEach((keyResult) => { - cy.get('label').contains(keyResult.slice(0, 30)).click(); + cy.get('label') + .contains(keyResult.slice(0, 30)) + .click(); }); return this; } - getPage(): Chainable { - return cy.get('app-objective-form').should('exist'); + getPage (): Chainable { + return cy.get('app-objective-form') + .should('exist'); } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts index c486595d2b..b48d4c0e9b 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts @@ -2,21 +2,23 @@ import Dialog from './dialog'; import Chainable = Cypress.Chainable; export default class TeamDialog extends Dialog { - override validatePage() { + override validatePage () { super.validatePage(); - this.getPage().contains('Team erfassen'); + this.getPage() + .contains('Team erfassen'); } - fillName(name: string) { + fillName (name: string) { this.fillInputByTestId('add-team-name', name); return this; } - override submit() { - cy.getByTestId('save').click(); + override submit () { + cy.getByTestId('save') + .click(); } - getPage(): Chainable { + getPage (): Chainable { return cy.get('app-add-edit-team-dialog'); } } diff --git a/frontend/cypress/support/helper/dom-helper/filterHelper.ts b/frontend/cypress/support/helper/dom-helper/filterHelper.ts index aaeae2c944..229b43d626 100644 --- a/frontend/cypress/support/helper/dom-helper/filterHelper.ts +++ b/frontend/cypress/support/helper/dom-helper/filterHelper.ts @@ -1,18 +1,23 @@ import { PageObjectMapperBase } from './pageObjectMapperBase'; export default class FilterHelper extends PageObjectMapperBase { - validatePage(): void {} + validatePage (): void {} - optionShouldBeSelected(text: string, onOverview = true): this { + optionShouldBeSelected (text: string, onOverview = true): this { if (onOverview) { - cy.contains('h1:visible', text).should('have.length', 1); + cy.contains('h1:visible', text) + .should('have.length', 1); } - this.getOption(text).should('have.length', 1).should('have.css', 'background-color').and('eq', 'rgb(30, 90, 150)'); + this.getOption(text) + .should('have.length', 1) + .should('have.css', 'background-color') + .and('eq', 'rgb(30, 90, 150)'); return this; } - optionShouldNotBeSelected(text: string): this { - cy.contains('h1:visible', text).should('not.exist'); + optionShouldNotBeSelected (text: string): this { + cy.contains('h1:visible', text) + .should('not.exist'); this.getOption(text) .should('have.length', 1) .should('have.css', 'background-color') @@ -20,12 +25,13 @@ export default class FilterHelper extends PageObjectMapperBase { return this; } - toggleOption(text: string): this { - this.getOption(text).click(); + toggleOption (text: string): this { + this.getOption(text) + .click(); return this; } - private getOption(text: string): Cypress.Chainable> { + private getOption (text: string): Cypress.Chainable> { return cy.contains('mat-chip:visible', text); } } diff --git a/frontend/cypress/support/helper/dom-helper/pageObjectMapperBase.ts b/frontend/cypress/support/helper/dom-helper/pageObjectMapperBase.ts index 9b98d8fe97..38464e51c2 100644 --- a/frontend/cypress/support/helper/dom-helper/pageObjectMapperBase.ts +++ b/frontend/cypress/support/helper/dom-helper/pageObjectMapperBase.ts @@ -1,25 +1,30 @@ export abstract class PageObjectMapperBase { - abstract validatePage(): void; + abstract validatePage (): void; static do(this: new () => T): T { return new this(); } - run(arg: any) { + run (arg: any) { return this; } - checkForToaster(content: any, type: 'success' | 'error') { - cy.get('#toast-container').find(`.toast-${type}`).contains(content).should('exist'); + checkForToaster (content: any, type: 'success' | 'error') { + cy.get('#toast-container') + .find(`.toast-${type}`) + .contains(content) + .should('exist'); return this; } - validateUrlParameter(key: string, value: any[]) { - cy.url().then((url) => { - const params = new URL(url).searchParams; - const queryParamValues = params.get(key)?.split(','); - expect(queryParamValues).to.have.length(value.length); - value.forEach((v) => expect(queryParamValues).to.include(v)); - }); + validateUrlParameter (key: string, value: any[]) { + cy.url() + .then((url) => { + const params = new URL(url).searchParams; + const queryParamValues = params.get(key) + ?.split(','); + expect(queryParamValues).to.have.length(value.length); + value.forEach((v) => expect(queryParamValues).to.include(v)); + }); } } diff --git a/frontend/cypress/support/helper/dom-helper/pages/keyResultDetailPage.ts b/frontend/cypress/support/helper/dom-helper/pages/keyResultDetailPage.ts index 4a06400230..9ddea57a8c 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/keyResultDetailPage.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/keyResultDetailPage.ts @@ -10,48 +10,57 @@ export default class KeyResultDetailPage extends Page { closeDrawer: () => cy.getByTestId('close-drawer'), addCheckin: () => cy.getByTestId('add-check-in'), showAllCheckins: () => cy.getByTestId('show-all-checkins'), - editKeyResult: () => cy.getByTestId('edit-keyResult'), + editKeyResult: () => cy.getByTestId('edit-keyResult') }; - override validatePage() { - this.elements.addCheckin().contains('Check-in erfassen'); - this.elements.editKeyResult().contains('Key Result bearbeiten'); + override validatePage () { + this.elements.addCheckin() + .contains('Check-in erfassen'); + this.elements.editKeyResult() + .contains('Key Result bearbeiten'); } - override visit(keyResultName: string): this { + override visit (keyResultName: string): this { this.doVisit(keyResultName); return this.afterVisit(); } - protected doVisit(keyResultName: string): this { - CyOverviewPage.do().getKeyResultByName(keyResultName).click(); + protected doVisit (keyResultName: string): this { + CyOverviewPage.do() + .getKeyResultByName(keyResultName) + .click(); return this; } - createCheckIn() { - this.elements.addCheckin().click(); + createCheckIn () { + this.elements.addCheckin() + .click(); return new CheckInDialog(); } - editKeyResult() { - this.elements.editKeyResult().click(); + editKeyResult () { + this.elements.editKeyResult() + .click(); return new KeyResultDialog(); } - showAllCheckins() { - this.elements.showAllCheckins().click(); + showAllCheckins () { + this.elements.showAllCheckins() + .click(); return new CheckInHistoryDialog(); } - close(): void { - this.elements.closeDrawer().click({ force: true }); + close (): void { + this.elements.closeDrawer() + .click({ force: true }); } - visitOverview(): void { - this.elements.logo().click(); + visitOverview (): void { + this.elements.logo() + .click(); } - getURL(): string { + getURL (): string { return '/details/keyresult'; } } diff --git a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts index 98e6251bfa..9a256ba7cc 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts @@ -7,81 +7,111 @@ import { filterByKeyResultName, getKeyResults } from '../../keyResultHelper'; export default class CyOverviewPage extends Page { elements = { logo: () => cy.getByTestId('logo'), - teammanagement: () => cy.getByTestId('team-management'), + teammanagement: () => cy.getByTestId('team-management') }; - visitGJForTests() { + visitGJForTests () { this.visitQuarter(998); } - visitBacklogQuarter() { + visitBacklogQuarter () { this.visitQuarter(999); } - visitCurrentQuarter() { + visitCurrentQuarter () { this.visitQuarter(2); } - visitNextQuarter() { + visitNextQuarter () { this.visitQuarter(3); } - private visitQuarter(quarter: number) { + private visitQuarter (quarter: number) { cy.visit(`/?quarter=${quarter}`); } - addObjective(teamName?: string) { + addObjective (teamName?: string) { if (teamName) { - this.getTeamByName(teamName).find('.add-objective').first().click(); + this.getTeamByName(teamName) + .find('.add-objective') + .first() + .click(); return new ObjectiveDialog(); } - cy.getByTestId('add-objective').first().click(); + cy.getByTestId('add-objective') + .first() + .click(); return new ObjectiveDialog(); } - addKeyResult(teamName?: string, objectiveName?: string) { + addKeyResult (teamName?: string, objectiveName?: string) { if (teamName && objectiveName) { - this.getObjectiveByTeamAndName(teamName, objectiveName).findByTestId('add-keyResult').first().click(); + this.getObjectiveByTeamAndName(teamName, objectiveName) + .findByTestId('add-keyResult') + .first() + .click(); } else if (teamName) { - this.getTeamByName(teamName).findByTestId('add-keyResult').first().click(); + this.getTeamByName(teamName) + .findByTestId('add-keyResult') + .first() + .click(); } else if (objectiveName) { - this.getObjectiveByName(objectiveName).findByTestId('add-keyResult').first().click(); + this.getObjectiveByName(objectiveName) + .findByTestId('add-keyResult') + .first() + .click(); } else { - cy.getByTestId('add-keyResult').first().click(); + cy.getByTestId('add-keyResult') + .first() + .click(); } return new KeyResultDialog(); } - addOngoingKeyResult() { - this.getObjectiveByState('ongoing').findByTestId('add-keyResult').first().click(); + addOngoingKeyResult () { + this.getObjectiveByState('ongoing') + .findByTestId('add-keyResult') + .first() + .click(); return new KeyResultDialog(); } - getTeamByName(teamName: string) { - return cy.contains('.team-title', teamName).parentsUntil('#overview').last(); + getTeamByName (teamName: string) { + return cy.contains('.team-title', teamName) + .parentsUntil('#overview') + .last(); } - getFirstObjective() { - return cy.get('.objective').first(); + getFirstObjective () { + return cy.get('.objective') + .first(); } - getObjectiveByNameAndState(objectiveName: string, state: string) { - this.getObjectivesByNameAndState(objectiveName, state).last().as('objective').scrollIntoView(); + getObjectiveByNameAndState (objectiveName: string, state: string) { + this.getObjectivesByNameAndState(objectiveName, state) + .last() + .as('objective') + .scrollIntoView(); return cy.get('@objective'); } - getObjectivesByNameAndState(objectiveName: string, state: string) { - return getObjectiveColumns().filter(filterByObjectiveName(objectiveName)).filter(filterByObjectiveState(state)); + getObjectivesByNameAndState (objectiveName: string, state: string) { + return getObjectiveColumns() + .filter(filterByObjectiveName(objectiveName)) + .filter(filterByObjectiveState(state)); } - getObjectiveByName(objectiveName: string) { - this.getObjectivesByName(objectiveName).last().as('objective').scrollIntoView(); + getObjectiveByName (objectiveName: string) { + this.getObjectivesByName(objectiveName) + .last() + .as('objective') + .scrollIntoView(); return cy.get('@objective'); } - getObjectiveByTeamAndName(teamName: string, objectiveName: string) { + getObjectiveByTeamAndName (teamName: string, objectiveName: string) { this.getTeamByName(teamName) .find('.objective') .filter(filterByObjectiveName(objectiveName)) @@ -92,62 +122,84 @@ export default class CyOverviewPage extends Page { return cy.get('@team'); } - getKeyResultOfObjective(objectiveName: string, keyResultName: string) { - return this.getAllKeyResultsOfObjective(objectiveName).filter(filterByKeyResultName(keyResultName)); + getKeyResultOfObjective (objectiveName: string, keyResultName: string) { + return this.getAllKeyResultsOfObjective(objectiveName) + .filter(filterByKeyResultName(keyResultName)); } - getAllKeyResultsOfObjective(objectiveName: string) { - return this.getObjectiveByName(objectiveName).find('.key-result'); + getAllKeyResultsOfObjective (objectiveName: string) { + return this.getObjectiveByName(objectiveName) + .find('.key-result'); } - getObjectivesByName(objectiveName: string) { - return getObjectiveColumns().filter(filterByObjectiveName(objectiveName)); + getObjectivesByName (objectiveName: string) { + return getObjectiveColumns() + .filter(filterByObjectiveName(objectiveName)); } - getObjectiveByState(state: string) { - this.getObjectivesByState(state).first().as('objective').scrollIntoView(); + getObjectiveByState (state: string) { + this.getObjectivesByState(state) + .first() + .as('objective') + .scrollIntoView(); return cy.get('@objective'); } - getObjectivesByState(state: string) { - return getObjectiveColumns().filter(filterByObjectiveState(state)); + getObjectivesByState (state: string) { + return getObjectiveColumns() + .filter(filterByObjectiveState(state)); } - getKeyResultByName(keyResultName: string) { - this.getKeyResultsByName(keyResultName).last().as('keyResult').scrollIntoView(); + getKeyResultByName (keyResultName: string) { + this.getKeyResultsByName(keyResultName) + .last() + .as('keyResult') + .scrollIntoView(); return cy.get('@keyResult'); } - getKeyResultsByName(keyresultName: string) { - return getKeyResults().filter(filterByKeyResultName(keyresultName)); + getKeyResultsByName (keyresultName: string) { + return getKeyResults() + .filter(filterByKeyResultName(keyresultName)); } - selectFromThreeDotMenu(optionName: string) { - cy.contains(optionName).should('exist'); - cy.get('.objective-three-dot-menu').contains(optionName).as('option').scrollIntoView(); + selectFromThreeDotMenu (optionName: string) { + cy.contains(optionName) + .should('exist'); + cy.get('.objective-three-dot-menu') + .contains(optionName) + .as('option') + .scrollIntoView(); - cy.get('@option').should('have.class', 'objective-menu-option').click(); + cy.get('@option') + .should('have.class', 'objective-menu-option') + .click(); } - duplicateObjective(objectiveName: string) { - cy.intercept('GET', '**/objectives/*/keyResults').as('keyResults'); - this.getObjectiveByName(objectiveName).findByTestId('three-dot-menu').click(); + duplicateObjective (objectiveName: string) { + cy.intercept('GET', '**/objectives/*/keyResults') + .as('keyResults'); + this.getObjectiveByName(objectiveName) + .findByTestId('three-dot-menu') + .click(); this.selectFromThreeDotMenu('Objective duplizieren'); cy.wait('@keyResults'); return new ObjectiveDialog(); } - visitTeammanagement(): void { - this.elements.teammanagement().click(); + visitTeammanagement (): void { + this.elements.teammanagement() + .click(); } - getURL(): string { + getURL (): string { return ''; } - validatePage(): void {} + validatePage (): void {} - protected doVisit(): void { - this.elements.logo().click(); + protected doVisit (): void { + this.elements.logo() + .click(); } } diff --git a/frontend/cypress/support/helper/dom-helper/pages/page.ts b/frontend/cypress/support/helper/dom-helper/pages/page.ts index 5cc2c63ec8..12db5e8c7c 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/page.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/page.ts @@ -1,23 +1,24 @@ import { PageObjectMapperBase } from '../pageObjectMapperBase'; export abstract class Page extends PageObjectMapperBase { - visit(arg?: any): this { + visit (arg?: any): this { this.doVisit(); return this.afterVisit(); } - visitViaURL(): this { + visitViaURL (): this { cy.visit(this.getURL()); return this.afterVisit(); } - protected abstract doVisit(arg?: any): void; + protected abstract doVisit (arg?: any): void; - afterVisit(): this { - cy.url().should('include', this.getURL()); + afterVisit (): this { + cy.url() + .should('include', this.getURL()); this.validatePage(); return this; } - abstract getURL(): string; + abstract getURL (): string; } diff --git a/frontend/cypress/support/helper/dom-helper/pages/teammanagementPage.ts b/frontend/cypress/support/helper/dom-helper/pages/teammanagementPage.ts index b2af165529..a150e13007 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/teammanagementPage.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/teammanagementPage.ts @@ -12,50 +12,63 @@ export default class TeammanagementPage extends Page { memberHeader: () => cy.get('#member-header'), registerMember: () => cy.getByTestId('invite-member'), addTeam: () => cy.getByTestId('add-team'), - teamSearch: () => AngularSearchBox.from('app-team-management-banner [data-testId="teamManagementSearch"]'), + teamSearch: () => AngularSearchBox.from('app-team-management-banner [data-testId="teamManagementSearch"]') }; - override validatePage() { - this.elements.teammanagement().contains('Teamverwaltung'); - this.elements.backToOverview().contains('Zurück zur OKR Übersicht'); - this.elements.addTeam().contains('Team erfassen'); - this.elements.teamMenu().contains('Alle Teams'); - this.elements.memberHeader().contains('Alle Teams'); - this.elements.memberHeader().contains('Members:'); - this.elements.registerMember().contains('Member registrieren'); + override validatePage () { + this.elements.teammanagement() + .contains('Teamverwaltung'); + this.elements.backToOverview() + .contains('Zurück zur OKR Übersicht'); + this.elements.addTeam() + .contains('Team erfassen'); + this.elements.teamMenu() + .contains('Alle Teams'); + this.elements.memberHeader() + .contains('Alle Teams'); + this.elements.memberHeader() + .contains('Members:'); + this.elements.registerMember() + .contains('Member registrieren'); } - protected doVisit(): this { - this.elements.logo().click(); + protected doVisit (): this { + this.elements.logo() + .click(); return this; } - backToOverview(): void { - this.elements.backToOverview().click(); + backToOverview (): void { + this.elements.backToOverview() + .click(); } - visitOverview(): void { - this.elements.logo().click(); + visitOverview (): void { + this.elements.logo() + .click(); } - addTeam(): TeamDialog { - this.elements.addTeam().click(); + addTeam (): TeamDialog { + this.elements.addTeam() + .click(); return new TeamDialog(); } - deleteTeam(teamName: string) { - cy.get('app-team-list .mat-mdc-list-item').contains(teamName).click(); - cy.getByTestId('teamMoreButton').click(); - cy.getByTestId('teamDeleteButton').click(); + deleteTeam (teamName: string) { + cy.get('app-team-list .mat-mdc-list-item') + .contains(teamName) + .click(); + cy.getByTestId('teamMoreButton') + .click(); + cy.getByTestId('teamDeleteButton') + .click(); return ConfirmDialog.do() .checkTitle('Team löschen') - .checkDescription( - `Möchtest du das Team '${teamName}' wirklich löschen? Zugehörige Objectives werden dadurch in allen Quartalen ebenfalls gelöscht!`, - ); + .checkDescription(`Möchtest du das Team '${teamName}' wirklich löschen? Zugehörige Objectives werden dadurch in allen Quartalen ebenfalls gelöscht!`); } - getURL(): string { + getURL (): string { return 'team-management'; } } diff --git a/frontend/cypress/support/helper/keyResultHelper.ts b/frontend/cypress/support/helper/keyResultHelper.ts index 9f86509330..f6107a3757 100644 --- a/frontend/cypress/support/helper/keyResultHelper.ts +++ b/frontend/cypress/support/helper/keyResultHelper.ts @@ -1,11 +1,12 @@ -export function filterByKeyResultName(keyResultName: string) { +export function filterByKeyResultName (keyResultName: string) { return (index: number, element: HTMLElement) => isKeyResultName(element, keyResultName); } const isKeyResultName = (element: HTMLElement, keyResultName: string) => { - return Cypress.$(element).find(`:contains("${keyResultName}")`).length > 0; + return Cypress.$(element) + .find(`:contains("${keyResultName}")`).length > 0; }; -export function getKeyResults() { +export function getKeyResults () { return cy.get('.key-result'); } diff --git a/frontend/cypress/support/helper/objectiveHelper.ts b/frontend/cypress/support/helper/objectiveHelper.ts index 54d633dbb3..f28627c2f3 100644 --- a/frontend/cypress/support/helper/objectiveHelper.ts +++ b/frontend/cypress/support/helper/objectiveHelper.ts @@ -1,19 +1,21 @@ -export function filterByObjectiveName(objectiveName: string) { +export function filterByObjectiveName (objectiveName: string) { return (index: number, element: HTMLElement) => isObjectiveName(element, objectiveName); } -export function filterByObjectiveState(icon: string) { +export function filterByObjectiveState (icon: string) { return (index: number, element: HTMLElement) => isObjectiveState(element, icon); } const isObjectiveState = (element: HTMLElement, icon: string) => { - return Cypress.$(element).find(`[src='assets/icons/${icon}-icon.svg']`).length > 0; + return Cypress.$(element) + .find(`[src='assets/icons/${icon}-icon.svg']`).length > 0; }; const isObjectiveName = (element: HTMLElement, objectiveName: string) => { - return Cypress.$(element).find(`:contains("${objectiveName}")`).length > 0; + return Cypress.$(element) + .find(`:contains("${objectiveName}")`).length > 0; }; -export function getObjectiveColumns() { +export function getObjectiveColumns () { return cy.get('.objective'); } diff --git a/frontend/cypress/support/helper/scoringSupport.ts b/frontend/cypress/support/helper/scoringSupport.ts index e6a92fdd13..cccb630f53 100644 --- a/frontend/cypress/support/helper/scoringSupport.ts +++ b/frontend/cypress/support/helper/scoringSupport.ts @@ -6,12 +6,14 @@ interface ScoringValue { targetPercent: number; } -export function validateScoring(isOverview: boolean, percentage: number) { - let rgbCode = colorFromPercentage(percentage); - let scoringValue = scoringValueFromPercentage(percentage); +export function validateScoring (isOverview: boolean, percentage: number) { + const rgbCode = colorFromPercentage(percentage); + const scoringValue = scoringValueFromPercentage(percentage); if (percentage >= 100) { - cy.getZone('stretch', isOverview).should('have.attr', 'src').should('include', 'star-filled-icon.svg'); + cy.getZone('stretch', isOverview) + .should('have.attr', 'src') + .should('include', 'star-filled-icon.svg'); } validateScoringWidth('fail', scoringValue.failPercent, isOverview); @@ -24,14 +26,14 @@ export function validateScoring(isOverview: boolean, percentage: number) { validateScoringColor('target', rgbCode, isOverview); } -export function getPercentageMetric(baseline: number, stretchGoal: number, value: number) { +export function getPercentageMetric (baseline: number, stretchGoal: number, value: number) { if (isLastCheckInNegative(baseline, stretchGoal, value)) { return -1; } return (Math.abs(value - baseline) / Math.abs(stretchGoal - baseline)) * 100; } -export function getPercentageOrdinal(zone: string) { +export function getPercentageOrdinal (zone: string) { if (zone == 'stretch') return 101; if (zone == 'target') return 99.99; if (zone == 'commit') return 70; @@ -39,7 +41,7 @@ export function getPercentageOrdinal(zone: string) { return 0; } -function validateScoringWidth(zone: string, percent: number, isOverview: boolean) { +function validateScoringWidth (zone: string, percent: number, isOverview: boolean) { cy.getZone(zone, isOverview) .parent() .invoke('width') @@ -51,10 +53,14 @@ function validateScoringWidth(zone: string, percent: number, isOverview: boolean }); } -function validateScoringColor(zone: string, rgbCode: string, isOverview: boolean) { - cy.getZone(zone, isOverview).invoke('css', 'background-color').should('equal', rgbCode); +function validateScoringColor (zone: string, rgbCode: string, isOverview: boolean) { + cy.getZone(zone, isOverview) + .invoke('css', 'background-color') + .should('equal', rgbCode); if (rgbCode == 'rgba(0, 0, 0, 0)') { - cy.getByTestId('star-scoring').invoke('css', 'background-image').should('contain', 'scoring-stars'); + cy.getByTestId('star-scoring') + .invoke('css', 'background-image') + .should('contain', 'scoring-stars'); checkVisibilityOfScoringComponent(isOverview, 'block', 'star-scoring'); checkVisibilityOfScoringComponent(isOverview, 'none', 'normal-scoring'); } else { @@ -63,30 +69,38 @@ function validateScoringColor(zone: string, rgbCode: string, isOverview: boolean } } -function checkVisibilityOfScoringComponent(isOverview: boolean, displayProperty: string, componentTestId: string) { +function checkVisibilityOfScoringComponent (isOverview: boolean, displayProperty: string, componentTestId: string) { (isOverview ? cy.focused() : cy.getByTestId('side-panel')) .findByTestId(componentTestId) .invoke('css', 'display') .should('equal', displayProperty); } -function colorFromPercentage(percentage: number) { +function colorFromPercentage (percentage: number) { if (percentage >= 100) return 'rgba(0, 0, 0, 0)'; if (percentage > 70) return 'rgb(30, 138, 41)'; if (percentage > 30) return 'rgb(255, 214, 0)'; return 'rgb(186, 56, 56)'; } -function scoringValueFromPercentage(percentage: number): ScoringValue { +function scoringValueFromPercentage (percentage: number): ScoringValue { if (percentage >= 100) { - return { failPercent: 0, commitPercent: 0, targetPercent: 0 }; + return { failPercent: 0, + commitPercent: 0, + targetPercent: 0 }; } else if (percentage > 70) { - let targetPercent = (percentage - 70) * (100 / 30); - return { failPercent: 100, commitPercent: 100, targetPercent: targetPercent }; + const targetPercent = (percentage - 70) * (100 / 30); + return { failPercent: 100, + commitPercent: 100, + targetPercent: targetPercent }; } else if (percentage > 30) { - let commitPercent = (percentage - 30) * (100 / 40); - return { failPercent: 100, commitPercent: commitPercent, targetPercent: -1 }; + const commitPercent = (percentage - 30) * (100 / 40); + return { failPercent: 100, + commitPercent: commitPercent, + targetPercent: -1 }; } - let failPercent = percentage * (100 / 30); - return { failPercent: failPercent, commitPercent: -1, targetPercent: -1 }; + const failPercent = percentage * (100 / 30); + return { failPercent: failPercent, + commitPercent: -1, + targetPercent: -1 }; } diff --git a/frontend/cypress/support/helper/utils.ts b/frontend/cypress/support/helper/utils.ts index 5b573b0b77..e89b1392cc 100644 --- a/frontend/cypress/support/helper/utils.ts +++ b/frontend/cypress/support/helper/utils.ts @@ -5,34 +5,42 @@ export const uniqueSuffix = (value: string): string => { return `${value}-${uuidv4()}`; }; -export function pressUntilContains(text: string, key: keyof typeof keyCodeDefinitions) { +export function pressUntilContains (text: string, key: keyof typeof keyCodeDefinitions) { const condition = (element: HTMLElement) => element.innerText.includes(text); pressUntil(key, condition); } -export function doUntilSelector(selector: string, tab: () => void, limit: number = 100, count: number = 0) { - const condition = (element: HTMLElement) => Cypress.$(element).is(selector); - doUntil(condition, tab, limit, count); +export function doUntilSelector ( + selector: string, tab: () => void, limit = 100, count = 0 +) { + const condition = (element: HTMLElement) => Cypress.$(element) + .is(selector); + doUntil( + condition, tab, limit, count + ); } -function pressUntil(key: keyof typeof keyCodeDefinitions, condition: (elem: HTMLElement) => boolean) { +function pressUntil (key: keyof typeof keyCodeDefinitions, condition: (elem: HTMLElement) => boolean) { doUntil(condition, () => cy.realPress(key)); } -function doUntil( +function doUntil ( condition: (element: HTMLElement) => boolean, tab: () => void, - limit: number = 100, - count: number = 0, + limit = 100, + count = 0 ) { if (count >= limit) return; - cy.focused().then((element) => { - if (condition(element.get(0))) { - return; - } else { - tab(); - doUntil(condition, tab, limit, count + 1); - } - }); + cy.focused() + .then((element) => { + if (condition(element.get(0))) { + return; + } else { + tab(); + doUntil( + condition, tab, limit, count + 1 + ); + } + }); } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index a45b15ce2b..d73c397344 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -24,39 +24,39 @@ const routes: Routes = [ path: '', component: OverviewComponent, resolve: { - user: currentUserResolver, + user: currentUserResolver }, - children: [ - { - path: 'details', - component: SidepanelComponent, - children: [ - { - path: 'objective/:id', - component: ObjectiveDetailComponent, - }, - { - path: 'keyresult/:id', - component: KeyresultDetailComponent, - }, - ], + children: [{ + path: 'details', + component: SidepanelComponent, + children: [{ + path: 'objective/:id', + component: ObjectiveDetailComponent }, - ], - canActivate: [authGuard], + { + path: 'keyresult/:id', + component: KeyresultDetailComponent + }] + }], + canActivate: [authGuard] }, { path: 'team-management', loadChildren: () => import('./team-management/team-management.module').then((m) => m.TeamManagementModule), canActivate: [authGuard], - resolve: { user: currentUserResolver }, + resolve: { user: currentUserResolver } }, - { path: 'objective', redirectTo: 'details/objective' }, - { path: 'keyresult', redirectTo: 'details/keyresult' }, - { path: '**', redirectTo: '', pathMatch: 'full' }, + { path: 'objective', + redirectTo: 'details/objective' }, + { path: 'keyresult', + redirectTo: 'details/keyresult' }, + { path: '**', + redirectTo: '', + pathMatch: 'full' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], - exports: [RouterModule], + exports: [RouterModule] }) export class AppRoutingModule {} diff --git a/frontend/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts index 05f5175a80..0d10e92017 100644 --- a/frontend/src/app/app.component.spec.ts +++ b/frontend/src/app/app.component.spec.ts @@ -18,31 +18,31 @@ import { ObjectiveDetailComponent } from './components/objective-detail/objectiv import { CommonModule } from '@angular/common'; const oauthServiceMock = { - configure(environment: AuthConfig): void {}, - initCodeFlow(): void {}, - setupAutomaticSilentRefresh(): void {}, - hasValidAccessToken(): boolean { + configure (environment: AuthConfig): void {}, + initCodeFlow (): void {}, + setupAutomaticSilentRefresh (): void {}, + hasValidAccessToken (): boolean { return true; }, - loadDiscoveryDocumentAndTryLogin(): Promise { + loadDiscoveryDocumentAndTryLogin (): Promise { this.initCodeFlow(); return Promise.resolve(); - }, + } }; const routerMock = { root: jest.fn(), // Router - events: of(new NavigationEnd(0, 'http://localhost:4200/objective/2', 'http://localhost:4200/objective/2')), + events: of(new NavigationEnd(0, 'http://localhost:4200/objective/2', 'http://localhost:4200/objective/2')) }; -const routes: Routes = [ - { - path: '', - component: OverviewComponent, - children: [{ path: 'objective/:id', component: ObjectiveDetailComponent, pathMatch: 'full' }], - }, -]; +const routes: Routes = [{ + path: '', + component: OverviewComponent, + children: [{ path: 'objective/:id', + component: ObjectiveDetailComponent, + pathMatch: 'full' }] +}]; describe('AppComponent', () => { let component: AppComponent; @@ -55,16 +55,18 @@ describe('AppComponent', () => { RouterTestingModule.withRoutes(routes), HttpClientTestingModule, TranslateTestingModule.withTranslations({ - de: de, + de: de }), OAuthModule.forRoot(), MatSidenavModule, NoopAnimationsModule, - CommonModule, + CommonModule ], - providers: [{ provide: OAuthService, useValue: oauthServiceMock }], - declarations: [AppComponent, OverviewComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [{ provide: OAuthService, + useValue: oauthServiceMock }], + declarations: [AppComponent, + OverviewComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] }) .compileComponents() .then(() => { @@ -78,6 +80,7 @@ describe('AppComponent', () => { }); test('should create the app', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); }); diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 854233b3af..b389755dcb 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -6,21 +6,16 @@ import { DomSanitizer } from '@angular/platform-browser'; selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.OnPush }) export class AppComponent { readonly PATH_PREFIX = '../assets/icons/'; - constructor( - private matIconRegistry: MatIconRegistry, - private domSanitizer: DomSanitizer, - ) { - this.matIconRegistry.addSvgIcon( - 'pz-search', - this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'search-icon.svg'), - ); - this.matIconRegistry.addSvgIcon( - 'pz-menu-icon', - this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'three-dot-menu-icon.svg'), - ); + + constructor (private matIconRegistry: MatIconRegistry, + private domSanitizer: DomSanitizer) { + this.matIconRegistry.addSvgIcon('pz-search', + this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'search-icon.svg')); + this.matIconRegistry.addSvgIcon('pz-menu-icon', + this.domSanitizer.bypassSecurityTrustResourceUrl(this.PATH_PREFIX + 'three-dot-menu-icon.svg')); } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index cd2e70a8d3..15918314ce 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -7,7 +7,7 @@ import { HttpBackend, HttpClient, provideHttpClient, - withInterceptorsFromDi, + withInterceptorsFromDi } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -70,35 +70,35 @@ import { A11yModule } from '@angular/cdk/a11y'; import { CustomizationService } from './services/customization.service'; import { MetricCheckInDirective } from './components/checkin/check-in-form-metric/metric-check-in-directive'; -function initOauthFactory(configService: ConfigService, oauthService: OAuthService) { +function initOauthFactory (configService: ConfigService, oauthService: OAuthService) { return async () => { const config = await firstValueFrom(configService.config$); oauthService.configure({ ...environment.oauth, issuer: config.issuer, - clientId: config.clientId, + clientId: config.clientId }); }; } -export function createTranslateLoader(http: HttpBackend) { +export function createTranslateLoader (http: HttpBackend) { return new TranslateHttpLoader(new HttpClient(http), './assets/i18n/', '.json'); } -export function storageFactory(): OAuthStorage { +export function storageFactory (): OAuthStorage { return localStorage; } export const MY_FORMATS = { parse: { - dateInput: 'LL', + dateInput: 'LL' }, display: { dateInput: 'DD.MM.YYYY', monthYearLabel: 'DD.MM.YYYY', dateA11yLabel: 'DD.MM.YYYY', - monthYearA11yLabel: 'DD.MM.YYYY', - }, + monthYearA11yLabel: 'DD.MM.YYYY' + } }; @NgModule({ @@ -124,7 +124,7 @@ export const MY_FORMATS = { CheckInFormMetricComponent, CheckInFormOrdinalComponent, CheckInFormComponent, - MetricCheckInDirective, + MetricCheckInDirective ], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], @@ -153,8 +153,8 @@ export const MY_FORMATS = { loader: { provide: TranslateLoader, useFactory: createTranslateLoader, - deps: [HttpBackend], - }, + deps: [HttpBackend] + } }), OAuthModule.forRoot(), MatRadioModule, @@ -170,32 +170,40 @@ export const MY_FORMATS = { CdkDrag, A11yModule, CdkDragHandle, - SharedModule, + SharedModule ], providers: [ { provide: DateAdapter, useClass: MomentDateAdapter, - deps: [MAT_DATE_LOCALE], + deps: [MAT_DATE_LOCALE] }, - { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS }, - { provide: HTTP_INTERCEPTORS, useClass: OauthInterceptor, multi: true }, - { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, - { provide: OAuthStorage, useFactory: storageFactory }, + { provide: MAT_DATE_FORMATS, + useValue: MY_FORMATS }, + { provide: HTTP_INTERCEPTORS, + useClass: OauthInterceptor, + multi: true }, + { provide: HTTP_INTERCEPTORS, + useClass: ErrorInterceptor, + multi: true }, + { provide: OAuthStorage, + useFactory: storageFactory }, { provide: APP_INITIALIZER, useFactory: initOauthFactory, - deps: [ConfigService, OAuthService, Injector], - multi: true, + deps: [ConfigService, + OAuthService, + Injector], + multi: true }, { provide: Router, - useClass: CustomRouter, + useClass: CustomRouter }, TranslateService, - provideHttpClient(withInterceptorsFromDi()), - ], + provideHttpClient(withInterceptorsFromDi()) + ] }) export class AppModule { - constructor(private readonly customizationService: CustomizationService) {} + constructor (private readonly customizationService: CustomizationService) {} } diff --git a/frontend/src/app/components/action-plan/action-plan.component.html b/frontend/src/app/components/action-plan/action-plan.component.html index 68388cea32..364623195b 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.html +++ b/frontend/src/app/components/action-plan/action-plan.component.html @@ -9,7 +9,11 @@ (cdkDropListDropped)="drop($event)" id="actionlist" > -
+
{ @@ -24,19 +24,24 @@ describe('ActionPlanComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ declarations: [ActionPlanComponent], - imports: [HttpClientTestingModule, CdkDropList, CdkDrag, TranslateModule.forRoot()], + imports: [ + HttpClientTestingModule, + CdkDropList, + CdkDrag, + TranslateModule.forRoot() + ], providers: [ TranslateService, DialogService, { provide: ActionService, - useValue: actionServiceMock, + useValue: actionServiceMock }, { provide: MatDialogRef, - useValue: matDialogRef, - }, - ], + useValue: matDialogRef + } + ] }); fixture = TestBed.createComponent(ActionPlanComponent); component = fixture.componentInstance; @@ -45,11 +50,13 @@ describe('ActionPlanComponent', () => { }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it('should remove item from actionplan array', () => { - component.control = new BehaviorSubject([action1, action2]); + component.control = new BehaviorSubject([action1, + action2]); actionServiceMock.deleteAction.mockReturnValue(of(null)); jest .spyOn(component.dialogService, 'openConfirmDialog') @@ -57,10 +64,14 @@ describe('ActionPlanComponent', () => { component.removeAction(0); - expect(actionServiceMock.deleteAction).toHaveBeenCalledWith(action1.id); - expect(component.control.getValue()).toHaveLength(1); - expect(component.control.getValue()![0]).toBe(action2); - expect(component.control.getValue()![0].priority).toBe(0); + expect(actionServiceMock.deleteAction) + .toHaveBeenCalledWith(action1.id); + expect(component.control.getValue()) + .toHaveLength(1); + expect(component.control.getValue()![0]) + .toBe(action2); + expect(component.control.getValue()![0].priority) + .toBe(0); }); it('should remove item from actionplan without opening dialog when action has no text and id', () => { @@ -69,35 +80,47 @@ describe('ActionPlanComponent', () => { component.removeAction(0); - expect(component.control.getValue()!).toHaveLength(0); - expect(dialogSpy).toHaveBeenCalledTimes(0); + expect(component.control.getValue()!) + .toHaveLength(0); + expect(dialogSpy) + .toHaveBeenCalledTimes(0); expect(actionServiceMock.deleteAction).not.toHaveBeenCalled(); }); it('should decrease index of active item when index is the same as the one of the removed item', () => { jest.spyOn(component.dialogService, 'open'); - component.control = new BehaviorSubject([action2, action3, action1]); + component.control = new BehaviorSubject([action2, + action3, + action1]); component.activeItem = 2; component.removeAction(2); - expect(component.activeItem).toBe(1); + expect(component.activeItem) + .toBe(1); }); it('should add new action with empty text into array', () => { component.control = new BehaviorSubject([]); component.keyResultId = addedAction.keyResultId; component.addNewAction(); - expect(component.control.getValue()).toHaveLength(1); - expect(component.control.getValue()![0]).toStrictEqual(addedAction); + expect(component.control.getValue()) + .toHaveLength(1); + expect(component.control.getValue()![0]) + .toStrictEqual(addedAction); }); it('should decrease index of active item', () => { const keyEvent = new KeyboardEvent('keydown', { key: 'ArrowUp' }); - component.control.next([action1, action2, action3]); + component.control.next([action1, + action2, + action3]); component.handleKeyDown(keyEvent, 2); expect((component.activeItem = 1)); - expect(component.control.getValue()!.toString()).toBe([action1, action3, action2].toString()); + expect(component.control.getValue()!.toString()) + .toBe([action1, + action3, + action2].toString()); expect(component.control.getValue()![0].priority == 0); expect(component.control.getValue()![1].priority == 1); expect(component.control.getValue()![2].priority == 2); @@ -105,11 +128,22 @@ describe('ActionPlanComponent', () => { it('should increase index of active item', () => { const keyEvent = new KeyboardEvent('keydown', { key: 'ArrowDown' }); - component.control.next([action1, action2, action3, action1]); + component.control.next([ + action1, + action2, + action3, + action1 + ]); component.handleKeyDown(keyEvent, 2); expect((component.activeItem = 3)); - expect(component.control.getValue()!.toString()).toBe([action1, action3, action1, action3].toString()); + expect(component.control.getValue()!.toString()) + .toBe([ + action1, + action3, + action1, + action3 + ].toString()); expect(component.control.getValue()![0].priority == 0); expect(component.control.getValue()![1].priority == 1); expect(component.control.getValue()![2].priority == 2); @@ -118,15 +152,21 @@ describe('ActionPlanComponent', () => { it('should increase active item index', () => { component.activeItem = 0; - component.control.next([action1, action2, action3]); + component.control.next([action1, + action2, + action3]); component.increaseActiveItemWithTab(); - expect(component.activeItem).toBe(1); + expect(component.activeItem) + .toBe(1); }); it('should decrease active item index', () => { component.activeItem = 2; - component.control.next([action1, action2, action3]); + component.control.next([action1, + action2, + action3]); component.decreaseActiveItemWithShiftTab(); - expect(component.activeItem).toBe(1); + expect(component.activeItem) + .toBe(1); }); }); diff --git a/frontend/src/app/components/action-plan/action-plan.component.ts b/frontend/src/app/components/action-plan/action-plan.component.ts index e08f5da787..2b7e8b9aa2 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.ts +++ b/frontend/src/app/components/action-plan/action-plan.component.ts @@ -9,22 +9,22 @@ import { DialogService } from '../../services/dialog.service'; @Component({ selector: 'app-action-plan', templateUrl: './action-plan.component.html', - styleUrls: ['./action-plan.component.scss'], + styleUrls: ['./action-plan.component.scss'] }) export class ActionPlanComponent { @Input() control: BehaviorSubject = new BehaviorSubject([]); + @Input() keyResultId!: number | null; - activeItem: number = 0; + + activeItem = 0; @ViewChildren('listItem') listItems!: QueryList; - constructor( - private actionService: ActionService, - public dialogService: DialogService, - ) {} + constructor (private actionService: ActionService, + public dialogService: DialogService) {} - handleKeyDown(event: Event, currentIndex: number) { + handleKeyDown (event: Event, currentIndex: number) { let newIndex = currentIndex; if ((event as KeyboardEvent).key === 'ArrowDown') { if (newIndex + 1 <= this.control.getValue()!.length - 1) { @@ -39,51 +39,53 @@ export class ActionPlanComponent { this.listItems.get(this.activeItem)?.nativeElement.focus(); } - changeItemPosition(newIndex: number, currentIndex: number) { + changeItemPosition (newIndex: number, currentIndex: number) { this.activeItem = newIndex; - let currentActionPlan: Action[] = this.control.getValue()!; + const currentActionPlan: Action[] = this.control.getValue()!; this.updateActionTexts(currentActionPlan); moveItemInArray(currentActionPlan, currentIndex, newIndex); currentActionPlan.forEach((action: Action, index: number) => (action.priority = index)); this.control.next(currentActionPlan); } - updateActionTexts(currentActionPlan: Action[]) { - let texts = Array.from(this.listItems).map((input: any) => input.nativeElement.value); + updateActionTexts (currentActionPlan: Action[]) { + const texts = Array.from(this.listItems) + .map((input: any) => input.nativeElement.value); currentActionPlan.forEach((action: Action, index: number) => (action.action = texts[index])); } - increaseActiveItemWithTab() { + increaseActiveItemWithTab () { if (this.activeItem <= this.control.value!.length - 2) { this.activeItem++; } } - decreaseActiveItemWithShiftTab() { + decreaseActiveItemWithShiftTab () { if (this.activeItem > 0) { this.activeItem--; } } - drop(event: CdkDragDrop) { - let value: string = (( - event.container.element.nativeElement.children[event.previousIndex].children[1] - )).value; + drop (event: CdkDragDrop) { + const value: string = (event.container.element.nativeElement.children[event.previousIndex].children[1] as HTMLInputElement).value; const actions: Action[] = this.control.getValue()!; if (actions[event.previousIndex].action == '' && value != '') { - actions[event.previousIndex] = { ...actions[event.previousIndex], action: value }; + actions[event.previousIndex] = { ...actions[event.previousIndex], + action: value }; this.control.next(actions); } if (event.previousContainer === event.container) { moveItemInArray(event.container.data!, event.previousIndex, event.currentIndex); } else { - transferArrayItem(event.previousContainer.data!, event.container.data!, event.previousIndex, event.currentIndex); + transferArrayItem( + event.previousContainer.data!, event.container.data!, event.previousIndex, event.currentIndex + ); } this.adjustPriorities(); this.activeItem = event.currentIndex; } - adjustPriorities() { + adjustPriorities () { const actions: Action[] = this.control.getValue()!; actions.forEach(function (action: Action, index: number) { action.priority = index; @@ -91,8 +93,8 @@ export class ActionPlanComponent { this.control.next(actions); } - removeAction(index: number) { - let actions: Action[] = this.control.getValue()!; + removeAction (index: number) { + const actions: Action[] = this.control.getValue()!; if (this.activeItem == index && this.activeItem > 0) { this.activeItem--; } @@ -103,7 +105,8 @@ export class ActionPlanComponent { .subscribe((result) => { if (result) { if (actions[index].id) { - this.actionService.deleteAction(actions[index].id!).subscribe(); + this.actionService.deleteAction(actions[index].id!) + .subscribe(); } actions.splice(index, 1); this.control.next(actions); @@ -117,16 +120,20 @@ export class ActionPlanComponent { } } - addNewAction() { + addNewAction () { const actions: Action[] = this.control.getValue()!; - actions.push({ action: '', priority: actions.length, keyResultId: this.keyResultId } as Action); + actions.push({ action: '', + priority: actions.length, + keyResultId: this.keyResultId } as Action); this.control.next(actions); this.activeItem = actions.length - 1; } - /* By default angular material adds a new entry inside the actionplan when the user presses enter - * to disable this behaviour we need this method which prevents the event from firing */ - preventAddingNewItems(event: Event) { + /* + * By default angular material adds a new entry inside the actionplan when the user presses enter + * to disable this behaviour we need this method which prevents the event from firing + */ + preventAddingNewItems (event: Event) { event.preventDefault(); } diff --git a/frontend/src/app/components/application-banner/application-banner.component.html b/frontend/src/app/components/application-banner/application-banner.component.html index db7340e387..62f600d334 100644 --- a/frontend/src/app/components/application-banner/application-banner.component.html +++ b/frontend/src/app/components/application-banner/application-banner.component.html @@ -22,15 +22,12 @@ id="header-accordion" class="content-center" > - +
{{ (quarterLabel$ | async) || quarterLabel$.getValue() - }} + }} Filter
diff --git a/frontend/src/app/components/application-banner/application-banner.component.scss b/frontend/src/app/components/application-banner/application-banner.component.scss index 9efe9b265f..6de85a2771 100644 --- a/frontend/src/app/components/application-banner/application-banner.component.scss +++ b/frontend/src/app/components/application-banner/application-banner.component.scss @@ -1,4 +1,4 @@ -@import "../style/variables"; +@import '../style/variables'; .header-content { padding-left: 1.5rem; diff --git a/frontend/src/app/components/application-banner/application-banner.component.spec.ts b/frontend/src/app/components/application-banner/application-banner.component.spec.ts index 86e542750c..1bde07e55d 100644 --- a/frontend/src/app/components/application-banner/application-banner.component.spec.ts +++ b/frontend/src/app/components/application-banner/application-banner.component.spec.ts @@ -21,24 +21,26 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; class ResizeObserverMock { - observe() {} - unobserve() {} - disconnect() {} + observe () {} + + unobserve () {} + + disconnect () {} } const refreshDataServiceMock = { okrBannerHeightSubject: { - next: jest.fn(), + next: jest.fn() }, - reloadOverviewSubject: of(null), + reloadOverviewSubject: of(null) }; const routeMock = { - queryParams: of(null), + queryParams: of(null) }; describe('ApplicationBannerComponent', () => { - //@ts-ignore + // @ts-ignore global.ResizeObserver = ResizeObserverMock; let component: ApplicationBannerComponent; let fixture: ComponentFixture; @@ -55,19 +57,19 @@ describe('ApplicationBannerComponent', () => { NoopAnimationsModule, FormsModule, ReactiveFormsModule, - MatInputModule, + MatInputModule ], declarations: [ ApplicationBannerComponent, TeamFilterComponent, QuarterFilterComponent, ObjectiveFilterComponent, - OkrTangramComponent, - ], - providers: [ - { provide: RefreshDataService, useValue: refreshDataServiceMock }, - { provide: ActivatedRoute, useValue: routeMock }, + OkrTangramComponent ], + providers: [{ provide: RefreshDataService, + useValue: refreshDataServiceMock }, + { provide: ActivatedRoute, + useValue: routeMock }] }); fixture = TestBed.createComponent(ApplicationBannerComponent); @@ -76,56 +78,57 @@ describe('ApplicationBannerComponent', () => { }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it('should should hide banner if scrolled down', fakeAsync(() => { - //Set bannerHeight to default - let bannerHeight: number = 160; - //Scroll more than the height of the banner - let scrollTop: number = 180; - //Set lastScrollPosition to smaller than scrollTop => user scrolls down + // Set bannerHeight to default + const bannerHeight = 160; + // Scroll more than the height of the banner + const scrollTop = 180; + // Set lastScrollPosition to smaller than scrollTop => user scrolls down component.lastScrollPosition = 160; component.bannerHeight = bannerHeight; - //Set banner style + // Set banner style component.refreshBanner(scrollTop); tick(600); - //Assert that banner is hidden was changed + // Assert that banner is hidden was changed fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('#okrBanner')).attributes['style']).toContain( - 'top: -' + (PUZZLE_TOP_BAR_HEIGHT + bannerHeight), - ); + expect(fixture.debugElement.query(By.css('#okrBanner')).attributes['style']) + .toContain('top: -' + (PUZZLE_TOP_BAR_HEIGHT + bannerHeight)); })); it('should show banner if scrolled up', fakeAsync(() => { - //Scroll more than the height of the banner - let scrollTop: number = 180; - //Set lastScrollPosition to bigger than scrollTop => user scrolls up + // Scroll more than the height of the banner + const scrollTop = 180; + // Set lastScrollPosition to bigger than scrollTop => user scrolls up component.lastScrollPosition = 200; - //Set banner style + // Set banner style component.refreshBanner(scrollTop); tick(600); - //Assert that banner is visible + // Assert that banner is visible fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('#okrBanner')).attributes['style']).toContain( - 'top: ' + PUZZLE_TOP_BAR_HEIGHT, - ); + expect(fixture.debugElement.query(By.css('#okrBanner')).attributes['style']) + .toContain('top: ' + PUZZLE_TOP_BAR_HEIGHT); })); it('should call setOKRBannerStyle() when changing header appearance', () => { - jest.spyOn(component, 'refreshBanner').mockReturnValue(); + jest.spyOn(component, 'refreshBanner') + .mockReturnValue(); - //Set bannerHeight to default and execute header appearance change + // Set bannerHeight to default and execute header appearance change component.bannerHeight = 160; component.changeHeaderAppearance(); - //Assert that banner is visible + // Assert that banner is visible fixture.detectChanges(); - expect(component.refreshBanner).toHaveBeenCalled(); + expect(component.refreshBanner) + .toHaveBeenCalled(); }); it('should call correct method after call scroll()', () => { @@ -133,6 +136,7 @@ describe('ApplicationBannerComponent', () => { component.scroll(); - expect(component.changeHeaderAppearance).toHaveBeenCalled(); + expect(component.changeHeaderAppearance) + .toHaveBeenCalled(); }); }); diff --git a/frontend/src/app/components/application-banner/application-banner.component.ts b/frontend/src/app/components/application-banner/application-banner.component.ts index d9a064f348..a5d64d1917 100644 --- a/frontend/src/app/components/application-banner/application-banner.component.ts +++ b/frontend/src/app/components/application-banner/application-banner.component.ts @@ -5,7 +5,7 @@ import { ElementRef, HostListener, OnDestroy, - ViewChild, + ViewChild } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { RefreshDataService } from '../../services/refresh-data.service'; @@ -15,17 +15,22 @@ import { DEFAULT_HEADER_HEIGHT_PX, PUZZLE_TOP_BAR_HEIGHT } from '../../shared/co selector: 'app-application-banner', templateUrl: './application-banner.component.html', styleUrls: ['./application-banner.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.OnPush }) export class ApplicationBannerComponent implements AfterViewInit, OnDestroy { @ViewChild('okrBanner') okrBanner!: ElementRef; + quarterLabel$: BehaviorSubject = new BehaviorSubject(''); + panelOpenState = false; + resizeObserver: ResizeObserver; + bannerHeight: number = DEFAULT_HEADER_HEIGHT_PX; - lastScrollPosition: number = 0; - constructor(private refreshDataService: RefreshDataService) { + lastScrollPosition = 0; + + constructor (private refreshDataService: RefreshDataService) { this.resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => { const newBannerHeight = entries[0].contentRect.height; if (newBannerHeight != this.bannerHeight) { @@ -35,18 +40,18 @@ export class ApplicationBannerComponent implements AfterViewInit, OnDestroy { }); } - ngAfterViewInit(): void { + ngAfterViewInit (): void { this.resizeObserver.observe(this.okrBanner.nativeElement); this.changeHeaderAppearance(); } - changeHeaderAppearance() { - let scrollTop: number = window.scrollY || document.documentElement.scrollTop; + changeHeaderAppearance () { + const scrollTop: number = window.scrollY || document.documentElement.scrollTop; this.refreshBanner(scrollTop); this.lastScrollPosition = scrollTop; } - refreshBanner(scrollTop: number) { + refreshBanner (scrollTop: number) { const newBannerPadding = this.getBannerTopPadding(scrollTop); this.okrBanner.nativeElement.style.top = newBannerPadding + 'px'; @@ -54,22 +59,22 @@ export class ApplicationBannerComponent implements AfterViewInit, OnDestroy { this.refreshDataService.okrBannerHeightSubject.next(overviewPadding); } - getBannerTopPadding(scrollTop: number) { + getBannerTopPadding (scrollTop: number) { return scrollTop > this.lastScrollPosition ? 0 - (PUZZLE_TOP_BAR_HEIGHT + this.bannerHeight) : PUZZLE_TOP_BAR_HEIGHT; } - getOverviewPadding(newBannerPadding: number, paddingAmount: number): number { + getOverviewPadding (newBannerPadding: number, paddingAmount: number): number { return newBannerPadding < 0 ? PUZZLE_TOP_BAR_HEIGHT * 2 : paddingAmount; } @HostListener('window:scroll') - scroll() { + scroll () { this.changeHeaderAppearance(); } - ngOnDestroy(): void { + ngOnDestroy (): void { this.resizeObserver.disconnect(); } } diff --git a/frontend/src/app/components/application-top-bar/application-top-bar.component.html b/frontend/src/app/components/application-top-bar/application-top-bar.component.html index 549b425893..432fecbb55 100644 --- a/frontend/src/app/components/application-top-bar/application-top-bar.component.html +++ b/frontend/src/app/components/application-top-bar/application-top-bar.component.html @@ -1,7 +1,17 @@
- - okr-logo + + okr-logo
@@ -21,7 +35,11 @@ [attr.data-testId]="'help-button'" (click)="window.open(helpSiteUrl, '_blank')" > - + Hilfe @@ -32,15 +50,29 @@ [matMenuTriggerFor]="menu" class="topBarEntry flex-nowrap btn" > - + {{ userFullName }} expand_more expand_less
- - diff --git a/frontend/src/app/components/application-top-bar/application-top-bar.component.scss b/frontend/src/app/components/application-top-bar/application-top-bar.component.scss index b1f8aa6596..30b03d13db 100644 --- a/frontend/src/app/components/application-top-bar/application-top-bar.component.scss +++ b/frontend/src/app/components/application-top-bar/application-top-bar.component.scss @@ -1,4 +1,4 @@ -@import "../style/variables"; +@import '../style/variables'; #topBarHeight { height: $top-bar-height; diff --git a/frontend/src/app/components/application-top-bar/application-top-bar.component.spec.ts b/frontend/src/app/components/application-top-bar/application-top-bar.component.spec.ts index 66fa554e88..06831bcdba 100644 --- a/frontend/src/app/components/application-top-bar/application-top-bar.component.spec.ts +++ b/frontend/src/app/components/application-top-bar/application-top-bar.component.spec.ts @@ -20,24 +20,24 @@ import { DialogService } from '../../services/dialog.service'; const oAuthMock = { getIdentityClaims: jest.fn(), logOut: jest.fn(), - hasValidIdToken: jest.fn(), + hasValidIdToken: jest.fn() }; const dialogServiceMock = { - open: jest.fn(), + open: jest.fn() }; const routerMock = { events: of(new NavigationEnd(1, '', '')), - navigateByUrl: jest.fn(), + navigateByUrl: jest.fn() }; const userServiceMock = { - getCurrentUser: () => testUser, + getCurrentUser: () => testUser }; const configServiceMock = { - config$: of({}), + config$: of({}) }; describe('ApplicationTopBarComponent', () => { @@ -47,10 +47,13 @@ describe('ApplicationTopBarComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [MatMenuModule, NoopAnimationsModule, MatDialogModule], + imports: [MatMenuModule, + NoopAnimationsModule, + MatDialogModule], declarations: [ApplicationTopBarComponent], providers: [ - { provide: OAuthService, useValue: oAuthMock }, + { provide: OAuthService, + useValue: oAuthMock }, { provide: HttpClient }, { provide: HttpHandler }, { provide: UrlHelperService }, @@ -58,23 +61,24 @@ describe('ApplicationTopBarComponent', () => { { provide: DateTimeProvider }, { provide: DialogService, - useValue: dialogServiceMock, + useValue: dialogServiceMock }, { provide: Router, - useValue: routerMock, + useValue: routerMock }, { provide: UserService, - useValue: userServiceMock, + useValue: userServiceMock }, { provide: ConfigService, - useValue: configServiceMock, - }, + useValue: configServiceMock + } ], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents(); + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); fixture = TestBed.createComponent(ApplicationTopBarComponent); component = fixture.componentInstance; @@ -83,21 +87,26 @@ describe('ApplicationTopBarComponent', () => { }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it('should set full name from user service', () => { - expect(component.userFullName).toBe('Bob Baumeister'); + expect(component.userFullName) + .toBe('Bob Baumeister'); }); it('logout function should get called on button click', async () => { - routerMock.navigateByUrl.mockReturnValue(of().toPromise()); + routerMock.navigateByUrl.mockReturnValue(of() + .toPromise()); const harness = await loader.getHarness(MatMenuHarness); await harness.open(); fixture.detectChanges(); - harness.getItems().then((items) => { - items[0].click(); - expect(oAuthMock.logOut).toBeCalledTimes(1); - }); + harness.getItems() + .then((items) => { + items[0].click(); + expect(oAuthMock.logOut) + .toBeCalledTimes(1); + }); }); }); diff --git a/frontend/src/app/components/application-top-bar/application-top-bar.component.ts b/frontend/src/app/components/application-top-bar/application-top-bar.component.ts index c5e7640771..2560e0a0c7 100644 --- a/frontend/src/app/components/application-top-bar/application-top-bar.component.ts +++ b/frontend/src/app/components/application-top-bar/application-top-bar.component.ts @@ -10,24 +10,28 @@ import { getFullNameFromUser } from '../../shared/types/model/User'; selector: 'app-application-top-bar', templateUrl: './application-top-bar.component.html', styleUrls: ['./application-top-bar.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.OnPush }) export class ApplicationTopBarComponent implements OnInit, OnDestroy { - userFullName: string = ''; + userFullName = ''; + menuIsOpen = false; - logoSrc$ = new BehaviorSubject('assets/images/empty.svg'); + + logoSrc$ = new BehaviorSubject('assets/images/empty.svg'); + helpSiteUrl = new BehaviorSubject('https://en.wikipedia.org/wiki/Objectives_and_key_results'); + private subscription?: Subscription; - constructor( + constructor ( private oauthService: OAuthService, private userService: UserService, private configService: ConfigService, private router: Router, - private readonly cd: ChangeDetectorRef, + private readonly cd: ChangeDetectorRef ) {} - ngOnInit(): void { + ngOnInit (): void { this.subscription = this.configService.config$.subscribe({ next: (config) => { if (config.logo) { @@ -36,23 +40,24 @@ export class ApplicationTopBarComponent implements OnInit, OnDestroy { if (config.helpSiteUrl) { this.helpSiteUrl.next(config.helpSiteUrl); } - }, + } }); this.initUserFullName(); } - ngOnDestroy(): void { + ngOnDestroy (): void { this.subscription?.unsubscribe(); } - logOut() { + logOut () { const currentUrlTree = this.router.createUrlTree([], { queryParams: {} }); - this.router.navigateByUrl(currentUrlTree).then(() => { - this.oauthService.logOut(); - }); + this.router.navigateByUrl(currentUrlTree) + .then(() => { + this.oauthService.logOut(); + }); } - private initUserFullName() { + private initUserFullName () { // user is loaded on base route resolver. We have to wait until routing is done. this.router.events.subscribe((val) => { if (!this.userFullName && val instanceof NavigationEnd) { diff --git a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.html b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.html index f7cc096fe7..28afdb4aae 100644 --- a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.html +++ b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.html @@ -15,7 +15,12 @@ *ngIf="!isComplete && checkIn.writeable" [attr.data-testId]="'edit-check-in'" > - edit check-in + edit check-in
@@ -24,9 +29,7 @@

Wert:

{{ metricCheckIn.value! | unitTransformation: getMetricKeyResult().unit }} - + {{ ordinalCheckIn.zone! }} @@ -50,7 +53,12 @@

Massnahmen:

- +
diff --git a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.spec.ts b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.spec.ts index ee75865c64..102e72399f 100644 --- a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.spec.ts +++ b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.spec.ts @@ -16,7 +16,7 @@ import { DialogTemplateCoreComponent } from '../../shared/custom/dialog-template import { MatDividerModule } from '@angular/material/divider'; const checkInService = { - getAllCheckInOfKeyResult: jest.fn(), + getAllCheckInOfKeyResult: jest.fn() }; describe('CheckInHistoryDialogComponent', () => { @@ -25,33 +25,46 @@ describe('CheckInHistoryDialogComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [CheckInHistoryDialogComponent, DialogTemplateCoreComponent, SpinnerComponent], + declarations: [CheckInHistoryDialogComponent, + DialogTemplateCoreComponent, + SpinnerComponent], - imports: [TranslateModule.forRoot(), MatIconModule, MatProgressSpinner, MatDividerModule, MatDialogModule], + imports: [ + TranslateModule.forRoot(), + MatIconModule, + MatProgressSpinner, + MatDividerModule, + MatDialogModule + ], providers: [ provideRouter([]), provideHttpClient(), provideHttpClientTesting(), TranslateService, DialogService, - { provide: MAT_DIALOG_DATA, useValue: { keyResult: keyResult } }, - { provide: MatDialogRef, useValue: {} }, - ], + { provide: MAT_DIALOG_DATA, + useValue: { keyResult: keyResult } }, + { provide: MatDialogRef, + useValue: {} } + ] }); jest .spyOn(checkInService, 'getAllCheckInOfKeyResult') - .mockReturnValue([checkInMetric, checkInMetricWriteableFalse]); + .mockReturnValue([checkInMetric, + checkInMetricWriteableFalse]); fixture = TestBed.createComponent(CheckInHistoryDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it.skip('should not display edit check-in button if writeable is false', async () => { const buttons = fixture.debugElement.queryAll(By.css('button')); - expect(buttons.length).toBe(1); + expect(buttons.length) + .toBe(1); }); }); diff --git a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.ts b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.ts index 8c2d5a709c..714829d5b2 100644 --- a/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.ts +++ b/frontend/src/app/components/check-in-history-dialog/check-in-history-dialog.component.ts @@ -15,43 +15,47 @@ import { CheckInOrdinalMin } from '../../shared/types/model/CheckInOrdinalMin'; @Component({ selector: 'app-check-in-history-dialog', templateUrl: './check-in-history-dialog.component.html', - styleUrls: ['./check-in-history-dialog.component.scss'], + styleUrls: ['./check-in-history-dialog.component.scss'] }) export class CheckInHistoryDialogComponent implements OnInit { keyResult!: KeyResult; + isComplete!: boolean; + checkInHistory$: Observable = of([]); + protected readonly DATE_FORMAT = DATE_FORMAT; - constructor( + constructor ( @Inject(MAT_DIALOG_DATA) public data: any, private checkInService: CheckInService, private dialogService: DialogService, public dialogRef: MatDialogRef, - private refreshDataService: RefreshDataService, + private refreshDataService: RefreshDataService ) {} - ngOnInit(): void { + ngOnInit (): void { this.keyResult = this.data.keyResult; this.isComplete = this.data.isComplete; this.loadCheckInHistory(); } - openCheckInDialogForm(checkIn: CheckInMin) { + openCheckInDialogForm (checkIn: CheckInMin) { const dialogRef = this.dialogService.open(CheckInFormComponent, { data: { keyResult: this.keyResult, - checkIn: checkIn, - }, - }); - dialogRef.afterClosed().subscribe(() => { - this.loadCheckInHistory(); - this.refreshDataService.reloadKeyResultSubject.next(); - this.refreshDataService.markDataRefresh(); + checkIn: checkIn + } }); + dialogRef.afterClosed() + .subscribe(() => { + this.loadCheckInHistory(); + this.refreshDataService.reloadKeyResultSubject.next(); + this.refreshDataService.markDataRefresh(); + }); } - loadCheckInHistory() { + loadCheckInHistory () { this.checkInHistory$ = this.checkInService.getAllCheckInOfKeyResult(this.keyResult.id); this.checkInHistory$.subscribe((result) => { if (result.length == 0) { @@ -60,15 +64,15 @@ export class CheckInHistoryDialogComponent implements OnInit { }); } - getMetricKeyResult(): KeyResultMetric { + getMetricKeyResult (): KeyResultMetric { return this.keyResult as KeyResultMetric; } - getCheckInMetric(checkIn: CheckInMin): CheckInMetricMin { + getCheckInMetric (checkIn: CheckInMin): CheckInMetricMin { return checkIn as CheckInMetricMin; } - getCheckInOrdinal(checkIn: CheckInMin): CheckInOrdinalMin { + getCheckInOrdinal (checkIn: CheckInMin): CheckInOrdinalMin { return checkIn as CheckInOrdinalMin; } } diff --git a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts index 6287808fcb..3ca966b7b8 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.spec.ts @@ -26,10 +26,10 @@ describe('CheckInFormComponent', () => { MatRadioModule, ReactiveFormsModule, TranslateTestingModule.withTranslations({ - de: de, - }), + de: de + }) ], - declarations: [CheckInFormMetricComponent], + declarations: [CheckInFormMetricComponent] }); fixture = TestBed.createComponent(CheckInFormMetricComponent); component = fixture.componentInstance; @@ -37,37 +37,50 @@ describe('CheckInFormComponent', () => { component.checkIn = checkInMetric; component.dialogForm = new FormGroup({ value: new FormControl('', [Validators.required]), - confidence: new FormControl(5, [Validators.required, Validators.min(1), Validators.max(10)]), + confidence: new FormControl(5, [Validators.required, + Validators.min(1), + Validators.max(10)]) }); fixture.detectChanges(); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it('should format percent correctly', waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, unit: Unit.PERCENT }; - expect(component.generateUnitLabel()).toEqual('%'); + component.keyResult = { ...keyResultMetric, + unit: Unit.PERCENT }; + expect(component.generateUnitLabel()) + .toEqual('%'); })); it('should format chf correctly', waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, unit: Unit.CHF }; - expect(component.generateUnitLabel()).toEqual('CHF'); + component.keyResult = { ...keyResultMetric, + unit: Unit.CHF }; + expect(component.generateUnitLabel()) + .toEqual('CHF'); })); it('should format eur correctly', waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, unit: Unit.EUR }; - expect(component.generateUnitLabel()).toEqual('EUR'); + component.keyResult = { ...keyResultMetric, + unit: Unit.EUR }; + expect(component.generateUnitLabel()) + .toEqual('EUR'); })); it('should format fte correctly', waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, unit: Unit.FTE }; - expect(component.generateUnitLabel()).toEqual('FTE'); + component.keyResult = { ...keyResultMetric, + unit: Unit.FTE }; + expect(component.generateUnitLabel()) + .toEqual('FTE'); })); it('should format number correctly', waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, unit: Unit.NUMBER }; - expect(component.generateUnitLabel()).toEqual(''); + component.keyResult = { ...keyResultMetric, + unit: Unit.NUMBER }; + expect(component.generateUnitLabel()) + .toEqual(''); })); }); diff --git a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts index 0b77bd593a..af87f47d10 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/check-in-form-metric.component.ts @@ -10,25 +10,30 @@ import { CheckInMetricMin } from '../../../shared/types/model/CheckInMetricMin'; selector: 'app-check-in-form-metric', templateUrl: './check-in-form-metric.component.html', styleUrls: ['./check-in-form-metric.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.OnPush }) export class CheckInFormMetricComponent implements OnInit { @Input() keyResult!: KeyResultMetric; + @Input() checkIn!: CheckInMin; + @Input() dialogForm!: FormGroup; + protected readonly formInputCheck = formInputCheck; + protected readonly hasFormFieldErrors = hasFormFieldErrors; - constructor(private translate: TranslateService) {} + constructor (private translate: TranslateService) {} - ngOnInit() { - this.dialogForm.controls['value'].setValidators([Validators.required, Validators.pattern('^-?\\d+\\.?\\d*$')]); + ngOnInit () { + this.dialogForm.controls['value'].setValidators([Validators.required, + Validators.pattern('^-?\\d+\\.?\\d*$')]); } - generateUnitLabel(): string { + generateUnitLabel (): string { switch (this.keyResult.unit) { case 'PERCENT': return '%'; @@ -43,11 +48,11 @@ export class CheckInFormMetricComponent implements OnInit { } } - getErrorMessage(error: string, field: string): string { + getErrorMessage (error: string, field: string): string { return field + this.translate.instant('DIALOG_ERRORS.' + error); } - getCheckInMetric(): CheckInMetricMin { + getCheckInMetric (): CheckInMetricMin { return this.checkIn as CheckInMetricMin; } } diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts index acd3577f2e..8498b4133d 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.spec.ts @@ -3,16 +3,23 @@ import { MetricCheckInDirective } from './metric-check-in-directive'; describe('MetricCheckInDirective', () => { it('create an instance', () => { const directive = new MetricCheckInDirective(); - expect(directive).toBeTruthy(); + expect(directive) + .toBeTruthy(); }); it.each([ - ['HelloWorld200', 200], - ['200HelloWorld', 200], - ["200'000", 200000], - ['1050&%ç*', 1050], - ['-1', -1], - ['-ç13&%', -13], + ['HelloWorld200', + 200], + ['200HelloWorld', + 200], + ["200'000", + 200000], + ['1050&%ç*', + 1050], + ['-1', + -1], + ['-ç13&%', + -13] ])('should parse value %s correctly to %s', (value: string, expected: number) => { const mockOnChange = jest.fn(); const directive = new MetricCheckInDirective(); @@ -20,6 +27,7 @@ describe('MetricCheckInDirective', () => { directive.handleInput(value); - expect(mockOnChange).toHaveBeenCalledWith(expected); + expect(mockOnChange) + .toHaveBeenCalledWith(expected); }); }); diff --git a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts index d7fa625061..73e636daa2 100644 --- a/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts +++ b/frontend/src/app/components/checkin/check-in-form-metric/metric-check-in-directive.ts @@ -3,37 +3,39 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @Directive({ selector: '[metricCheckIn]', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => MetricCheckInDirective), - multi: true, - }, - ], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => MetricCheckInDirective), + multi: true + }] }) export class MetricCheckInDirective implements ControlValueAccessor { private onChange: (value: number | null) => void = () => {}; + protected readonly CHAR_REGEX = /[^0-9.]/g; - writeValue(value: any): void { + writeValue (value: any): void { // does not need to be implemented because the display value does not need to be modified } - registerOnChange(fn: (value: number | null) => void): void { + registerOnChange (fn: (value: number | null) => void): void { this.onChange = fn; } - registerOnTouched(fn: () => void): void { + registerOnTouched (fn: () => void): void { // does not need to be implemented } @HostListener('input', ['$event.target.value']) - handleInput(param: string): void { + handleInput (param: string): void { const value: string = param || '0'; - if (value.toString().at(0) == '-') { - this.onChange(+('-' + value.toString().replace(this.CHAR_REGEX, ''))); + if (value.toString() + .at(0) == '-') { + this.onChange(+('-' + value.toString() + .replace(this.CHAR_REGEX, ''))); return; } - this.onChange(Number(value.toString().replace(this.CHAR_REGEX, ''))); + this.onChange(Number(value.toString() + .replace(this.CHAR_REGEX, ''))); } } diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html index 1477819976..a15793ca9b 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.html @@ -1,26 +1,46 @@
- - + +
Fail:  Commit / Target / Stretch noch nicht erreicht
- +
Commit: {{ keyResult.commitZone }}
- +
Target: {{ keyResult.targetZone }}
- +
Stretch: {{ keyResult.stretchZone }}
diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.scss b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.scss index 62b280fbef..b7febe31a8 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.scss +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.scss @@ -1,4 +1,4 @@ -@import "../style/variables"; +@import '../style/variables'; .submit { background-color: $pz-dark-blue; diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts index f1b32bf4c0..84931bfa71 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.spec.ts @@ -27,57 +27,66 @@ describe('CheckInFormOrdinalComponent', () => { MatSelectModule, MatInputModule, MatRadioModule, - ReactiveFormsModule, + ReactiveFormsModule ], - declarations: [CheckInFormOrdinalComponent], + declarations: [CheckInFormOrdinalComponent] }); fixture = TestBed.createComponent(CheckInFormOrdinalComponent); component = fixture.componentInstance; component.keyResult = keyResultOrdinalMin as unknown as KeyResultOrdinal; component.dialogForm = new FormGroup({ value: new FormControl('', [Validators.required]), - confidence: new FormControl(5, [Validators.required, Validators.min(1), Validators.max(10)]), + confidence: new FormControl(5, [Validators.required, + Validators.min(1), + Validators.max(10)]) }); fixture.detectChanges(); loader = TestbedHarnessEnvironment.loader(fixture); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(component) + .toBeTruthy(); }); it('should set zone of check-in to fail if value is empty', waitForAsync(async () => { - expect(component.dialogForm.controls['value'].value).toBe(''); + expect(component.dialogForm.controls['value'].value) + .toBe(''); })); it('should set zone to Fail', waitForAsync(async () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[0].check(); - expect(component.dialogForm.controls['value'].value).toBe(Zone.FAIL); + expect(component.dialogForm.controls['value'].value) + .toBe(Zone.FAIL); })); it('should set zone to Commit', waitForAsync(async () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[1].check(); - expect(component.dialogForm.controls['value'].value).toBe(Zone.COMMIT); + expect(component.dialogForm.controls['value'].value) + .toBe(Zone.COMMIT); })); it('should set zone to Target', waitForAsync(async () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[2].check(); - expect(component.dialogForm.controls['value'].value).toBe(Zone.TARGET); + expect(component.dialogForm.controls['value'].value) + .toBe(Zone.TARGET); })); it('should set zone to Stretch', waitForAsync(async () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[3].check(); - expect(component.dialogForm.controls['value'].value).toBe(Zone.STRETCH); + expect(component.dialogForm.controls['value'].value) + .toBe(Zone.STRETCH); })); it('should be able to switch options ', waitForAsync(async () => { const radioButtons = await loader.getAllHarnesses(MatRadioButtonHarness); await radioButtons[3].check(); await radioButtons[1].check(); - expect(component.dialogForm.controls['value'].value).toBe(Zone.COMMIT); + expect(component.dialogForm.controls['value'].value) + .toBe(Zone.COMMIT); })); }); diff --git a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.ts b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.ts index 192c5156fb..ed8354c380 100644 --- a/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.ts +++ b/frontend/src/app/components/checkin/check-in-form-ordinal/check-in-form-ordinal.component.ts @@ -7,14 +7,17 @@ import { CheckInMin } from '../../../shared/types/model/CheckInMin'; @Component({ selector: 'app-check-in-form-ordinal', templateUrl: './check-in-form-ordinal.component.html', - styleUrls: ['./check-in-form-ordinal.component.scss'], + styleUrls: ['./check-in-form-ordinal.component.scss'] }) export class CheckInFormOrdinalComponent { @Input() keyResult!: KeyResultOrdinal; + @Input() checkIn!: CheckInMin; + @Input() dialogForm!: FormGroup; + protected readonly Zone = Zone; } diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html index 4c0fbdbb69..e979005f62 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.html @@ -12,12 +12,14 @@
- - -
+ +
{{ action.action }}
@@ -25,8 +27,7 @@
- Kommentar/ Veränderung seit letztem Check-in (optional):