From 0d45a33f0427dd2a9cbfce87b84ec820e2df88c9 Mon Sep 17 00:00:00 2001 From: Nevio Di Gennaro Date: Thu, 19 Dec 2024 10:37:49 +0100 Subject: [PATCH] turn on stylistic rules --- frontend/cypress/e2e/check-in.cy.ts | 598 ++++--- .../cypress/e2e/duplicate-objective.cy.ts | 274 ++-- frontend/cypress/e2e/key-result.cy.ts | 766 ++++----- frontend/cypress/e2e/login.cy.ts | 80 +- frontend/cypress/e2e/objective-backlog.cy.ts | 437 +++-- frontend/cypress/e2e/objective-crud.cy.ts | 193 ++- frontend/cypress/e2e/objective.cy.ts | 637 ++++---- frontend/cypress/e2e/overview.cy.ts | 80 +- frontend/cypress/e2e/routing.cy.ts | 69 +- frontend/cypress/e2e/scoring.cy.ts | 214 ++- frontend/cypress/e2e/tab.cy.ts | 779 ++++----- frontend/cypress/e2e/team.cy.ts | 298 ++-- frontend/cypress/e2e/teammanagement.cy.ts | 1123 ++++++------- frontend/cypress/support/commands.ts | 147 +- .../helper/dom-helper/angularSearchBox.ts | 9 +- .../dom-helper/dialogs/checkInDialog.ts | 9 +- .../dialogs/checkInHistoryDialog.ts | 3 +- .../helper/dom-helper/dialogs/dialog.ts | 3 +- .../dom-helper/dialogs/inviteMembersDialog.ts | 9 +- .../dom-helper/dialogs/keyResultDialog.ts | 24 +- .../dom-helper/dialogs/objectiveDialog.ts | 9 +- .../helper/dom-helper/dialogs/teamDialog.ts | 3 +- .../support/helper/dom-helper/filterHelper.ts | 30 +- .../helper/dom-helper/pages/overviewPage.ts | 15 +- .../support/helper/dom-helper/pages/page.ts | 3 +- .../cypress/support/helper/keyResultHelper.ts | 3 +- .../cypress/support/helper/objectiveHelper.ts | 6 +- .../cypress/support/helper/scoringSupport.ts | 84 +- frontend/cypress/support/helper/utils.ts | 16 +- frontend/eslint.config.mjs | 21 +- frontend/src/app/app.component.spec.ts | 74 +- frontend/src/app/app.component.ts | 6 +- frontend/src/app/app.module.ts | 4 +- .../action-plan/action-plan.component.spec.ts | 319 ++-- .../action-plan/action-plan.component.ts | 22 +- .../application-banner.component.spec.ts | 202 ++- .../application-banner.component.ts | 3 +- .../application-top-bar.component.spec.ts | 134 +- .../application-top-bar.component.ts | 3 +- .../check-in-history-dialog.component.spec.ts | 90 +- .../check-in-history-dialog.component.ts | 13 +- .../check-in-form-metric.component.spec.ts | 137 +- .../metric-check-in-directive.spec.ts | 57 +- .../metric-check-in-directive.ts | 9 +- .../check-in-form-ordinal.component.spec.ts | 144 +- .../check-in-form.component.spec.ts | 310 ++-- .../check-in-form/check-in-form.component.ts | 16 +- .../confidence/confidence.component.spec.ts | 100 +- .../key-result-form.component.spec.ts | 461 +++--- .../key-result-form.component.ts | 7 +- .../keyresult-detail.component.spec.ts | 209 ++- .../keyresult-detail.component.ts | 37 +- .../keyresult-dialog.component.spec.ts | 1425 ++++++++--------- .../keyresult-dialog.component.ts | 15 +- .../keyresult-type.component.spec.ts | 576 ++++--- .../keyresult-type.component.ts | 6 +- .../keyresult/keyresult.component.spec.ts | 44 +- .../objective-detail.component.spec.ts | 118 +- .../objective-detail.component.ts | 28 +- .../objective-filter.component.spec.ts | 159 +- .../objective-filter.component.ts | 3 +- .../objective/ObjectiveMenuActions.ts | 15 +- .../objective/objective.component.spec.ts | 186 ++- .../objective/objective.component.ts | 19 +- .../overview/overview.component.spec.ts | 310 ++-- .../components/overview/overview.component.ts | 8 +- .../quarter-filter.component.spec.ts | 191 +-- .../quarter-filter.component.ts | 3 +- .../team-filter/team-filter.component.spec.ts | 659 ++++---- .../team-filter/team-filter.component.ts | 9 +- .../components/team/team.component.spec.ts | 215 ++- .../src/app/components/team/team.component.ts | 26 +- frontend/src/app/guards/auth.guard.spec.ts | 173 +- .../interceptors/error-interceptor.service.ts | 34 +- .../interceptors/error.interceptor.spec.ts | 619 ++++--- .../interceptors/oauth.interceptor.spec.ts | 34 +- .../src/app/interceptors/oauth.interceptor.ts | 23 +- .../src/app/services/action.service.spec.ts | 24 +- frontend/src/app/services/action.service.ts | 3 +- .../src/app/services/check-in.service.spec.ts | 51 +- frontend/src/app/services/check-in.service.ts | 6 +- frontend/src/app/services/completed.servce.ts | 3 +- .../app/services/completed.service.spec.ts | 24 +- .../src/app/services/config.service.spec.ts | 24 +- .../services/customization.service.spec.ts | 304 ++-- .../src/app/services/customization.service.ts | 6 +- .../src/app/services/dialog.service.spec.ts | 421 +++-- frontend/src/app/services/dialog.service.ts | 53 +- .../app/services/keyresult.service.spec.ts | 22 +- .../src/app/services/keyresult.service.ts | 6 +- .../objective-menu-actions.service.spec.ts | 174 +- .../objective-menu-actions.service.ts | 8 +- .../app/services/objective.service.spec.ts | 24 +- .../src/app/services/objective.service.ts | 9 +- .../src/app/services/overview.service.spec.ts | 52 +- frontend/src/app/services/overview.service.ts | 3 +- .../src/app/services/quarter.service.spec.ts | 24 +- frontend/src/app/services/quarter.service.ts | 5 +- .../app/services/refresh-data.service.spec.ts | 22 +- .../src/app/services/team.service.spec.ts | 24 +- frontend/src/app/services/team.service.ts | 15 +- .../src/app/services/toaster.service.spec.ts | 116 +- frontend/src/app/services/toaster.service.ts | 9 +- .../src/app/services/user.service.spec.ts | 178 +- frontend/src/app/services/user.service.ts | 15 +- frontend/src/app/shared/common.spec.ts | 725 ++++----- frontend/src/app/shared/common.ts | 9 +- .../custom/scoring/scoring.component.spec.ts | 348 ++-- frontend/src/app/shared/customRouter.ts | 3 +- .../complete-dialog.component.spec.ts | 218 ++- .../complete-dialog.component.ts | 6 +- .../confirm-dialog.component.spec.ts | 100 +- .../example-dialog.component.spec.ts | 366 +++-- .../example-dialog.component.ts | 13 +- .../objective-form.component.spec.ts | 848 +++++----- .../objective-form.component.ts | 54 +- .../unit-transformation.pipe.spec.ts | 122 +- .../unit-transformation.pipe.ts | 3 +- frontend/src/app/shared/routeUtils.spec.ts | 60 +- .../shared/sidepanel/sidepanel.component.ts | 3 +- frontend/src/app/shared/testData.ts | 50 +- frontend/src/app/shared/validators.ts | 12 +- .../add-edit-team-dialog.component.spec.ts | 171 +- .../add-edit-team-dialog.component.ts | 10 +- ...dd-member-to-team-dialog.component.spec.ts | 255 ++- .../add-member-to-team-dialog.component.ts | 21 +- .../add-user-team.component.spec.ts | 213 ++- .../add-user-team/add-user-team.component.ts | 22 +- .../delete-user/delete-user.component.spec.ts | 427 +++-- .../delete-user/delete-user.component.ts | 34 +- .../edit-okr-champion.component.ts | 6 +- .../invite-user-dialog.component.spec.ts | 238 ++- .../invite-user-dialog.component.ts | 23 +- .../member-detail.component.spec.ts | 386 +++-- .../member-detail/member-detail.component.ts | 28 +- .../member-list-mobile.component.spec.ts | 84 +- .../member-list-mobile.component.ts | 3 +- .../member-list-table.component.spec.ts | 365 ++--- .../member-list-table.component.ts | 13 +- .../member-list/member-list.component.spec.ts | 512 +++--- .../member-list/member-list.component.ts | 37 +- .../new-user/new-user.component.spec.ts | 62 +- .../new-user/unique-mail.directive.spec.ts | 75 +- .../team-management/okr-champion.pipe.spec.ts | 42 +- .../search-team-management.component.spec.ts | 298 ++-- .../search-team-management.component.ts | 47 +- .../show-edit-role.component.spec.ts | 89 +- .../show-edit-role.component.ts | 6 +- .../team-list/team-list.component.spec.ts | 104 +- .../team-management-banner.component.spec.ts | 95 +- ...management-mobile-filter.component.spec.ts | 176 +- ...team-management-mobile-filter.component.ts | 3 +- .../team-management.component.spec.ts | 124 +- .../team-role-dropdown.component.spec.ts | 85 +- .../team-role-dropdown.component.ts | 3 +- .../app/team-management/teams.pipe.spec.ts | 74 +- .../src/app/team-management/teams.pipe.ts | 6 +- frontend/src/global.ts | 7 +- 158 files changed, 10227 insertions(+), 11679 deletions(-) diff --git a/frontend/cypress/e2e/check-in.cy.ts b/frontend/cypress/e2e/check-in.cy.ts index 470cf0c039..e52b2416a9 100644 --- a/frontend/cypress/e2e/check-in.cy.ts +++ b/frontend/cypress/e2e/check-in.cy.ts @@ -7,344 +7,302 @@ import CheckInDialog from "../support/helper/dom-helper/dialogs/checkInDialog"; import CheckInHistoryDialog from "../support/helper/dom-helper/dialogs/checkInHistoryDialog"; import ConfirmDialog from "../support/helper/dom-helper/dialogs/confirmDialog"; -describe("OKR Check-in e2e tests", - () => { - describe("tests via click", - () => { - let overviewPage = new CyOverviewPage(); - let keyresultDetailPage = new KeyResultDetailPage(); +describe("OKR Check-in e2e tests", () => { + describe("tests via click", () => { + let overviewPage = new CyOverviewPage(); + let keyresultDetailPage = new KeyResultDetailPage(); - beforeEach(() => { - overviewPage = new CyOverviewPage(); - keyresultDetailPage = new KeyResultDetailPage(); - cy.loginAsUser(users.gl); - }); + beforeEach(() => { + overviewPage = new CyOverviewPage(); + keyresultDetailPage = new KeyResultDetailPage(); + cy.loginAsUser(users.gl); + }); - it("Create checkin metric", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Very important keyresult") - .withMetricValues(Unit.PERCENT, - "21", - "51") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("Very important keyresult") - .createCheckIn() - .checkForDialogTextMetric() - .fillMetricCheckInValue("30") - .setCheckInConfidence(6) - .fillCheckInCommentary("We bought a new house") - .fillCheckInInitiatives("We have to buy more PCs") - .submit(); - cy.contains("30%"); - cy.contains("6/10"); - cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); - cy.contains("We bought a new house"); - }); + it("Create checkin metric", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Very important keyresult") + .withMetricValues(Unit.PERCENT, "21", "51") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("Very important keyresult") + .createCheckIn() + .checkForDialogTextMetric() + .fillMetricCheckInValue("30") + .setCheckInConfidence(6) + .fillCheckInCommentary("We bought a new house") + .fillCheckInInitiatives("We have to buy more PCs") + .submit(); + cy.contains("30%"); + cy.contains("6/10"); + cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); + cy.contains("We bought a new house"); + }); - it("Create checkin metric with confidence 0", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Very important keyresult") - .withMetricValues(Unit.PERCENT, - "21", - "51") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("Very important keyresult") - .createCheckIn() - .fillMetricCheckInValue("30") - .setCheckInConfidence(0) - .fillCheckInCommentary("We bought a new house") - .fillCheckInInitiatives("We have to buy more PCs") - .submit(); + it("Create checkin metric with confidence 0", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Very important keyresult") + .withMetricValues(Unit.PERCENT, "21", "51") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("Very important keyresult") + .createCheckIn() + .fillMetricCheckInValue("30") + .setCheckInConfidence(0) + .fillCheckInCommentary("We bought a new house") + .fillCheckInInitiatives("We have to buy more PCs") + .submit(); - cy.contains("30%"); - cy.contains("6/10"); - cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); - cy.contains("We bought a new house"); - }); + cy.contains("30%"); + cy.contains("6/10"); + cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); + cy.contains("We bought a new house"); + }); - it("Create checkin metric with value below baseline", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("This will not be good") - .withMetricValues(Unit.PERCENT, - "21", - "52") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("This will not be good") - .createCheckIn() - .fillMetricCheckInValue("5") - .setCheckInConfidence(5) - .submit(); + it("Create checkin metric with value below baseline", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("This will not be good") + .withMetricValues(Unit.PERCENT, "21", "52") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("This will not be good") + .createCheckIn() + .fillMetricCheckInValue("5") + .setCheckInConfidence(5) + .submit(); - cy.contains("5%"); - cy.contains("!"); - cy.contains("5/10"); - cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); - }); + cy.contains("5%"); + cy.contains("!"); + cy.contains("5/10"); + cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); + }); - it("Create checkin ordinal", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("A new ordinal keyresult for our company") - .withOrdinalValues("New house", - "New car", - "New pool") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("A new ordinal keyresult for our company") - .createCheckIn() - .checkForDialogTextOrdinal() - .selectOrdinalCheckInZone("commit") - .setCheckInConfidence(6) - .fillCheckInCommentary("There is a new car") - .fillCheckInInitiatives("Buy a new pool") - .submit(); + it("Create checkin ordinal", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("A new ordinal keyresult for our company") + .withOrdinalValues("New house", "New car", "New pool") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("A new ordinal keyresult for our company") + .createCheckIn() + .checkForDialogTextOrdinal() + .selectOrdinalCheckInZone("commit") + .setCheckInConfidence(6) + .fillCheckInCommentary("There is a new car") + .fillCheckInInitiatives("Buy a new pool") + .submit(); - cy.contains("6/10"); - cy.contains("There is a new car"); - cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); - }); + cy.contains("6/10"); + cy.contains("There is a new car"); + cy.contains("Letztes Check-in (" + getCurrentDate() + ")"); + }); - it("Should generate checkin list", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("This will give a checkin list") - .withMetricValues(Unit.PERCENT, - "21", - "52") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("This will give a checkin list") - .createCheckIn() - .fillMetricCheckInValue("30") - .setCheckInConfidence(5) - .fillCheckInCommentary("We bought a new house") - .fillCheckInInitiatives("We have to buy more PCs") - .submit(); - keyresultDetailPage - .createCheckIn() - .fillMetricCheckInValue("50") - .setCheckInConfidence(6) - .fillCheckInCommentary("This was a good idea") - .fillCheckInInitiatives("Will be difficult") - .submit(); - keyresultDetailPage - .showAllCheckins() - .checkForAttribute("Confidence:", - "5 / 10") - .checkForAttribute("Confidence:", - "6 / 10") - .checkForAttribute("Veränderungen:", - "We bought a new house") - .checkForAttribute("Veränderungen:", - "This was a good idea") - .checkForAttribute("Massnahmen:", - "We have to buy more PCs") - .checkForAttribute("Massnahmen:", - "Will be difficult"); + it("Should generate checkin list", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("This will give a checkin list") + .withMetricValues(Unit.PERCENT, "21", "52") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("This will give a checkin list") + .createCheckIn() + .fillMetricCheckInValue("30") + .setCheckInConfidence(5) + .fillCheckInCommentary("We bought a new house") + .fillCheckInInitiatives("We have to buy more PCs") + .submit(); + keyresultDetailPage + .createCheckIn() + .fillMetricCheckInValue("50") + .setCheckInConfidence(6) + .fillCheckInCommentary("This was a good idea") + .fillCheckInInitiatives("Will be difficult") + .submit(); + keyresultDetailPage + .showAllCheckins() + .checkForAttribute("Confidence:", "5 / 10") + .checkForAttribute("Confidence:", "6 / 10") + .checkForAttribute("Veränderungen:", "We bought a new house") + .checkForAttribute("Veränderungen:", "This was a good idea") + .checkForAttribute("Massnahmen:", "We have to buy more PCs") + .checkForAttribute("Massnahmen:", "Will be difficult"); - cy.contains("Check-in History"); - cy.contains(getCurrentDate()); - cy.contains("Wert: 30%"); - cy.contains("Wert: 50%"); - }); + cy.contains("Check-in History"); + cy.contains(getCurrentDate()); + cy.contains("Wert: 30%"); + cy.contains("Wert: 50%"); + }); - it("Edit metric checkin", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Here we edit a metric checkin") - .withMetricValues(Unit.CHF, - "10", - "300") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("Here we edit a metric checkin") - .createCheckIn() - .fillMetricCheckInValue("30") - .setCheckInConfidence(5) - .fillCheckInCommentary("Here we are") - .fillCheckInInitiatives("A cat would be great") - .submit(); - cy.contains("Aktuell: 30 CHF"); - keyresultDetailPage.showAllCheckins(); - cy.contains("Check-in History"); - cy.contains("Wert: 30 CHF"); - 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(); - cy.contains("200 CHF"); - cy.contains("We bought a new sheep"); - }); + it("Edit metric checkin", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Here we edit a metric checkin") + .withMetricValues(Unit.CHF, "10", "300") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("Here we edit a metric checkin") + .createCheckIn() + .fillMetricCheckInValue("30") + .setCheckInConfidence(5) + .fillCheckInCommentary("Here we are") + .fillCheckInInitiatives("A cat would be great") + .submit(); + cy.contains("Aktuell: 30 CHF"); + keyresultDetailPage.showAllCheckins(); + cy.contains("Check-in History"); + cy.contains("Wert: 30 CHF"); + 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(); + cy.contains("200 CHF"); + cy.contains("We bought a new sheep"); + }); - it("Should generate right labels in checkin history list", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("A new KeyResult for checking checkin list") - .withMetricValues(Unit.EUR, - "10", - "300") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("A new KeyResult for checking checkin list") - .createCheckIn() - .fillMetricCheckInValue("30") - .setCheckInConfidence(5) - .fillCheckInCommentary("Here we are") - .fillCheckInInitiatives("A cat would be great") - .submit(); - cy.contains("Aktuell: 30 EUR"); - keyresultDetailPage.showAllCheckins(); - cy.contains("Check-in History"); - cy.contains("Wert: 30 EUR"); - CheckInHistoryDialog.do() - .close(); - keyresultDetailPage.close(); + it("Should generate right labels in checkin history list", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("A new KeyResult for checking checkin list") + .withMetricValues(Unit.EUR, "10", "300") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("A new KeyResult for checking checkin list") + .createCheckIn() + .fillMetricCheckInValue("30") + .setCheckInConfidence(5) + .fillCheckInCommentary("Here we are") + .fillCheckInInitiatives("A cat would be great") + .submit(); + cy.contains("Aktuell: 30 EUR"); + keyresultDetailPage.showAllCheckins(); + cy.contains("Check-in History"); + cy.contains("Wert: 30 EUR"); + CheckInHistoryDialog.do() + .close(); + keyresultDetailPage.close(); - overviewPage - .addKeyResult() - .fillKeyResultTitle("There is another kr with fte") - .withMetricValues(Unit.FTE, - "10", - "300") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("There is another kr with fte") - .createCheckIn() - .fillMetricCheckInValue("30") - .setCheckInConfidence(5) - .fillCheckInCommentary("Here we are") - .fillCheckInInitiatives("A cat would be great") - .submit(); - cy.contains("Aktuell: 30 FTE"); - keyresultDetailPage.showAllCheckins(); - cy.contains("Check-in History"); - cy.contains("Wert: 30 FTE"); - }); + overviewPage + .addKeyResult() + .fillKeyResultTitle("There is another kr with fte") + .withMetricValues(Unit.FTE, "10", "300") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("There is another kr with fte") + .createCheckIn() + .fillMetricCheckInValue("30") + .setCheckInConfidence(5) + .fillCheckInCommentary("Here we are") + .fillCheckInInitiatives("A cat would be great") + .submit(); + cy.contains("Aktuell: 30 FTE"); + keyresultDetailPage.showAllCheckins(); + cy.contains("Check-in History"); + cy.contains("Wert: 30 FTE"); + }); - it("Edit ordinal checkin", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("For editing ordinal checkin") - .withOrdinalValues("New house", - "New car", - "New pool") - .fillKeyResultDescription("This is my description") - .submit(); - keyresultDetailPage - .visit("For editing ordinal checkin") - .createCheckIn() - .selectOrdinalCheckInZone("fail") - .setCheckInConfidence(6) - .fillCheckInCommentary("There is a new car") - .fillCheckInInitiatives("Buy now a new pool") - .submit(); - 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(); - cy.contains("We bought a new dog"); - cy.contains("Buy now a new pool"); - cy.contains("STRETCH"); - }); + it("Edit ordinal checkin", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("For editing ordinal checkin") + .withOrdinalValues("New house", "New car", "New pool") + .fillKeyResultDescription("This is my description") + .submit(); + keyresultDetailPage + .visit("For editing ordinal checkin") + .createCheckIn() + .selectOrdinalCheckInZone("fail") + .setCheckInConfidence(6) + .fillCheckInCommentary("There is a new car") + .fillCheckInInitiatives("Buy now a new pool") + .submit(); + 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(); + 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.visitNextQuarter(); - overviewPage - .addKeyResult(undefined, - "draft objective title") - .fillKeyResultTitle("I am a metric keyresult for testing") - .withMetricValues(Unit.PERCENT, - "21", - "52") - .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?"); - }); + it("Should display confirm dialog when creating checkin on draft objective", () => { + overviewPage.addObjective() + .fillObjectiveTitle("draft objective title") + .selectQuarter("3") + .submitDraftObjective(); + overviewPage.visitNextQuarter(); + overviewPage + .addKeyResult(undefined, "draft objective title") + .fillKeyResultTitle("I am a metric keyresult for testing") + .withMetricValues(Unit.PERCENT, "21", "52") + .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?"); + }); - it("Should only display last value div if last checkin is present", - () => { - const objectiveName = uniqueSuffix("new objective"); + 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.visitNextQuarter(); - overviewPage - .addKeyResult(undefined, - objectiveName) - .fillKeyResultTitle("I am a keyresult metric") - .withMetricValues(Unit.PERCENT, - "45", - "60") - .fillKeyResultDescription("Description") - .submit(); - keyresultDetailPage.visit("I am a keyresult metric") - .createCheckIn(); - cy.getByTestId("old-checkin-value") - .should("not.exist"); - CheckInDialog.do() - .fillMetricCheckInValue("10") - .setCheckInConfidence(0) - .fillCheckInCommentary("changeinfo") - .fillCheckInInitiatives("initiatives") - .submit(); - cy.contains(`Letztes Check-in (${getCurrentDate()})`); - keyresultDetailPage.createCheckIn(); - cy.contains("Letzter Wert") - .siblings("div") - .contains("10%"); - }); - }); + overviewPage.addObjective() + .fillObjectiveTitle(objectiveName) + .selectQuarter("3") + .submit(); + overviewPage.visitNextQuarter(); + overviewPage + .addKeyResult(undefined, objectiveName) + .fillKeyResultTitle("I am a keyresult metric") + .withMetricValues(Unit.PERCENT, "45", "60") + .fillKeyResultDescription("Description") + .submit(); + keyresultDetailPage.visit("I am a keyresult metric") + .createCheckIn(); + cy.getByTestId("old-checkin-value") + .should("not.exist"); + CheckInDialog.do() + .fillMetricCheckInValue("10") + .setCheckInConfidence(0) + .fillCheckInCommentary("changeinfo") + .fillCheckInInitiatives("initiatives") + .submit(); + cy.contains(`Letztes Check-in (${getCurrentDate()})`); + keyresultDetailPage.createCheckIn(); + cy.contains("Letzter Wert") + .siblings("div") + .contains("10%"); + }); }); +}); function getCurrentDate () { const today = new Date(); diff --git a/frontend/cypress/e2e/duplicate-objective.cy.ts b/frontend/cypress/e2e/duplicate-objective.cy.ts index e6b396b985..c612428c00 100644 --- a/frontend/cypress/e2e/duplicate-objective.cy.ts +++ b/frontend/cypress/e2e/duplicate-objective.cy.ts @@ -10,163 +10,141 @@ beforeEach(() => { cy.loginAsUser(users.gl); }); -describe("Functionality of duplicating objectives and their belonging keyResults", - () => { - const firstKeyResultName = "New structure that rewards funny guys and innovation before the end of Q1."; - const secondKeyResultName = "Monthly town halls between our people and leadership teams over the next four months."; - const thirdKeyResultName = "High employee satisfaction scores (80%+) throughout the year."; - - it("Should be able to duplicate a objective into this quarter, including all keyResults", - () => { - const duplicatedTitle = "This is a duplicated objective with all keyResults"; - - overviewPage - .duplicateObjective("Build a company culture that kills the competition.") - .fillObjectiveTitle(duplicatedTitle) - .submit(); - - cy.contains(duplicatedTitle); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - firstKeyResultName) - .should("exist"); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - secondKeyResultName) - .should("exist"); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - thirdKeyResultName) - .should("exist"); - }); +describe("Functionality of duplicating objectives and their belonging keyResults", () => { + const firstKeyResultName = "New structure that rewards funny guys and innovation before the end of Q1."; + const secondKeyResultName = "Monthly town halls between our people and leadership teams over the next four months."; + const thirdKeyResultName = "High employee satisfaction scores (80%+) throughout the year."; + + it("Should be able to duplicate a objective into this quarter, including all keyResults", () => { + const duplicatedTitle = "This is a duplicated objective with all keyResults"; + + overviewPage + .duplicateObjective("Build a company culture that kills the competition.") + .fillObjectiveTitle(duplicatedTitle) + .submit(); + + cy.contains(duplicatedTitle); + 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", - () => { - const duplicatedTitle = "This is a duplicated objective with one keyResult"; - - overviewPage - .duplicateObjective("Build a company culture that kills the competition.") - .fillObjectiveTitle(duplicatedTitle) - .excludeKeyResults([secondKeyResultName, - thirdKeyResultName]) - .submit(); - - overviewPage.getKeyResultOfObjective(duplicatedTitle, - firstKeyResultName); - - overviewPage - .getAllKeyResultsOfObjective(duplicatedTitle) - .should("not.contain", - secondKeyResultName) - .should("not.contain", - thirdKeyResultName); - }); + it("Should be able to duplicate a objective into this quarter, only including one keyResult", () => { + const duplicatedTitle = "This is a duplicated objective with one keyResult"; - 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("Build a company culture that kills the competition.") + .fillObjectiveTitle(duplicatedTitle) + .excludeKeyResults([secondKeyResultName, + thirdKeyResultName]) + .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.getKeyResultOfObjective(duplicatedTitle, firstKeyResultName); - overviewPage.getObjectiveByName(duplicatedTitle) - .should("exist"); - }); + overviewPage + .getAllKeyResultsOfObjective(duplicatedTitle) + .should("not.contain", secondKeyResultName) + .should("not.contain", thirdKeyResultName); + }); - it("Should be able to duplicate a objective into the next quarter, including all keyResults", - () => { - const duplicatedTitle = "This is a default objective with all keyResults in quarter 3!"; - - overviewPage - .duplicateObjective("Build a company culture that kills the competition.") - .fillObjectiveTitle(duplicatedTitle) - .selectQuarter("3") - .submit(); - - overviewPage.visitNextQuarter(); - - cy.contains(duplicatedTitle); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - firstKeyResultName) - .should("exist"); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - secondKeyResultName) - .should("exist"); - overviewPage.getKeyResultOfObjective(duplicatedTitle, - thirdKeyResultName) - .should("exist"); - }); + 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(); - it("Should not duplicate objective when cancel button is clicked", - () => { - const duplicatedTitle = "This is a never existing objective"; + overviewPage.getObjectiveByName(duplicatedTitle) + .should("exist"); + }); - overviewPage - .duplicateObjective("Build a company culture that kills the competition.") - .fillObjectiveTitle(duplicatedTitle) - .fillObjectiveDescription("Wow this is a very nice description!") - .cancel(); + it("Should be able to duplicate a objective into the next quarter, including all keyResults", () => { + const duplicatedTitle = "This is a default objective with all keyResults in quarter 3!"; - cy.contains(duplicatedTitle) - .should("not.exist"); - }); + overviewPage + .duplicateObjective("Build a company culture that kills the competition.") + .fillObjectiveTitle(duplicatedTitle) + .selectQuarter("3") + .submit(); + + overviewPage.visitNextQuarter(); + + cy.contains(duplicatedTitle); + 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", () => { + const duplicatedTitle = "This is a never existing objective"; + + overviewPage + .duplicateObjective("Build a company culture that kills the competition.") + .fillObjectiveTitle(duplicatedTitle) + .fillObjectiveDescription("Wow this is a very nice description!") + .cancel(); + + cy.contains(duplicatedTitle) + .should("not.exist"); }); +}); -describe("Verify functionality of scoring adjustment on duplicated objectives", - () => { - const keyresultDetailPage = new KeyResultDetailPage(); - - it("Duplicate ordinal checkin and validate value of scoring component", - () => { - overviewPage - .addKeyResult("Puzzle ITC", - "Wir wollen die Kundenzufriedenheit steigern") - .fillKeyResultTitle("stretch keyresult for testing") - .withOrdinalValues("Ex. val", - "Ex. val", - "Ex. val") - .submit(); - - cy.contains("stretch keyresult for testing"); - keyresultDetailPage - .visit("stretch keyresult for testing") - .createCheckIn() - .selectOrdinalCheckInZone("stretch") - .setCheckInConfidence(8) - .fillCheckInCommentary("Testveränderungen") - .fillCheckInInitiatives("Testmassnahmen") - .submit(); - - cy.intercept("GET", - "**/overview?*") - .as("indexPage"); - keyresultDetailPage.close(); - cy.wait("@indexPage"); - - overviewPage - .duplicateObjective("Wir wollen die Kundenzufriedenheit steigern") - .fillObjectiveTitle("A duplicated Objective for this tool") - .selectQuarter("3") - .submit(); - - overviewPage.checkForToaster("Das Objective wurde erfolgreich erstellt.", - "success"); - - overviewPage.visitNextQuarter(); - - overviewPage - .getKeyResultByName("stretch keyresult for testing") - .findByTestId("scoring-component") - .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"); - }); +describe("Verify functionality of scoring adjustment on duplicated objectives", () => { + const keyresultDetailPage = new KeyResultDetailPage(); + + it("Duplicate ordinal checkin and validate value of scoring component", () => { + overviewPage + .addKeyResult("Puzzle ITC", "Wir wollen die Kundenzufriedenheit steigern") + .fillKeyResultTitle("stretch keyresult for testing") + .withOrdinalValues("Ex. val", "Ex. val", "Ex. val") + .submit(); + + cy.contains("stretch keyresult for testing"); + keyresultDetailPage + .visit("stretch keyresult for testing") + .createCheckIn() + .selectOrdinalCheckInZone("stretch") + .setCheckInConfidence(8) + .fillCheckInCommentary("Testveränderungen") + .fillCheckInInitiatives("Testmassnahmen") + .submit(); + + cy.intercept("GET", "**/overview?*") + .as("indexPage"); + keyresultDetailPage.close(); + cy.wait("@indexPage"); + + overviewPage + .duplicateObjective("Wir wollen die Kundenzufriedenheit steigern") + .fillObjectiveTitle("A duplicated Objective for this tool") + .selectQuarter("3") + .submit(); + + overviewPage.checkForToaster("Das Objective wurde erfolgreich erstellt.", "success"); + + overviewPage.visitNextQuarter(); + + overviewPage + .getKeyResultByName("stretch keyresult for testing") + .findByTestId("scoring-component") + .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"); }); }); +}); diff --git a/frontend/cypress/e2e/key-result.cy.ts b/frontend/cypress/e2e/key-result.cy.ts index 252e201d9e..7f4a7ba647 100644 --- a/frontend/cypress/e2e/key-result.cy.ts +++ b/frontend/cypress/e2e/key-result.cy.ts @@ -4,418 +4,356 @@ import KeyResultDetailPage from "../support/helper/dom-helper/pages/keyResultDet import { Unit } from "../../src/app/shared/types/enums/Unit"; import KeyResultDialog from "../support/helper/dom-helper/dialogs/keyResultDialog"; -describe("OKR Overview", - () => { - let overviewPage = new CyOverviewPage(); - let keyResultDetailPage = new KeyResultDetailPage(); - - beforeEach(() => { - overviewPage = new CyOverviewPage(); - keyResultDetailPage = new KeyResultDetailPage(); - cy.loginAsUser(users.gl); - }); - - it("Create new metric KeyResult", - () => { - overviewPage - .addKeyResult() - .checkForDialogTextMetric() - .fillKeyResultTitle("I am a metric keyresult") - .withMetricValues(Unit.PERCENT, - "21", - "52") - .fillOwner("Bob Baumeister") - .fillKeyResultDescription("This is my description") - .submit(); - keyResultDetailPage.visit("I am a metric keyresult"); - - cy.contains("I am a metric keyresult"); - cy.contains("Metrisch"); - cy.contains("Bob Baumeister"); - cy.contains("21%"); - cy.contains("52%"); - cy.contains("Stretch"); - cy.contains("Confidence"); - cy.contains("Beschrieb"); - cy.contains("This is my description"); - cy.contains("Check-in erfassen"); - cy.contains("Key Result bearbeiten"); - }); - - it("Create new ordinal KeyResult", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("I am a ordinal keyresult") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillOwner("Bob Baumeister") - .fillKeyResultDescription("This is my description") - .submit(); - keyResultDetailPage.visit("I am a ordinal keyresult"); - - cy.contains("I am a ordinal keyresult"); - cy.contains("Ordinal"); - cy.contains("Bob Baumeister"); - cy.contains("Fail"); - cy.contains("Commit"); - cy.contains("Target"); - cy.contains("My commit zone"); - cy.contains("My target zone"); - cy.contains("My stretch goal"); - cy.contains("Stretch"); - cy.contains("Confidence"); - cy.contains("Beschrieb"); - cy.contains("This is my description"); - cy.contains("Check-in erfassen"); - cy.contains("Key Result bearbeiten"); - }); - - it("Create new KeyResult and Save and New", - () => { - overviewPage - .addKeyResult() - .checkForDialogTextMetric() - .fillKeyResultTitle("I am a metric keyresult with a new one") - .withMetricValues(Unit.PERCENT, - "21", - "52") - .fillOwner("Bob Baumeister") - .fillKeyResultDescription("This is my description when creating and then open a new") - .saveAndNew(); - cy.contains("Jaya Norris"); - KeyResultDialog.do() - .checkForDialogTextMetric(); - }); - - it("Create and edit KeyResult with Action Plan", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("This is a keyresult with an action plan") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .fillOwner("Bob Baumeister") - .fillKeyResultDescription("This is my description") - .addActionPlanElement("A new car") - .addActionPlanElement("A new house") - .addActionPlanElement("A new company") - .submit(); - - keyResultDetailPage.visit("This is a keyresult with an action plan"); - - cy.contains("This is a keyresult with an action plan"); - cy.contains("Ordinal"); - cy.contains("My commit zone"); - cy.contains("My target zone"); - cy.contains("My stretch goal"); - cy.contains("A new car"); - cy.contains("A new house"); - cy.contains("A new company"); - - keyResultDetailPage.editKeyResult(); - cy.getByTestId("actionInput") - .should("have.length", - 3); - }); - - it("Edit a KeyResult without type change", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("We want not to change keyresult title") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillKeyResultDescription("This is my description") - .submit(); - keyResultDetailPage.visit("We want not to change keyresult title") - .editKeyResult(); - - 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"); - - KeyResultDialog.do() - .fillKeyResultTitle("This is the new title") - .withOrdinalValues("New commit", - "New target", - "New stretch") - .fillKeyResultDescription("This is my new description") - .submit(); - - cy.contains("This is the new title"); - cy.contains("New commit"); - cy.contains("New target"); - cy.contains("New stretch"); - cy.contains("Jaya Norris"); - cy.contains("This is my new description"); - }); - - it("Edit a KeyResult with type change", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Here we want to change keyresult title") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillKeyResultDescription("This is my description") - .addActionPlanElement("Action 1") - .addActionPlanElement("Action 2") - .submit(); - keyResultDetailPage.visit("Here we want to change keyresult title") - .editKeyResult(); - - 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"); - - KeyResultDialog.do() - .fillKeyResultTitle("This is my new title for the new metric keyresult") - .withMetricValues(Unit.PERCENT, - "21", - "56") - .fillKeyResultDescription("This is my new description") - .submit(); - - cy.contains("This is my new title for the new metric keyresult"); - cy.contains("21%"); - cy.contains("56%"); - cy.contains("Metrisch"); - cy.contains("Jaya Norris"); - cy.contains("This is my new description"); - cy.contains("Action 1"); - cy.contains("Action 2"); - }); - - it("A KeyResult should not be able to change type after a checkin", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Here we want to create a checkin") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillKeyResultDescription("This is my description") - .addActionPlanElement("Action 1") - .addActionPlanElement("Action 2") - .submit(); - - keyResultDetailPage - .visit("Here we want to create a checkin") - .createCheckIn() - .selectOrdinalCheckInZone("commit") - .setCheckInConfidence(6) - .submit(); - - keyResultDetailPage.close(); - - keyResultDetailPage.visit("Here we want to create a checkin") - .editKeyResult(); - - cy.getByTestId("metricTab") - .should("have.class", - "non-active"); - }); - - it("Check validation in keyresult dialog", - () => { - 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("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"); - cy.contains("Baseline muss eine Zahl sein"); - - 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"); - cy.contains("Stretch Goal muss eine Zahl sein"); - - 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"); - 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() - .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"); - 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"); - 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"); - }); - - it("Delete existing keyresult", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("A keyresult to delete") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillKeyResultDescription("This is my description") - .submit(); - keyResultDetailPage - .visit("A keyresult to delete") - .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!") - .submit(); - - cy.contains("Puzzle ITC"); - cy.get("A keyresult to delete") - .should("not.exist"); - }); +describe("OKR Overview", () => { + let overviewPage = new CyOverviewPage(); + let keyResultDetailPage = new KeyResultDetailPage(); + + beforeEach(() => { + overviewPage = new CyOverviewPage(); + keyResultDetailPage = new KeyResultDetailPage(); + cy.loginAsUser(users.gl); }); + + it("Create new metric KeyResult", () => { + overviewPage + .addKeyResult() + .checkForDialogTextMetric() + .fillKeyResultTitle("I am a metric keyresult") + .withMetricValues(Unit.PERCENT, "21", "52") + .fillOwner("Bob Baumeister") + .fillKeyResultDescription("This is my description") + .submit(); + keyResultDetailPage.visit("I am a metric keyresult"); + + cy.contains("I am a metric keyresult"); + cy.contains("Metrisch"); + cy.contains("Bob Baumeister"); + cy.contains("21%"); + cy.contains("52%"); + cy.contains("Stretch"); + cy.contains("Confidence"); + cy.contains("Beschrieb"); + cy.contains("This is my description"); + cy.contains("Check-in erfassen"); + cy.contains("Key Result bearbeiten"); + }); + + it("Create new ordinal KeyResult", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("I am a ordinal keyresult") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillOwner("Bob Baumeister") + .fillKeyResultDescription("This is my description") + .submit(); + keyResultDetailPage.visit("I am a ordinal keyresult"); + + cy.contains("I am a ordinal keyresult"); + cy.contains("Ordinal"); + cy.contains("Bob Baumeister"); + cy.contains("Fail"); + cy.contains("Commit"); + cy.contains("Target"); + cy.contains("My commit zone"); + cy.contains("My target zone"); + cy.contains("My stretch goal"); + cy.contains("Stretch"); + cy.contains("Confidence"); + cy.contains("Beschrieb"); + cy.contains("This is my description"); + cy.contains("Check-in erfassen"); + cy.contains("Key Result bearbeiten"); + }); + + it("Create new KeyResult and Save and New", () => { + overviewPage + .addKeyResult() + .checkForDialogTextMetric() + .fillKeyResultTitle("I am a metric keyresult with a new one") + .withMetricValues(Unit.PERCENT, "21", "52") + .fillOwner("Bob Baumeister") + .fillKeyResultDescription("This is my description when creating and then open a new") + .saveAndNew(); + cy.contains("Jaya Norris"); + KeyResultDialog.do() + .checkForDialogTextMetric(); + }); + + it("Create and edit KeyResult with Action Plan", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("This is a keyresult with an action plan") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .fillOwner("Bob Baumeister") + .fillKeyResultDescription("This is my description") + .addActionPlanElement("A new car") + .addActionPlanElement("A new house") + .addActionPlanElement("A new company") + .submit(); + + keyResultDetailPage.visit("This is a keyresult with an action plan"); + + cy.contains("This is a keyresult with an action plan"); + cy.contains("Ordinal"); + cy.contains("My commit zone"); + cy.contains("My target zone"); + cy.contains("My stretch goal"); + cy.contains("A new car"); + cy.contains("A new house"); + cy.contains("A new company"); + + keyResultDetailPage.editKeyResult(); + cy.getByTestId("actionInput") + .should("have.length", 3); + }); + + it("Edit a KeyResult without type change", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("We want not to change keyresult title") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillKeyResultDescription("This is my description") + .submit(); + keyResultDetailPage.visit("We want not to change keyresult title") + .editKeyResult(); + + 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"); + + KeyResultDialog.do() + .fillKeyResultTitle("This is the new title") + .withOrdinalValues("New commit", "New target", "New stretch") + .fillKeyResultDescription("This is my new description") + .submit(); + + cy.contains("This is the new title"); + cy.contains("New commit"); + cy.contains("New target"); + cy.contains("New stretch"); + cy.contains("Jaya Norris"); + cy.contains("This is my new description"); + }); + + it("Edit a KeyResult with type change", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Here we want to change keyresult title") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillKeyResultDescription("This is my description") + .addActionPlanElement("Action 1") + .addActionPlanElement("Action 2") + .submit(); + keyResultDetailPage.visit("Here we want to change keyresult title") + .editKeyResult(); + + 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"); + + KeyResultDialog.do() + .fillKeyResultTitle("This is my new title for the new metric keyresult") + .withMetricValues(Unit.PERCENT, "21", "56") + .fillKeyResultDescription("This is my new description") + .submit(); + + cy.contains("This is my new title for the new metric keyresult"); + cy.contains("21%"); + cy.contains("56%"); + cy.contains("Metrisch"); + cy.contains("Jaya Norris"); + cy.contains("This is my new description"); + cy.contains("Action 1"); + cy.contains("Action 2"); + }); + + it("A KeyResult should not be able to change type after a checkin", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Here we want to create a checkin") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillKeyResultDescription("This is my description") + .addActionPlanElement("Action 1") + .addActionPlanElement("Action 2") + .submit(); + + keyResultDetailPage + .visit("Here we want to create a checkin") + .createCheckIn() + .selectOrdinalCheckInZone("commit") + .setCheckInConfidence(6) + .submit(); + + keyResultDetailPage.close(); + + keyResultDetailPage.visit("Here we want to create a checkin") + .editKeyResult(); + + cy.getByTestId("metricTab") + .should("have.class", "non-active"); + }); + + it("Check validation in keyresult dialog", () => { + 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("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"); + cy.contains("Baseline muss eine Zahl sein"); + + 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"); + cy.contains("Stretch Goal muss eine Zahl sein"); + + 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"); + 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() + .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"); + 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"); + 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"); + }); + + it("Delete existing keyresult", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("A keyresult to delete") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillKeyResultDescription("This is my description") + .submit(); + keyResultDetailPage + .visit("A keyresult to delete") + .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!") + .submit(); + + cy.contains("Puzzle ITC"); + 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 214735a9bb..dfe84ec8d3 100644 --- a/frontend/cypress/e2e/login.cy.ts +++ b/frontend/cypress/e2e/login.cy.ts @@ -1,52 +1,42 @@ import * as users from "../fixtures/users.json"; -describe("OKR Login", - () => { - beforeEach(() => { - cy.loginAsUser(users.gl); - }); - - it("Login and check correct name is displayed", - () => { - cy.title() - .should("equal", - "Puzzle OKR"); - cy.getByTestId("user-name") - .contains(users.gl.name); - }); +describe("OKR Login", () => { + beforeEach(() => { + cy.loginAsUser(users.gl); + }); - it("Login and logout", - () => { - 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"); - }); - }); + it("Login and check correct name is displayed", () => { + cy.title() + .should("equal", "Puzzle OKR"); + cy.getByTestId("user-name") + .contains(users.gl.name); + }); - 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"); - }); + it("Login and logout", () => { + 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.get("#hilfeButton") - .click(); - cy.get("@openWindow") - .should("be.calledWith", - "https://wiki.puzzle.ch/Puzzle/OKRs"); + 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.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 380bcd07e0..cf9e3a315e 100644 --- a/frontend/cypress/e2e/objective-backlog.cy.ts +++ b/frontend/cypress/e2e/objective-backlog.cy.ts @@ -2,236 +2,209 @@ import * as users from "../fixtures/users.json"; import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import ObjectiveDialog from "../support/helper/dom-helper/dialogs/objectiveDialog"; -describe("OKR Objective Backlog e2e tests", - () => { - let overviewPage = new CyOverviewPage(); - - beforeEach(() => { - overviewPage = new CyOverviewPage(); - cy.loginAsUser(users.gl); - }); - - it("Create Objective in backlog quarter should not have save button", - () => { - overviewPage - .addObjective() - .fillObjectiveTitle("Objective in quarter backlog") - .selectQuarter("Backlog") - .run(cy.contains("Speichern") - .should("not.exist")) - .run(cy.contains("Als Draft speichern")) - .submitDraftObjective(); - - 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 - .getObjectiveByNameAndState("Move to another quarter on edit", - "draft") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); - - ObjectiveDialog.do() - .fillObjectiveTitle("This goes now to backlog") - .selectQuarter("Backlog") - .submit(); - - 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 - .getObjectiveByNameAndState("We can not move this to backlog", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); - - 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.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.contains("Speichern"); - cy.getByTestId("save") - .click(); - - cy.contains("This is our first released objective") - .should("not.exist"); - - overviewPage.visitGJForTests(); - cy.contains("This is our first released objective"); - }); - - it("Can edit Objective title in backlog", - () => { - overviewPage.visitBacklogQuarter(); - overviewPage.addObjective() - .fillObjectiveTitle("This is possible for edit") - .submitDraftObjective(); - - overviewPage - .getObjectiveByNameAndState("This is possible for edit", - "draft") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); - - 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 - .getObjectiveByNameAndState("This goes to other quarter later", - "draft") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); - - ObjectiveDialog.do() - .selectQuarter("GJ ForTests") - .submit(); - - overviewPage.visitGJForTests(); - overviewPage.getObjectiveByNameAndState("This goes to other quarter later", - "draft"); - }); - - it("Can duplicate in backlog", - () => { - overviewPage.visitBacklogQuarter(); - overviewPage.addObjective() - .fillObjectiveTitle("Ready for duplicate in backlog") - .submitDraftObjective(); - - overviewPage - .getObjectiveByNameAndState("Ready for duplicate in backlog", - "draft") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective duplizieren"); - - 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"); - }); - - it("should duplicate from backlog", - () => { - overviewPage.visitBacklogQuarter(); - 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(); - - 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"); - }); - - it("Can duplicate ongoing Objective to backlog", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("Possible to duplicate into backlog") - .submit(); - - overviewPage - .getObjectiveByNameAndState("Possible to duplicate into backlog", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective duplizieren"); - - ObjectiveDialog.do() - .selectQuarter("Backlog") - .submit(); - - overviewPage.visitBacklogQuarter(); - cy.contains("Possible to duplicate into backlog"); - }); +describe("OKR Objective Backlog e2e tests", () => { + let overviewPage = new CyOverviewPage(); + + beforeEach(() => { + overviewPage = new CyOverviewPage(); + cy.loginAsUser(users.gl); + }); + + it("Create Objective in backlog quarter should not have save button", () => { + overviewPage + .addObjective() + .fillObjectiveTitle("Objective in quarter backlog") + .selectQuarter("Backlog") + .run(cy.contains("Speichern") + .should("not.exist")) + .run(cy.contains("Als Draft speichern")) + .submitDraftObjective(); + + 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 + .getObjectiveByNameAndState("Move to another quarter on edit", "draft") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + + ObjectiveDialog.do() + .fillObjectiveTitle("This goes now to backlog") + .selectQuarter("Backlog") + .submit(); + + 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 + .getObjectiveByNameAndState("We can not move this to backlog", "ongoing") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + + 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.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.contains("Speichern"); + cy.getByTestId("save") + .click(); + + cy.contains("This is our first released objective") + .should("not.exist"); + + overviewPage.visitGJForTests(); + cy.contains("This is our first released objective"); + }); + + it("Can edit Objective title in backlog", () => { + overviewPage.visitBacklogQuarter(); + overviewPage.addObjective() + .fillObjectiveTitle("This is possible for edit") + .submitDraftObjective(); + + overviewPage + .getObjectiveByNameAndState("This is possible for edit", "draft") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + + 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 + .getObjectiveByNameAndState("This goes to other quarter later", "draft") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + + ObjectiveDialog.do() + .selectQuarter("GJ ForTests") + .submit(); + + overviewPage.visitGJForTests(); + overviewPage.getObjectiveByNameAndState("This goes to other quarter later", "draft"); + }); + + it("Can duplicate in backlog", () => { + overviewPage.visitBacklogQuarter(); + overviewPage.addObjective() + .fillObjectiveTitle("Ready for duplicate in backlog") + .submitDraftObjective(); + + overviewPage + .getObjectiveByNameAndState("Ready for duplicate in backlog", "draft") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective duplizieren"); + + 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"); + }); + + it("should duplicate from backlog", () => { + overviewPage.visitBacklogQuarter(); + 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(); + + 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"); + }); + + it("Can duplicate ongoing Objective to backlog", () => { + overviewPage.addObjective() + .fillObjectiveTitle("Possible to duplicate into backlog") + .submit(); + + overviewPage + .getObjectiveByNameAndState("Possible to duplicate into backlog", "ongoing") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective duplizieren"); + + 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 63aad0ab9b..632a558fd1 100644 --- a/frontend/cypress/e2e/objective-crud.cy.ts +++ b/frontend/cypress/e2e/objective-crud.cy.ts @@ -2,115 +2,104 @@ import * as users from "../fixtures/users.json"; import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import ObjectiveDialog from "../support/helper/dom-helper/dialogs/objectiveDialog"; -describe("CRUD operations", - () => { - let overviewPage = new CyOverviewPage(); +describe("CRUD operations", () => { + let overviewPage = new CyOverviewPage(); - beforeEach(() => { - overviewPage = new CyOverviewPage(); - cy.loginAsUser(users.gl); - }); + beforeEach(() => { + overviewPage = new CyOverviewPage(); + cy.loginAsUser(users.gl); + }); - [["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.visitNextQuarter(); - overviewPage - .getObjectiveByName(objectiveTitle) - .findByTestId("objective-state") - .should("have.attr", - "src", - `assets/icons/${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.visitNextQuarter(); + overviewPage + .getObjectiveByName(objectiveTitle) + .findByTestId("objective-state") + .should("have.attr", "src", `assets/icons/${icon}`); }); + }); - it("Create objective, should display error message", - () => { - overviewPage.addObjective(); - 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"); - }); + it("Create objective, should display error message", () => { + overviewPage.addObjective(); + 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"); + }); - it("Create objective, cancel", - () => { - const objectiveTitle = "this is a canceled objective"; - overviewPage.addObjective() - .selectQuarter("3") - .cancel(); - overviewPage.visitNextQuarter(); - cy.contains(objectiveTitle) - .should("not.exist"); - }); + it("Create objective, cancel", () => { + const objectiveTitle = "this is a canceled objective"; + overviewPage.addObjective() + .selectQuarter("3") + .cancel(); + overviewPage.visitNextQuarter(); + cy.contains(objectiveTitle) + .should("not.exist"); + }); - it("Delete existing objective", - () => { - 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!") - .submit(); - }); + it("Delete existing objective", () => { + 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!") + .submit(); + }); - it("Open objective aside via click", - () => { - overviewPage.getFirstObjective() - .find(".title") - .click(); - cy.url() - .should("include", - "objective"); - }); + it("Open objective aside via click", () => { + 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.selectFromThreeDotMenu("Objective bearbeiten"); - ObjectiveDialog.do() - .fillObjectiveTitle(updatedTitle) - .submit(); - cy.contains(updatedTitle) - .should("exist"); - }); + it("update objective", () => { + const updatedTitle = "This is an updated title"; + overviewPage.getFirstObjective() + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + 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.selectFromThreeDotMenu("Objective duplizieren"); - ObjectiveDialog.do() - .fillObjectiveTitle(duplicatedTitle) - .submit(); - cy.contains(duplicatedTitle) - .should("exist"); - }); + it("Duplicate objective", () => { + const duplicatedTitle = "This is a duplicated objective"; + overviewPage.getFirstObjective() + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective duplizieren"); + 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 94c394b57b..28da14fa94 100644 --- a/frontend/cypress/e2e/objective.cy.ts +++ b/frontend/cypress/e2e/objective.cy.ts @@ -3,341 +3,308 @@ import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import ObjectiveDialog from "../support/helper/dom-helper/dialogs/objectiveDialog"; import ConfirmDialog from "../support/helper/dom-helper/dialogs/confirmDialog"; -describe("OKR Objective e2e tests", - () => { - let overviewPage = new CyOverviewPage(); - beforeEach(() => { - overviewPage = new CyOverviewPage(); - cy.loginAsUser(users.gl); +describe("OKR Objective e2e tests", () => { + let overviewPage = new CyOverviewPage(); + beforeEach(() => { + overviewPage = new CyOverviewPage(); + cy.loginAsUser(users.gl); + }); + + describe("tests via click", () => { + it("Release Objective from Draft to Ongoing", () => { + overviewPage.addObjective() + .fillObjectiveTitle("A objective in state draft") + .submitDraftObjective(); + + overviewPage + .getObjectiveByNameAndState("A objective in state draft", "draft") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective veröffentlichen"); + + ConfirmDialog.do() + .checkTitle("Objective veröffentlichen") + .checkDescription("Soll dieses Objective veröffentlicht werden?") + .submit(); + + 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 + .getObjectiveByNameAndState("We want to complete this successful", "ongoing") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective abschliessen"); + + cy.contains("Bewertung"); + cy.contains("Objective erreicht"); + cy.contains("Objective nicht erreicht"); + cy.contains("Kommentar (optional)"); + cy.contains("Objective abschliessen"); + cy.contains("Abbrechen"); + + 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 + .getObjectiveByNameAndState("A not successful objective", "ongoing") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective abschliessen"); + + cy.contains("Bewertung"); + cy.contains("Objective erreicht"); + cy.contains("Objective nicht erreicht"); + cy.contains("Kommentar (optional)"); + cy.contains("Objective abschliessen"); + cy.contains("Abbrechen"); + + 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 + .getObjectiveByNameAndState("This objective will be reopened after", "ongoing") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective abschliessen"); + + cy.getByTestId("successful") + .click(); + cy.getByTestId("submit") + .click(); + + cy.wait(500); + + overviewPage + .getObjectiveByNameAndState("This objective will be reopened after", "successful") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective wiedereröffnen"); + + ConfirmDialog.do() + .checkTitle("Objective wiedereröffnen") + .checkDescription("Soll dieses Objective wiedereröffnet werden?") + .submit(); + + 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 + .getObjectiveByNameAndState("The reopening of this objective will be canceled", "ongoing") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective abschliessen"); + + cy.getByTestId("successful") + .click(); + cy.getByTestId("submit") + .click(); + + cy.wait(500); + + overviewPage + .getObjectiveByNameAndState("he reopening of this objective will be canceled", "successful") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective wiedereröffnen"); + + ConfirmDialog.do() + .checkTitle("Objective wiedereröffnen") + .checkDescription("Soll dieses Objective wiedereröffnet werden?") + .cancel(); + + overviewPage + .getObjectiveByNameAndState("The reopening of this objective will be canceled", "successful") + .should("exist"); }); - describe("tests via click", - () => { - it("Release Objective from Draft to Ongoing", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("A objective in state draft") - .submitDraftObjective(); - - overviewPage - .getObjectiveByNameAndState("A objective in state draft", - "draft") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective veröffentlichen"); - - ConfirmDialog.do() - .checkTitle("Objective veröffentlichen") - .checkDescription("Soll dieses Objective veröffentlicht werden?") - .submit(); - - 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 - .getObjectiveByNameAndState("We want to complete this successful", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective abschliessen"); - - cy.contains("Bewertung"); - cy.contains("Objective erreicht"); - cy.contains("Objective nicht erreicht"); - cy.contains("Kommentar (optional)"); - cy.contains("Objective abschliessen"); - cy.contains("Abbrechen"); - - 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 - .getObjectiveByNameAndState("A not successful objective", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective abschliessen"); - - cy.contains("Bewertung"); - cy.contains("Objective erreicht"); - cy.contains("Objective nicht erreicht"); - cy.contains("Kommentar (optional)"); - cy.contains("Objective abschliessen"); - cy.contains("Abbrechen"); - - 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 - .getObjectiveByNameAndState("This objective will be reopened after", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective abschliessen"); - - cy.getByTestId("successful") - .click(); - cy.getByTestId("submit") - .click(); - - cy.wait(500); - - overviewPage - .getObjectiveByNameAndState("This objective will be reopened after", - "successful") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective wiedereröffnen"); - - ConfirmDialog.do() - .checkTitle("Objective wiedereröffnen") - .checkDescription("Soll dieses Objective wiedereröffnet werden?") - .submit(); - - 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 - .getObjectiveByNameAndState("The reopening of this objective will be canceled", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective abschliessen"); - - cy.getByTestId("successful") - .click(); - cy.getByTestId("submit") - .click(); - - cy.wait(500); - - overviewPage - .getObjectiveByNameAndState("he reopening of this objective will be canceled", - "successful") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective wiedereröffnen"); - - ConfirmDialog.do() - .checkTitle("Objective wiedereröffnen") - .checkDescription("Soll dieses Objective wiedereröffnet werden?") - .cancel(); - - overviewPage - .getObjectiveByNameAndState("The reopening of this objective will be canceled", - "successful") - .should("exist"); - }); - - it("Cancel Ongoing objective back to draft state", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("This objective will be returned to draft state") - .submit(); - - overviewPage - .getObjectiveByNameAndState("This objective will be returned to draft state", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective als Draft speichern"); - - ConfirmDialog.do() - .checkTitle("Objective als Draft speichern") - .checkDescription("Soll dieses Objective als Draft gespeichert werden?") - .submit(); - - overviewPage - .getObjectiveByNameAndState("This objective will be returned to draft state", - "draft") - .should("exist"); - }); - - it("Ongoing objective back to draft state", - () => { - overviewPage - .addObjective() - .fillObjectiveTitle("Putting this objective back to draft state will be canceled") - .submit(); - - overviewPage - .getObjectiveByNameAndState("Putting this objective back to draft state will be canceled", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - overviewPage.selectFromThreeDotMenu("Objective als Draft speichern"); - - ConfirmDialog.do() - .checkTitle("Objective als Draft speichern") - .checkDescription("Soll dieses Objective als Draft gespeichert werden?") - .cancel(); - - overviewPage - .getObjectiveByNameAndState("Putting this objective back to draft state will be canceled", - "ongoing") - .should("exist"); - }); - - it("Search for Objective", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("Search after this objective") - .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"); - - cy.scrollTo(0, - 0); - cy.wait(500); - - 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.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.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"); - }); - - it("Create Objective in other quarter", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("Objective in quarter 3") - .selectQuarter("3") - .submit(); - - cy.contains("Objective in quarter 3") - .should("not.exist"); - - overviewPage.visitNextQuarter(); - - cy.contains("Objective in quarter 3"); - }); - - it("Edit Objective and move to other quarter", - () => { - overviewPage.addObjective() - .fillObjectiveTitle("Move to another quarter on edit") - .submit(); - - overviewPage - .getObjectiveByNameAndState("Move to another quarter on edit", - "ongoing") - .findByTestId("three-dot-menu") - .click(); - - overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); - ObjectiveDialog.do() - .selectQuarter("3") - .submit(); - - cy.contains("Move to another quarter on edit") - .should("not.exist"); - - overviewPage.visitNextQuarter(); - cy.contains("Move to another quarter on edit"); - }); - }); - - describe("tests via keyboard", - () => { - it("Open objective aside via enter", - () => { - cy.getByTestId("objective") - .first() - .find("[tabindex]") - .first() - .focus(); - cy.realPress("Enter"); - cy.url() - .should("include", - "objective"); - }); - }); + it("Cancel Ongoing objective back to draft state", () => { + overviewPage.addObjective() + .fillObjectiveTitle("This objective will be returned to draft state") + .submit(); + + overviewPage + .getObjectiveByNameAndState("This objective will be returned to draft state", "ongoing") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective als Draft speichern"); + + ConfirmDialog.do() + .checkTitle("Objective als Draft speichern") + .checkDescription("Soll dieses Objective als Draft gespeichert werden?") + .submit(); + + overviewPage + .getObjectiveByNameAndState("This objective will be returned to draft state", "draft") + .should("exist"); + }); + + it("Ongoing objective back to draft state", () => { + overviewPage + .addObjective() + .fillObjectiveTitle("Putting this objective back to draft state will be canceled") + .submit(); + + overviewPage + .getObjectiveByNameAndState("Putting this objective back to draft state will be canceled", "ongoing") + .findByTestId("three-dot-menu") + .click(); + overviewPage.selectFromThreeDotMenu("Objective als Draft speichern"); + + ConfirmDialog.do() + .checkTitle("Objective als Draft speichern") + .checkDescription("Soll dieses Objective als Draft gespeichert werden?") + .cancel(); + + overviewPage + .getObjectiveByNameAndState("Putting this objective back to draft state will be canceled", "ongoing") + .should("exist"); + }); + + it("Search for Objective", () => { + overviewPage.addObjective() + .fillObjectiveTitle("Search after this objective") + .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"); + + cy.scrollTo(0, 0); + cy.wait(500); + + 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.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.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"); + }); + + it("Create Objective in other quarter", () => { + overviewPage.addObjective() + .fillObjectiveTitle("Objective in quarter 3") + .selectQuarter("3") + .submit(); + + cy.contains("Objective in quarter 3") + .should("not.exist"); + + overviewPage.visitNextQuarter(); + + cy.contains("Objective in quarter 3"); + }); + + it("Edit Objective and move to other quarter", () => { + overviewPage.addObjective() + .fillObjectiveTitle("Move to another quarter on edit") + .submit(); + + overviewPage + .getObjectiveByNameAndState("Move to another quarter on edit", "ongoing") + .findByTestId("three-dot-menu") + .click(); + + overviewPage.selectFromThreeDotMenu("Objective bearbeiten"); + ObjectiveDialog.do() + .selectQuarter("3") + .submit(); + + cy.contains("Move to another quarter on edit") + .should("not.exist"); + + overviewPage.visitNextQuarter(); + cy.contains("Move to another quarter on edit"); + }); + }); + + describe("tests via keyboard", () => { + it("Open objective aside via enter", () => { + cy.getByTestId("objective") + .first() + .find("[tabindex]") + .first() + .focus(); + cy.realPress("Enter"); + cy.url() + .should("include", "objective"); + }); }); +}); diff --git a/frontend/cypress/e2e/overview.cy.ts b/frontend/cypress/e2e/overview.cy.ts index 3da0d36f41..bd390d73cd 100644 --- a/frontend/cypress/e2e/overview.cy.ts +++ b/frontend/cypress/e2e/overview.cy.ts @@ -1,52 +1,44 @@ import * as users from "../fixtures/users.json"; import FilterHelper from "../support/helper/dom-helper/filterHelper"; -describe("OKR Overview", - () => { - beforeEach(() => { - cy.loginAsUser(users.gl); - }); +describe("OKR Overview", () => { + beforeEach(() => { + cy.loginAsUser(users.gl); + }); - it("should have the current quarter with label Aktuell", - () => { - cy.getByTestId("quarterFilter") - .contains("Aktuell"); - }); + it("should have the current quarter with label 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.³" - ]; - 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); - }); + it("Check order of teams", () => { + 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); }); + }); - 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"); - }); + 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"); }); +}); diff --git a/frontend/cypress/e2e/routing.cy.ts b/frontend/cypress/e2e/routing.cy.ts index 651874ed9a..41196d2372 100644 --- a/frontend/cypress/e2e/routing.cy.ts +++ b/frontend/cypress/e2e/routing.cy.ts @@ -2,47 +2,40 @@ import * as users from "../fixtures/users.json"; import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import TeammanagementPage from "../support/helper/dom-helper/pages/teammanagementPage"; -describe("Routing", - () => { - beforeEach(() => { - cy.loginAsUser(users.gl); - }); +describe("Routing", () => { + beforeEach(() => { + cy.loginAsUser(users.gl); + }); - describe("Route via url", - () => { - it("should route to overview", - () => { - // Visit autocalls the validatePage method - CyOverviewPage.do() - .visitViaURL(); - }); + describe("Route via url", () => { + it("should route to overview", () => { + // Visit autocalls the validatePage method + CyOverviewPage.do() + .visitViaURL(); + }); - it("should route to teammanagement", - () => { - // Visit autocalls the validatePage method - TeammanagementPage.do() - .visitViaURL(); - }); + it("should route to teammanagement", () => { + // Visit autocalls the validatePage method + TeammanagementPage.do() + .visitViaURL(); + }); - it("should route from overview to team management ", - () => { - CyOverviewPage.do() - .visitViaURL() - .visitTeammanagement(); - }); + it("should route from overview to team management ", () => { + CyOverviewPage.do() + .visitViaURL() + .visitTeammanagement(); + }); - it("should route from team management to Overview via back button", - () => { - TeammanagementPage.do() - .visitViaURL() - .backToOverview(); - }); + it("should route from team management to Overview via back button", () => { + TeammanagementPage.do() + .visitViaURL() + .backToOverview(); + }); - it("should route from team management to Overview via logo", - () => { - TeammanagementPage.do() - .visitViaURL() - .visitOverview(); - }); - }); + it("should route from team management to Overview via logo", () => { + TeammanagementPage.do() + .visitViaURL() + .visitOverview(); + }); }); +}); diff --git a/frontend/cypress/e2e/scoring.cy.ts b/frontend/cypress/e2e/scoring.cy.ts index 9d524a83a7..fc3972091a 100644 --- a/frontend/cypress/e2e/scoring.cy.ts +++ b/frontend/cypress/e2e/scoring.cy.ts @@ -4,136 +4,112 @@ import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import { Unit } from "../../src/app/shared/types/enums/Unit"; import KeyResultDetailPage from "../support/helper/dom-helper/pages/keyResultDetailPage"; -describe("Scoring component e2e tests", - () => { - let overviewPage = new CyOverviewPage(); - let keyresultDetailPage = new KeyResultDetailPage(); +describe("Scoring component e2e tests", () => { + let overviewPage = new CyOverviewPage(); + let keyresultDetailPage = new KeyResultDetailPage(); - beforeEach(() => { - overviewPage = new CyOverviewPage(); - keyresultDetailPage = new KeyResultDetailPage(); - cy.loginAsUser(users.gl); - }); + beforeEach(() => { + overviewPage = new CyOverviewPage(); + keyresultDetailPage = new KeyResultDetailPage(); + cy.loginAsUser(users.gl); + }); - [ - [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 - ); - const percentage = getPercentageMetric(baseline, - stretchgoal, - value); - cy.validateScoring(false, - percentage); - cy.get(".keyResult-detail-attribute-show") - .contains("Aktuell") - .parent() - .not(":contains(!)") - .should("have.css", - "border-color") - .and("not.equal", - "rgb(186, 56, 56)"); + [ + [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 + ); + const percentage = getPercentageMetric(baseline, stretchgoal, value); + cy.validateScoring(false, percentage); + cy.get(".keyResult-detail-attribute-show") + .contains("Aktuell") + .parent() + .not(":contains(!)") + .should("have.css", "border-color") + .and("not.equal", "rgb(186, 56, 56)"); - keyresultDetailPage.close(); - cy.validateScoring(true, - percentage); + keyresultDetailPage.close(); + cy.validateScoring(true, percentage); - overviewPage - .getKeyResultByName(`Metric kr with check-in value ${value}`) - .not(":contains(*[class=\"scoring-error-badge\"])"); - }); + overviewPage + .getKeyResultByName(`Metric kr with check-in value ${value}`) + .not(":contains(*[class=\"scoring-error-badge\"])"); }); + }); - [[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 - ); - cy.validateScoring(false, - 0); - cy.get(".keyResult-detail-attribute-show") - .contains("Aktuell") - .parent() - .contains("!") - .should("have.css", - "border-color") - .and("equal", - "rgb(186, 56, 56)"); + [[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 + ); + cy.validateScoring(false, 0); + cy.get(".keyResult-detail-attribute-show") + .contains("Aktuell") + .parent() + .contains("!") + .should("have.css", "border-color") + .and("equal", "rgb(186, 56, 56)"); - keyresultDetailPage.close(); - cy.validateScoring(true, - 0); + 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]) => { - it("Create ordinal checkin and validate value of scoring component", - () => { - overviewPage - .addKeyResult() - .fillKeyResultTitle("Ordinal scoring keyresult") - .withOrdinalValues("My commit zone", - "My target zone", - "My stretch goal") - .checkForDialogTextOrdinal() - .fillKeyResultDescription("This is my description") - .submit(); + [ + ["fail"], + ["commit"], + ["target"], + ["stretch"] + ].forEach(([zoneName]) => { + it("Create ordinal checkin and validate value of scoring component", () => { + overviewPage + .addKeyResult() + .fillKeyResultTitle("Ordinal scoring keyresult") + .withOrdinalValues("My commit zone", "My target zone", "My stretch goal") + .checkForDialogTextOrdinal() + .fillKeyResultDescription("This is my description") + .submit(); - keyresultDetailPage - .visit("Ordinal scoring keyresult") - .createCheckIn() - .selectOrdinalCheckInZone(zoneName as "fail" | "commit" | "target" | "stretch") - .setCheckInConfidence(8) - .fillCheckInCommentary("Testveränderungen") - .fillCheckInInitiatives("Testmassnahmen") - .submit(); - const percentage = getPercentageOrdinal(zoneName); - cy.validateScoring(false, - percentage); - keyresultDetailPage.close(); - cy.validateScoring(true, - percentage); - }); + keyresultDetailPage + .visit("Ordinal scoring keyresult") + .createCheckIn() + .selectOrdinalCheckInZone(zoneName as "fail" | "commit" | "target" | "stretch") + .setCheckInConfidence(8) + .fillCheckInCommentary("Testveränderungen") + .fillCheckInInitiatives("Testmassnahmen") + .submit(); + const percentage = getPercentageOrdinal(zoneName); + cy.validateScoring(false, percentage); + keyresultDetailPage.close(); + cy.validateScoring(true, percentage); }); }); +}); function setupMetricKR ( name: string, baseline: number, stretchgoal: number, value: number @@ -141,9 +117,7 @@ function setupMetricKR ( CyOverviewPage.do() .addKeyResult() .fillKeyResultTitle(name) - .withMetricValues(Unit.PERCENT, - baseline.toString(), - stretchgoal.toString()) + .withMetricValues(Unit.PERCENT, baseline.toString(), stretchgoal.toString()) .submit(); KeyResultDetailPage.do() .visit(name) diff --git a/frontend/cypress/e2e/tab.cy.ts b/frontend/cypress/e2e/tab.cy.ts index 3964274c1b..e203824061 100644 --- a/frontend/cypress/e2e/tab.cy.ts +++ b/frontend/cypress/e2e/tab.cy.ts @@ -3,473 +3,368 @@ import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import { Unit } from "../../src/app/shared/types/enums/Unit"; import KeyResultDetailPage from "../support/helper/dom-helper/pages/keyResultDetailPage"; -describe("Tab workflow tests", - () => { - let overviewPage = new CyOverviewPage(); - beforeEach(() => { - cy.loginAsUser(users.gl); - overviewPage = new CyOverviewPage(); - overviewPage.elements.logo() - .parent() - .focus(); - }); +describe("Tab workflow tests", () => { + let overviewPage = new CyOverviewPage(); + beforeEach(() => { + cy.loginAsUser(users.gl); + overviewPage = new CyOverviewPage(); + 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) { - cy.tabForwardUntil(`[data-testId="${testId}"]`); - focusedShouldHaveTestId(testId); - if (text) { - cy.focused() - .contains(text); - } + function tabAndCheck (testId: string, text?: string) { + cy.tabForwardUntil(`[data-testId="${testId}"]`); + focusedShouldHaveTestId(testId); + if (text) { + cy.focused() + .contains(text); } + } - it("should be able to tab to header items", - () => { - tabAndCheck("team-management", - "Teamverwaltung"); - tabAndCheck("help-button", - "Hilfe"); - tabAndCheck("user-options", - "Jaya Norris"); - cy.realPress("Enter"); - cy.pressUntilContains("Logout", - "ArrowDown"); - focusedShouldHaveTestId("logout"); - cy.realPress("Escape"); - tabAndCheck("quarterFilter", - "GJ"); - tabAndCheck("objectiveSearch"); - cy.tabForward(); - cy.focused() - .children("img") - .first() - .should("have.attr", - "src") - .and("match", - /search-icon.svg/); - cy.tabForward(); - cy.focused() - .contains("Alle"); - }); + it("should be able to tab to header items", () => { + tabAndCheck("team-management", "Teamverwaltung"); + tabAndCheck("help-button", "Hilfe"); + tabAndCheck("user-options", "Jaya Norris"); + cy.realPress("Enter"); + cy.pressUntilContains("Logout", "ArrowDown"); + focusedShouldHaveTestId("logout"); + cy.realPress("Escape"); + tabAndCheck("quarterFilter", "GJ"); + tabAndCheck("objectiveSearch"); + cy.tabForward(); + cy.focused() + .children("img") + .first() + .should("have.attr", "src") + .and("match", /search-icon.svg/); + cy.tabForward(); + cy.focused() + .contains("Alle"); + }); - it("should be able to tab to overview items", - () => { - tabAndCheck("team-management", - "Teamverwaltung"); - tabAndCheck("add-objective", - "Objective hinzufügen"); - tabAndCheck("objective"); - tabAndCheck("three-dot-menu"); - tabAndCheck("key-result"); - tabAndCheck("add-keyResult", - "Key Result hinzufügen"); - }); + it("should be able to tab to overview items", () => { + tabAndCheck("team-management", "Teamverwaltung"); + tabAndCheck("add-objective", "Objective hinzufügen"); + tabAndCheck("objective"); + tabAndCheck("three-dot-menu"); + tabAndCheck("key-result"); + tabAndCheck("add-keyResult", "Key Result hinzufügen"); + }); - describe("Objective", - () => { - it("should be able to tab objective dialog", - () => { - tabAndCheck("add-objective", - "Objective hinzufügen"); - cy.realPress("Enter"); - cy.contains("h2", - "Objective für"); - tabAndCheck("title"); - cy.realType("title"); - tabAndCheck("description"); - cy.realType("description"); - tabAndCheck("quarterSelect"); - tabAndCheck("save-draft"); - tabAndCheck("save"); - tabAndCheck("cancel"); - }); + describe("Objective", () => { + it("should be able to tab objective dialog", () => { + tabAndCheck("add-objective", "Objective hinzufügen"); + cy.realPress("Enter"); + cy.contains("h2", "Objective für"); + tabAndCheck("title"); + cy.realType("title"); + tabAndCheck("description"); + cy.realType("description"); + tabAndCheck("quarterSelect"); + tabAndCheck("save-draft"); + tabAndCheck("save"); + tabAndCheck("cancel"); + }); - it("should focus three dot menu after edit objective", - () => { - overviewPage.getObjectiveByState("ongoing") - .focus(); - tabAndCheck("three-dot-menu"); - cy.realPress("Enter"); - tabToThreeDotMenuOption("Objective bearbeiten"); - cy.contains("h2", - "Objective von"); - tabAndCheck("title"); - cy.realType("title"); - tabAndCheck("description"); - cy.realType("description"); - tabAndCheck("quarterSelect"); - tabAndCheck("cancel", - "Abbrechen"); - tabAndCheck("save", - "Speichern"); - cy.realPress("Enter"); - focusedShouldHaveTestId("three-dot-menu"); - }); + it("should focus three dot menu after edit objective", () => { + overviewPage.getObjectiveByState("ongoing") + .focus(); + tabAndCheck("three-dot-menu"); + cy.realPress("Enter"); + tabToThreeDotMenuOption("Objective bearbeiten"); + cy.contains("h2", "Objective von"); + tabAndCheck("title"); + cy.realType("title"); + tabAndCheck("description"); + cy.realType("description"); + tabAndCheck("quarterSelect"); + tabAndCheck("cancel", "Abbrechen"); + tabAndCheck("save", "Speichern"); + cy.realPress("Enter"); + focusedShouldHaveTestId("three-dot-menu"); + }); - it("should be able to complete and reopen objective", - () => { - 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.realPress("Enter"); - cy.tabForward(); - cy.focused() - .contains("Objective nicht erreicht"); - tabAndCheck("completeComment"); - tabAndCheck("cancel", - "Abbrechen"); - tabAndCheck("submit", - "Objective abschliessen"); - cy.realPress("Enter"); + it("should be able to complete and reopen objective", () => { + 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.realPress("Enter"); + cy.tabForward(); + cy.focused() + .contains("Objective nicht erreicht"); + tabAndCheck("completeComment"); + tabAndCheck("cancel", "Abbrechen"); + tabAndCheck("submit", "Objective abschliessen"); + cy.realPress("Enter"); - focusedShouldHaveTestId("three-dot-menu"); - cy.realPress("Enter"); + focusedShouldHaveTestId("three-dot-menu"); + cy.realPress("Enter"); - tabToThreeDotMenuOption("Objective wiedereröffnen"); - cy.contains("h2", - "Objective wiedereröffnen"); - focusedShouldHaveTestId("close-dialog"); - cy.contains("Soll dieses Objective wiedereröffnet werden?"); - tabAndCheck("confirm-no", - "Nein"); - tabAndCheck("confirm-yes", - "Ja"); - cy.realPress("Enter"); - focusedShouldHaveTestId("three-dot-menu"); - }); + tabToThreeDotMenuOption("Objective wiedereröffnen"); + cy.contains("h2", "Objective wiedereröffnen"); + focusedShouldHaveTestId("close-dialog"); + cy.contains("Soll dieses Objective wiedereröffnet werden?"); + tabAndCheck("confirm-no", "Nein"); + tabAndCheck("confirm-yes", "Ja"); + cy.realPress("Enter"); + focusedShouldHaveTestId("three-dot-menu"); + }); - it("should be able to set objective to draft and publish it", - () => { - overviewPage.getObjectiveByState("ongoing") - .focus(); - tabAndCheck("three-dot-menu"); - cy.realPress("Enter"); - tabToThreeDotMenuOption("Objective als Draft speichern"); - cy.contains("h2", - "Objective als Draft speichern"); - focusedShouldHaveTestId("close-dialog"); - cy.contains("Soll dieses Objective als Draft gespeichert werden?"); - tabAndCheck("confirm-no", - "Nein"); - tabAndCheck("confirm-yes", - "Ja"); - cy.realPress("Enter"); + it("should be able to set objective to draft and publish it", () => { + overviewPage.getObjectiveByState("ongoing") + .focus(); + tabAndCheck("three-dot-menu"); + cy.realPress("Enter"); + tabToThreeDotMenuOption("Objective als Draft speichern"); + cy.contains("h2", "Objective als Draft speichern"); + focusedShouldHaveTestId("close-dialog"); + cy.contains("Soll dieses Objective als Draft gespeichert werden?"); + tabAndCheck("confirm-no", "Nein"); + tabAndCheck("confirm-yes", "Ja"); + cy.realPress("Enter"); - focusedShouldHaveTestId("three-dot-menu"); - cy.realPress("Enter"); + focusedShouldHaveTestId("three-dot-menu"); + cy.realPress("Enter"); - tabToThreeDotMenuOption("Objective veröffentlichen"); - cy.contains("h2", - "Objective veröffentlichen"); - focusedShouldHaveTestId("close-dialog"); - cy.contains("Soll dieses Objective veröffentlicht werden?"); - tabAndCheck("confirm-no", - "Nein"); - tabAndCheck("confirm-yes", - "Ja"); - cy.realPress("Enter"); - focusedShouldHaveTestId("three-dot-menu"); - }); + tabToThreeDotMenuOption("Objective veröffentlichen"); + cy.contains("h2", "Objective veröffentlichen"); + focusedShouldHaveTestId("close-dialog"); + cy.contains("Soll dieses Objective veröffentlicht werden?"); + tabAndCheck("confirm-no", "Nein"); + tabAndCheck("confirm-yes", "Ja"); + cy.realPress("Enter"); + focusedShouldHaveTestId("three-dot-menu"); + }); - it("should be able to open objective detail view", - () => { - overviewPage.getObjectiveByState("ongoing") - .focus(); - cy.realPress("Enter") - .tabForward(); - focusedShouldHaveTestId("closeDrawer"); - tabAndCheck("add-keyResult-objective-detail", - "Key Result hinzufügen"); - tabAndCheck("edit-objective", - "Objective bearbeiten"); - }); - }); + it("should be able to open objective detail view", () => { + overviewPage.getObjectiveByState("ongoing") + .focus(); + cy.realPress("Enter") + .tabForward(); + focusedShouldHaveTestId("closeDrawer"); + tabAndCheck("add-keyResult-objective-detail", "Key Result hinzufügen"); + tabAndCheck("edit-objective", "Objective bearbeiten"); + }); + }); - describe("Keyresult & Check-In", - () => { - it("Should be able to tab Keyresult dialog", - () => { - tabAndCheck("add-keyResult", - "Key Result hinzufügen"); - cy.realPress("Enter"); - focusedShouldHaveTestId("close-dialog"); - tabAndCheck("titleInput"); - cy.focused() - .type("Title"); - tabAndCheck("unit"); - tabAndCheck("baseline"); - tabAndCheck("stretchGoal"); - tabAndCheck("ownerInput"); - tabAndCheck("descriptionInput"); - tabAndCheck("actionInput"); - tabAndCheck("add-action-plan-line", - "Weitere Action hinzufügen"); - tabAndCheck("ordinalTab", - "Ordinal"); - cy.realPress("Enter"); - tabAndCheck("commitZone"); - cy.focused() - .type("Commit"); - tabAndCheck("targetZone"); - cy.focused() - .type("Target"); - tabAndCheck("stretchZone"); - cy.focused() - .type("Stretch"); - tabAndCheck("submit", - "Speichern"); - tabAndCheck("saveAndNew", - "Speichern & Neu"); - tabAndCheck("cancel", - "Abbrechen"); - }); + describe("Keyresult & Check-In", () => { + it("Should be able to tab Keyresult dialog", () => { + tabAndCheck("add-keyResult", "Key Result hinzufügen"); + cy.realPress("Enter"); + focusedShouldHaveTestId("close-dialog"); + tabAndCheck("titleInput"); + cy.focused() + .type("Title"); + tabAndCheck("unit"); + tabAndCheck("baseline"); + tabAndCheck("stretchGoal"); + tabAndCheck("ownerInput"); + tabAndCheck("descriptionInput"); + tabAndCheck("actionInput"); + tabAndCheck("add-action-plan-line", "Weitere Action hinzufügen"); + tabAndCheck("ordinalTab", "Ordinal"); + cy.realPress("Enter"); + tabAndCheck("commitZone"); + cy.focused() + .type("Commit"); + tabAndCheck("targetZone"); + cy.focused() + .type("Target"); + tabAndCheck("stretchZone"); + 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(); - focusedShouldHaveTestId("close-drawer"); - tabAndCheck("show-all-checkins", - "Alle Check-ins anzeigen"); - cy.realPress("Enter"); - cy.contains("Check-in History"); - focusedShouldHaveTestId("close-dialog"); - tabAndCheck("edit-check-in"); - tabAndCheck("closeButton", - "Schliessen"); - cy.realPress("Enter"); - tabAndCheck("add-check-in", - "Check-in erfassen"); - tabAndCheck("edit-keyResult", - "Key Result bearbeiten"); - }); + it("Should tab keyresult detail view", () => { + 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"); + cy.contains("Check-in History"); + focusedShouldHaveTestId("close-dialog"); + tabAndCheck("edit-check-in"); + tabAndCheck("closeButton", "Schliessen"); + cy.realPress("Enter"); + tabAndCheck("add-check-in", "Check-in erfassen"); + tabAndCheck("edit-keyResult", "Key Result bearbeiten"); + }); - it("Should tab create-check-in metric", - () => { - overviewPage - .addOngoingKeyResult() - .fillKeyResultTitle("A metric Keyresult for tabbing tests") - .withMetricValues(Unit.CHF, - "10", - "100") - .submit(); - 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"); - tabAndCheck("initiatives"); - cy.contains("5/10"); - cy.tabForward(); - cy.realPress("ArrowLeft"); - cy.contains("4/10"); - tabAndCheck("submit-check-in", - "Check-in speichern"); - tabAndCheck("cancel", - "Abbrechen"); - }); + it("Should tab create-check-in metric", () => { + overviewPage + .addOngoingKeyResult() + .fillKeyResultTitle("A metric Keyresult for tabbing tests") + .withMetricValues(Unit.CHF, "10", "100") + .submit(); + 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"); + tabAndCheck("initiatives"); + cy.contains("5/10"); + cy.tabForward(); + cy.realPress("ArrowLeft"); + cy.contains("4/10"); + tabAndCheck("submit-check-in", "Check-in speichern"); + tabAndCheck("cancel", "Abbrechen"); + }); - it("Should tab create-check-in ordinal", - () => { - overviewPage - .addOngoingKeyResult() - .fillKeyResultTitle("A ordinal Keyresult for tabbing tests") - .withOrdinalValues("Commit", - "Target", - "Stretch") - .submit(); - 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.realPress("ArrowDown"); - 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.realPress("ArrowDown"); - cy.focused() - .closest("mat-radio-button") - .should("have.attr", - "data-testId", - "stretch-radio"); - tabAndCheck("initiatives"); - cy.contains("5/10"); - cy.tabForward(); - cy.realPress("ArrowLeft"); - cy.contains("4/10"); - tabAndCheck("submit-check-in", - "Check-in speichern"); - tabAndCheck("cancel", - "Abbrechen"); - }); - }); + it("Should tab create-check-in ordinal", () => { + overviewPage + .addOngoingKeyResult() + .fillKeyResultTitle("A ordinal Keyresult for tabbing tests") + .withOrdinalValues("Commit", "Target", "Stretch") + .submit(); + 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.realPress("ArrowDown"); + 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.realPress("ArrowDown"); + cy.focused() + .closest("mat-radio-button") + .should("have.attr", "data-testId", "stretch-radio"); + tabAndCheck("initiatives"); + cy.contains("5/10"); + cy.tabForward(); + cy.realPress("ArrowLeft"); + cy.contains("4/10"); + tabAndCheck("submit-check-in", "Check-in speichern"); + tabAndCheck("cancel", "Abbrechen"); + }); + }); - describe("Team management", - () => { - it("Should tab team management", - () => { - tabAndCheck("team-management", - "Teamverwaltung"); - cy.realPress("Enter"); - tabAndCheck("routerLink-to-overview", - "Zurück zur OKR Übersicht"); - tabAndCheck("teamManagementSearch"); - tabAndCheck("add-team", - "Team erfassen"); - tabAndCheck("all-teams-selector", - "Alle Teams (4)"); - tabAndCheck("invite-member", - "Member registrieren"); - }); - it("Should tab create team", - () => { - 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"); - tabAndCheck("save", - "Speichern"); - tabAndCheck("cancel", - "Abbrechen"); - }); - it("Should tab register member", - () => { - cy.getByTestId("team-management") - .click(); - tabAndCheck("invite-member"); - cy.realPress("Enter"); - cy.contains("Member registrieren"); - focusedShouldHaveTestId("close-dialog"); - tabAndCheck("new-member-first-name"); - 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"); - 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.pressUntilContains("Alice Wunderland", - "Tab"); - cy.tabForward(); - cy.realPress("Enter"); - cy.tabForward(); - focusedShouldHaveTestId("close-drawer"); + describe("Team management", () => { + it("Should tab team management", () => { + tabAndCheck("team-management", "Teamverwaltung"); + cy.realPress("Enter"); + tabAndCheck("routerLink-to-overview", "Zurück zur OKR Übersicht"); + tabAndCheck("teamManagementSearch"); + tabAndCheck("add-team", "Team erfassen"); + tabAndCheck("all-teams-selector", "Alle Teams (4)"); + tabAndCheck("invite-member", "Member registrieren"); + }); + it("Should tab create team", () => { + 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"); + tabAndCheck("save", "Speichern"); + tabAndCheck("cancel", "Abbrechen"); + }); + it("Should tab register member", () => { + cy.getByTestId("team-management") + .click(); + tabAndCheck("invite-member"); + cy.realPress("Enter"); + cy.contains("Member registrieren"); + focusedShouldHaveTestId("close-dialog"); + tabAndCheck("new-member-first-name"); + 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"); + 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.pressUntilContains("Alice Wunderland", "Tab"); + cy.tabForward(); + cy.realPress("Enter"); + cy.tabForward(); + focusedShouldHaveTestId("close-drawer"); - // Field to toggle if user is OKR-Champion - cy.tabForward(); - 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"); + // Field to toggle if user is OKR-Champion + cy.tabForward(); + 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"); - // Field to edit role of assigned team - cy.tabForward(); - cy.focused() - .closest("app-puzzle-icon-button") - .should("have.attr", - "icon", - "edit.svg"); - cy.realPress("Enter"); - cy.tabForward(); - tabAndCheck("select-team-role", - "Team-Member"); + // Field to edit role of assigned team + cy.tabForward(); + 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"); + // Button to delete assigned team + cy.tabForward(); + cy.focused() + .closest("app-puzzle-icon-button") + .should("have.attr", "icon", "delete-icon.svg"); - // Button to add user to another team - tabAndCheck("add-user"); - cy.realPress("Enter"); - cy.tabForward(); - tabAndCheck("select-team-dropdown", - "Puzzle ITC"); - tabAndCheck("select-team-role", - "Team-Member"); - tabAndCheck("add-user-to-team-save", - "Hinzufügen"); - tabAndCheck("add-user-to-team-cancel", - "Abbrechen"); - }); - }); + // Button to add user to another team + tabAndCheck("add-user"); + cy.realPress("Enter"); + cy.tabForward(); + tabAndCheck("select-team-dropdown", "Puzzle ITC"); + tabAndCheck("select-team-role", "Team-Member"); + tabAndCheck("add-user-to-team-save", "Hinzufügen"); + tabAndCheck("add-user-to-team-cancel", "Abbrechen"); + }); }); +}); function tabToThreeDotMenuOption (name: string) { - cy.pressUntilContains(name, - "ArrowDown"); + cy.pressUntilContains(name, "ArrowDown"); cy.realPress("Enter"); } diff --git a/frontend/cypress/e2e/team.cy.ts b/frontend/cypress/e2e/team.cy.ts index ff6301a900..f4dc510ce0 100644 --- a/frontend/cypress/e2e/team.cy.ts +++ b/frontend/cypress/e2e/team.cy.ts @@ -3,161 +3,145 @@ import FilterHelper from "../support/helper/dom-helper/filterHelper"; import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import TeammanagementPage from "../support/helper/dom-helper/pages/teammanagementPage"; -describe("OKR team e2e tests", - () => { - describe("tests via click", - () => { - beforeEach(() => { - cy.loginAsUser(users.gl); - CyOverviewPage.do() - .visitCurrentQuarter(); - }); - - it("Should select teams from teamfilter", - () => { - const filterHelper = FilterHelper.do() - .optionShouldBeSelected("Puzzle ITC") - .optionShouldBeSelected("LoremIpsum") - .optionShouldNotBeSelected("Alle") - .optionShouldNotBeSelected("/BBT") - .optionShouldNotBeSelected("we are cube"); - - filterHelper - .toggleOption("Alle") - .optionShouldBeSelected("Alle", - false) - .optionShouldBeSelected("/BBT") - .optionShouldBeSelected("Puzzle ITC") - .optionShouldBeSelected("LoremIpsum") - .optionShouldBeSelected("we are cube"); - - filterHelper - .toggleOption("/BBT") - .optionShouldBeSelected("/BBT") - .optionShouldNotBeSelected("Alle") - .optionShouldNotBeSelected("Puzzle ITC") - .optionShouldNotBeSelected("LoremIpsum") - .optionShouldNotBeSelected("we are cube"); - - filterHelper - .toggleOption("Puzzle ITC") - .optionShouldBeSelected("/BBT") - .optionShouldNotBeSelected("Alle") - .optionShouldBeSelected("Puzzle ITC") - .optionShouldNotBeSelected("LoremIpsum") - .optionShouldNotBeSelected("we are cube"); - }); - - it("Deselect all teams from filter will display text on overview", - () => { - const filterHelper = FilterHelper.do() - .optionShouldBeSelected("Puzzle ITC") - .optionShouldBeSelected("LoremIpsum") - .optionShouldNotBeSelected("Alle") - .optionShouldNotBeSelected("/BBT") - .optionShouldNotBeSelected("we are cube"); - - filterHelper.toggleOption("Puzzle ITC") - .toggleOption("LoremIpsum"); - - cy.contains("Kein Team ausgewählt"); - }); - - it("URL changes to the selected teams", - () => { - const filterHelper = FilterHelper.do() - .optionShouldBeSelected("Puzzle ITC") - .optionShouldBeSelected("LoremIpsum") - .optionShouldNotBeSelected("Alle") - .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="); - }); - - it("Select teams by url", - () => { - cy.url() - .should("not.include", - "teams"); - - cy.visit("/?quarter=2&teams=4,5,8"); - FilterHelper.do() - .optionShouldNotBeSelected("Alle") - .optionShouldBeSelected("/BBT") - .optionShouldBeSelected("Puzzle ITC") - .optionShouldBeSelected("we are cube") - .optionShouldNotBeSelected("LoremIpsum"); - }); - - it("should display less button on mobile header", - () => { - 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(); - cy.wait("@addTeam"); - cy.contains("Y-Team"); - teammanagementPage.addTeam() - .fillName("Z-Team") - .submit(); - cy.wait("@addTeam"); - cy.contains("Z-Team"); - - teammanagementPage.visitOverview(); - - // set viewport to < 768 to trigger mobile header - cy.viewport(767, - 1200); - - 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"); - - teammanagementPage.deleteTeam("X-Team") - .submit(); - cy.wait("@deleteTeam"); - - teammanagementPage.deleteTeam("Y-Team") - .submit(); - cy.wait("@deleteTeam"); - - teammanagementPage.deleteTeam("Z-Team") - .submit(); - cy.wait("@deleteTeam"); - }); - }); +describe("OKR team e2e tests", () => { + describe("tests via click", () => { + beforeEach(() => { + cy.loginAsUser(users.gl); + CyOverviewPage.do() + .visitCurrentQuarter(); + }); + + it("Should select teams from teamfilter", () => { + const filterHelper = FilterHelper.do() + .optionShouldBeSelected("Puzzle ITC") + .optionShouldBeSelected("LoremIpsum") + .optionShouldNotBeSelected("Alle") + .optionShouldNotBeSelected("/BBT") + .optionShouldNotBeSelected("we are cube"); + + filterHelper + .toggleOption("Alle") + .optionShouldBeSelected("Alle", false) + .optionShouldBeSelected("/BBT") + .optionShouldBeSelected("Puzzle ITC") + .optionShouldBeSelected("LoremIpsum") + .optionShouldBeSelected("we are cube"); + + filterHelper + .toggleOption("/BBT") + .optionShouldBeSelected("/BBT") + .optionShouldNotBeSelected("Alle") + .optionShouldNotBeSelected("Puzzle ITC") + .optionShouldNotBeSelected("LoremIpsum") + .optionShouldNotBeSelected("we are cube"); + + filterHelper + .toggleOption("Puzzle ITC") + .optionShouldBeSelected("/BBT") + .optionShouldNotBeSelected("Alle") + .optionShouldBeSelected("Puzzle ITC") + .optionShouldNotBeSelected("LoremIpsum") + .optionShouldNotBeSelected("we are cube"); + }); + + it("Deselect all teams from filter will display text on overview", () => { + const filterHelper = FilterHelper.do() + .optionShouldBeSelected("Puzzle ITC") + .optionShouldBeSelected("LoremIpsum") + .optionShouldNotBeSelected("Alle") + .optionShouldNotBeSelected("/BBT") + .optionShouldNotBeSelected("we are cube"); + + filterHelper.toggleOption("Puzzle ITC") + .toggleOption("LoremIpsum"); + + cy.contains("Kein Team ausgewählt"); + }); + + it("URL changes to the selected teams", () => { + const filterHelper = FilterHelper.do() + .optionShouldBeSelected("Puzzle ITC") + .optionShouldBeSelected("LoremIpsum") + .optionShouldNotBeSelected("Alle") + .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="); + }); + + it("Select teams by url", () => { + cy.url() + .should("not.include", "teams"); + + cy.visit("/?quarter=2&teams=4,5,8"); + FilterHelper.do() + .optionShouldNotBeSelected("Alle") + .optionShouldBeSelected("/BBT") + .optionShouldBeSelected("Puzzle ITC") + .optionShouldBeSelected("we are cube") + .optionShouldNotBeSelected("LoremIpsum"); + }); + + it("should display less button on mobile header", () => { + 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(); + cy.wait("@addTeam"); + cy.contains("Y-Team"); + teammanagementPage.addTeam() + .fillName("Z-Team") + .submit(); + cy.wait("@addTeam"); + cy.contains("Z-Team"); + + teammanagementPage.visitOverview(); + + // set viewport to < 768 to trigger mobile header + cy.viewport(767, 1200); + + 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"); + + teammanagementPage.deleteTeam("X-Team") + .submit(); + cy.wait("@deleteTeam"); + + teammanagementPage.deleteTeam("Y-Team") + .submit(); + cy.wait("@deleteTeam"); + + 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 79b940c222..822a9e27f8 100644 --- a/frontend/cypress/e2e/teammanagement.cy.ts +++ b/frontend/cypress/e2e/teammanagement.cy.ts @@ -6,617 +6,561 @@ import CyOverviewPage from "../support/helper/dom-helper/pages/overviewPage"; import InviteMembersDialog from "../support/helper/dom-helper/dialogs/inviteMembersDialog"; import FilterHelper from "../support/helper/dom-helper/filterHelper"; -describe("Team management tests", - () => { - const teamName = uniqueSuffix("New Team"); - const nameEsha = users.bl.name; - - describe("Routing to overview", - () => { - beforeEach(() => { - cy.loginAsUser(users.gl); - }); +describe("Team management tests", () => { + const teamName = uniqueSuffix("New Team"); + const nameEsha = users.bl.name; + + describe("Routing to overview", () => { + beforeEach(() => { + cy.loginAsUser(users.gl); + }); + + it("should preserve team filter", () => { + CyOverviewPage.do() + .visitViaURL(); + FilterHelper.do() + .toggleOption("/BBT") + .toggleOption("Puzzle ITC"); + checkTeamsSelected(); + CyOverviewPage.do() + .visitTeammanagement(); + checkTeamsSelected(); + TeammanagementPage.do() + .backToOverview(); + checkTeamsSelected(); + CyOverviewPage.do() + .visitTeammanagement(); + TeammanagementPage.do() + .visitOverview(); + checkTeamsSelected(); + }); + + function checkTeamsSelected () { + FilterHelper.do() + .optionShouldBeSelected("LoremIpsum") + .optionShouldBeSelected("/BBT"); + } + }); - it("should preserve team filter", - () => { - CyOverviewPage.do() - .visitViaURL(); - FilterHelper.do() - .toggleOption("/BBT") - .toggleOption("Puzzle ITC"); - checkTeamsSelected(); - CyOverviewPage.do() - .visitTeammanagement(); - checkTeamsSelected(); - TeammanagementPage.do() - .backToOverview(); - checkTeamsSelected(); - CyOverviewPage.do() - .visitTeammanagement(); - TeammanagementPage.do() - .visitOverview(); - checkTeamsSelected(); - }); - - function checkTeamsSelected () { - FilterHelper.do() - .optionShouldBeSelected("LoremIpsum") - .optionShouldBeSelected("/BBT"); - } + describe("As GL", () => { + let teammanagementPage: TeammanagementPage; + before(() => { + // login as bl to ensure this user exists in database + cy.loginAsUser(users.bl); + cy.getByTestId("user-name") + .click(); + cy.getByTestId("logout") + .click(); + }); + + beforeEach(() => { + cy.loginAsUser(users.gl); + teammanagementPage = TeammanagementPage.do() + .visitViaURL(); + }); + + it("Create team", () => { + cy.intercept("POST", "**/teams") + .as("addTeam"); + + 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.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") + .checkDescription(`Möchtest du Jaya Norris wirklich aus dem Team '${teamName}' entfernen?`) + .submit(); + + cy.wait("@removeUser"); + + 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.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() + .checkTitle("Mitglied entfernen") + .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); + }); + }); + + it("Edit team", () => { + cy.intercept("GET", "**/users") + .as("getUsers"); + cy.intercept("GET", "**/teams") + .as("getTeams"); + + cy.get("app-team-list .mat-mdc-list-item") + .contains("LoremIpsum") + .click(); + editTeamNameAndTest("IpsumLorem"); + cy.visit("team-management"); + + cy.wait(["@getUsers", + "@getTeams"]); + + 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(); + editTeamNameAndTest("LoremIpsum"); + }); + + it("Delete team", () => { + // Click delete button and cancel + teammanagementPage.deleteTeam(teamName) + .cancel(); + + // try again and confirm dialog + teammanagementPage.deleteTeam(teamName) + .submit(); + }); + + describe("Search", () => { + it("Search user", () => { + teammanagementPage.elements + .teamSearch() + .fill("pa") + .shouldHaveOption("Paco Eggimann (peggimann@puzzle.ch)") + .shouldHaveOption("Paco Egiman (egiman@puzzle.ch)") + .selectOption("Robin Papierer (papierer@puzzle.ch)"); + + cy.contains("app-member-detail h2", "Robin Papierer"); }); - describe("As GL", - () => { - let teammanagementPage: TeammanagementPage; - before(() => { - // login as bl to ensure this user exists in database - cy.loginAsUser(users.bl); - cy.getByTestId("user-name") - .click(); - cy.getByTestId("logout") - .click(); - }); + it("Search team", () => { + teammanagementPage.elements.teamSearch() + .fill("we are") + .selectOption("we are cube.³"); - beforeEach(() => { - cy.loginAsUser(users.gl); - teammanagementPage = TeammanagementPage.do() - .visitViaURL(); - }); + cy.contains("app-member-list h2", "we are cube.³"); + }); - it("Create team", - () => { - cy.intercept("POST", - "**/teams") - .as("addTeam"); - - 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.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") - .checkDescription(`Möchtest du Jaya Norris wirklich aus dem Team '${teamName}' entfernen?`) - .submit(); - - cy.wait("@removeUser"); - - 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.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() - .checkTitle("Mitglied entfernen") - .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); - }); - }); - - it("Edit team", - () => { - cy.intercept("GET", - "**/users") - .as("getUsers"); - cy.intercept("GET", - "**/teams") - .as("getTeams"); - - cy.get("app-team-list .mat-mdc-list-item") - .contains("LoremIpsum") - .click(); - editTeamNameAndTest("IpsumLorem"); - cy.visit("team-management"); - - cy.wait(["@getUsers", - "@getTeams"]); - - 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(); - editTeamNameAndTest("LoremIpsum"); - }); - - it("Delete team", - () => { - // Click delete button and cancel - teammanagementPage.deleteTeam(teamName) - .cancel(); - - // try again and confirm dialog - teammanagementPage.deleteTeam(teamName) - .submit(); - }); - - describe("Search", - () => { - it("Search user", - () => { - teammanagementPage.elements - .teamSearch() - .fill("pa") - .shouldHaveOption("Paco Eggimann (peggimann@puzzle.ch)") - .shouldHaveOption("Paco Egiman (egiman@puzzle.ch)") - .selectOption("Robin Papierer (papierer@puzzle.ch)"); - - cy.contains("app-member-detail h2", - "Robin Papierer"); - }); - - it("Search team", - () => { - teammanagementPage.elements.teamSearch() - .fill("we are") - .selectOption("we are cube.³"); - - cy.contains("app-member-list h2", - "we are cube.³"); - }); - - it("Search mixed", - () => { - teammanagementPage.elements - .teamSearch() - .fill("puz") - .shouldHaveLabel("Members") - .shouldHaveLabel("Teams") - .shouldHaveOption("Paco Eggimann (peggimann@puzzle.ch)") - .shouldHaveOption("Paco Egiman (egiman@puzzle.ch)") - .shouldHaveOption("Robin Papierer (papierer@puzzle.ch)") - .shouldHaveOption("Puzzle ITC"); - }); - }); - - describe("invite members", - () => { - it("invite two members", - () => { - teammanagementPage.elements.registerMember() - .click(); - const firstNames = InviteMembersDialog.do() - .enterUser("Claudia", - "Meier", - "claudia.meier@test.ch") - .addAnotherUser() - .enterUser("Stefan", - "Schmidt", - "stefan.schmidt@test.ch") - .addAnotherUser() - .getFirstNames(); - - // test error messages - fillOutNewUser("Robin", - "", - "papierer"); - cy.getByTestId("invite") - .click(); - cy.contains("Angabe benötigt"); - cy.contains("E-Mail ungültig"); - cy.getByTestId("email-col_2") - .focus(); - cy.realType("@puzzle.ch"); - 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"); - - // delete last entry - cy.tabForward(); - cy.tabForward(); - cy.realPress("Enter"); - cy.contains("papiererr@puzzle.ch") - .should("not.exist"); - - // save - 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"); - - 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.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(); - - // team BBT should not be in list anymore - 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.wait("@updateEsha"); - // check table - checkRolesForEsha(); - - closeOverlay(); - - let foundEsha = false; - cy.get("app-member-list tbody tr") - .each(($row) => { - const usernameCell = $row.find("td:nth-child(2)"); - if (usernameCell.text() - .trim() === nameEsha) { - foundEsha = true; - 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; - }) - .then(() => { - expect(foundEsha).to.equal(true); - }); - }); - - 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.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"); - - // test click outside of element - 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"); - }); + it("Search mixed", () => { + teammanagementPage.elements + .teamSearch() + .fill("puz") + .shouldHaveLabel("Members") + .shouldHaveLabel("Teams") + .shouldHaveOption("Paco Eggimann (peggimann@puzzle.ch)") + .shouldHaveOption("Paco Egiman (egiman@puzzle.ch)") + .shouldHaveOption("Robin Papierer (papierer@puzzle.ch)") + .shouldHaveOption("Puzzle ITC"); }); + }); + + describe("invite members", () => { + it("invite two members", () => { + teammanagementPage.elements.registerMember() + .click(); + const firstNames = InviteMembersDialog.do() + .enterUser("Claudia", "Meier", "claudia.meier@test.ch") + .addAnotherUser() + .enterUser("Stefan", "Schmidt", "stefan.schmidt@test.ch") + .addAnotherUser() + .getFirstNames(); + + // test error messages + fillOutNewUser("Robin", "", "papierer"); + cy.getByTestId("invite") + .click(); + cy.contains("Angabe benötigt"); + cy.contains("E-Mail ungültig"); + cy.getByTestId("email-col_2") + .focus(); + cy.realType("@puzzle.ch"); + 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"); + + // delete last entry + cy.tabForward(); + cy.tabForward(); + cy.realPress("Enter"); + cy.contains("papiererr@puzzle.ch") + .should("not.exist"); + + // save + 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"); + + 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.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(); + + // team BBT should not be in list anymore + 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.wait("@updateEsha"); + // check table + checkRolesForEsha(); + + closeOverlay(); + + let foundEsha = false; + cy.get("app-member-list tbody tr") + .each(($row) => { + const usernameCell = $row.find("td:nth-child(2)"); + if (usernameCell.text() + .trim() === nameEsha) { + foundEsha = true; + 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; + }) + .then(() => { + expect(foundEsha).to.equal(true); + }); + }); + + 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.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"); + + // test click outside of element + 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"); + }); + }); - describe("As BL", - () => { - beforeEach(() => { - cy.loginAsUser(users.bl); - cy.getByTestId("team-management") + describe("As BL", () => { + beforeEach(() => { + cy.loginAsUser(users.bl); + 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.wait("@getEsha"); + + checkRolesForEsha(); + closeOverlay(); + }); + + 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"); + }); + + 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"); + 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(); + + // esha should not exist (is already member of team) + const matOption = ".cdk-overlay-container mat-option"; + 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(); + + // 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(); + + // 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"); + + // remove robin papierer from list + cy.get(allMemberTableTr + " button") + .eq(1) + .click(); + cy.get(allMemberTableTr) + .eq(1) + .should("not.exist"); + + 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-member-list tbody tr") + .each(($row) => { + const usernameCell = $row.find("td:nth-child(2)"); + if (usernameCell.text() + .trim() !== "Findus Peterson") { + return; + } + $row.find("[data-testId='edit-role']") + .click(); + cy.wait(500); // wait for dialog to open + }) + .then(() => { + cy.getByTestId("select-team-role") .click(); - cy.intercept("GET", - "**/users/*") - .as("getEsha"); + cy.getByTestId("select-team-role-admin") + .click(); + cy.getByTestId("select-team-role") + .should("not.exist"); + cy.contains("Das Team wurde erfolgreich aktualisiert."); }); - - it("should check if correct roles for BL are set", - () => { - cy.get("td") - .contains(nameEsha) - .click(); - cy.wait("@getEsha"); - - checkRolesForEsha(); - closeOverlay(); - }); - - 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"); - }); - - 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"); - 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(); - - // esha should not exist (is already member of team) - const matOption = ".cdk-overlay-container mat-option"; - 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(); - - // 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(); - - // 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"); - - // remove robin papierer from list - cy.get(allMemberTableTr + " button") - .eq(1) - .click(); - cy.get(allMemberTableTr) - .eq(1) - .should("not.exist"); - - 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-member-list tbody tr") - .each(($row) => { - const usernameCell = $row.find("td:nth-child(2)"); - if (usernameCell.text() - .trim() !== "Findus Peterson") { - return; - } - $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.contains("Das Team wurde erfolgreich aktualisiert."); - }); - }); - - 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"); - }); - - it("should remove BBT membership of findus", - () => { - navigateToUser("Findus Peterson"); - 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"); - }); - - it("should remove added memberships from esha", - () => { - cy.intercept("PUT", - "**/removeuser") - .as("removeUser"); - - navigateToUser(nameEsha); - cy.getByTestId("delete-team-member") - .eq(0) - .click(); - - ConfirmDialog.do() - .checkTitle("Mitglied entfernen") - .checkDescription(`Möchtest du ${nameEsha} wirklich aus dem Team '/BBT' entfernen?`) - .submit(); - - cy.wait("@removeUser"); - - 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"); - }); - - 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"); - }); - }); + }); + + 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"); + }); + + it("should remove BBT membership of findus", () => { + navigateToUser("Findus Peterson"); + 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"); + }); + + it("should remove added memberships from esha", () => { + cy.intercept("PUT", "**/removeuser") + .as("removeUser"); + + navigateToUser(nameEsha); + cy.getByTestId("delete-team-member") + .eq(0) + .click(); + + ConfirmDialog.do() + .checkTitle("Mitglied entfernen") + .checkDescription(`Möchtest du ${nameEsha} wirklich aus dem Team '/BBT' entfernen?`) + .submit(); + + cy.wait("@removeUser"); + + 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"); + }); + + 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"); + }); }); +}); function closeOverlay () { cy.get(".cdk-overlay-backdrop") - .click(-50, - -50, - { force: true }); + .click(-50, -50, { force: true }); } function checkRolesForEsha () { cy.get("app-member-detail tbody tr") .eq(0) - .should("contain", - "/BBT") - .and("contain", - "Team-Admin"); + .should("contain", "/BBT") + .and("contain", "Team-Admin"); cy.get("app-member-detail tbody tr") .eq(1) - .should("contain", - "LoremIpsum") - .and("contain", - "Team-Member"); + .should("contain", "LoremIpsum") + .and("contain", "Team-Member"); } function editTeamNameAndTest (teamName: string) { - cy.intercept("PUT", - "**/teams/*") + cy.intercept("PUT", "**/teams/*") .as("saveTeam"); cy.getByTestId("editTeamButton") .click(); @@ -634,8 +578,7 @@ function editTeamNameAndTest (teamName: string) { } function navigateToUser (userName: string) { - cy.intercept("GET", - "**/users/*") + cy.intercept("GET", "**/users/*") .as("getUser"); cy.get("td") .contains(userName) diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index d3f5aab512..1022da0037 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -3,103 +3,81 @@ import { keyCodeDefinitions } from "cypress-real-events/keyCodeDefinitions"; import { doUntilSelector, pressUntilContains } from "./helper/utils"; import Chainable = Cypress.Chainable; -Cypress.Commands.add("loginAsUser", - (user: any) => { - loginWithCredentials(user.username, - user.password); - overviewIsLoaded(); - }); +Cypress.Commands.add("loginAsUser", (user: any) => { + loginWithCredentials(user.username, user.password); + overviewIsLoaded(); +}); -Cypress.Commands.add("getByTestId", - (testId: string, text?: string): Chainable => { - const selector = `[data-testId=${testId}]`; +Cypress.Commands.add("getByTestId", (testId: string, text?: string): Chainable => { + const selector = `[data-testId=${testId}]`; - if (text) { - return cy.get(selector) - .contains(text); - } else { - return cy.get(selector); - } - }); + if (text) { + return cy.get(selector) + .contains(text); + } else { + return cy.get(selector); + } +}); -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); - } else { - return cy.wrap(subject) - .find(selector); - } - }); +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); + } else { + return cy.wrap(subject) + .find(selector); + } +}); -Cypress.Commands.add("pressUntilContains", - (text: string, key: keyof typeof keyCodeDefinitions) => { - pressUntilContains(text, - key); - }); +Cypress.Commands.add("pressUntilContains", (text: string, key: keyof typeof keyCodeDefinitions) => { + pressUntilContains(text, key); +}); -Cypress.Commands.add("tabForward", - () => { - cy.realPress("Tab"); - }); +Cypress.Commands.add("tabForward", () => { + cy.realPress("Tab"); +}); -Cypress.Commands.add("tabBackward", - () => { - cy.realPress(["Shift", - "Tab"]); - }); +Cypress.Commands.add("tabBackward", () => { + cy.realPress(["Shift", + "Tab"]); +}); -Cypress.Commands.add("tabForwardUntil", - (selector: string, limit?: number) => { - doUntilSelector(selector, - cy.tabForward, - limit); - }); +Cypress.Commands.add("tabForwardUntil", (selector: string, limit?: number) => { + doUntilSelector(selector, cy.tabForward, limit); +}); -Cypress.Commands.add("tabBackwardUntil", - (selector: string, limit?: number) => { - doUntilSelector(selector, - cy.tabBackward, - limit); - }); +Cypress.Commands.add("tabBackwardUntil", (selector: string, limit?: number) => { + doUntilSelector(selector, cy.tabBackward, limit); +}); -Cypress.Commands.add("getZone", - (zone: string, onOverview: boolean) => { - return (onOverview ? cy.focused() : cy.getByTestId("side-panel")).findByTestId(zone); - }); +Cypress.Commands.add("getZone", (zone: string, onOverview: boolean) => { + return (onOverview ? cy.focused() : cy.getByTestId("side-panel")).findByTestId(zone); +}); -Cypress.Commands.add("validateScoring", - (isOverview: boolean, percentage: number) => { - validateScoring(isOverview, - percentage); - }); +Cypress.Commands.add("validateScoring", (isOverview: boolean, percentage: number) => { + validateScoring(isOverview, percentage); +}); function loginWithCredentials (username: string, password: string) { cy.visit("/"); - cy.intercept("GET", - "**/users/current") + 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.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); @@ -110,8 +88,7 @@ function loginWithCredentials (username: string, password: string) { } const overviewIsLoaded = () => cy.get("mat-chip") - .should("have.length.at.least", - 2); + .should("have.length.at.least", 2); /* * -- This is a parent command -- diff --git a/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts b/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts index 7c8d65f984..22603028c4 100644 --- a/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts +++ b/frontend/cypress/support/helper/dom-helper/angularSearchBox.ts @@ -18,20 +18,17 @@ export default class AngularSearchBox extends PageObjectMapperBase { } shouldHaveOption (option: string) { - cy.contains(".mat-mdc-autocomplete-panel mat-option", - option); + cy.contains(".mat-mdc-autocomplete-panel mat-option", option); return this; } shouldHaveLabel (label: string) { - cy.contains(".mat-mdc-autocomplete-panel .mat-mdc-optgroup-label", - label); + 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) + cy.contains(".mat-mdc-autocomplete-panel mat-option", option) .click(); } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts index 642ee9e0b0..40d7a3638a 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/checkInDialog.ts @@ -3,14 +3,12 @@ import Chainable = Cypress.Chainable; export default class CheckInDialog extends Dialog { fillCheckInCommentary (commentary: string) { - this.fillInputByTestId("changeInfo", - commentary); + this.fillInputByTestId("changeInfo", commentary); return this; } fillMetricCheckInValue (value: string) { - this.fillInputByTestId("check-in-metric-value", - value); + this.fillInputByTestId("check-in-metric-value", value); return this; } @@ -37,8 +35,7 @@ export default class CheckInDialog extends Dialog { } fillCheckInInitiatives (value: string) { - this.fillInputByTestId("initiatives", - value); + this.fillInputByTestId("initiatives", value); return this; } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts index 1828ff4d55..906d1898d6 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/checkInHistoryDialog.ts @@ -27,8 +27,7 @@ export default class CheckInHistoryDialog extends Dialog { cy.get("mat-dialog-container") .contains(value) .parent() - .should("contain", - title); + .should("contain", title); return this; } } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts index 790910c763..a0b9185cae 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/dialog.ts @@ -29,8 +29,7 @@ export default abstract class Dialog extends PageObjectMapperBase { protected fillInputByTestId (testId: string, value: string) { const elem = cy.getByTestId(testId); - this.fillInput(elem, - value); + this.fillInput(elem, value); } protected fillInput (elem: Cypress.Chainable>, value: string) { diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts index ae32422173..9c4bc78182 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/inviteMembersDialog.ts @@ -22,12 +22,9 @@ export default class InviteMembersDialog extends Dialog { .last(); const emailInput = cy.get("[formcontrolname=\"email\"]") .last(); - this.fillInput(firstNameInput, - firstName); - this.fillInput(lastNameInput, - lastName); - this.fillInput(emailInput, - email); + this.fillInput(firstNameInput, firstName); + this.fillInput(lastNameInput, lastName); + this.fillInput(emailInput, email); return this; } diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts index 5e5a014672..7dcda24452 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/keyResultDialog.ts @@ -5,14 +5,12 @@ import Chainable = Cypress.Chainable; export default class KeyResultDialog extends Dialog { fillKeyResultTitle (title: string) { - this.fillInputByTestId("titleInput", - title); + this.fillInputByTestId("titleInput", title); return this; } fillKeyResultDescription (description: string) { - this.fillInputByTestId("descriptionInput", - description); + this.fillInputByTestId("descriptionInput", description); return this; } @@ -21,28 +19,22 @@ export default class KeyResultDialog extends Dialog { .click(); cy.getByTestId("unit") .select(unit); - this.fillInputByTestId("baseline", - baseline); - this.fillInputByTestId("stretchGoal", - stretchGoal); + this.fillInputByTestId("baseline", baseline); + this.fillInputByTestId("stretchGoal", stretchGoal); return this; } withOrdinalValues (commitZone: string, targetZone: string, stretchGoal: string) { cy.getByTestId("ordinalTab") .click(); - this.fillInputByTestId("commitZone", - commitZone); - this.fillInputByTestId("targetZone", - targetZone); - this.fillInputByTestId("stretchZone", - stretchGoal); + this.fillInputByTestId("commitZone", commitZone); + this.fillInputByTestId("targetZone", targetZone); + this.fillInputByTestId("stretchZone", stretchGoal); return this; } fillOwner (owner: string) { - this.fillInputByTestId("ownerInput", - owner); + this.fillInputByTestId("ownerInput", owner); cy.realPress("ArrowDown") .realPress("Enter"); return this; diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts index b479fdd920..ca63916076 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/objectiveDialog.ts @@ -4,14 +4,12 @@ import Chainable = Cypress.Chainable; export default class ObjectiveDialog extends Dialog { fillObjectiveTitle (title: string) { - this.fillInputByTestId("title", - title); + this.fillInputByTestId("title", title); return this; } fillObjectiveDescription (description: string) { - this.fillInputByTestId("description", - description); + this.fillInputByTestId("description", description); return this; } @@ -42,8 +40,7 @@ export default class ObjectiveDialog extends Dialog { excludeKeyResults (keyResults: string[]) { keyResults.forEach((keyResult) => { cy.get("label") - .contains(keyResult.slice(0, - 30)) + .contains(keyResult.slice(0, 30)) .click(); }); return this; diff --git a/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts b/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts index a6d628ccc3..8bf5a9796b 100644 --- a/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts +++ b/frontend/cypress/support/helper/dom-helper/dialogs/teamDialog.ts @@ -9,8 +9,7 @@ export default class TeamDialog extends Dialog { } fillName (name: string) { - this.fillInputByTestId("add-team-name", - name); + this.fillInputByTestId("add-team-name", name); return this; } diff --git a/frontend/cypress/support/helper/dom-helper/filterHelper.ts b/frontend/cypress/support/helper/dom-helper/filterHelper.ts index 9c16d45d62..36934c0be0 100644 --- a/frontend/cypress/support/helper/dom-helper/filterHelper.ts +++ b/frontend/cypress/support/helper/dom-helper/filterHelper.ts @@ -7,32 +7,23 @@ export default class FilterHelper extends PageObjectMapperBase { 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)"); + .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) + cy.contains("h1:visible", text) .should("not.exist"); this.getOption(text) - .should("have.length", - 1) - .should("have.css", - "background-color") - .and("eq", - "rgb(255, 255, 255)"); + .should("have.length", 1) + .should("have.css", "background-color") + .and("eq", "rgb(255, 255, 255)"); return this; } @@ -43,7 +34,6 @@ export default class FilterHelper extends PageObjectMapperBase { } private getOption (text: string): Cypress.Chainable> { - return cy.contains("mat-chip:visible", - text); + return cy.contains("mat-chip:visible", text); } } diff --git a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts index 06ef0fa290..66c8162266 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/overviewPage.ts @@ -46,8 +46,7 @@ export default class CyOverviewPage extends Page { addKeyResult (teamName?: string, objectiveName?: string) { if (teamName && objectiveName) { - this.getObjectiveByTeamAndName(teamName, - objectiveName) + this.getObjectiveByTeamAndName(teamName, objectiveName) .findByTestId("add-keyResult") .first() .click(); @@ -80,8 +79,7 @@ export default class CyOverviewPage extends Page { } getTeamByName (teamName: string) { - return cy.contains(".team-title", - teamName) + return cy.contains(".team-title", teamName) .parentsUntil("#overview") .last(); } @@ -92,8 +90,7 @@ export default class CyOverviewPage extends Page { } getObjectiveByNameAndState (objectiveName: string, state: string) { - this.getObjectivesByNameAndState(objectiveName, - state) + this.getObjectivesByNameAndState(objectiveName, state) .last() .as("objective") .scrollIntoView(); @@ -175,14 +172,12 @@ export default class CyOverviewPage extends Page { .scrollIntoView(); cy.get("@option") - .should("have.class", - "objective-menu-option") + .should("have.class", "objective-menu-option") .click(); } duplicateObjective (objectiveName: string) { - cy.intercept("GET", - "**/objectives/*/keyResults") + cy.intercept("GET", "**/objectives/*/keyResults") .as("keyResults"); this.getObjectiveByName(objectiveName) .findByTestId("three-dot-menu") diff --git a/frontend/cypress/support/helper/dom-helper/pages/page.ts b/frontend/cypress/support/helper/dom-helper/pages/page.ts index 983574d8c4..da46b1a2f0 100644 --- a/frontend/cypress/support/helper/dom-helper/pages/page.ts +++ b/frontend/cypress/support/helper/dom-helper/pages/page.ts @@ -15,8 +15,7 @@ export abstract class Page extends PageObjectMapperBase { afterVisit (): this { cy.url() - .should("include", - this.getURL()); + .should("include", this.getURL()); this.validatePage(); return this; } diff --git a/frontend/cypress/support/helper/keyResultHelper.ts b/frontend/cypress/support/helper/keyResultHelper.ts index 938719ab07..aaa000a010 100644 --- a/frontend/cypress/support/helper/keyResultHelper.ts +++ b/frontend/cypress/support/helper/keyResultHelper.ts @@ -1,6 +1,5 @@ export function filterByKeyResultName (keyResultName: string) { - return (index: number, element: HTMLElement) => isKeyResultName(element, - keyResultName); + return (index: number, element: HTMLElement) => isKeyResultName(element, keyResultName); } const isKeyResultName = (element: HTMLElement, keyResultName: string) => { diff --git a/frontend/cypress/support/helper/objectiveHelper.ts b/frontend/cypress/support/helper/objectiveHelper.ts index 56c8bff577..955b59d5c3 100644 --- a/frontend/cypress/support/helper/objectiveHelper.ts +++ b/frontend/cypress/support/helper/objectiveHelper.ts @@ -1,11 +1,9 @@ export function filterByObjectiveName (objectiveName: string) { - return (index: number, element: HTMLElement) => isObjectiveName(element, - objectiveName); + return (index: number, element: HTMLElement) => isObjectiveName(element, objectiveName); } export function filterByObjectiveState (icon: string) { - return (index: number, element: HTMLElement) => isObjectiveState(element, - icon); + return (index: number, element: HTMLElement) => isObjectiveState(element, icon); } const isObjectiveState = (element: HTMLElement, icon: string) => { diff --git a/frontend/cypress/support/helper/scoringSupport.ts b/frontend/cypress/support/helper/scoringSupport.ts index da566596ea..06ece1def2 100644 --- a/frontend/cypress/support/helper/scoringSupport.ts +++ b/frontend/cypress/support/helper/scoringSupport.ts @@ -11,40 +11,23 @@ export function validateScoring (isOverview: boolean, percentage: number) { 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); - validateScoringWidth("commit", - scoringValue.commitPercent, - isOverview); - validateScoringWidth("target", - scoringValue.targetPercent, - isOverview); + validateScoringWidth("fail", scoringValue.failPercent, isOverview); + validateScoringWidth("commit", scoringValue.commitPercent, isOverview); + validateScoringWidth("target", scoringValue.targetPercent, isOverview); if (percentage == 0) return; - validateScoringColor("fail", - rgbCode, - isOverview); - validateScoringColor("commit", - rgbCode, - isOverview); - validateScoringColor("target", - rgbCode, - isOverview); + validateScoringColor("fail", rgbCode, isOverview); + validateScoringColor("commit", rgbCode, isOverview); + validateScoringColor("target", rgbCode, isOverview); } export function getPercentageMetric (baseline: number, stretchGoal: number, value: number) { - if (isLastCheckInNegative(baseline, - stretchGoal, - value)) { + if (isLastCheckInNegative(baseline, stretchGoal, value)) { return -1; } return Math.abs(value - baseline) / Math.abs(stretchGoal - baseline) * 100; @@ -59,59 +42,40 @@ export function getPercentageOrdinal (zone: string) { } function validateScoringWidth (zone: string, percent: number, isOverview: boolean) { - cy.getZone(zone, - isOverview) + cy.getZone(zone, isOverview) .parent() .invoke("width") .then((parentWidth) => { expect(parentWidth).not.to.equal(undefined); if (parentWidth) { - cy.getZone(zone, - isOverview) + cy.getZone(zone, isOverview) .invoke("width") - .should("be.within", - parentWidth * (percent / 100) - 3, - parentWidth * (percent / 100) + 3); + .should("be.within", parentWidth * (percent / 100) - 3, parentWidth * (percent / 100) + 3); } }); } function validateScoringColor (zone: string, rgbCode: string, isOverview: boolean) { - cy.getZone(zone, - isOverview) - .invoke("css", - "background-color") - .should("equal", - rgbCode); + 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"); - checkVisibilityOfScoringComponent(isOverview, - "block", - "star-scoring"); - checkVisibilityOfScoringComponent(isOverview, - "none", - "normal-scoring"); + .invoke("css", "background-image") + .should("contain", "scoring-stars"); + checkVisibilityOfScoringComponent(isOverview, "block", "star-scoring"); + checkVisibilityOfScoringComponent(isOverview, "none", "normal-scoring"); } else { - checkVisibilityOfScoringComponent(isOverview, - "none", - "star-scoring"); - checkVisibilityOfScoringComponent(isOverview, - "flex", - "normal-scoring"); + checkVisibilityOfScoringComponent(isOverview, "none", "star-scoring"); + checkVisibilityOfScoringComponent(isOverview, "flex", "normal-scoring"); } } function checkVisibilityOfScoringComponent (isOverview: boolean, displayProperty: string, componentTestId: string) { (isOverview ? cy.focused() : cy.getByTestId("side-panel")) .findByTestId(componentTestId) - .invoke("css", - "display") - .should("equal", - displayProperty); + .invoke("css", "display") + .should("equal", displayProperty); } function colorFromPercentage (percentage: number) { diff --git a/frontend/cypress/support/helper/utils.ts b/frontend/cypress/support/helper/utils.ts index 1906b09d70..a9593f20e4 100644 --- a/frontend/cypress/support/helper/utils.ts +++ b/frontend/cypress/support/helper/utils.ts @@ -7,8 +7,7 @@ export const uniqueSuffix = (value: string): string => { export function pressUntilContains (text: string, key: keyof typeof keyCodeDefinitions) { const condition = (element: HTMLElement) => element.innerText.includes(text); - pressUntil(key, - condition); + pressUntil(key, condition); } export function doUntilSelector ( @@ -17,16 +16,12 @@ export function doUntilSelector ( const condition = (element: HTMLElement) => Cypress.$(element) .is(selector); doUntil( - condition, - tab, - limit, - count + condition, tab, limit, count ); } function pressUntil (key: keyof typeof keyCodeDefinitions, condition: (elem: HTMLElement) => boolean) { - doUntil(condition, - () => cy.realPress(key)); + doUntil(condition, () => cy.realPress(key)); } function doUntil ( @@ -44,10 +39,7 @@ function doUntil ( } else { tab(); doUntil( - condition, - tab, - limit, - count + 1 + condition, tab, limit, count + 1 ); } }); diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index c60ef92ca7..4886709599 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -78,20 +78,17 @@ export default tsEslint.config( ], 'prefer-rest-params': 'error', '@typescript-eslint/no-empty-function': ['error', { allow: ['arrowFunctions', 'constructors'] }], - '@stylistic/lines-around-comment': 'off', '@angular-eslint/no-empty-lifecycle-method': 'error', '@angular-eslint/component-class-suffix': 'error', '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', '@typescript-eslint/no-non-null-assertion': 'error', '@stylistic/no-extra-parens': 'error', '@typescript-eslint/no-confusing-non-null-assertion': 'error', - //Delete these rules after fixing all the issues and enabling the actual rules - '@stylistic/quotes': 'off', - '@stylistic/function-call-argument-newline': 'off', - //Actual formatting rules - // '@stylistic/function-call-argument-newline': ['error', 'never'], - // '@stylistic/quotes': ['error', 'double'], + '@stylistic/function-call-argument-newline': ['error', 'never'], + '@stylistic/quotes': ['error', 'double'], + // This rule makes no sense + '@stylistic/lines-around-comment': 'off', '@stylistic/padded-blocks': ['error', 'never'], '@stylistic/dot-location': ['error', 'property'], '@stylistic/newline-per-chained-call': ['error', { ignoreChainWithDepth: 1 }], @@ -103,6 +100,7 @@ export default tsEslint.config( '@stylistic/array-bracket-newline': ['error', { minItems: 4 }], '@stylistic/semi-style': ['error'], '@stylistic/function-paren-newline': ['error', { minItems: 4 }], + //Angular eslint rules '@angular-eslint/directive-selector': [ 'error', { @@ -149,13 +147,14 @@ export default tsEslint.config( // Combine all sets of rules ...html.configs.recommended.rules, ...html.configs['flat/recommended'].rules, - + //Angular template eslint rules '@angular-eslint/template/eqeqeq': 'error', - '@html-eslint/indent': ['error', 2], - '@html-eslint/require-img-alt': 'error', - '@html-eslint/require-closing-tags': ['error', { selfClosing: 'always' }], '@angular-eslint/template/banana-in-box': 'error', '@angular-eslint/template/no-negated-async': 'error', + //Html eslint rules + '@html-eslint/require-img-alt': 'error', + '@html-eslint/indent': ['error', 2], + '@html-eslint/require-closing-tags': ['error', { selfClosing: 'always' }], //For Some reason the following rule does not work with the angular-parser '@html-eslint/element-newline': 'off', }, diff --git a/frontend/src/app/app.component.spec.ts b/frontend/src/app/app.component.spec.ts index d0bbbb9cd3..a8dec66230 100644 --- a/frontend/src/app/app.component.spec.ts +++ b/frontend/src/app/app.component.spec.ts @@ -26,45 +26,43 @@ const routes: Routes = [{ }] }]; -describe("AppComponent", - () => { - let component: AppComponent; - let fixture: ComponentFixture; +describe("AppComponent", () => { + let component: AppComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes(routes), - HttpClientTestingModule, - TranslateTestingModule.withTranslations({ - de: de - }), - OAuthModule.forRoot(), - MatSidenavModule, - NoopAnimationsModule, - CommonModule - ], - providers: [{ - provide: OAuthService, - useValue: oauthServiceMock - }], - declarations: [AppComponent, - OverviewComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }) - .compileComponents() - .then(() => { - fixture = TestBed.createComponent(AppComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes(routes), + HttpClientTestingModule, + TranslateTestingModule.withTranslations({ + de: de + }), + OAuthModule.forRoot(), + MatSidenavModule, + NoopAnimationsModule, + CommonModule + ], + providers: [{ + provide: OAuthService, + useValue: oauthServiceMock + }], + declarations: [AppComponent, + OverviewComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(AppComponent); + component = fixture.componentInstance; + fixture.detectChanges(); - fixture.detectChanges(); - }); - }); - - test("should create the app", - () => { - expect(component) - .toBeTruthy(); + fixture.detectChanges(); }); }); + + test("should create the app", () => { + expect(component) + .toBeTruthy(); + }); +}); diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index bee02c0c1f..f15d5ecf62 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -13,9 +13,7 @@ export class AppComponent { 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")); + 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 57ad0444ae..d2ec68e9b3 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -82,9 +82,7 @@ function initOauthFactory (configService: ConfigService, oauthService: OAuthServ } export function createTranslateLoader (http: HttpBackend) { - return new TranslateHttpLoader(new HttpClient(http), - "./assets/i18n/", - ".json"); + return new TranslateHttpLoader(new HttpClient(http), "./assets/i18n/", ".json"); } export function storageFactory (): OAuthStorage { diff --git a/frontend/src/app/components/action-plan/action-plan.component.spec.ts b/frontend/src/app/components/action-plan/action-plan.component.spec.ts index 58b9bd5bde..dacd347490 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.spec.ts +++ b/frontend/src/app/components/action-plan/action-plan.component.spec.ts @@ -16,174 +16,157 @@ const actionServiceMock = { deleteAction: jest.fn() }; -describe("ActionPlanComponent", - () => { - let component: ActionPlanComponent; - let fixture: ComponentFixture; - let matDialogRef: MatDialogRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ActionPlanComponent], - imports: [ - HttpClientTestingModule, - CdkDropList, - CdkDrag, - TranslateModule.forRoot() - ], - providers: [ - TranslateService, - DialogService, - { - provide: ActionService, - useValue: actionServiceMock - }, - { - provide: MatDialogRef, - useValue: matDialogRef - } - ] - }); - fixture = TestBed.createComponent(ActionPlanComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - actionServiceMock.deleteAction.mockReset(); +describe("ActionPlanComponent", () => { + let component: ActionPlanComponent; + let fixture: ComponentFixture; + let matDialogRef: MatDialogRef; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ActionPlanComponent], + imports: [ + HttpClientTestingModule, + CdkDropList, + CdkDrag, + TranslateModule.forRoot() + ], + providers: [ + TranslateService, + DialogService, + { + provide: ActionService, + useValue: actionServiceMock + }, + { + provide: MatDialogRef, + useValue: matDialogRef + } + ] }); + fixture = TestBed.createComponent(ActionPlanComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + actionServiceMock.deleteAction.mockReset(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should remove item from actionplan array", () => { + component.control = new BehaviorSubject([action1, + action2]); + actionServiceMock.deleteAction.mockReturnValue(of(null)); + jest + .spyOn(component.dialogService, "openConfirmDialog") + .mockReturnValue({ afterClosed: () => of(true) } as MatDialogRef); + + 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); + }); + + it("should remove item from actionplan without opening dialog when action has no text and id", () => { + const dialogSpy = jest.spyOn(component.dialogService, "open"); + component.control = new BehaviorSubject([action3]); + + component.removeAction(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.activeItem = 2; + + component.removeAction(2); + 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); + }); + + it("should decrease index of active item", () => { + const keyEvent = new KeyboardEvent("keydown", { key: "ArrowUp" }); + 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()![0].priority == 0); + expect(component.control.getValue()![1].priority == 1); + expect(component.control.getValue()![2].priority == 2); + }); + + it("should increase index of active item", () => { + const keyEvent = new KeyboardEvent("keydown", { key: "ArrowDown" }); + 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()![0].priority == 0); + expect(component.control.getValue()![1].priority == 1); + expect(component.control.getValue()![2].priority == 2); + expect(component.control.getValue()![3].priority == 3); + }); + + it("should increase active item index", () => { + component.activeItem = 0; + component.control.next([action1, + action2, + action3]); + component.increaseActiveItemWithTab(); + expect(component.activeItem) + .toBe(1); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should remove item from actionplan array", - () => { - component.control = new BehaviorSubject([action1, - action2]); - actionServiceMock.deleteAction.mockReturnValue(of(null)); - jest - .spyOn(component.dialogService, - "openConfirmDialog") - .mockReturnValue({ afterClosed: () => of(true) } as MatDialogRef); - - 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); - }); - - it("should remove item from actionplan without opening dialog when action has no text and id", - () => { - const dialogSpy = jest.spyOn(component.dialogService, - "open"); - component.control = new BehaviorSubject([action3]); - - component.removeAction(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.activeItem = 2; - - component.removeAction(2); - 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); - }); - - it("should decrease index of active item", - () => { - const keyEvent = new KeyboardEvent("keydown", - { key: "ArrowUp" }); - 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()![0].priority == 0); - expect(component.control.getValue()![1].priority == 1); - expect(component.control.getValue()![2].priority == 2); - }); - - it("should increase index of active item", - () => { - const keyEvent = new KeyboardEvent("keydown", - { key: "ArrowDown" }); - 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()![0].priority == 0); - expect(component.control.getValue()![1].priority == 1); - expect(component.control.getValue()![2].priority == 2); - expect(component.control.getValue()![3].priority == 3); - }); - - it("should increase active item index", - () => { - component.activeItem = 0; - component.control.next([action1, - action2, - action3]); - component.increaseActiveItemWithTab(); - expect(component.activeItem) - .toBe(1); - }); - - it("should decrease active item index", - () => { - component.activeItem = 2; - component.control.next([action1, - action2, - action3]); - component.decreaseActiveItemWithShiftTab(); - expect(component.activeItem) - .toBe(1); - }); + it("should decrease active item index", () => { + component.activeItem = 2; + component.control.next([action1, + action2, + action3]); + component.decreaseActiveItemWithShiftTab(); + 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 754ec9a438..0851f96113 100644 --- a/frontend/src/app/components/action-plan/action-plan.component.ts +++ b/frontend/src/app/components/action-plan/action-plan.component.ts @@ -36,8 +36,7 @@ export class ActionPlanComponent { newIndex -= 1; } } - this.changeItemPosition(newIndex, - currentIndex); + this.changeItemPosition(newIndex, currentIndex); this.listItems.get(this.activeItem)?.nativeElement.focus(); } @@ -45,9 +44,7 @@ export class ActionPlanComponent { this.activeItem = newIndex; const currentActionPlan: Action[] = this.control.getValue() ?? []; this.updateActionTexts(currentActionPlan); - moveItemInArray(currentActionPlan, - currentIndex, - newIndex); + moveItemInArray(currentActionPlan, currentIndex, newIndex); currentActionPlan.forEach((action: Action, index: number) => action.priority = index); this.control.next(currentActionPlan); } @@ -81,15 +78,10 @@ export class ActionPlanComponent { this.control.next(actions); } if (event.previousContainer === event.container) { - moveItemInArray(event.container.data ?? [], - event.previousIndex, - event.currentIndex); + moveItemInArray(event.container.data ?? [], event.previousIndex, event.currentIndex); } else { transferArrayItem( - event.previousContainer.data ?? [], - event.container.data ?? [], - event.previousIndex, - event.currentIndex + event.previousContainer.data ?? [], event.container.data ?? [], event.previousIndex, event.currentIndex ); } this.adjustPriorities(); @@ -119,15 +111,13 @@ export class ActionPlanComponent { this.actionService.deleteAction(actions[index].id) .subscribe(); } - actions.splice(index, - 1); + actions.splice(index, 1); this.control.next(actions); this.adjustPriorities(); } }); } else { - actions.splice(index, - 1); + actions.splice(index, 1); this.control.next(actions); this.adjustPriorities(); } 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 c57ec75be8..e5bb2ebf27 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 @@ -39,112 +39,104 @@ const routeMock = { queryParams: of(null) }; -describe("ApplicationBannerComponent", - () => { +describe("ApplicationBannerComponent", () => { // @ts-ignore - global.ResizeObserver = ResizeObserverMock; - let component: ApplicationBannerComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - MatExpansionModule, - MatFormFieldModule, - MatChipsModule, - MatSelectModule, - MatIconModule, - NoopAnimationsModule, - FormsModule, - ReactiveFormsModule, - MatInputModule - ], - declarations: [ - ApplicationBannerComponent, - TeamFilterComponent, - QuarterFilterComponent, - ObjectiveFilterComponent, - OkrTangramComponent - ], - providers: [{ provide: RefreshDataService, - useValue: refreshDataServiceMock }, - { provide: ActivatedRoute, - useValue: routeMock }] - }); - - fixture = TestBed.createComponent(ApplicationBannerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + global.ResizeObserver = ResizeObserverMock; + let component: ApplicationBannerComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + MatExpansionModule, + MatFormFieldModule, + MatChipsModule, + MatSelectModule, + MatIconModule, + NoopAnimationsModule, + FormsModule, + ReactiveFormsModule, + MatInputModule + ], + declarations: [ + ApplicationBannerComponent, + TeamFilterComponent, + QuarterFilterComponent, + ObjectiveFilterComponent, + OkrTangramComponent + ], + providers: [{ provide: RefreshDataService, + useValue: refreshDataServiceMock }, + { provide: ActivatedRoute, + useValue: routeMock }] }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should should hide banner if scrolled down", - fakeAsync(() => { - // 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 - component.refreshBanner(scrollTop); - tick(600); - - // 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)); - })); - - it("should show banner if scrolled up", - fakeAsync(() => { - // 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 - component.refreshBanner(scrollTop); - tick(600); - - // Assert that banner is visible - fixture.detectChanges(); - 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(); - - // Set bannerHeight to default and execute header appearance change - component.bannerHeight = 160; - component.changeHeaderAppearance(); - - // Assert that banner is visible - fixture.detectChanges(); - expect(component.refreshBanner) - .toHaveBeenCalled(); - }); - - it("should call correct method after call scroll()", - () => { - jest.spyOn(component, - "changeHeaderAppearance"); - - component.scroll(); - - expect(component.changeHeaderAppearance) - .toHaveBeenCalled(); - }); + fixture = TestBed.createComponent(ApplicationBannerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should should hide banner if scrolled down", fakeAsync(() => { + // 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 + component.refreshBanner(scrollTop); + tick(600); + + // 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)); + })); + + it("should show banner if scrolled up", fakeAsync(() => { + // 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 + component.refreshBanner(scrollTop); + tick(600); + + // Assert that banner is visible + fixture.detectChanges(); + 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(); + + // Set bannerHeight to default and execute header appearance change + component.bannerHeight = 160; + component.changeHeaderAppearance(); + + // Assert that banner is visible + fixture.detectChanges(); + expect(component.refreshBanner) + .toHaveBeenCalled(); + }); + + it("should call correct method after call scroll()", () => { + jest.spyOn(component, "changeHeaderAppearance"); + + component.scroll(); + + 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 9ccfc6dd29..2df61ead6b 100644 --- a/frontend/src/app/components/application-banner/application-banner.component.ts +++ b/frontend/src/app/components/application-banner/application-banner.component.ts @@ -55,8 +55,7 @@ export class ApplicationBannerComponent implements AfterViewInit, OnDestroy { const newBannerPadding = this.getBannerTopPadding(scrollTop); this.okrBanner.nativeElement.style.top = newBannerPadding + "px"; - const overviewPadding = this.getOverviewPadding(newBannerPadding, - this.bannerHeight); + const overviewPadding = this.getOverviewPadding(newBannerPadding, this.bannerHeight); this.refreshDataService.okrBannerHeightSubject.next(overviewPadding); } 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 ba2242c6e1..ba8db187e3 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 @@ -28,9 +28,7 @@ const dialogServiceMock = { }; const routerMock = { - events: of(new NavigationEnd(1, - "", - "")), + events: of(new NavigationEnd(1, "", "")), navigateByUrl: jest.fn() }; @@ -42,77 +40,73 @@ const configServiceMock = { config$: of({}) }; -describe("ApplicationTopBarComponent", - () => { - let component: ApplicationTopBarComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; +describe("ApplicationTopBarComponent", () => { + let component: ApplicationTopBarComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [MatMenuModule, - NoopAnimationsModule, - MatDialogModule], - declarations: [ApplicationTopBarComponent], - providers: [ - { provide: OAuthService, - useValue: oAuthMock }, - { provide: HttpClient }, - { provide: HttpHandler }, - { provide: UrlHelperService }, - { provide: OAuthLogger }, - { provide: DateTimeProvider }, - { - provide: DialogService, - useValue: dialogServiceMock - }, - { - provide: Router, - useValue: routerMock - }, - { - provide: UserService, - useValue: userServiceMock - }, - { - provide: ConfigService, - useValue: configServiceMock - } - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }) - .compileComponents(); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [MatMenuModule, + NoopAnimationsModule, + MatDialogModule], + declarations: [ApplicationTopBarComponent], + providers: [ + { provide: OAuthService, + useValue: oAuthMock }, + { provide: HttpClient }, + { provide: HttpHandler }, + { provide: UrlHelperService }, + { provide: OAuthLogger }, + { provide: DateTimeProvider }, + { + provide: DialogService, + useValue: dialogServiceMock + }, + { + provide: Router, + useValue: routerMock + }, + { + provide: UserService, + useValue: userServiceMock + }, + { + provide: ConfigService, + useValue: configServiceMock + } + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); - fixture = TestBed.createComponent(ApplicationTopBarComponent); - component = fixture.componentInstance; - loader = TestbedHarnessEnvironment.loader(fixture); - component.ngOnInit(); - }); + fixture = TestBed.createComponent(ApplicationTopBarComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + component.ngOnInit(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should set full name from user service", - () => { - expect(component.userFullName) - .toBe("Bob Baumeister"); - }); + it("should set full name from user service", () => { + expect(component.userFullName) + .toBe("Bob Baumeister"); + }); - it("logout function should get called on button click", - async () => { - 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); - }); + it("logout function should get called on button click", async () => { + 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); }); }); +}); 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 39a8b6eaf7..bb3aeb9280 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 @@ -50,8 +50,7 @@ export class ApplicationTopBarComponent implements OnInit, OnDestroy { } logOut () { - const currentUrlTree = this.router.createUrlTree([], - { queryParams: {} }); + const currentUrlTree = this.router.createUrlTree([], { queryParams: {} }); this.router.navigateByUrl(currentUrlTree) .then(() => { this.oauthService.logOut(); 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 c5e0b1a160..acde25487e 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 @@ -19,56 +19,52 @@ const checkInService = { getAllCheckInOfKeyResult: jest.fn() }; -describe("CheckInHistoryDialogComponent", - () => { - let component: CheckInHistoryDialogComponent; - let fixture: ComponentFixture; +describe("CheckInHistoryDialogComponent", () => { + let component: CheckInHistoryDialogComponent; + let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [CheckInHistoryDialogComponent, - DialogTemplateCoreComponent, - SpinnerComponent], + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [CheckInHistoryDialogComponent, + DialogTemplateCoreComponent, + SpinnerComponent], - imports: [ - TranslateModule.forRoot(), - MatIconModule, - MatProgressSpinner, - MatDividerModule, - MatDialogModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - TranslateService, - DialogService, - { provide: MAT_DIALOG_DATA, - useValue: { keyResult: keyResult } }, - { provide: MatDialogRef, - useValue: {} } - ] - }); - jest - .spyOn(checkInService, - "getAllCheckInOfKeyResult") - .mockReturnValue([checkInMetric, - checkInMetricWriteableFalse]); - fixture = TestBed.createComponent(CheckInHistoryDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + imports: [ + TranslateModule.forRoot(), + MatIconModule, + MatProgressSpinner, + MatDividerModule, + MatDialogModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + TranslateService, + DialogService, + { provide: MAT_DIALOG_DATA, + useValue: { keyResult: keyResult } }, + { provide: MatDialogRef, + useValue: {} } + ] }); + jest + .spyOn(checkInService, "getAllCheckInOfKeyResult") + .mockReturnValue([checkInMetric, + checkInMetricWriteableFalse]); + fixture = TestBed.createComponent(CheckInHistoryDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + 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); - }); + 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); }); +}); 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 9def5acd5f..9c23809fd0 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 @@ -40,13 +40,12 @@ export class CheckInHistoryDialogComponent implements OnInit { } openCheckInDialogForm (checkIn: CheckInMin) { - const dialogRef = this.dialogService.open(CheckInFormComponent, - { - data: { - keyResult: this.keyResult, - checkIn: checkIn - } - }); + const dialogRef = this.dialogService.open(CheckInFormComponent, { + data: { + keyResult: this.keyResult, + checkIn: checkIn + } + }); dialogRef.afterClosed() .subscribe(() => { this.loadCheckInHistory(); 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 46d96e36a8..f618e46b9c 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 @@ -12,84 +12,75 @@ import { Unit } from "../../../shared/types/enums/Unit"; import { TranslateTestingModule } from "ngx-translate-testing"; import * as de from "../../../../assets/i18n/de.json"; -describe("CheckInFormComponent", - () => { - let component: CheckInFormMetricComponent; - let fixture: ComponentFixture; +describe("CheckInFormComponent", () => { + let component: CheckInFormMetricComponent; + let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule, - TranslateTestingModule.withTranslations({ - de: de - }) - ], - declarations: [CheckInFormMetricComponent] - }); - fixture = TestBed.createComponent(CheckInFormMetricComponent); - component = fixture.componentInstance; - component.keyResult = keyResultMetric; - component.checkIn = checkInMetric; - component.dialogForm = new FormGroup({ - value: new FormControl("", - [Validators.required]), - confidence: new FormControl(5, - [Validators.required, - Validators.min(1), - Validators.max(10)]) - }); - fixture.detectChanges(); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de + }) + ], + declarations: [CheckInFormMetricComponent] }); + fixture = TestBed.createComponent(CheckInFormMetricComponent); + component = fixture.componentInstance; + component.keyResult = keyResultMetric; + component.checkIn = checkInMetric; + component.dialogForm = new FormGroup({ + value: new FormControl("", [Validators.required]), + confidence: new FormControl(5, [Validators.required, + Validators.min(1), + Validators.max(10)]) + }); + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should format percent correctly", - waitForAsync(async () => { - component.keyResult = { ...keyResultMetric, - unit: Unit.PERCENT }; - expect(component.generateUnitLabel()) - .toEqual("%"); - })); + it("should format percent correctly", waitForAsync(async () => { + 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"); - })); + it("should format chf correctly", waitForAsync(async () => { + 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"); - })); + it("should format eur correctly", waitForAsync(async () => { + 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"); - })); + it("should format fte correctly", waitForAsync(async () => { + 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(""); - })); - }); + it("should format number correctly", waitForAsync(async () => { + component.keyResult = { ...keyResultMetric, + unit: Unit.NUMBER }; + expect(component.generateUnitLabel()) + .toEqual(""); + })); +}); 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 89eb07991a..2b2e765d83 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 @@ -1,36 +1,33 @@ import { MetricCheckInDirective } from "./metric-check-in-directive"; -describe("MetricCheckInDirective", - () => { - it("create an instance", - () => { - const directive = new MetricCheckInDirective(); - expect(directive) - .toBeTruthy(); - }); +describe("MetricCheckInDirective", () => { + it("create an instance", () => { + const directive = new MetricCheckInDirective(); + expect(directive) + .toBeTruthy(); + }); - it.each([ - ["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(); - directive.registerOnChange(mockOnChange); + it.each([ + ["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(); + directive.registerOnChange(mockOnChange); - directive.handleInput(value); + 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 5b23c89c15..e2e8bd3b92 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 @@ -27,19 +27,16 @@ export class MetricCheckInDirective implements ControlValueAccessor { // does not need to be implemented } - @HostListener("input", - ["$event.target.value"]) + @HostListener("input", ["$event.target.value"]) handleInput (param: string): void { const value: string = param || "0"; if (value.toString() .at(0) == "-") { this.onChange(+("-" + value.toString() - .replace(this.CHAR_REGEX, - ""))); + .replace(this.CHAR_REGEX, ""))); return; } this.onChange(Number(value.toString() - .replace(this.CHAR_REGEX, - ""))); + .replace(this.CHAR_REGEX, ""))); } } 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 15ba97f076..2f7b10798d 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 @@ -14,89 +14,79 @@ import { MatRadioButtonHarness } from "@angular/material/radio/testing"; import { HarnessLoader } from "@angular/cdk/testing"; import { TestbedHarnessEnvironment } from "@angular/cdk/testing/testbed"; -describe("CheckInFormOrdinalComponent", - () => { - let component: CheckInFormOrdinalComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; +describe("CheckInFormOrdinalComponent", () => { + let component: CheckInFormOrdinalComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule - ], - 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)]) - }); - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule + ], + 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)]) + }); + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + 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(""); - })); + it("should set zone of check-in to fail if value is empty", waitForAsync(async () => { + 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); - })); + 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); + })); - 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); - })); + 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); + })); - 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); - })); + 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); + })); - 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); - })); + 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); + })); - 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); - })); - }); + 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); + })); +}); diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts index de3f63ce81..4a4cea152a 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.spec.ts @@ -44,165 +44,157 @@ const actionServiceMock = { updateActions: jest.fn() }; -describe("CheckInFormComponent", - () => { - let component: CheckInFormComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - MatIconModule, - MatFormFieldModule, - MatSelectModule, - ReactiveFormsModule, - MatInputModule, - NoopAnimationsModule, - MatCheckboxModule, - MatSliderModule, - FormsModule, - ReactiveFormsModule, - TranslateTestingModule.withTranslations({ - de: de - }), - MatDividerModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: MAT_DIALOG_DATA, - useValue: { keyResult: {} } }, - { provide: MatDialogRef, - useValue: dialogMock }, - { provide: CheckInService, - useValue: checkInServiceMock }, - { provide: ActionService, - useValue: actionServiceMock } - ], - declarations: [CheckInFormComponent, - DialogTemplateCoreComponent, - ConfidenceComponent] - }); - fixture = TestBed.createComponent(CheckInFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); +describe("CheckInFormComponent", () => { + let component: CheckInFormComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + ReactiveFormsModule, + MatInputModule, + NoopAnimationsModule, + MatCheckboxModule, + MatSliderModule, + FormsModule, + ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de + }), + MatDividerModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: MAT_DIALOG_DATA, + useValue: { keyResult: {} } }, + { provide: MatDialogRef, + useValue: dialogMock }, + { provide: CheckInService, + useValue: checkInServiceMock }, + { provide: ActionService, + useValue: actionServiceMock } + ], + declarations: [CheckInFormComponent, + DialogTemplateCoreComponent, + ConfidenceComponent] }); + fixture = TestBed.createComponent(CheckInFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should save check-in correctly if key result is metric", - waitForAsync(async () => { - component.checkIn = checkInMetric; - component.keyResult = keyResultMetric; - component.dialogForm.controls["value"].setValue(checkInMetric?.value!.toString()); - component.dialogForm.controls["confidence"].setValue(checkInMetric.confidence); - component.dialogForm.controls["changeInfo"].setValue(checkInMetric.changeInfo); - component.dialogForm.controls["initiatives"].setValue(checkInMetric.initiatives); - - checkInServiceMock.saveCheckIn.mockReturnValue(of(checkInMetric)); - actionServiceMock.updateActions.mockReturnValue(of(action2)); - component.saveCheckIn(); - - expect(checkInServiceMock.saveCheckIn) - .toHaveBeenCalledWith({ - id: checkInMetric.id, - version: checkInMetric.version, - confidence: checkInMetric.confidence, - value: checkInMetric.value!.toString(), - changeInfo: checkInMetric.changeInfo, - initiatives: checkInMetric.initiatives, - keyResultId: keyResultMetric.id - }); - expect(actionServiceMock.updateActions) - .toHaveBeenCalled(); - })); - - it("should save check-in correctly if key result is ordinal", - waitForAsync(async () => { - component.checkIn = checkInOrdinal; - component.keyResult = keyResultOrdinal; - component.dialogForm.controls["value"].setValue(checkInOrdinal?.zone!.toString()); - component.dialogForm.controls["confidence"].setValue(checkInOrdinal.confidence); - component.dialogForm.controls["changeInfo"].setValue(checkInOrdinal.changeInfo); - component.dialogForm.controls["initiatives"].setValue(checkInOrdinal.initiatives); - - checkInServiceMock.saveCheckIn.mockReturnValue(of(checkInOrdinal)); - actionServiceMock.updateActions.mockReturnValue(of(action2)); - component.saveCheckIn(); - - expect(checkInServiceMock.saveCheckIn) - .toHaveBeenCalledWith({ - id: checkInOrdinal.id, - version: checkInOrdinal.version, - confidence: checkInOrdinal.confidence, - zone: checkInOrdinal.zone, - changeInfo: checkInOrdinal.changeInfo, - initiatives: checkInOrdinal.initiatives, - keyResultId: keyResultOrdinal.id - }); - })); - - it("should set default values if form check-in input is not null", - waitForAsync(async () => { - component.data.checkIn = checkInMetric; - component.setDefaultValues(); - expect(component.dialogForm.value) - .toStrictEqual({ - confidence: checkInMetric.confidence, - value: checkInMetric.value!.toString(), - changeInfo: checkInMetric.changeInfo, - initiatives: checkInMetric.initiatives, - actionList: undefined - }); - })); - - it("should set default values if last check-in of key result is not null", - waitForAsync(async () => { - component.keyResult = keyResultOrdinal; - component.ngOnInit(); - component.setDefaultValues(); - expect(component.dialogForm.value) - .toStrictEqual({ - confidence: keyResultOrdinal.lastCheckIn!.confidence, - value: "", - changeInfo: "", - initiatives: "", - actionList: [] - }); - })); - - it("should set default values with actionList on KeyResult", - waitForAsync(async () => { - component.keyResult = keyResultActions; - component.ngOnInit(); - component.setDefaultValues(); - expect(component.dialogForm.value) - .toStrictEqual({ - confidence: keyResultActions.lastCheckIn!.confidence, - value: "", - changeInfo: "", - initiatives: "", - actionList: [action1, - action2] - }); - })); - - it("should call actionService when saving CheckIn", - waitForAsync(async () => { - checkInServiceMock.saveCheckIn.mockReturnValue(of(true)); - actionServiceMock.updateActions.mockReturnValue(of(true)); - - component.keyResult = keyResultActions; - component.ngOnInit(); - component.setDefaultValues(); - component.saveCheckIn(); - expect(actionServiceMock.updateActions) - .toHaveBeenCalled(); - })); + it("should create", () => { + expect(component) + .toBeTruthy(); }); + + it("should save check-in correctly if key result is metric", waitForAsync(async () => { + component.checkIn = checkInMetric; + component.keyResult = keyResultMetric; + component.dialogForm.controls["value"].setValue(checkInMetric?.value!.toString()); + component.dialogForm.controls["confidence"].setValue(checkInMetric.confidence); + component.dialogForm.controls["changeInfo"].setValue(checkInMetric.changeInfo); + component.dialogForm.controls["initiatives"].setValue(checkInMetric.initiatives); + + checkInServiceMock.saveCheckIn.mockReturnValue(of(checkInMetric)); + actionServiceMock.updateActions.mockReturnValue(of(action2)); + component.saveCheckIn(); + + expect(checkInServiceMock.saveCheckIn) + .toHaveBeenCalledWith({ + id: checkInMetric.id, + version: checkInMetric.version, + confidence: checkInMetric.confidence, + value: checkInMetric.value!.toString(), + changeInfo: checkInMetric.changeInfo, + initiatives: checkInMetric.initiatives, + keyResultId: keyResultMetric.id + }); + expect(actionServiceMock.updateActions) + .toHaveBeenCalled(); + })); + + it("should save check-in correctly if key result is ordinal", waitForAsync(async () => { + component.checkIn = checkInOrdinal; + component.keyResult = keyResultOrdinal; + component.dialogForm.controls["value"].setValue(checkInOrdinal?.zone!.toString()); + component.dialogForm.controls["confidence"].setValue(checkInOrdinal.confidence); + component.dialogForm.controls["changeInfo"].setValue(checkInOrdinal.changeInfo); + component.dialogForm.controls["initiatives"].setValue(checkInOrdinal.initiatives); + + checkInServiceMock.saveCheckIn.mockReturnValue(of(checkInOrdinal)); + actionServiceMock.updateActions.mockReturnValue(of(action2)); + component.saveCheckIn(); + + expect(checkInServiceMock.saveCheckIn) + .toHaveBeenCalledWith({ + id: checkInOrdinal.id, + version: checkInOrdinal.version, + confidence: checkInOrdinal.confidence, + zone: checkInOrdinal.zone, + changeInfo: checkInOrdinal.changeInfo, + initiatives: checkInOrdinal.initiatives, + keyResultId: keyResultOrdinal.id + }); + })); + + it("should set default values if form check-in input is not null", waitForAsync(async () => { + component.data.checkIn = checkInMetric; + component.setDefaultValues(); + expect(component.dialogForm.value) + .toStrictEqual({ + confidence: checkInMetric.confidence, + value: checkInMetric.value!.toString(), + changeInfo: checkInMetric.changeInfo, + initiatives: checkInMetric.initiatives, + actionList: undefined + }); + })); + + it("should set default values if last check-in of key result is not null", waitForAsync(async () => { + component.keyResult = keyResultOrdinal; + component.ngOnInit(); + component.setDefaultValues(); + expect(component.dialogForm.value) + .toStrictEqual({ + confidence: keyResultOrdinal.lastCheckIn!.confidence, + value: "", + changeInfo: "", + initiatives: "", + actionList: [] + }); + })); + + it("should set default values with actionList on KeyResult", waitForAsync(async () => { + component.keyResult = keyResultActions; + component.ngOnInit(); + component.setDefaultValues(); + expect(component.dialogForm.value) + .toStrictEqual({ + confidence: keyResultActions.lastCheckIn!.confidence, + value: "", + changeInfo: "", + initiatives: "", + actionList: [action1, + action2] + }); + })); + + it("should call actionService when saving CheckIn", waitForAsync(async () => { + checkInServiceMock.saveCheckIn.mockReturnValue(of(true)); + actionServiceMock.updateActions.mockReturnValue(of(true)); + + component.keyResult = keyResultActions; + component.ngOnInit(); + component.setDefaultValues(); + component.saveCheckIn(); + expect(actionServiceMock.updateActions) + .toHaveBeenCalled(); + })); +}); diff --git a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts index e19b99879e..78ec7f976f 100644 --- a/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts +++ b/frontend/src/app/components/checkin/check-in-form/check-in-form.component.ts @@ -30,16 +30,12 @@ export class CheckInFormComponent implements OnInit { continued = false; dialogForm = new FormGroup({ - value: new FormControl("", - [Validators.required]), - confidence: new FormControl(5, - [Validators.required, - Validators.min(0), - Validators.max(10)]), - changeInfo: new FormControl("", - [Validators.maxLength(4096)]), - initiatives: new FormControl("", - [Validators.maxLength(4096)]), + value: new FormControl("", [Validators.required]), + confidence: new FormControl(5, [Validators.required, + Validators.min(0), + Validators.max(10)]), + changeInfo: new FormControl("", [Validators.maxLength(4096)]), + initiatives: new FormControl("", [Validators.maxLength(4096)]), actionList: new FormControl([]) }); diff --git a/frontend/src/app/components/confidence/confidence.component.spec.ts b/frontend/src/app/components/confidence/confidence.component.spec.ts index 04592ab74a..bab69caa22 100644 --- a/frontend/src/app/components/confidence/confidence.component.spec.ts +++ b/frontend/src/app/components/confidence/confidence.component.spec.ts @@ -8,62 +8,56 @@ import { FormsModule } from "@angular/forms"; import { SimpleChange } from "@angular/core"; import { By } from "@angular/platform-browser"; -describe("ConfidenceComponent", - () => { - let component: ConfidenceComponent; - let fixture: ComponentFixture; +describe("ConfidenceComponent", () => { + let component: ConfidenceComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ConfidenceComponent], + imports: [MatSliderModule, + FormsModule] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ConfidenceComponent); + component = fixture.componentInstance; + component.checkIn = checkInMetric; + component.edit = true; + }); - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ConfidenceComponent], - imports: [MatSliderModule, - FormsModule] - }) - .compileComponents(); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - fixture = TestBed.createComponent(ConfidenceComponent); - component = fixture.componentInstance; - component.checkIn = checkInMetric; - component.edit = true; + it.each([[{ confidence: 8 } as CheckInMin, + "8"], + [null, + "5"]])("should set confidence of component with right value", async (checkIn: CheckInMin | null, expected: string) => { + component.checkIn = checkIn!; + component.ngOnChanges({ + checkIn: new SimpleChange(null, component.checkIn, true) }); + fixture.detectChanges(); + await fixture.whenStable(); + const textField = fixture.debugElement.query(By.css("[data-testid='confidence']")); + const expectedLabel = expected + "/" + component.max; + const sliderInputField = fixture.debugElement.query(By.css("mat-slider > input ")); + + expect(await sliderInputField.nativeElement.value) + .toBe(expected); + expect(textField.nativeElement.innerHTML) + .toContain(expectedLabel); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it.each([[{ confidence: 8 } as CheckInMin, - "8"], - [null, - "5"]])("should set confidence of component with right value", - async (checkIn: CheckInMin | null, expected: string) => { - component.checkIn = checkIn!; - component.ngOnChanges({ - checkIn: new SimpleChange(null, - component.checkIn, - true) - }); - fixture.detectChanges(); - await fixture.whenStable(); - const textField = fixture.debugElement.query(By.css("[data-testid='confidence']")); - const expectedLabel = expected + "/" + component.max; - const sliderInputField = fixture.debugElement.query(By.css("mat-slider > input ")); - - expect(await sliderInputField.nativeElement.value) - .toBe(expected); - expect(textField.nativeElement.innerHTML) - .toContain(expectedLabel); - }); - - it.each([[true], - [false]])("should show slider on based on input var", - async (editable) => { - component.edit = editable; - fixture.detectChanges(); - const slider = fixture.debugElement.query(By.css("mat-slider")); + it.each([[true], + [false]])("should show slider on based on input var", async (editable) => { + component.edit = editable; + fixture.detectChanges(); + const slider = fixture.debugElement.query(By.css("mat-slider")); - expect(!!slider) - .toBe(editable); - }); + expect(!!slider) + .toBe(editable); }); +}); diff --git a/frontend/src/app/components/key-result-form/key-result-form.component.spec.ts b/frontend/src/app/components/key-result-form/key-result-form.component.spec.ts index a6fc5ff71c..2ef2bedce9 100644 --- a/frontend/src/app/components/key-result-form/key-result-form.component.spec.ts +++ b/frontend/src/app/components/key-result-form/key-result-form.component.spec.ts @@ -32,269 +32,250 @@ import { provideHttpClient } from "@angular/common/http"; import { DialogTemplateCoreComponent } from "../../shared/custom/dialog-template-core/dialog-template-core.component"; import { Quarter } from "../../shared/types/model/Quarter"; -describe("KeyResultFormComponent", - () => { - let component: KeyResultFormComponent; - let fixture: ComponentFixture; +describe("KeyResultFormComponent", () => { + let component: KeyResultFormComponent; + let fixture: ComponentFixture; - const oauthMockService = { - getIdentityClaims () { - return { name: users[1].firstname + " " + users[1].lastname }; - } - }; + const oauthMockService = { + getIdentityClaims () { + return { name: users[1].firstname + " " + users[1].lastname }; + } + }; - const userService = { - getUsers () { - return of(users); - }, - getCurrentUser: jest.fn() - }; + const userService = { + getUsers () { + return of(users); + }, + getCurrentUser: jest.fn() + }; - const matDialogRefMock = { - close: jest.fn() - }; + const matDialogRefMock = { + close: jest.fn() + }; - const mockUserService = { - getUsers: jest.fn() - }; + const mockUserService = { + getUsers: jest.fn() + }; - const keyResultForm = { - owner: null, - actionList: [], - title: "Title", - baseline: 0, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: "FTE", - description: null, - stretchGoal: 0, - keyResultType: "metric" - }; + const keyResultForm = { + owner: null, + actionList: [], + title: "Title", + baseline: 0, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: "FTE", + description: null, + stretchGoal: 0, + keyResultType: "metric" + }; - const keyResultObjective: KeyResultObjective = { - id: 2, - state: State.ONGOING, - quarter: new Quarter( - 1, - "GJ 22/23-Q2", - new Date(), - new Date() - ) - }; + const keyResultObjective: KeyResultObjective = { + id: 2, + state: State.ONGOING, + quarter: new Quarter( + 1, "GJ 22/23-Q2", new Date(), new Date() + ) + }; - const keyResultFormGroup = new FormGroup({ - title: new FormControl("", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("", - [Validators.maxLength(4096)]), - owner: new FormControl(null, - [Validators.required, - Validators.nullValidator]), - actionList: new FormControl([]), - unit: new FormControl(null), - baseline: new FormControl(null), - stretchGoal: new FormControl(null), - commitZone: new FormControl(null), - targetZone: new FormControl(null), - stretchZone: new FormControl(null), - keyResultType: new FormControl("metric") - }); + const keyResultFormGroup = new FormGroup({ + title: new FormControl("", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("", [Validators.maxLength(4096)]), + owner: new FormControl(null, [Validators.required, + Validators.nullValidator]), + actionList: new FormControl([]), + unit: new FormControl(null), + baseline: new FormControl(null), + stretchGoal: new FormControl(null), + commitZone: new FormControl(null), + targetZone: new FormControl(null), + stretchZone: new FormControl(null), + keyResultType: new FormControl("metric") + }); - describe("New KeyResult", - () => { - beforeEach(() => { - mockUserService.getUsers.mockReturnValue(users); - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatIconModule, - TranslateModule.forRoot(), - DragDropModule, - TranslateTestingModule.withTranslations({ - de: de - }) - ], - providers: [ - KeyresultService, - TranslateService, - { provide: UserService, - useValue: userService }, - { - provide: MatDialogRef, - useValue: matDialogRefMock - }, - { - provide: OAuthService, - useValue: oauthMockService - }, - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting() - ], - declarations: [ - KeyResultFormComponent, - DialogTemplateCoreComponent, - KeyresultTypeComponent, - ActionPlanComponent - ] + describe("New KeyResult", () => { + beforeEach(() => { + mockUserService.getUsers.mockReturnValue(users); + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule, + MatAutocompleteModule, + MatIconModule, + TranslateModule.forRoot(), + DragDropModule, + TranslateTestingModule.withTranslations({ + de: de }) - .compileComponents(); + ], + providers: [ + KeyresultService, + TranslateService, + { provide: UserService, + useValue: userService }, + { + provide: MatDialogRef, + useValue: matDialogRefMock + }, + { + provide: OAuthService, + useValue: oauthMockService + }, + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting() + ], + declarations: [ + KeyResultFormComponent, + DialogTemplateCoreComponent, + KeyresultTypeComponent, + ActionPlanComponent + ] + }) + .compileComponents(); - fixture = TestBed.createComponent(KeyResultFormComponent); - component = fixture.componentInstance; - component.keyResultForm = keyResultFormGroup; - userService.getCurrentUser.mockReturnValue(testUser); - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(KeyResultFormComponent); + component = fixture.componentInstance; + component.keyResultForm = keyResultFormGroup; + userService.getCurrentUser.mockReturnValue(testUser); + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should have logged in user as owner", - waitForAsync(async () => { - const userServiceSpy = jest.spyOn(userService, - "getUsers"); - component.keyResultForm.setValue(keyResultForm); - component.ngOnInit(); - fixture.detectChanges(); + it("should have logged in user as owner", waitForAsync(async () => { + const userServiceSpy = jest.spyOn(userService, "getUsers"); + component.keyResultForm.setValue(keyResultForm); + component.ngOnInit(); + fixture.detectChanges(); - const formObject = component.keyResultForm.value; - expect(formObject.title) - .toBe("Title"); - expect(formObject.description) - .toBe(null); - expect(userServiceSpy) - .toHaveBeenCalled(); - expect(component.keyResultForm.controls["owner"].value) - .toBe(testUser); - expect(component.keyResultForm.invalid) - .toBeFalsy(); - })); + const formObject = component.keyResultForm.value; + expect(formObject.title) + .toBe("Title"); + expect(formObject.description) + .toBe(null); + expect(userServiceSpy) + .toHaveBeenCalled(); + expect(component.keyResultForm.controls["owner"].value) + .toBe(testUser); + expect(component.keyResultForm.invalid) + .toBeFalsy(); + })); - it("should return right filtered user", - () => { - let userObservable: Observable = component.filter("baum"); + it("should return right filtered user", () => { + let userObservable: Observable = component.filter("baum"); - userObservable.subscribe((userList) => { - expect(userList.length) - .toEqual(1); - }); - userObservable = component.filter("ob"); + userObservable.subscribe((userList) => { + expect(userList.length) + .toEqual(1); + }); + userObservable = component.filter("ob"); - userObservable.subscribe((userList) => { - expect(userList.length) - .toEqual(2); - }); - }); + userObservable.subscribe((userList) => { + expect(userList.length) + .toEqual(2); + }); + }); - it("should return label from user", - () => { - const userName: string = component.getUserNameFromUser(testUser); - expect(userName) - .toEqual("Bob Baumeister"); - }); + it("should return label from user", () => { + const userName: string = component.getUserNameFromUser(testUser); + expect(userName) + .toEqual("Bob Baumeister"); + }); - it("should set metric values", - () => { - const fullKeyResultMetric: KeyResultMetric = { - id: 3, - version: 2, - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - baseline: 3, - keyResultType: "metric", - lastCheckIn: null, - actionList: null, - stretchGoal: 25, - unit: "CHF", - createdOn: new Date(), - modifiedOn: new Date(), - writeable: true - }; - component.setMetricValuesInForm(fullKeyResultMetric); + it("should set metric values", () => { + const fullKeyResultMetric: KeyResultMetric = { + id: 3, + version: 2, + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + baseline: 3, + keyResultType: "metric", + lastCheckIn: null, + actionList: null, + stretchGoal: 25, + unit: "CHF", + createdOn: new Date(), + modifiedOn: new Date(), + writeable: true + }; + component.setMetricValuesInForm(fullKeyResultMetric); - expect(component.keyResultForm.controls["baseline"].value) - .toEqual(3); - expect(component.keyResultForm.controls["stretchGoal"].value) - .toEqual(25); - expect(component.keyResultForm.controls["unit"].value) - .toEqual("CHF"); - }); + expect(component.keyResultForm.controls["baseline"].value) + .toEqual(3); + expect(component.keyResultForm.controls["stretchGoal"].value) + .toEqual(25); + expect(component.keyResultForm.controls["unit"].value) + .toEqual("CHF"); + }); - it("should set ordinal values", - () => { - const fullKeyResultOrdinal: KeyResultOrdinal = { - id: 3, - version: 2, - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - commitZone: "Eine Kuh", - keyResultType: "metric", - lastCheckIn: null, - actionList: null, - targetZone: "Ein Schaf", - stretchZone: "Eine Ziege", - createdOn: new Date(), - modifiedOn: new Date(), - writeable: true - }; - component.setOrdinalValuesInForm(fullKeyResultOrdinal); + it("should set ordinal values", () => { + const fullKeyResultOrdinal: KeyResultOrdinal = { + id: 3, + version: 2, + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + commitZone: "Eine Kuh", + keyResultType: "metric", + lastCheckIn: null, + actionList: null, + targetZone: "Ein Schaf", + stretchZone: "Eine Ziege", + createdOn: new Date(), + modifiedOn: new Date(), + writeable: true + }; + component.setOrdinalValuesInForm(fullKeyResultOrdinal); - expect(component.keyResultForm.controls["commitZone"].value) - .toEqual("Eine Kuh"); - expect(component.keyResultForm.controls["targetZone"].value) - .toEqual("Ein Schaf"); - expect(component.keyResultForm.controls["stretchZone"].value) - .toEqual("Eine Ziege"); - }); + expect(component.keyResultForm.controls["commitZone"].value) + .toEqual("Eine Kuh"); + expect(component.keyResultForm.controls["targetZone"].value) + .toEqual("Ein Schaf"); + expect(component.keyResultForm.controls["stretchZone"].value) + .toEqual("Eine Ziege"); + }); - it("should get metric value right", - () => { - expect(component.isMetricKeyResult()) - .toBeTruthy(); - component.keyResultForm.patchValue({ keyResultType: "ordinal" }); - expect(component.isMetricKeyResult()) - .toBeFalsy(); - }); + it("should get metric value right", () => { + expect(component.isMetricKeyResult()) + .toBeTruthy(); + component.keyResultForm.patchValue({ keyResultType: "ordinal" }); + expect(component.isMetricKeyResult()) + .toBeFalsy(); + }); - it("should get username from user right", - () => { - const user = users[0]; - expect(component.getUserNameFromUser(user)) - .toEqual("Bob Baumeister"); - expect(component.getUserNameFromUser(null!)) - .toEqual(""); - }); + it("should get username from user right", () => { + const user = users[0]; + expect(component.getUserNameFromUser(user)) + .toEqual("Bob Baumeister"); + expect(component.getUserNameFromUser(null!)) + .toEqual(""); + }); - it("should get keyresult id right", - () => { - expect(component.getKeyResultId()) - .toEqual(null); - component.keyResult = keyResultOrdinal; - expect(component.getKeyResultId()) - .toEqual(101); - }); + it("should get keyresult id right", () => { + expect(component.getKeyResultId()) + .toEqual(null); + component.keyResult = keyResultOrdinal; + expect(component.getKeyResultId()) + .toEqual(101); + }); - it("should get username from oauthService right", - () => { - expect(component.getLoggedInUserName()) - .toEqual(testUser.firstname + " " + testUser.lastname); - }); - }); + it("should get username from oauthService right", () => { + expect(component.getLoggedInUserName()) + .toEqual(testUser.firstname + " " + testUser.lastname); + }); }); +}); diff --git a/frontend/src/app/components/key-result-form/key-result-form.component.ts b/frontend/src/app/components/key-result-form/key-result-form.component.ts index d6d0d878ea..9ac447dd1c 100644 --- a/frontend/src/app/components/key-result-form/key-result-form.component.ts +++ b/frontend/src/app/components/key-result-form/key-result-form.component.ts @@ -43,9 +43,7 @@ export class KeyResultFormComponent implements OnInit, OnDestroy { ngOnInit (): void { this.users$ = this.userService.getUsers(); - this.filteredUsers$ = this.keyResultForm.get("owner")?.valueChanges.pipe(startWith(""), - filter((value) => typeof value === "string"), - switchMap((value) => this.filter(value as string))); + this.filteredUsers$ = this.keyResultForm.get("owner")?.valueChanges.pipe(startWith(""), filter((value) => typeof value === "string"), switchMap((value) => this.filter(value as string))); if (this.keyResult) { this.keyResultForm.patchValue({ actionList: this.keyResult.actionList }); this.keyResultForm.controls["title"].setValue(this.keyResult.title); @@ -129,8 +127,7 @@ export class KeyResultFormComponent implements OnInit, OnDestroy { error: string, field: string, firstNumber: number | null, secondNumber: number | null ): string { return field + this.translate.instant("DIALOG_ERRORS." + error) - .format(firstNumber, - secondNumber); + .format(firstNumber, secondNumber); } filter (value: string): Observable { diff --git a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.spec.ts b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.spec.ts index 6cfbdb1e0f..7bd74ee0ec 100644 --- a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.spec.ts +++ b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.spec.ts @@ -26,116 +26,101 @@ const activatedRouteMock = { } }; -describe("KeyresultDetailComponent", - () => { - let component: KeyresultDetailComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - MatDialogModule, - MatIconModule, - TranslateModule.forRoot() - ], - declarations: [KeyresultDetailComponent, - ScoringComponent, - ConfidenceComponent], - providers: [{ - provide: KeyresultService, - useValue: keyResultServiceMock - }, - { - provide: ActivatedRoute, - useValue: activatedRouteMock - }] - }) - .compileComponents(); - - jest.spyOn(keyResultServiceMock, - "getFullKeyResult") - .mockReturnValue(of(keyResult)); - activatedRouteMock.snapshot.paramMap.get.mockReturnValue(of(1)); - - fixture = TestBed.createComponent(KeyresultDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should throw error when id is undefined", - () => { - activatedRouteMock.snapshot.paramMap.get.mockReturnValue(undefined); - expect(() => component.ngOnInit()) - .toThrowError("keyresult id is undefined"); - }); - - it("should display edit keyresult button if writeable is true", - async () => { - const button = fixture.debugElement.query(By.css("[data-testId=\"edit-keyResult\"]")); - expect(button) - .toBeTruthy(); - }); - - it("should not display edit keyresult button if writeable is false", - async () => { - jest.spyOn(keyResultServiceMock, - "getFullKeyResult") - .mockReturnValue(of(keyResultWriteableFalse)); - component.ngOnInit(); - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"edit-keyResult\"]")); - expect(button) - .toBeFalsy(); - }); - - it("should display add check-in button if writeable is true", - async () => { - const button = fixture.debugElement.query(By.css("[data-testId=\"add-check-in\"]")); - expect(button) - .toBeTruthy(); - }); - - it("should not display add check-in button if writeable is false", - async () => { - jest.spyOn(keyResultServiceMock, - "getFullKeyResult") - .mockReturnValue(of(keyResultWriteableFalse)); - component.ngOnInit(); - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"add-check-in\"]")); - expect(button) - .toBeFalsy(); - }); - - it("should trigger observable when subject gets next value", - () => { - const spy = jest.spyOn(component, - "loadKeyResult"); - const refreshDataService = TestBed.inject(RefreshDataService); - refreshDataService.reloadKeyResultSubject.next(); - expect(spy) - .toHaveBeenCalled(); - }); - - it("should close subscription on destroy", - () => { - const spyNext = jest.spyOn(component.ngDestroy$, - "next"); - const spyComplete = jest.spyOn(component.ngDestroy$, - "complete"); - - component.ngOnDestroy(); - - expect(spyNext) - .toHaveBeenCalled(); - expect(spyComplete) - .toHaveBeenCalled(); - }); +describe("KeyresultDetailComponent", () => { + let component: KeyresultDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + MatDialogModule, + MatIconModule, + TranslateModule.forRoot() + ], + declarations: [KeyresultDetailComponent, + ScoringComponent, + ConfidenceComponent], + providers: [{ + provide: KeyresultService, + useValue: keyResultServiceMock + }, + { + provide: ActivatedRoute, + useValue: activatedRouteMock + }] + }) + .compileComponents(); + + jest.spyOn(keyResultServiceMock, "getFullKeyResult") + .mockReturnValue(of(keyResult)); + activatedRouteMock.snapshot.paramMap.get.mockReturnValue(of(1)); + + fixture = TestBed.createComponent(KeyresultDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should throw error when id is undefined", () => { + activatedRouteMock.snapshot.paramMap.get.mockReturnValue(undefined); + expect(() => component.ngOnInit()) + .toThrowError("keyresult id is undefined"); + }); + + it("should display edit keyresult button if writeable is true", async () => { + const button = fixture.debugElement.query(By.css("[data-testId=\"edit-keyResult\"]")); + expect(button) + .toBeTruthy(); + }); + + it("should not display edit keyresult button if writeable is false", async () => { + jest.spyOn(keyResultServiceMock, "getFullKeyResult") + .mockReturnValue(of(keyResultWriteableFalse)); + component.ngOnInit(); + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"edit-keyResult\"]")); + expect(button) + .toBeFalsy(); + }); + + it("should display add check-in button if writeable is true", async () => { + const button = fixture.debugElement.query(By.css("[data-testId=\"add-check-in\"]")); + expect(button) + .toBeTruthy(); + }); + + it("should not display add check-in button if writeable is false", async () => { + jest.spyOn(keyResultServiceMock, "getFullKeyResult") + .mockReturnValue(of(keyResultWriteableFalse)); + component.ngOnInit(); + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"add-check-in\"]")); + expect(button) + .toBeFalsy(); + }); + + it("should trigger observable when subject gets next value", () => { + const spy = jest.spyOn(component, "loadKeyResult"); + const refreshDataService = TestBed.inject(RefreshDataService); + refreshDataService.reloadKeyResultSubject.next(); + expect(spy) + .toHaveBeenCalled(); + }); + + it("should close subscription on destroy", () => { + const spyNext = jest.spyOn(component.ngDestroy$, "next"); + const spyComplete = jest.spyOn(component.ngDestroy$, "complete"); + + component.ngOnDestroy(); + + expect(spyNext) + .toHaveBeenCalled(); + expect(spyComplete) + .toHaveBeenCalled(); + }); +}); diff --git a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.ts b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.ts index 62ea3bffcb..4895f98c4e 100644 --- a/frontend/src/app/components/keyresult-detail/keyresult-detail.component.ts +++ b/frontend/src/app/components/keyresult-detail/keyresult-detail.component.ts @@ -87,13 +87,12 @@ export class KeyresultDetailComponent implements OnInit, OnDestroy { } checkInHistory () { - const dialogRef = this.dialogService.open(CheckInHistoryDialogComponent, - { - data: { - keyResult: this.keyResult$.getValue(), - isComplete: this.isComplete - } - }); + const dialogRef = this.dialogService.open(CheckInHistoryDialogComponent, { + data: { + keyResult: this.keyResult$.getValue(), + isComplete: this.isComplete + } + }); dialogRef.afterClosed() .subscribe(() => { this.refreshDataService.markDataRefresh(); @@ -102,13 +101,12 @@ export class KeyresultDetailComponent implements OnInit, OnDestroy { openEditKeyResultDialog (keyResult: KeyResult) { this.dialogService - .open(KeyresultDialogComponent, - { - data: { - objective: keyResult.objective, - keyResult: keyResult - } - }) + .open(KeyresultDialogComponent, { + data: { + objective: keyResult.objective, + keyResult: keyResult + } + }) .afterClosed() .subscribe((result) => { if (result?.closeState === CloseState.SAVED && result.id) { @@ -139,12 +137,11 @@ export class KeyresultDetailComponent implements OnInit, OnDestroy { } openCheckInForm () { - const dialogRef = this.dialogService.open(CheckInFormComponent, - { - data: { - keyResult: this.keyResult$.getValue() - } - }); + const dialogRef = this.dialogService.open(CheckInFormComponent, { + data: { + keyResult: this.keyResult$.getValue() + } + }); dialogRef.afterClosed() .subscribe(() => { this.refreshDataService.reloadKeyResultSubject.next(); diff --git a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.spec.ts b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.spec.ts index 1884a8e2c9..0dd1cebb56 100644 --- a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.spec.ts +++ b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.spec.ts @@ -29,739 +29,712 @@ import { MatDividerModule } from "@angular/material/divider"; import { DialogTemplateCoreComponent } from "../../shared/custom/dialog-template-core/dialog-template-core.component"; import { Quarter } from "../../shared/types/model/Quarter"; -describe("KeyresultDialogComponent", - () => { - let component: KeyresultDialogComponent; - let fixture: ComponentFixture; - let keyResultService: KeyresultService; - - const oauthMockService = { - getIdentityClaims () { - return { name: users[1].firstname + " " + users[1].lastname }; - } - }; - - const userService = { - getUsers () { - return of(users); - }, - getCurrentUser: jest.fn() - }; - - const fullObjective = { +describe("KeyresultDialogComponent", () => { + let component: KeyresultDialogComponent; + let fixture: ComponentFixture; + let keyResultService: KeyresultService; + + const oauthMockService = { + getIdentityClaims () { + return { name: users[1].firstname + " " + users[1].lastname }; + } + }; + + const userService = { + getUsers () { + return of(users); + }, + getCurrentUser: jest.fn() + }; + + const fullObjective = { + id: 1, + title: "Das ist ein Objective", + description: "Das ist die Beschreibung", + state: State.ONGOING, + team: { id: 1, + name: "Das Puzzle Team" }, + quarter: { id: 1, + label: "GJ 22/23-Q2" } + }; + + const keyResultObjective: KeyResultObjective = { + id: 2, + state: State.ONGOING, + quarter: new Quarter( + 1, "GJ 22/23-Q2", new Date(), new Date() + ) + }; + + const fullKeyResultMetric = { + id: 3, + version: 2, + actionList: [{ id: 1, - title: "Das ist ein Objective", - description: "Das ist die Beschreibung", - state: State.ONGOING, - team: { id: 1, - name: "Das Puzzle Team" }, - quarter: { id: 1, - label: "GJ 22/23-Q2" } - }; - - const keyResultObjective: KeyResultObjective = { + action: "Test", + isChecked: false, + keyResultId: 3, + priority: 0 + }, + { id: 2, - state: State.ONGOING, - quarter: new Quarter( - 1, - "GJ 22/23-Q2", - new Date(), - new Date() - ) - }; - - const fullKeyResultMetric = { + action: "Katze", + isChecked: false, + keyResultId: 3, + priority: 1 + }, + { id: 3, - version: 2, - actionList: [{ - id: 1, - action: "Test", - isChecked: false, - keyResultId: 3, - priority: 0 - }, - { - id: 2, - action: "Katze", - isChecked: false, - keyResultId: 3, - priority: 1 - }, - { - id: 3, - action: "Hund", - isChecked: true, - keyResultId: 3, - priority: 2 - }], - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - baseline: 3, - keyResultType: "metric", - stretchGoal: 25, - unit: "CHF" - }; - - const receivedKeyResultMetric = { + action: "Hund", + isChecked: true, + keyResultId: 3, + priority: 2 + }], + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + baseline: 3, + keyResultType: "metric", + stretchGoal: 25, + unit: "CHF" + }; + + const receivedKeyResultMetric = { + id: 3, + version: 2, + actionList: [{ + id: 1, + action: "Test", + isChecked: false, + keyResultId: 3, + priority: 0 + }, + { + id: 2, + action: "Katze", + isChecked: false, + keyResultId: 3, + priority: 1 + }, + { + id: 3, + action: "Hund", + isChecked: true, + keyResultId: 3, + priority: 2 + }], + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + baseline: 3, + keyResultType: "metric", + stretchGoal: 25, + unit: "CHF", + commitZone: null, + targetZone: null, + stretchZone: null + }; + + const fullKeyResultOrdinal = { + id: 6, + version: 2, + actionList: [{ + id: 1, + action: "Test", + isChecked: false, + keyResultId: 3, + priority: 0 + }, + { + id: 2, + action: "Katze", + isChecked: false, + keyResultId: 3, + priority: 1 + }, + { + id: 3, + action: "Hund", + isChecked: true, + keyResultId: 3, + priority: 2 + }], + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + keyResultType: "ordinal", + commitZone: "Commit zone", + targetZone: "Target zone", + stretchZone: "Stretch goal" + }; + + const receivedKeyResultOrdinal = { + id: 6, + version: 2, + actionList: [{ + id: 1, + action: "Test", + isChecked: false, + keyResultId: 3, + priority: 0 + }, + { + id: 2, + action: "Katze", + isChecked: false, + keyResultId: 3, + priority: 1 + }, + { id: 3, - version: 2, - actionList: [{ - id: 1, - action: "Test", - isChecked: false, - keyResultId: 3, - priority: 0 - }, - { - id: 2, - action: "Katze", - isChecked: false, - keyResultId: 3, - priority: 1 - }, - { - id: 3, - action: "Hund", - isChecked: true, - keyResultId: 3, - priority: 2 - }], - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - baseline: 3, - keyResultType: "metric", - stretchGoal: 25, - unit: "CHF", - commitZone: null, - targetZone: null, - stretchZone: null - }; - - const fullKeyResultOrdinal = { - id: 6, - version: 2, - actionList: [{ - id: 1, - action: "Test", - isChecked: false, - keyResultId: 3, - priority: 0 - }, - { - id: 2, - action: "Katze", - isChecked: false, - keyResultId: 3, - priority: 1 - }, - { - id: 3, - action: "Hund", - isChecked: true, - keyResultId: 3, - priority: 2 - }], - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - keyResultType: "ordinal", - commitZone: "Commit zone", - targetZone: "Target zone", - stretchZone: "Stretch goal" - }; - - const receivedKeyResultOrdinal = { - id: 6, - version: 2, - actionList: [{ - id: 1, - action: "Test", - isChecked: false, - keyResultId: 3, - priority: 0 - }, - { - id: 2, - action: "Katze", - isChecked: false, - keyResultId: 3, - priority: 1 - }, - { - id: 3, - action: "Hund", - isChecked: true, - keyResultId: 3, - priority: 2 - }], - title: "Der Titel ist hier", - description: "Die Beschreibung", - owner: testUser, - objective: keyResultObjective, - keyResultType: "ordinal", - commitZone: "Commit zone", - targetZone: "Target zone", - stretchZone: "Stretch goal", - baseline: null, - stretchGoal: null, - unit: null - }; - - const initKeyResult = { - id: undefined, - title: "", - description: "", - owner: testUser, - objective: fullObjective, - baseline: 3, - keyResultType: "metric", - stretchGoal: 25, - unit: "CHF", - commitZone: null, - targetZone: null, - stretchZone: null, - actionList: [] - }; - - const savedKeyResult = { - id: undefined, - version: undefined, - title: "Neuer Titel", - description: "Description", - owner: testUser, - objective: fullObjective, - baseline: 3, - keyResultType: "metric", - stretchGoal: 25, - unit: "CHF", - commitZone: null, - targetZone: null, - stretchZone: null, - actionList: [] - }; - - const matDialogRefMock = { - close: jest.fn() - }; - - const mockUserService = { - getUsers: jest.fn() - }; - - describe("New KeyResult", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule, - MatAutocompleteModule, - MatIconModule, - TranslateModule.forRoot(), - DragDropModule, - MatDividerModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - KeyresultService, - TranslateService, - { provide: UserService, - useValue: userService }, - { - provide: MatDialogRef, - useValue: matDialogRefMock - }, - { - provide: MAT_DIALOG_DATA, - useValue: { objective: fullObjective, - keyResult: undefined } - }, - { - provide: OAuthService, - useValue: oauthMockService - } - ], - declarations: [ - KeyresultDialogComponent, - KeyResultFormComponent, - KeyresultTypeComponent, - ActionPlanComponent, - DialogTemplateCoreComponent - ] - }) - .compileComponents(); - - fixture = TestBed.createComponent(KeyresultDialogComponent); - component = fixture.componentInstance; - - userService.getCurrentUser.mockReturnValue(testUser); - - fixture.detectChanges(); - keyResultService = TestBed.inject(KeyresultService); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should be able to set title", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: null, - actionList: [], - title: "Title", - baseline: 0, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: "FTE", - description: null, - stretchGoal: 0, - keyResultType: "metric" - }); - fixture.detectChanges(); - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.getAttribute("disabled")) - .toBeFalsy(); - - const formObject = component.keyResultForm.value; - expect(formObject.title) - .toBe("Title"); - expect(formObject.description) - .toBe(null); - })); - - it("should display error message of too short input", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "T", - baseline: null, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: null, - description: "", - stretchGoal: null, - keyResultType: null - }); - fixture.detectChanges(); - - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.getAttribute("disabled")) - .toEqual(""); - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["minlength"]) - .toBeTruthy(); - })); - - it("should display error message of required", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: null, - baseline: null, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: null, - description: "", - stretchGoal: null, - keyResultType: null - }); - fixture.detectChanges(); - - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.getAttribute("disabled")) - .toEqual(""); - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["required"]) - .toBeTruthy(); - })); - - it("should call service save method", - waitForAsync(() => { - const spy = jest.spyOn(keyResultService, - "saveKeyResult"); - spy.mockImplementation(() => of({ id: 2 } as KeyResult)); - - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "Neuer Titel", - baseline: 3, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: "CHF", - description: "Description", - stretchGoal: 25, - keyResultType: "metric" - }); - - initKeyResult.title = "Neuer Titel"; - initKeyResult.description = "Description"; - - component.saveKeyResult(); - - expect(spy) - .toBeCalledTimes(1); - expect(spy) - .toHaveBeenCalledWith(savedKeyResult); - })); + action: "Hund", + isChecked: true, + keyResultId: 3, + priority: 2 + }], + title: "Der Titel ist hier", + description: "Die Beschreibung", + owner: testUser, + objective: keyResultObjective, + keyResultType: "ordinal", + commitZone: "Commit zone", + targetZone: "Target zone", + stretchZone: "Stretch goal", + baseline: null, + stretchGoal: null, + unit: null + }; + + const initKeyResult = { + id: undefined, + title: "", + description: "", + owner: testUser, + objective: fullObjective, + baseline: 3, + keyResultType: "metric", + stretchGoal: 25, + unit: "CHF", + commitZone: null, + targetZone: null, + stretchZone: null, + actionList: [] + }; + + const savedKeyResult = { + id: undefined, + version: undefined, + title: "Neuer Titel", + description: "Description", + owner: testUser, + objective: fullObjective, + baseline: 3, + keyResultType: "metric", + stretchGoal: 25, + unit: "CHF", + commitZone: null, + targetZone: null, + stretchZone: null, + actionList: [] + }; + + const matDialogRefMock = { + close: jest.fn() + }; + + const mockUserService = { + getUsers: jest.fn() + }; + + describe("New KeyResult", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule, + MatAutocompleteModule, + MatIconModule, + TranslateModule.forRoot(), + DragDropModule, + MatDividerModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + KeyresultService, + TranslateService, + { provide: UserService, + useValue: userService }, + { + provide: MatDialogRef, + useValue: matDialogRefMock + }, + { + provide: MAT_DIALOG_DATA, + useValue: { objective: fullObjective, + keyResult: undefined } + }, + { + provide: OAuthService, + useValue: oauthMockService + } + ], + declarations: [ + KeyresultDialogComponent, + KeyResultFormComponent, + KeyresultTypeComponent, + ActionPlanComponent, + DialogTemplateCoreComponent + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KeyresultDialogComponent); + component = fixture.componentInstance; + + userService.getCurrentUser.mockReturnValue(testUser); + + fixture.detectChanges(); + keyResultService = TestBed.inject(KeyresultService); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should be able to set title", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: null, + actionList: [], + title: "Title", + baseline: 0, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: "FTE", + description: null, + stretchGoal: 0, + keyResultType: "metric" + }); + fixture.detectChanges(); + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.getAttribute("disabled")) + .toBeFalsy(); + + const formObject = component.keyResultForm.value; + expect(formObject.title) + .toBe("Title"); + expect(formObject.description) + .toBe(null); + })); + + it("should display error message of too short input", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "T", + baseline: null, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: null, + description: "", + stretchGoal: null, + keyResultType: null }); + fixture.detectChanges(); + + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.getAttribute("disabled")) + .toEqual(""); + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["minlength"]) + .toBeTruthy(); + })); + + it("should display error message of required", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: null, + baseline: null, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: null, + description: "", + stretchGoal: null, + keyResultType: null + }); + fixture.detectChanges(); + + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.getAttribute("disabled")) + .toEqual(""); + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["required"]) + .toBeTruthy(); + })); + + it("should call service save method", waitForAsync(() => { + const spy = jest.spyOn(keyResultService, "saveKeyResult"); + spy.mockImplementation(() => of({ id: 2 } as KeyResult)); + + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "Neuer Titel", + baseline: 3, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: "CHF", + description: "Description", + stretchGoal: 25, + keyResultType: "metric" + }); + + initKeyResult.title = "Neuer Titel"; + initKeyResult.description = "Description"; - describe("Edit KeyResult Metric", - () => { - beforeEach(() => { - mockUserService.getUsers.mockReturnValue(users); - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatInputModule, - ReactiveFormsModule, - MatIconModule, - MatAutocompleteModule, - DragDropModule, - TranslateModule.forRoot(), - MatDividerModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - KeyresultService, - { - provide: MatDialogRef, - useValue: { - close: () => {} - } - }, - { - provide: OAuthService, - useValue: oauthMockService - }, - { - provide: MAT_DIALOG_DATA, - useValue: { keyResult: fullKeyResultMetric, - objective: keyResultObjective } - } - ], - declarations: [ - KeyresultDialogComponent, - KeyResultFormComponent, - DialogTemplateCoreComponent, - ActionPlanComponent, - KeyresultTypeComponent - ] - }) - .compileComponents(); - - fixture = TestBed.createComponent(KeyresultDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - keyResultService = TestBed.inject(KeyresultService); - fullKeyResultMetric.id = 3; - }); - - afterEach(() => { - mockUserService.getUsers.mockReset(); - }); - - it("should use KeyResult value from data input", - waitForAsync(() => { - const formObject = fixture.componentInstance.keyResultForm.value; - expect(formObject.title) - .toBe("Der Titel ist hier"); - expect(formObject.description) - .toBe("Die Beschreibung"); - expect(formObject.owner) - .toBe(testUser); - })); - - it("should be able to set title and description", - waitForAsync(async () => { - expect(component.keyResultForm.value.title) - .toEqual("Der Titel ist hier"); - expect(component.keyResultForm.value.description) - .toEqual("Die Beschreibung"); - - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "Title", - baseline: 0, - stretchZone: "", - targetZone: "", - commitZone: "", - unit: "FTE", - description: "Description", - stretchGoal: 0, - keyResultType: "metric" - }); - fixture.detectChanges(); - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.getAttribute("disabled")) - .toBeFalsy(); - - const formObject = fixture.componentInstance.keyResultForm.value; - expect(formObject.title) - .toBe("Title"); - expect(formObject.description) - .toBe("Description"); - expect(component.keyResultForm.invalid) - .toBeFalsy(); - })); - - it("should display error message of too short input", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "T", - baseline: null, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: null, - description: "", - stretchGoal: null, - keyResultType: null - }); - fixture.detectChanges(); - - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["minlength"]) - .toBeTruthy(); - })); - - it("should display error message of required", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: null, - baseline: null, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: null, - description: "", - stretchGoal: null, - keyResultType: null - }); - fixture.detectChanges(); - - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["required"]) - .toBeTruthy(); - })); - - it("should call service save method", - waitForAsync(() => { - const spy = jest.spyOn(keyResultService, - "saveKeyResult"); - spy.mockImplementation(() => of({ id: 2 } as KeyResult)); - - component.saveKeyResult(); - - expect(spy) - .toBeCalledTimes(1); - expect(spy) - .toHaveBeenCalledWith(receivedKeyResultMetric); - })); - - it("should not display logged in user when editing", - waitForAsync(() => { - jest.resetAllMocks(); - const userServiceSpy = jest.spyOn(userService, - "getUsers"); - fixture.detectChanges(); - expect(userServiceSpy) - .toHaveBeenCalledTimes(0); - expect(component.keyResultForm.controls.owner.value) - .toBe(testUser); - })); + component.saveKeyResult(); + + expect(spy) + .toBeCalledTimes(1); + expect(spy) + .toHaveBeenCalledWith(savedKeyResult); + })); + }); + + describe("Edit KeyResult Metric", () => { + beforeEach(() => { + mockUserService.getUsers.mockReturnValue(users); + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatInputModule, + ReactiveFormsModule, + MatIconModule, + MatAutocompleteModule, + DragDropModule, + TranslateModule.forRoot(), + MatDividerModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + KeyresultService, + { + provide: MatDialogRef, + useValue: { + close: () => {} + } + }, + { + provide: OAuthService, + useValue: oauthMockService + }, + { + provide: MAT_DIALOG_DATA, + useValue: { keyResult: fullKeyResultMetric, + objective: keyResultObjective } + } + ], + declarations: [ + KeyresultDialogComponent, + KeyResultFormComponent, + DialogTemplateCoreComponent, + ActionPlanComponent, + KeyresultTypeComponent + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KeyresultDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + keyResultService = TestBed.inject(KeyresultService); + fullKeyResultMetric.id = 3; + }); + + afterEach(() => { + mockUserService.getUsers.mockReset(); + }); + + it("should use KeyResult value from data input", waitForAsync(() => { + const formObject = fixture.componentInstance.keyResultForm.value; + expect(formObject.title) + .toBe("Der Titel ist hier"); + expect(formObject.description) + .toBe("Die Beschreibung"); + expect(formObject.owner) + .toBe(testUser); + })); + + it("should be able to set title and description", waitForAsync(async () => { + expect(component.keyResultForm.value.title) + .toEqual("Der Titel ist hier"); + expect(component.keyResultForm.value.description) + .toEqual("Die Beschreibung"); + + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "Title", + baseline: 0, + stretchZone: "", + targetZone: "", + commitZone: "", + unit: "FTE", + description: "Description", + stretchGoal: 0, + keyResultType: "metric" }); + fixture.detectChanges(); + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.getAttribute("disabled")) + .toBeFalsy(); + + const formObject = fixture.componentInstance.keyResultForm.value; + expect(formObject.title) + .toBe("Title"); + expect(formObject.description) + .toBe("Description"); + expect(component.keyResultForm.invalid) + .toBeFalsy(); + })); + + it("should display error message of too short input", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "T", + baseline: null, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: null, + description: "", + stretchGoal: null, + keyResultType: null + }); + fixture.detectChanges(); + + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["minlength"]) + .toBeTruthy(); + })); + + it("should display error message of required", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: null, + baseline: null, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: null, + description: "", + stretchGoal: null, + keyResultType: null + }); + fixture.detectChanges(); + + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["required"]) + .toBeTruthy(); + })); + + it("should call service save method", waitForAsync(() => { + const spy = jest.spyOn(keyResultService, "saveKeyResult"); + spy.mockImplementation(() => of({ id: 2 } as KeyResult)); + + component.saveKeyResult(); + + expect(spy) + .toBeCalledTimes(1); + expect(spy) + .toHaveBeenCalledWith(receivedKeyResultMetric); + })); + + it("should not display logged in user when editing", waitForAsync(() => { + jest.resetAllMocks(); + const userServiceSpy = jest.spyOn(userService, "getUsers"); + fixture.detectChanges(); + expect(userServiceSpy) + .toHaveBeenCalledTimes(0); + expect(component.keyResultForm.controls.owner.value) + .toBe(testUser); + })); + }); - describe("Edit KeyResult Ordinal", - () => { - beforeEach(() => { - mockUserService.getUsers.mockReturnValue(users); - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatInputModule, - ReactiveFormsModule, - MatIconModule, - MatAutocompleteModule, - DragDropModule, - TranslateModule.forRoot(), - MatDividerModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - KeyresultService, - { - provide: MatDialogRef, - useValue: matDialogRefMock - }, - { - provide: OAuthService, - useValue: oauthMockService - }, - { - provide: MAT_DIALOG_DATA, - useValue: { keyResult: fullKeyResultOrdinal, - objective: keyResultObjective } - } - ], - declarations: [ - KeyresultDialogComponent, - KeyResultFormComponent, - DialogTemplateCoreComponent, - ActionPlanComponent, - KeyresultTypeComponent - ] - }) - .compileComponents(); - - fixture = TestBed.createComponent(KeyresultDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - keyResultService = TestBed.inject(KeyresultService); - }); - - afterEach(() => { - mockUserService.getUsers.mockReset(); - }); - - it("should use KeyResult value from data input", - waitForAsync(() => { - const formObject = fixture.componentInstance.keyResultForm.value; - expect(formObject.title) - .toBe("Der Titel ist hier"); - expect(formObject.description) - .toBe("Die Beschreibung"); - expect(formObject.owner) - .toBe(testUser); - })); - - it("should be able to set title and description", - waitForAsync(async () => { - expect(component.keyResultForm.value.title) - .toEqual("Der Titel ist hier"); - expect(component.keyResultForm.value.description) - .toEqual("Die Beschreibung"); - - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "Title", - baseline: 0, - stretchZone: "stretchZone", - targetZone: "targetZone", - commitZone: "commitZone", - unit: "FTE", - description: "Description", - stretchGoal: 0, - keyResultType: "ordinal" - }); - fixture.detectChanges(); - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.getAttribute("disabled")) - .toBeFalsy(); - - const formObject = fixture.componentInstance.keyResultForm.value; - expect(formObject.title) - .toBe("Title"); - expect(formObject.description) - .toBe("Description"); - expect(component.keyResultForm.invalid) - .toBeFalsy(); - })); - - it("should display error message of too short input", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: "T", - baseline: 0, - stretchZone: "", - targetZone: "", - commitZone: "", - unit: "FTE", - description: "Description", - stretchGoal: 0, - keyResultType: "metric" - }); - fixture.detectChanges(); - - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["minlength"]) - .toBeTruthy(); - })); - - it("should display error message of required", - waitForAsync(async () => { - component.keyResultForm.setValue({ - owner: testUser, - actionList: [], - title: null, - baseline: null, - stretchZone: null, - targetZone: null, - commitZone: null, - unit: null, - description: "", - stretchGoal: null, - keyResultType: null - }); - fixture.detectChanges(); - - expect(component.keyResultForm.invalid) - .toBeTruthy(); - expect(component.keyResultForm.get("title")!.errors?.["required"]) - .toBeTruthy(); - })); - - it("should call service save method", - waitForAsync(() => { - const spy = jest.spyOn(keyResultService, - "saveKeyResult"); - spy.mockImplementation(() => of({ id: 2 } as KeyResult)); - - component.saveKeyResult(); - - expect(spy) - .toBeCalledTimes(1); - expect(spy) - .toHaveBeenCalledWith(receivedKeyResultOrdinal); - })); + describe("Edit KeyResult Ordinal", () => { + beforeEach(() => { + mockUserService.getUsers.mockReturnValue(users); + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatInputModule, + ReactiveFormsModule, + MatIconModule, + MatAutocompleteModule, + DragDropModule, + TranslateModule.forRoot(), + MatDividerModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + KeyresultService, + { + provide: MatDialogRef, + useValue: matDialogRefMock + }, + { + provide: OAuthService, + useValue: oauthMockService + }, + { + provide: MAT_DIALOG_DATA, + useValue: { keyResult: fullKeyResultOrdinal, + objective: keyResultObjective } + } + ], + declarations: [ + KeyresultDialogComponent, + KeyResultFormComponent, + DialogTemplateCoreComponent, + ActionPlanComponent, + KeyresultTypeComponent + ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KeyresultDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + keyResultService = TestBed.inject(KeyresultService); + }); + + afterEach(() => { + mockUserService.getUsers.mockReset(); + }); + + it("should use KeyResult value from data input", waitForAsync(() => { + const formObject = fixture.componentInstance.keyResultForm.value; + expect(formObject.title) + .toBe("Der Titel ist hier"); + expect(formObject.description) + .toBe("Die Beschreibung"); + expect(formObject.owner) + .toBe(testUser); + })); + + it("should be able to set title and description", waitForAsync(async () => { + expect(component.keyResultForm.value.title) + .toEqual("Der Titel ist hier"); + expect(component.keyResultForm.value.description) + .toEqual("Die Beschreibung"); + + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "Title", + baseline: 0, + stretchZone: "stretchZone", + targetZone: "targetZone", + commitZone: "commitZone", + unit: "FTE", + description: "Description", + stretchGoal: 0, + keyResultType: "ordinal" }); + fixture.detectChanges(); + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.getAttribute("disabled")) + .toBeFalsy(); + + const formObject = fixture.componentInstance.keyResultForm.value; + expect(formObject.title) + .toBe("Title"); + expect(formObject.description) + .toBe("Description"); + expect(component.keyResultForm.invalid) + .toBeFalsy(); + })); + + it("should display error message of too short input", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: "T", + baseline: 0, + stretchZone: "", + targetZone: "", + commitZone: "", + unit: "FTE", + description: "Description", + stretchGoal: 0, + keyResultType: "metric" + }); + fixture.detectChanges(); + + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["minlength"]) + .toBeTruthy(); + })); + + it("should display error message of required", waitForAsync(async () => { + component.keyResultForm.setValue({ + owner: testUser, + actionList: [], + title: null, + baseline: null, + stretchZone: null, + targetZone: null, + commitZone: null, + unit: null, + description: "", + stretchGoal: null, + keyResultType: null + }); + fixture.detectChanges(); + + expect(component.keyResultForm.invalid) + .toBeTruthy(); + expect(component.keyResultForm.get("title")!.errors?.["required"]) + .toBeTruthy(); + })); + + it("should call service save method", waitForAsync(() => { + const spy = jest.spyOn(keyResultService, "saveKeyResult"); + spy.mockImplementation(() => of({ id: 2 } as KeyResult)); + + component.saveKeyResult(); + + expect(spy) + .toBeCalledTimes(1); + expect(spy) + .toHaveBeenCalledWith(receivedKeyResultOrdinal); + })); }); +}); diff --git a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts index 3a43805897..c9db7e03a4 100644 --- a/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts +++ b/frontend/src/app/components/keyresult-dialog/keyresult-dialog.component.ts @@ -18,15 +18,12 @@ import { DialogService } from "../../services/dialog.service"; }) export class KeyresultDialogComponent { keyResultForm = new FormGroup({ - title: new FormControl("", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("", - [Validators.maxLength(4096)]), - owner: new FormControl(null, - [Validators.required, - Validators.nullValidator]), + title: new FormControl("", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("", [Validators.maxLength(4096)]), + owner: new FormControl(null, [Validators.required, + Validators.nullValidator]), actionList: new FormControl([]), unit: new FormControl(null), baseline: new FormControl(null), diff --git a/frontend/src/app/components/keyresult-type/keyresult-type.component.spec.ts b/frontend/src/app/components/keyresult-type/keyresult-type.component.spec.ts index 8658124616..3bcb6575a2 100644 --- a/frontend/src/app/components/keyresult-type/keyresult-type.component.spec.ts +++ b/frontend/src/app/components/keyresult-type/keyresult-type.component.spec.ts @@ -9,316 +9,288 @@ import { By } from "@angular/platform-browser"; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; import { User } from "../../shared/types/model/User"; -describe("KeyresultTypeComponent", - () => { - let component: KeyresultTypeComponent; - let fixture: ComponentFixture; - - const metricKeyResult: KeyResult = keyResultMetric; - const ordinalKeyResult: KeyResult = keyResultOrdinal; - - const metricKeyResultForm = new FormGroup({ - title: new FormControl("100% aller Schweizer Kunden betreuen", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", - [Validators.maxLength(4096)]), - owner: new FormControl(testUser, - [Validators.required, - Validators.nullValidator]), - unit: new FormControl("PERCENT"), - baseline: new FormControl(30), - stretchGoal: new FormControl(100), - commitZone: new FormControl(null), - targetZone: new FormControl(null), - stretchZone: new FormControl(null), - keyResultType: new FormControl("metric") +describe("KeyresultTypeComponent", () => { + let component: KeyresultTypeComponent; + let fixture: ComponentFixture; + + const metricKeyResult: KeyResult = keyResultMetric; + const ordinalKeyResult: KeyResult = keyResultOrdinal; + + const metricKeyResultForm = new FormGroup({ + title: new FormControl("100% aller Schweizer Kunden betreuen", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", [Validators.maxLength(4096)]), + owner: new FormControl(testUser, [Validators.required, + Validators.nullValidator]), + unit: new FormControl("PERCENT"), + baseline: new FormControl(30), + stretchGoal: new FormControl(100), + commitZone: new FormControl(null), + targetZone: new FormControl(null), + stretchZone: new FormControl(null), + keyResultType: new FormControl("metric") + }); + + const ordinalKeyResultForm = new FormGroup({ + title: new FormControl("100% aller Schweizer Kunden betreuen", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", [Validators.maxLength(4096)]), + owner: new FormControl(testUser, [Validators.required, + Validators.nullValidator]), + unit: new FormControl(null), + baseline: new FormControl(null), + stretchGoal: new FormControl(null), + commitZone: new FormControl("Commit"), + targetZone: new FormControl("Target"), + stretchZone: new FormControl("Stretch"), + keyResultType: new FormControl("metric") + }); + + const emptyKeyResultForm = new FormGroup({ + title: new FormControl("100% aller Schweizer Kunden betreuen", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", [Validators.maxLength(4096)]), + owner: new FormControl(testUser, [Validators.required, + Validators.nullValidator]), + unit: new FormControl(null), + baseline: new FormControl(null), + stretchGoal: new FormControl(null), + commitZone: new FormControl(null), + targetZone: new FormControl(null), + stretchZone: new FormControl(null), + keyResultType: new FormControl("metric") + }); + + describe("Edit Metric", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [KeyresultTypeComponent], + imports: [TranslateTestingModule.withTranslations({ + de: de + }), + ReactiveFormsModule] + }); + fixture = TestBed.createComponent(KeyresultTypeComponent); + component = fixture.componentInstance; + component.keyResultForm = metricKeyResultForm; + fixture.detectChanges(); + component.keyresult = metricKeyResult; + fixture.detectChanges(); }); - const ordinalKeyResultForm = new FormGroup({ - title: new FormControl("100% aller Schweizer Kunden betreuen", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", - [Validators.maxLength(4096)]), - owner: new FormControl(testUser, - [Validators.required, - Validators.nullValidator]), - unit: new FormControl(null), - baseline: new FormControl(null), - stretchGoal: new FormControl(null), - commitZone: new FormControl("Commit"), - targetZone: new FormControl("Target"), - stretchZone: new FormControl("Stretch"), - keyResultType: new FormControl("metric") + it("should create", () => { + expect(component) + .toBeTruthy(); }); - const emptyKeyResultForm = new FormGroup({ - title: new FormControl("100% aller Schweizer Kunden betreuen", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("Puzzle ITC erledigt die IT-Aufträge für 100% aller Unternehmen.", - [Validators.maxLength(4096)]), - owner: new FormControl(testUser, - [Validators.required, - Validators.nullValidator]), - unit: new FormControl(null), - baseline: new FormControl(null), - stretchGoal: new FormControl(null), - commitZone: new FormControl(null), - targetZone: new FormControl(null), - stretchZone: new FormControl(null), - keyResultType: new FormControl("metric") + it("should use values from input", () => { + expect(component.typeChangeAllowed) + .toBeTruthy(); + expect(component.isMetric) + .toBeTruthy(); + expect(component.keyResultForm.value.unit) + .toEqual("PERCENT"); + expect(component.keyResultForm.value.baseline) + .toEqual(30); + expect(component.keyResultForm.value.stretchGoal) + .toEqual(100); + expect(component.keyResultForm.value.targetZone) + .toBeNull(); + expect(component.keyResultForm.value.commitZone) + .toBeNull(); + expect(component.keyResultForm.value.stretchZone) + .toBeNull(); }); - describe("Edit Metric", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [KeyresultTypeComponent], - imports: [TranslateTestingModule.withTranslations({ - de: de - }), - ReactiveFormsModule] - }); - fixture = TestBed.createComponent(KeyresultTypeComponent); - component = fixture.componentInstance; - component.keyResultForm = metricKeyResultForm; - fixture.detectChanges(); - component.keyresult = metricKeyResult; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should use values from input", - () => { - expect(component.typeChangeAllowed) - .toBeTruthy(); - expect(component.isMetric) - .toBeTruthy(); - expect(component.keyResultForm.value.unit) - .toEqual("PERCENT"); - expect(component.keyResultForm.value.baseline) - .toEqual(30); - expect(component.keyResultForm.value.stretchGoal) - .toEqual(100); - expect(component.keyResultForm.value.targetZone) - .toBeNull(); - expect(component.keyResultForm.value.commitZone) - .toBeNull(); - expect(component.keyResultForm.value.stretchZone) - .toBeNull(); - }); - - it("should switch type of KeyResult", - () => { - component.isMetric = true; - component.typeChangeAllowed = true; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeTruthy(); - component.switchKeyResultType("ordinal"); - expect(component.isMetric) - .toBeFalsy(); - component.typeChangeAllowed = false; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeFalsy(); - }); - - it("should select metric tab", - () => { - component.isMetric = true; - - const activeTab = document.getElementsByClassName("active")[0]; - expect(activeTab.innerHTML) - .toContain("Metrisch"); - }); - - it("should change to ordinal from html click", - () => { - component.typeChangeAllowed = true; - - expect(component.isMetric) - .toBeTruthy(); - const ordinalTab = fixture.debugElement.query(By.css("[data-testId=\"ordinalTab\"]")); - ordinalTab.nativeElement.click(); - expect(component.isMetric) - .toBeFalsy(); - }); - }); + it("should switch type of KeyResult", () => { + component.isMetric = true; + component.typeChangeAllowed = true; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeTruthy(); + component.switchKeyResultType("ordinal"); + expect(component.isMetric) + .toBeFalsy(); + component.typeChangeAllowed = false; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeFalsy(); + }); + + it("should select metric tab", () => { + component.isMetric = true; + + const activeTab = document.getElementsByClassName("active")[0]; + expect(activeTab.innerHTML) + .toContain("Metrisch"); + }); + + it("should change to ordinal from html click", () => { + component.typeChangeAllowed = true; + + expect(component.isMetric) + .toBeTruthy(); + const ordinalTab = fixture.debugElement.query(By.css("[data-testId=\"ordinalTab\"]")); + ordinalTab.nativeElement.click(); + expect(component.isMetric) + .toBeFalsy(); + }); + }); - describe("Edit Ordinal", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [KeyresultTypeComponent], - imports: [TranslateTestingModule.withTranslations({ - de: de - }), - ReactiveFormsModule] - }); - fixture = TestBed.createComponent(KeyresultTypeComponent); - component = fixture.componentInstance; - component.keyResultForm = ordinalKeyResultForm; - fixture.detectChanges(); - component.keyresult = ordinalKeyResult; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should use values from input", - () => { - expect(component.typeChangeAllowed) - .toBeTruthy(); - expect(component.keyResultForm.value.unit) - .toBeNull(); - expect(component.keyResultForm.value.baseline) - .toBeNull(); - expect(component.keyResultForm.value.stretchGoal) - .toBeNull(); - expect(component.keyResultForm.value.commitZone) - .toEqual("Commit"); - expect(component.keyResultForm.value.targetZone) - .toEqual("Target"); - expect(component.keyResultForm.value.stretchZone) - .toEqual("Stretch"); - }); - - it("should switch type of KeyResult", - () => { - component.isMetric = true; - component.typeChangeAllowed = true; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeTruthy(); - component.switchKeyResultType("ordinal"); - expect(component.isMetric) - .toBeFalsy(); - component.typeChangeAllowed = false; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeFalsy(); - }); - - it("should select ordinal tab", - () => { - component.isMetric = false; - fixture.detectChanges(); - - const activeTab = document.getElementsByClassName("active")[0]; - expect(activeTab.innerHTML) - .toContain("Ordinal"); - }); - - it("should change to metric from html click", - () => { - component.typeChangeAllowed = true; - component.isMetric = false; - - expect(component.isMetric) - .toBeFalsy(); - const metricTab = fixture.debugElement.query(By.css("[data-testId=\"metricTab\"]")); - metricTab.nativeElement.click(); - expect(component.isMetric) - .toBeTruthy(); - }); + describe("Edit Ordinal", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [KeyresultTypeComponent], + imports: [TranslateTestingModule.withTranslations({ + de: de + }), + ReactiveFormsModule] }); + fixture = TestBed.createComponent(KeyresultTypeComponent); + component = fixture.componentInstance; + component.keyResultForm = ordinalKeyResultForm; + fixture.detectChanges(); + component.keyresult = ordinalKeyResult; + fixture.detectChanges(); + }); - describe("Create", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [KeyresultTypeComponent], - imports: [TranslateTestingModule.withTranslations({ - de: de - }), - ReactiveFormsModule] - }); - fixture = TestBed.createComponent(KeyresultTypeComponent); - component = fixture.componentInstance; - component.keyResultForm = emptyKeyResultForm; - fixture.detectChanges(); - component.keyresult = {} as KeyResult; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should use default values", - () => { - expect(component.keyResultForm.value.unit) - .toBeNull(); - expect(component.keyResultForm.value.baseline) - .toBeNull(); - expect(component.keyResultForm.value.stretchGoal) - .toBeNull(); - expect(component.keyResultForm.value.commitZone) - .toBeNull(); - expect(component.keyResultForm.value.targetZone) - .toBeNull(); - expect(component.keyResultForm.value.stretchZone) - .toBeNull(); - }); - - it("should switch type of KeyResult", - () => { - component.isMetric = true; - component.typeChangeAllowed = true; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeTruthy(); - component.switchKeyResultType("ordinal"); - expect(component.isMetric) - .toBeFalsy(); - component.typeChangeAllowed = false; - - component.switchKeyResultType("metric"); - expect(component.isMetric) - .toBeFalsy(); - }); - - it("should select metric tab", - () => { - component.isMetric = true; - - const activeTab = document.getElementsByClassName("active")[0]; - expect(activeTab.innerHTML) - .toContain("Metrisch"); - }); - - it("should change to ordinal from html click", - () => { - component.typeChangeAllowed = true; - - expect(component.isMetric) - .toBeTruthy(); - const ordinalTab = fixture.debugElement.query(By.css("[data-testId=\"ordinalTab\"]")); - ordinalTab.nativeElement.click(); - expect(component.isMetric) - .toBeFalsy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should use values from input", () => { + expect(component.typeChangeAllowed) + .toBeTruthy(); + expect(component.keyResultForm.value.unit) + .toBeNull(); + expect(component.keyResultForm.value.baseline) + .toBeNull(); + expect(component.keyResultForm.value.stretchGoal) + .toBeNull(); + expect(component.keyResultForm.value.commitZone) + .toEqual("Commit"); + expect(component.keyResultForm.value.targetZone) + .toEqual("Target"); + expect(component.keyResultForm.value.stretchZone) + .toEqual("Stretch"); + }); + + it("should switch type of KeyResult", () => { + component.isMetric = true; + component.typeChangeAllowed = true; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeTruthy(); + component.switchKeyResultType("ordinal"); + expect(component.isMetric) + .toBeFalsy(); + component.typeChangeAllowed = false; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeFalsy(); + }); + + it("should select ordinal tab", () => { + component.isMetric = false; + fixture.detectChanges(); + + const activeTab = document.getElementsByClassName("active")[0]; + expect(activeTab.innerHTML) + .toContain("Ordinal"); + }); + + it("should change to metric from html click", () => { + component.typeChangeAllowed = true; + component.isMetric = false; + + expect(component.isMetric) + .toBeFalsy(); + const metricTab = fixture.debugElement.query(By.css("[data-testId=\"metricTab\"]")); + metricTab.nativeElement.click(); + expect(component.isMetric) + .toBeTruthy(); + }); + }); + + describe("Create", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [KeyresultTypeComponent], + imports: [TranslateTestingModule.withTranslations({ + de: de + }), + ReactiveFormsModule] }); + fixture = TestBed.createComponent(KeyresultTypeComponent); + component = fixture.componentInstance; + component.keyResultForm = emptyKeyResultForm; + fixture.detectChanges(); + component.keyresult = {} as KeyResult; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should use default values", () => { + expect(component.keyResultForm.value.unit) + .toBeNull(); + expect(component.keyResultForm.value.baseline) + .toBeNull(); + expect(component.keyResultForm.value.stretchGoal) + .toBeNull(); + expect(component.keyResultForm.value.commitZone) + .toBeNull(); + expect(component.keyResultForm.value.targetZone) + .toBeNull(); + expect(component.keyResultForm.value.stretchZone) + .toBeNull(); + }); + + it("should switch type of KeyResult", () => { + component.isMetric = true; + component.typeChangeAllowed = true; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeTruthy(); + component.switchKeyResultType("ordinal"); + expect(component.isMetric) + .toBeFalsy(); + component.typeChangeAllowed = false; + + component.switchKeyResultType("metric"); + expect(component.isMetric) + .toBeFalsy(); + }); + + it("should select metric tab", () => { + component.isMetric = true; + + const activeTab = document.getElementsByClassName("active")[0]; + expect(activeTab.innerHTML) + .toContain("Metrisch"); + }); + + it("should change to ordinal from html click", () => { + component.typeChangeAllowed = true; + + expect(component.isMetric) + .toBeTruthy(); + const ordinalTab = fixture.debugElement.query(By.css("[data-testId=\"ordinalTab\"]")); + ordinalTab.nativeElement.click(); + expect(component.isMetric) + .toBeFalsy(); + }); }); +}); diff --git a/frontend/src/app/components/keyresult-type/keyresult-type.component.ts b/frontend/src/app/components/keyresult-type/keyresult-type.component.ts index 6bdcc7264f..9add58fae8 100644 --- a/frontend/src/app/components/keyresult-type/keyresult-type.component.ts +++ b/frontend/src/app/components/keyresult-type/keyresult-type.component.ts @@ -63,8 +63,7 @@ export class KeyresultTypeComponent implements OnInit { } async updateFormValidity () { - await new Promise((r) => setTimeout(r, - 100)); + await new Promise((r) => setTimeout(r, 100)); } setValidatorsMetric () { @@ -109,7 +108,6 @@ export class KeyresultTypeComponent implements OnInit { error: string, field: string, firstNumber: number | null, secondNumber: number | null ): string { return field + this.translate.instant("DIALOG_ERRORS." + error) - .format(firstNumber, - secondNumber); + .format(firstNumber, secondNumber); } } diff --git a/frontend/src/app/components/keyresult/keyresult.component.spec.ts b/frontend/src/app/components/keyresult/keyresult.component.spec.ts index 411000a916..5708fa4e80 100644 --- a/frontend/src/app/components/keyresult/keyresult.component.spec.ts +++ b/frontend/src/app/components/keyresult/keyresult.component.spec.ts @@ -6,30 +6,28 @@ import { ScoringComponent } from "../../shared/custom/scoring/scoring.component" import { ConfidenceComponent } from "../confidence/confidence.component"; import { provideHttpClient, withInterceptorsFromDi } from "@angular/common/http"; -describe("KeyresultComponent", - () => { - let component: KeyresultComponent; - let fixture: ComponentFixture; +describe("KeyresultComponent", () => { + let component: KeyresultComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [KeyresultComponent, - ScoringComponent, - ConfidenceComponent], - imports: [MatDialogModule], - providers: [provideHttpClient(withInterceptorsFromDi())] - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [KeyresultComponent, + ScoringComponent, + ConfidenceComponent], + imports: [MatDialogModule], + providers: [provideHttpClient(withInterceptorsFromDi())] + }) + .compileComponents(); - fixture = TestBed.createComponent(KeyresultComponent); - component = fixture.componentInstance; - component.keyResult = keyResultMetricMin; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(KeyresultComponent); + component = fixture.componentInstance; + component.keyResult = keyResultMetricMin; + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/components/objective-detail/objective-detail.component.spec.ts b/frontend/src/app/components/objective-detail/objective-detail.component.spec.ts index 9089b9f351..7416225599 100644 --- a/frontend/src/app/components/objective-detail/objective-detail.component.spec.ts +++ b/frontend/src/app/components/objective-detail/objective-detail.component.spec.ts @@ -23,73 +23,67 @@ const activatedRouteMock = { } }; -describe("ObjectiveDetailComponent", - () => { - let component: ObjectiveDetailComponent; - let fixture: ComponentFixture; +describe("ObjectiveDetailComponent", () => { + let component: ObjectiveDetailComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - MatDialogModule, - MatIconModule, - TranslateModule.forRoot() - ], - providers: [{ provide: ObjectiveService, - useValue: objectiveService }, - { provide: ActivatedRoute, - useValue: activatedRouteMock }], - declarations: [ObjectiveDetailComponent] - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + MatDialogModule, + MatIconModule, + TranslateModule.forRoot() + ], + providers: [{ provide: ObjectiveService, + useValue: objectiveService }, + { provide: ActivatedRoute, + useValue: activatedRouteMock }], + declarations: [ObjectiveDetailComponent] + }) + .compileComponents(); - fixture = TestBed.createComponent(ObjectiveDetailComponent); - component = fixture.componentInstance; - objectiveService.getFullObjective.mockReturnValue(of(objective)); - activatedRouteMock.snapshot.paramMap.get = jest.fn(); - activatedRouteMock.snapshot.paramMap.get.mockReturnValue(of(1)); - }); + fixture = TestBed.createComponent(ObjectiveDetailComponent); + component = fixture.componentInstance; + objectiveService.getFullObjective.mockReturnValue(of(objective)); + activatedRouteMock.snapshot.paramMap.get = jest.fn(); + activatedRouteMock.snapshot.paramMap.get.mockReturnValue(of(1)); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should throw an exception, if id is undefined", - () => { - activatedRouteMock.snapshot.paramMap.get = () => undefined; - expect(() => component.ngOnInit()) - .toThrowError("objective id is undefined"); - }); + it("should throw an exception, if id is undefined", () => { + activatedRouteMock.snapshot.paramMap.get = () => undefined; + expect(() => component.ngOnInit()) + .toThrowError("objective id is undefined"); + }); - it("get data from backend", - () => { - fixture.detectChanges(); - component.objectiveId = 2; - const title = fixture.debugElement.query(By.css("[data-testId=\"objective-title\"]"))?.nativeElement.innerHTML; - const description = fixture.debugElement.query(By.css("[data-testId=\"description\"]"))?.nativeElement.innerHTML; - expect(title) - .toContain(objective.title); - expect(description) - .toContain(objective.description); - }); + it("get data from backend", () => { + fixture.detectChanges(); + component.objectiveId = 2; + const title = fixture.debugElement.query(By.css("[data-testId=\"objective-title\"]"))?.nativeElement.innerHTML; + const description = fixture.debugElement.query(By.css("[data-testId=\"description\"]"))?.nativeElement.innerHTML; + expect(title) + .toContain(objective.title); + expect(description) + .toContain(objective.description); + }); - it("should display add keyresult button if writeable is true", - async () => { - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult-objective-detail\"]")); - expect(button) - .toBeTruthy(); - }); + it("should display add keyresult button if writeable is true", async () => { + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult-objective-detail\"]")); + expect(button) + .toBeTruthy(); + }); - it("should not display add keyresult button if writeable is false", - async () => { - objectiveService.getFullObjective.mockReturnValue(of(objectiveWriteableFalse)); - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult-objective-detail\"]")); - expect(button) - .toBeFalsy(); - }); + it("should not display add keyresult button if writeable is false", async () => { + objectiveService.getFullObjective.mockReturnValue(of(objectiveWriteableFalse)); + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult-objective-detail\"]")); + expect(button) + .toBeFalsy(); }); +}); diff --git a/frontend/src/app/components/objective-detail/objective-detail.component.ts b/frontend/src/app/components/objective-detail/objective-detail.component.ts index 32e83df68b..641e7ff70f 100644 --- a/frontend/src/app/components/objective-detail/objective-detail.component.ts +++ b/frontend/src/app/components/objective-detail/objective-detail.component.ts @@ -49,13 +49,12 @@ export class ObjectiveDetailComponent implements OnInit { openAddKeyResultDialog () { this.dialogService - .open(KeyresultDialogComponent, - { - data: { - objective: this.objective$.getValue(), - keyResult: null - } - }) + .open(KeyresultDialogComponent, { + data: { + objective: this.objective$.getValue(), + keyResult: null + } + }) .afterClosed() .subscribe((result) => { if (result?.openNew) { @@ -67,15 +66,14 @@ export class ObjectiveDetailComponent implements OnInit { openEditObjectiveDialog () { this.dialogService - .open(ObjectiveFormComponent, - { - data: { - objective: { - objectiveId: this.objective$.getValue().id, - teamId: this.objective$.value.teamId - } + .open(ObjectiveFormComponent, { + data: { + objective: { + objectiveId: this.objective$.getValue().id, + teamId: this.objective$.value.teamId } - }) + } + }) .afterClosed() .subscribe((result) => { this.refreshDataService.markDataRefresh(); diff --git a/frontend/src/app/components/objective-filter/objective-filter.component.spec.ts b/frontend/src/app/components/objective-filter/objective-filter.component.spec.ts index 8bce393768..b69533a10c 100644 --- a/frontend/src/app/components/objective-filter/objective-filter.component.spec.ts +++ b/frontend/src/app/components/objective-filter/objective-filter.component.spec.ts @@ -17,94 +17,87 @@ import { authGuard } from "../../guards/auth.guard"; import { OverviewComponent } from "../overview/overview.component"; import { OAuthService } from "angular-oauth2-oidc"; -describe("ObjectiveFilterComponent", - () => { - let component: ObjectiveFilterComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; - let router: Router; +describe("ObjectiveFilterComponent", () => { + let component: ObjectiveFilterComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + let router: Router; - const authGuardMock = () => { - return Promise.resolve(true); - }; + const authGuardMock = () => { + return Promise.resolve(true); + }; - const oauthServiceMock = { - hasValidIdToken: jest.fn() - }; + const oauthServiceMock = { + hasValidIdToken: jest.fn() + }; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ObjectiveFilterComponent, - OverviewComponent], - providers: [{ - provide: authGuard, - useValue: authGuardMock - }, - { - provide: OAuthService, - useValue: oauthServiceMock - }], - imports: [ - HttpClientTestingModule, - AppRoutingModule, - MatFormFieldModule, - MatIconModule, - FormsModule, - MatInputModule, - NoopAnimationsModule - ] - }); - fixture = TestBed.createComponent(ObjectiveFilterComponent); - component = fixture.componentInstance; - loader = TestbedHarnessEnvironment.loader(fixture); - router = TestBed.inject(Router); - - fixture.detectChanges(); + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ObjectiveFilterComponent, + OverviewComponent], + providers: [{ + provide: authGuard, + useValue: authGuardMock + }, + { + provide: OAuthService, + useValue: oauthServiceMock + }], + imports: [ + HttpClientTestingModule, + AppRoutingModule, + MatFormFieldModule, + MatIconModule, + FormsModule, + MatInputModule, + NoopAnimationsModule + ] }); + fixture = TestBed.createComponent(ObjectiveFilterComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + router = TestBed.inject(Router); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + fixture.detectChanges(); + }); - it("should route correctly", - fakeAsync(() => { - loader.getHarness(MatInputHarness) - .then((search) => { - jest.spyOn(router, - "navigate"); - jest.spyOn(component, - "updateURL"); - search.setValue("this is a test"); - fixture.detectChanges(); - component.refresh.next(); - tick(200); - expect(component.updateURL) - .toHaveBeenCalledTimes(0); - tick(200); - expect(router.navigate) - .toHaveBeenCalledWith([], - { queryParams: { objectiveQuery: "this is a test" } }); - expect(router.url) - .toBe("/?objectiveQuery=this%20is%20a%20test"); - }); - })); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should read from query correctly", - fakeAsync(() => { - const searchPromise = loader.getHarness(MatInputHarness); - const routerPromise = RouterTestingHarness.create(); + it("should route correctly", fakeAsync(() => { + loader.getHarness(MatInputHarness) + .then((search) => { + jest.spyOn(router, "navigate"); + jest.spyOn(component, "updateURL"); + search.setValue("this is a test"); + fixture.detectChanges(); + component.refresh.next(); + tick(200); + expect(component.updateURL) + .toHaveBeenCalledTimes(0); + tick(200); + expect(router.navigate) + .toHaveBeenCalledWith([], { queryParams: { objectiveQuery: "this is a test" } }); + expect(router.url) + .toBe("/?objectiveQuery=this%20is%20a%20test"); + }); + })); - Promise.all([searchPromise, - routerPromise]) - .then(([search, - router]: [MatInputHarness, RouterTestingHarness]) => { - router.navigateByUrl("/?objectiveQuery=this%20is%20a%20test"); - tick(500); - fixture.detectChanges(); - expect(component.query) - .toBe("this is a test"); - }); - })); - }); + it("should read from query correctly", fakeAsync(() => { + const searchPromise = loader.getHarness(MatInputHarness); + const routerPromise = RouterTestingHarness.create(); + + Promise.all([searchPromise, + routerPromise]) + .then(([search, + router]: [MatInputHarness, RouterTestingHarness]) => { + router.navigateByUrl("/?objectiveQuery=this%20is%20a%20test"); + tick(500); + fixture.detectChanges(); + expect(component.query) + .toBe("this is a test"); + }); + })); +}); diff --git a/frontend/src/app/components/objective-filter/objective-filter.component.ts b/frontend/src/app/components/objective-filter/objective-filter.component.ts index e1f32ef6c6..ec268b6654 100644 --- a/frontend/src/app/components/objective-filter/objective-filter.component.ts +++ b/frontend/src/app/components/objective-filter/objective-filter.component.ts @@ -24,8 +24,7 @@ export class ObjectiveFilterComponent implements OnInit { const sanitizedQuery = sanitize(this.query); const params = { objectiveQuery: sanitizedQuery }; const optionalParams = optionalReplaceWithNulls(params); - this.router.navigate([], - { queryParams: optionalParams }); + this.router.navigate([], { queryParams: optionalParams }); } ngOnInit () { diff --git a/frontend/src/app/components/objective/ObjectiveMenuActions.ts b/frontend/src/app/components/objective/ObjectiveMenuActions.ts index be0ecc671f..daf215a29c 100644 --- a/frontend/src/app/components/objective/ObjectiveMenuActions.ts +++ b/frontend/src/app/components/objective/ObjectiveMenuActions.ts @@ -26,8 +26,7 @@ export class ObjectiveMenuActions { releaseFromBacklogAction (objective: ObjectiveMin): ObjectiveMenuEntry { const config = { data: { objective: { objectiveId: objective.id }, action: "releaseBacklog" } }; - const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, - config); + const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, config); const afterAction: ObjectiveMenuAfterAction = () => this.refreshDataService.markDataRefresh(); return { displayName: "Objective veröffentlichen", action: action, @@ -36,8 +35,7 @@ export class ObjectiveMenuActions { editObjectiveAction (objective: ObjectiveMin): ObjectiveMenuEntry { const config = { data: { objective: { objectiveId: objective.id } } }; - const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, - config); + const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, config); const afterAction: ObjectiveMenuAfterAction = () => { this.refreshDataService.markDataRefresh(); }; @@ -49,8 +47,7 @@ export class ObjectiveMenuActions { duplicateObjectiveAction (objective: ObjectiveMin): ObjectiveMenuEntry { const config = { data: { objective: { objectiveId: objective.id }, action: "duplicate" } }; - const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, - config); + const action: ObjectiveMenuAction = () => this.dialogService.open(ObjectiveFormComponent, config); const afterAction: ObjectiveMenuAfterAction = () => this.refreshDataService.markDataRefresh(); return { displayName: "Objective duplizieren", action: action, @@ -61,10 +58,8 @@ export class ObjectiveMenuActions { const config = { data: { objectiveTitle: objective.title } }; - const action: ObjectiveMenuAction = () => this.dialogService.open(CompleteDialogComponent, - config); - const afterAction: ObjectiveMenuAfterAction = (obj: ObjectiveMin, result: any) => this.afterActions.completeObjective(obj, - result); + const action: ObjectiveMenuAction = () => this.dialogService.open(CompleteDialogComponent, config); + const afterAction: ObjectiveMenuAfterAction = (obj: ObjectiveMin, result: any) => this.afterActions.completeObjective(obj, result); return { displayName: "Objective abschliessen", action: action, diff --git a/frontend/src/app/components/objective/objective.component.spec.ts b/frontend/src/app/components/objective/objective.component.spec.ts index 42cdf8a6ab..d6779550e3 100644 --- a/frontend/src/app/components/objective/objective.component.spec.ts +++ b/frontend/src/app/components/objective/objective.component.spec.ts @@ -37,109 +37,103 @@ const completedServiceMock = { deleteCompleted: jest.fn() }; -describe("ObjectiveColumnComponent", - () => { - let component: ObjectiveComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; - beforeEach(() => { - overviewServiceMock.getObjectiveWithKeyresults.mockReset(); +describe("ObjectiveColumnComponent", () => { + let component: ObjectiveComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + beforeEach(() => { + overviewServiceMock.getObjectiveWithKeyresults.mockReset(); - TestBed.configureTestingModule({ - declarations: [ - ObjectiveComponent, - KeyresultComponent, - ScoringComponent, - ConfidenceComponent, - KeyresultComponent - ], - imports: [ - MatMenuModule, - MatCardModule, - NoopAnimationsModule, - MatDialogModule, - MatIconModule, - MatTooltipModule, - ReactiveFormsModule, - TranslateTestingModule.withTranslations({ - de: de - }) - ], - providers: [ - { provide: OverviewService, - useValue: overviewServiceMock }, - { provide: ObjectiveService, - useValue: objectiveServiceMock }, - { provide: CompletedService, - useValue: completedServiceMock }, - provideHttpClient(withInterceptorsFromDi()) - ] - }) - .compileComponents(); + TestBed.configureTestingModule({ + declarations: [ + ObjectiveComponent, + KeyresultComponent, + ScoringComponent, + ConfidenceComponent, + KeyresultComponent + ], + imports: [ + MatMenuModule, + MatCardModule, + NoopAnimationsModule, + MatDialogModule, + MatIconModule, + MatTooltipModule, + ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de + }) + ], + providers: [ + { provide: OverviewService, + useValue: overviewServiceMock }, + { provide: ObjectiveService, + useValue: objectiveServiceMock }, + { provide: CompletedService, + useValue: completedServiceMock }, + provideHttpClient(withInterceptorsFromDi()) + ] + }) + .compileComponents(); - fixture = TestBed.createComponent(ObjectiveComponent); - component = fixture.componentInstance; + fixture = TestBed.createComponent(ObjectiveComponent); + component = fixture.componentInstance; - loader = TestbedHarnessEnvironment.loader(fixture); - component.objective = objectiveMin; - }); + loader = TestbedHarnessEnvironment.loader(fixture); + component.objective = objectiveMin; + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - test("Mat-menu should open and close", - async () => { - component.isWritable = true; - fixture.detectChanges(); + test("Mat-menu should open and close", async () => { + component.isWritable = true; + fixture.detectChanges(); - const menu = await loader.getHarness(MatMenuHarness.with({ selector: "[data-testid=\"three-dot-menu\"]" })); - expect(await menu.isOpen()) - .toBeFalsy(); - await menu.open(); - expect(await menu.isOpen()) - .toBeTruthy(); - await menu.close(); - expect(await menu.isOpen()) - .toBeFalsy(); - }); + const menu = await loader.getHarness(MatMenuHarness.with({ selector: "[data-testid=\"three-dot-menu\"]" })); + expect(await menu.isOpen()) + .toBeFalsy(); + await menu.open(); + expect(await menu.isOpen()) + .toBeTruthy(); + await menu.close(); + expect(await menu.isOpen()) + .toBeFalsy(); + }); - test.each([ - [State.DRAFT, - "assets/icons/draft-icon.svg"], - [State.ONGOING, - "assets/icons/ongoing-icon.svg"], - [State.SUCCESSFUL, - "assets/icons/successful-icon.svg"], - [State.NOTSUCCESSFUL, - "assets/icons/not-successful-icon.svg"] - ])("Status-indicator should change based on the state given by the service", - (state: State, path) => { - component.objective = { ...objectiveMin, - state: state }; - fixture.detectChanges(); - const image = fixture.debugElement.query(By.css("[data-testid=\"objective-state\"]")); - const statusIndicatorSrc = image.attributes["src"]; - expect(statusIndicatorSrc) - .toBe(path); - }); + test.each([ + [State.DRAFT, + "assets/icons/draft-icon.svg"], + [State.ONGOING, + "assets/icons/ongoing-icon.svg"], + [State.SUCCESSFUL, + "assets/icons/successful-icon.svg"], + [State.NOTSUCCESSFUL, + "assets/icons/not-successful-icon.svg"] + ])("Status-indicator should change based on the state given by the service", (state: State, path) => { + component.objective = { ...objectiveMin, + state: state }; + fixture.detectChanges(); + const image = fixture.debugElement.query(By.css("[data-testid=\"objective-state\"]")); + const statusIndicatorSrc = image.attributes["src"]; + expect(statusIndicatorSrc) + .toBe(path); + }); - test("Mat-menu should not be present if writeable is false", - async () => { - component.isWritable = false; - fixture.detectChanges(); - const menu = fixture.debugElement.query(By.css("[data-testid=\"objective-menu\"]")); - expect(menu) - .toBeFalsy(); - }); + test("Mat-menu should not be present if writeable is false", async () => { + component.isWritable = false; + fixture.detectChanges(); + const menu = fixture.debugElement.query(By.css("[data-testid=\"objective-menu\"]")); + expect(menu) + .toBeFalsy(); + }); - test("Create keyresult button should not be present if writeable is false", - async () => { - component.isWritable = false; - const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult\"]")); - expect(button) - .toBeFalsy(); - }); + test("Create keyresult button should not be present if writeable is false", async () => { + component.isWritable = false; + const button = fixture.debugElement.query(By.css("[data-testId=\"add-keyResult\"]")); + expect(button) + .toBeFalsy(); }); +}); diff --git a/frontend/src/app/components/objective/objective.component.ts b/frontend/src/app/components/objective/objective.component.ts index 0f4a3b2b7e..56da7f5363 100644 --- a/frontend/src/app/components/objective/objective.component.ts +++ b/frontend/src/app/components/objective/objective.component.ts @@ -43,8 +43,7 @@ export class ObjectiveComponent { getStateTooltip (stateString: string): string { const state = this.getStateByValue(stateString); - return this.translate.instant("INFORMATION.OBJECTIVE_STATE_TOOLTIP", - { state: state }); + return this.translate.instant("INFORMATION.OBJECTIVE_STATE_TOOLTIP", { state: state }); } redirect (menuEntry: ObjectiveMenuEntry, objectiveMin: ObjectiveMin) { @@ -54,8 +53,7 @@ export class ObjectiveComponent { .pipe(take(1)) .subscribe((result) => { if (result) { - menuEntry.afterAction(objectiveMin, - result); + menuEntry.afterAction(objectiveMin, result); } this.trigger?.focus(); }); @@ -68,13 +66,12 @@ export class ObjectiveComponent { openAddKeyResultDialog (objective: ObjectiveMin) { this.dialogService - .open(KeyresultDialogComponent, - { - data: { - objective: objective, - keyResult: null - } - }) + .open(KeyresultDialogComponent, { + data: { + objective: objective, + keyResult: null + } + }) .afterClosed() .subscribe((result) => { if (result?.openNew) { diff --git a/frontend/src/app/components/overview/overview.component.spec.ts b/frontend/src/app/components/overview/overview.component.spec.ts index f3a5ba7d41..5a1379416a 100644 --- a/frontend/src/app/components/overview/overview.component.spec.ts +++ b/frontend/src/app/components/overview/overview.component.spec.ts @@ -40,172 +40,152 @@ class ResizeObserverMock { disconnect () {} } -describe("OverviewComponent", - () => { +describe("OverviewComponent", () => { // @ts-ignore - global.ResizeObserver = ResizeObserverMock; - - let component: OverviewComponent; - let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - AppRoutingModule, - MatDialogModule, - MatIconModule, - MatMenuModule - ], - declarations: [OverviewComponent, - ApplicationBannerComponent, - ApplicationTopBarComponent], - providers: [ - { - provide: OverviewService, - useValue: overviewService - }, - { - provide: authGuard, - useValue: authGuardMock - }, - { - provide: RefreshDataService, - useValue: refreshDataServiceMock - }, - { - provide: MatDialogRef, - useValue: {} - }, - OAuthService, - UrlHelperService, - OAuthLogger, - DateTimeProvider - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] - }) - .compileComponents(); - - fixture = TestBed.createComponent(OverviewComponent); - component = fixture.componentInstance; - overviewService.getOverview.mockReturnValue(of([overViewEntity1])); - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should load default overview when no quarter is defined in route-params", - () => { - jest.spyOn(overviewService, - "getOverview"); - markFiltersAsReady(); - expect(overviewService.getOverview) - .toHaveBeenCalled(); - }); - - it("should load default overview on init", - async () => { - jest.spyOn(overviewService, - "getOverview"); - markFiltersAsReady(); - expect(overviewService.getOverview) - .toHaveBeenCalledWith(undefined, - [], - ""); - }); - - it.each([ - [ - "?quarter=7", - 7, - [], - "" + global.ResizeObserver = ResizeObserverMock; + + let component: OverviewComponent; + let fixture: ComponentFixture; + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + AppRoutingModule, + MatDialogModule, + MatIconModule, + MatMenuModule ], - [ - "?teams=1,2", - undefined, - [1, - 2], - "" + declarations: [OverviewComponent, + ApplicationBannerComponent, + ApplicationTopBarComponent], + providers: [ + { + provide: OverviewService, + useValue: overviewService + }, + { + provide: authGuard, + useValue: authGuardMock + }, + { + provide: RefreshDataService, + useValue: refreshDataServiceMock + }, + { + provide: MatDialogRef, + useValue: {} + }, + OAuthService, + UrlHelperService, + OAuthLogger, + DateTimeProvider ], - [ - "?objectiveQuery=a%20a", - undefined, - [], - "a a" - ], - [ - "?teams=1,2&objectiveQuery=a%20a", - undefined, - [1, - 2], - "a a" - ], - [ - "?teams=1,2&quarter=7", - 7, - [1, - 2], - "" - ], - [ - "?quarter=7&objectiveQuery=a%20a", - 7, - [], - "a a" - ] - ])("should load overview based on queryparams", - async ( - query: string, quarterParam?: number, teamsParam?: number[], objectiveQueryParam?: string - ) => { - jest.spyOn(overviewService, - "getOverview"); - jest.spyOn(component, - "loadOverview"); - const routerHarness = await RouterTestingHarness.create(); - await routerHarness.navigateByUrl("/" + query); - routerHarness.detectChanges(); - component.loadOverviewWithParams(); - expect(overviewService.getOverview) - .toHaveBeenCalledWith(quarterParam, - teamsParam, - objectiveQueryParam); - expect(component.loadOverview) - .toHaveBeenCalledWith(quarterParam, - teamsParam, - objectiveQueryParam); - }); - - it("should refresh overview Entities after getOverview is called", - async () => { - jest.spyOn(component.overviewEntities$, - "next"); - jest.spyOn(component, - "loadOverview"); - component.loadOverview(); - expect(component.loadOverview) - .toHaveBeenCalledTimes(1); - expect(component.overviewEntities$.next) - .toHaveBeenCalledWith([overViewEntity1]); - }); - - it("should get default if call throws error", - async () => { - overviewService.getOverview.mockReturnValue(of(new Error(""))); - - jest.spyOn(component, - "loadOverview"); - component.loadOverview(); - expect(component.loadOverview) - .toHaveBeenLastCalledWith(); - }); - - function markFiltersAsReady () { - refreshDataServiceMock.quarterFilterReady.next(null); - refreshDataServiceMock.teamFilterReady.next(null); - fixture.detectChanges(); - } + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }) + .compileComponents(); + + fixture = TestBed.createComponent(OverviewComponent); + component = fixture.componentInstance; + overviewService.getOverview.mockReturnValue(of([overViewEntity1])); + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should load default overview when no quarter is defined in route-params", () => { + jest.spyOn(overviewService, "getOverview"); + markFiltersAsReady(); + expect(overviewService.getOverview) + .toHaveBeenCalled(); + }); + + it("should load default overview on init", async () => { + jest.spyOn(overviewService, "getOverview"); + markFiltersAsReady(); + expect(overviewService.getOverview) + .toHaveBeenCalledWith(undefined, [], ""); }); + + it.each([ + [ + "?quarter=7", + 7, + [], + "" + ], + [ + "?teams=1,2", + undefined, + [1, + 2], + "" + ], + [ + "?objectiveQuery=a%20a", + undefined, + [], + "a a" + ], + [ + "?teams=1,2&objectiveQuery=a%20a", + undefined, + [1, + 2], + "a a" + ], + [ + "?teams=1,2&quarter=7", + 7, + [1, + 2], + "" + ], + [ + "?quarter=7&objectiveQuery=a%20a", + 7, + [], + "a a" + ] + ])("should load overview based on queryparams", async ( + query: string, quarterParam?: number, teamsParam?: number[], objectiveQueryParam?: string + ) => { + jest.spyOn(overviewService, "getOverview"); + jest.spyOn(component, "loadOverview"); + const routerHarness = await RouterTestingHarness.create(); + await routerHarness.navigateByUrl("/" + query); + routerHarness.detectChanges(); + component.loadOverviewWithParams(); + expect(overviewService.getOverview) + .toHaveBeenCalledWith(quarterParam, teamsParam, objectiveQueryParam); + expect(component.loadOverview) + .toHaveBeenCalledWith(quarterParam, teamsParam, objectiveQueryParam); + }); + + it("should refresh overview Entities after getOverview is called", async () => { + jest.spyOn(component.overviewEntities$, "next"); + jest.spyOn(component, "loadOverview"); + component.loadOverview(); + expect(component.loadOverview) + .toHaveBeenCalledTimes(1); + expect(component.overviewEntities$.next) + .toHaveBeenCalledWith([overViewEntity1]); + }); + + it("should get default if call throws error", async () => { + overviewService.getOverview.mockReturnValue(of(new Error(""))); + + jest.spyOn(component, "loadOverview"); + component.loadOverview(); + expect(component.loadOverview) + .toHaveBeenLastCalledWith(); + }); + + function markFiltersAsReady () { + refreshDataServiceMock.quarterFilterReady.next(null); + refreshDataServiceMock.teamFilterReady.next(null); + fixture.detectChanges(); + } +}); diff --git a/frontend/src/app/components/overview/overview.component.ts b/frontend/src/app/components/overview/overview.component.ts index 4d8749d292..08344c7524 100644 --- a/frontend/src/app/components/overview/overview.component.ts +++ b/frontend/src/app/components/overview/overview.component.ts @@ -80,16 +80,12 @@ export class OverviewComponent implements OnInit, OnDestroy { const teamIds = getValueFromQuery(teamQuery); const quarterId = getValueFromQuery(quarterQuery)[0]; const objectiveQueryString = getQueryString(objectiveQuery); - this.loadOverview(quarterId, - teamIds, - objectiveQueryString); + this.loadOverview(quarterId, teamIds, objectiveQueryString); } loadOverview (quarterId?: number, teamIds?: number[], objectiveQuery?: string) { this.overviewService - .getOverview(quarterId, - teamIds, - objectiveQuery) + .getOverview(quarterId, teamIds, objectiveQuery) .pipe(catchError(() => { this.loadOverview(); return EMPTY; diff --git a/frontend/src/app/components/quarter-filter/quarter-filter.component.spec.ts b/frontend/src/app/components/quarter-filter/quarter-filter.component.spec.ts index f1c3a221bd..7a5d41186b 100644 --- a/frontend/src/app/components/quarter-filter/quarter-filter.component.spec.ts +++ b/frontend/src/app/components/quarter-filter/quarter-filter.component.spec.ts @@ -21,28 +21,16 @@ const overviewService = { const quarters = [ new Quarter( - 999, - "Backlog", - null, - null + 999, "Backlog", null, null ), new Quarter( - 2, - "23.02.2025", - new Date(), - new Date() + 2, "23.02.2025", new Date(), new Date() ), new Quarter( - 5, - "23.02.2025", - new Date(), - new Date() + 5, "23.02.2025", new Date(), new Date() ), new Quarter( - 7, - "23.02.2025", - new Date(), - new Date() + 7, "23.02.2025", new Date(), new Date() ) ]; @@ -55,110 +43,101 @@ const quarterService = { } }; -describe("QuarterFilterComponent", - () => { - let component: QuarterFilterComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; - let router: Router; +describe("QuarterFilterComponent", () => { + let component: QuarterFilterComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + let router: Router; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [QuarterFilterComponent], - imports: [ - HttpClientTestingModule, - RouterTestingModule, - FormsModule, - MatSelectModule, - MatFormFieldModule, - NoopAnimationsModule - ], - providers: [{ provide: OverviewService, - useValue: overviewService }, - { provide: QuarterService, - useValue: quarterService }] - }); - fixture = TestBed.createComponent(QuarterFilterComponent); - component = fixture.componentInstance; - loader = TestbedHarnessEnvironment.loader(fixture); - router = TestBed.inject(Router); - fixture.detectChanges(); + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [QuarterFilterComponent], + imports: [ + HttpClientTestingModule, + RouterTestingModule, + FormsModule, + MatSelectModule, + MatFormFieldModule, + NoopAnimationsModule + ], + providers: [{ provide: OverviewService, + useValue: overviewService }, + { provide: QuarterService, + useValue: quarterService }] }); + fixture = TestBed.createComponent(QuarterFilterComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + router = TestBed.inject(Router); + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should set correct default quarter if no route param is defined", - async () => { - jest.spyOn(component, - "changeDisplayedQuarter"); - jest.spyOn(quarters[2] as any, - "isCurrent") - .mockReturnValue(true); - const quarterSelect = await loader.getHarness(MatSelectHarness); - expect(quarterSelect) - .toBeTruthy(); - component.ngOnInit(); - fixture.detectChanges(); - expect(component.currentQuarterId) - .toBe(quarters[2].id); - expect(await quarterSelect.getValueText()) - .toBe(quarters[2].label + " Aktuell"); - expect(component.changeDisplayedQuarter) - .toHaveBeenCalledTimes(1); - }); - - it("should set correct value in form according to route param", - async () => { - jest.spyOn(component, - "changeDisplayedQuarter"); - const routerHarnessPromise = RouterTestingHarness.create(); - const quarterSelectPromise = loader.getHarness(MatSelectHarness); - await Promise.all([routerHarnessPromise, - quarterSelectPromise]) - .then(async ([routerHarness, - quarterSelect]) => { - await routerHarness.navigateByUrl("/?quarter=" + quarters[3].id); - - expect(quarterSelect) - .toBeTruthy(); - routerHarness.detectChanges(); - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.currentQuarterId) - .toBe(quarters[3].id); - expect(await quarterSelect.getValueText()) - .toBe(quarters[3].label); - expect(component.changeDisplayedQuarter) - .toHaveBeenCalledTimes(1); - }); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should set default quarter if quarter id in route params does not exist", - async () => { - jest.spyOn(component, - "changeDisplayedQuarter"); - const quarterSelect = await loader.getHarness(MatSelectHarness); + it("should set correct default quarter if no route param is defined", async () => { + jest.spyOn(component, "changeDisplayedQuarter"); + jest.spyOn(quarters[2] as any, "isCurrent") + .mockReturnValue(true); + const quarterSelect = await loader.getHarness(MatSelectHarness); + expect(quarterSelect) + .toBeTruthy(); + component.ngOnInit(); + fixture.detectChanges(); + expect(component.currentQuarterId) + .toBe(quarters[2].id); + expect(await quarterSelect.getValueText()) + .toBe(quarters[2].label + " Aktuell"); + expect(component.changeDisplayedQuarter) + .toHaveBeenCalledTimes(1); + }); - const routerHarness = await RouterTestingHarness.create(); - await routerHarness.navigateByUrl("/?quarter=1000"); + it("should set correct value in form according to route param", async () => { + jest.spyOn(component, "changeDisplayedQuarter"); + const routerHarnessPromise = RouterTestingHarness.create(); + const quarterSelectPromise = loader.getHarness(MatSelectHarness); + await Promise.all([routerHarnessPromise, + quarterSelectPromise]) + .then(async ([routerHarness, + quarterSelect]) => { + await routerHarness.navigateByUrl("/?quarter=" + quarters[3].id); expect(quarterSelect) .toBeTruthy(); routerHarness.detectChanges(); component.ngOnInit(); fixture.detectChanges(); + expect(component.currentQuarterId) - .toBe(quarters[2].id); + .toBe(quarters[3].id); expect(await quarterSelect.getValueText()) - .toBe(quarters[2].label + " Aktuell"); + .toBe(quarters[3].label); expect(component.changeDisplayedQuarter) .toHaveBeenCalledTimes(1); - expect(router.url) - .toBe("/?quarter=" + quarters[2].id); }); }); + + it("should set default quarter if quarter id in route params does not exist", async () => { + jest.spyOn(component, "changeDisplayedQuarter"); + const quarterSelect = await loader.getHarness(MatSelectHarness); + + const routerHarness = await RouterTestingHarness.create(); + await routerHarness.navigateByUrl("/?quarter=1000"); + + expect(quarterSelect) + .toBeTruthy(); + routerHarness.detectChanges(); + component.ngOnInit(); + fixture.detectChanges(); + expect(component.currentQuarterId) + .toBe(quarters[2].id); + expect(await quarterSelect.getValueText()) + .toBe(quarters[2].label + " Aktuell"); + expect(component.changeDisplayedQuarter) + .toHaveBeenCalledTimes(1); + expect(router.url) + .toBe("/?quarter=" + quarters[2].id); + }); +}); diff --git a/frontend/src/app/components/quarter-filter/quarter-filter.component.ts b/frontend/src/app/components/quarter-filter/quarter-filter.component.ts index fe8bd9c8a4..49320afd13 100644 --- a/frontend/src/app/components/quarter-filter/quarter-filter.component.ts +++ b/frontend/src/app/components/quarter-filter/quarter-filter.component.ts @@ -59,8 +59,7 @@ export class QuarterFilterComponent implements OnInit { this.quarterLabel$.next(quarterLabel); this.router - .navigate([], - { queryParams: { quarter: id } }) + .navigate([], { queryParams: { quarter: id } }) .then(() => this.refreshDataService.quarterFilterReady.next()); } } diff --git a/frontend/src/app/components/team-filter/team-filter.component.spec.ts b/frontend/src/app/components/team-filter/team-filter.component.spec.ts index 4ebc4fd212..1175c37cb6 100644 --- a/frontend/src/app/components/team-filter/team-filter.component.spec.ts +++ b/frontend/src/app/components/team-filter/team-filter.component.spec.ts @@ -28,361 +28,330 @@ const userServiceMock = { getCurrentUser: jest.fn() }; -describe("TeamFilterComponent", - () => { - let component: TeamFilterComponent; - let fixture: ComponentFixture; - let router: Router; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TeamFilterComponent, - ApplicationBannerComponent], - imports: [ - HttpClientTestingModule, - RouterTestingModule, - MatChipsModule, - MatIconModule - ], - providers: [{ provide: TeamService, - useValue: teamServiceMock }, - { provide: RefreshDataService, - useValue: refreshDataServiceMock }, - { provide: UserService, - useValue: userServiceMock }] - }); - fixture = TestBed.createComponent(TeamFilterComponent); - component = fixture.componentInstance; - teamServiceMock.getAllTeams.mockReturnValue(of(teamList)); - refreshDataServiceMock - .markDataRefresh() - .mockImplementation(() => refreshDataServiceMock.reloadOverviewSubject.next(null)); - router = TestBed.inject(Router); - userServiceMock.getCurrentUser.mockReturnValue(testUser); - fixture.detectChanges(); +describe("TeamFilterComponent", () => { + let component: TeamFilterComponent; + let fixture: ComponentFixture; + let router: Router; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [TeamFilterComponent, + ApplicationBannerComponent], + imports: [ + HttpClientTestingModule, + RouterTestingModule, + MatChipsModule, + MatIconModule + ], + providers: [{ provide: TeamService, + useValue: teamServiceMock }, + { provide: RefreshDataService, + useValue: refreshDataServiceMock }, + { provide: UserService, + useValue: userServiceMock }] }); + fixture = TestBed.createComponent(TeamFilterComponent); + component = fixture.componentInstance; + teamServiceMock.getAllTeams.mockReturnValue(of(teamList)); + refreshDataServiceMock + .markDataRefresh() + .mockImplementation(() => refreshDataServiceMock.reloadOverviewSubject.next(null)); + router = TestBed.inject(Router); + userServiceMock.getCurrentUser.mockReturnValue(testUser); + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should select all chips per default", - waitForAsync(async () => { - jest.spyOn(component.teams$, - "next"); - jest.spyOn(component, - "changeTeamFilterParams"); - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.teams$.next) - .toHaveBeenCalledWith(teamList); - expect(component.teams$.next) - .toHaveBeenCalledTimes(1); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - })); - - it("should select the right chips", - waitForAsync(async () => { - const teamIds = teamList.map((e) => e.id) - .filter((e, i) => i < 2); - jest.spyOn(component.teams$, - "next"); - jest.spyOn(component, - "changeTeamFilterParams"); - const routerHarness = await RouterTestingHarness.create(); - - await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.teams$.next) - .toHaveBeenCalledWith(teamList); - expect(component.teams$.next) - .toHaveBeenCalledTimes(1); - expect(component.activeTeams) - .toStrictEqual(teamIds); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - })); - - it("activeTeams array should contain every team when all teams are shown", - waitForAsync(async () => { - const teamIds = teamList.map((e) => e.id); - jest.spyOn(component.teams$, - "next"); - jest.spyOn(component, - "changeTeamFilterParams"); - const routerHarness = await RouterTestingHarness.create(); - - await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.teams$.next) - .toHaveBeenCalledWith(teamList); - expect(component.teams$.next) - .toHaveBeenCalledTimes(1); - expect(component.activeTeams.length) - .toBe(3); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - })); - - it("change filter params and reload", - fakeAsync(async () => { - component.activeTeams = teamList.map((e) => e.id) - .filter((e, i) => i < 2); - const routerHarness = await RouterTestingHarness.create(); - jest.spyOn(component, - "changeTeamFilterParams"); - jest.spyOn(refreshDataServiceMock, - "markDataRefresh"); - - component.activeTeams = [8, - 5, - 10]; - fixture.detectChanges(); - await component.changeTeamFilterParams(); - routerHarness.detectChanges(); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - expect(router.url) - .toBe("/?teams=8,5,10"); - })); - - it.each([ - [[1], - 2, - [1, - 2]], - [[1, - 2], + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should select all chips per default", waitForAsync(async () => { + jest.spyOn(component.teams$, "next"); + jest.spyOn(component, "changeTeamFilterParams"); + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.teams$.next) + .toHaveBeenCalledWith(teamList); + expect(component.teams$.next) + .toHaveBeenCalledTimes(1); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + })); + + it("should select the right chips", waitForAsync(async () => { + const teamIds = teamList.map((e) => e.id) + .filter((e, i) => i < 2); + jest.spyOn(component.teams$, "next"); + jest.spyOn(component, "changeTeamFilterParams"); + const routerHarness = await RouterTestingHarness.create(); + + await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.teams$.next) + .toHaveBeenCalledWith(teamList); + expect(component.teams$.next) + .toHaveBeenCalledTimes(1); + expect(component.activeTeams) + .toStrictEqual(teamIds); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + })); + + it("activeTeams array should contain every team when all teams are shown", waitForAsync(async () => { + const teamIds = teamList.map((e) => e.id); + jest.spyOn(component.teams$, "next"); + jest.spyOn(component, "changeTeamFilterParams"); + const routerHarness = await RouterTestingHarness.create(); + + await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.teams$.next) + .toHaveBeenCalledWith(teamList); + expect(component.teams$.next) + .toHaveBeenCalledTimes(1); + expect(component.activeTeams.length) + .toBe(3); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + })); + + it("change filter params and reload", fakeAsync(async () => { + component.activeTeams = teamList.map((e) => e.id) + .filter((e, i) => i < 2); + const routerHarness = await RouterTestingHarness.create(); + jest.spyOn(component, "changeTeamFilterParams"); + jest.spyOn(refreshDataServiceMock, "markDataRefresh"); + + component.activeTeams = [8, + 5, + 10]; + fixture.detectChanges(); + await component.changeTeamFilterParams(); + routerHarness.detectChanges(); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + expect(router.url) + .toBe("/?teams=8,5,10"); + })); + + it.each([ + [[1], + 2, + [1, + 2]], + [[1, + 2], + 2, + [1]], + [[1, + 2], + 3, + [1, 2, - [1]], - [[1, - 2], + 3]], + [[], + 3, + [3]], + [[3], 3, + []] + ])("toggle Selection", (activeTeams: number[], selected: number, expected: number[]) => { + component.activeTeams = activeTeams; + jest.spyOn(component, "areAllTeamsShown"); + jest.spyOn(component, "changeTeamFilterParams"); + + component.toggleSelection(selected); + fixture.detectChanges(); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + expect(component.areAllTeamsShown) + .toHaveBeenCalledTimes(1); + expect(component.activeTeams) + .toStrictEqual(expected); + }); + + it.each([ + [[1], + false], + [[1, + 2], + false], + [[1, + 2, + 3], + true], + [[], + false], + [[1, + 2, + 4], + false] + ])("are all teams shown", (activeTeams: number[], expected: boolean) => { + component.activeTeams = activeTeams; + expect(component.areAllTeamsShown()) + .toBe(expected); + }); + + it.each([ + [[], [1, 2, 3]], - [[], - 3, - [3]], - [[3], - 3, - []] - ])("toggle Selection", - (activeTeams: number[], selected: number, expected: number[]) => { - component.activeTeams = activeTeams; - jest.spyOn(component, - "areAllTeamsShown"); - jest.spyOn(component, - "changeTeamFilterParams"); - - component.toggleSelection(selected); - fixture.detectChanges(); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - expect(component.areAllTeamsShown) - .toHaveBeenCalledTimes(1); - expect(component.activeTeams) - .toStrictEqual(expected); - }); - - it.each([ - [[1], - false], - [[1, - 2], - false], - [[1, - 2, - 3], - true], - [[], - false], - [[1, - 2, - 4], - false] - ])("are all teams shown", - (activeTeams: number[], expected: boolean) => { - component.activeTeams = activeTeams; - expect(component.areAllTeamsShown()) - .toBe(expected); - }); - - it.each([ - [[], - [1, - 2, - 3]], - [[1], - [1, - 2, - 3]], - [[1, - 2], + [[1], [1, 2, 3]], - [[1, - 2, - 3], - []] - ])("select all", - (currentTeams: number[], expectedTeams: number[]) => { - component.activeTeams = currentTeams; - jest.spyOn(component, - "changeTeamFilterParams"); - component.toggleAll(); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - expect(component.activeTeams) - .toStrictEqual(expectedTeams); - }); - - it("should refresh teams on data refresh", - () => { - component.ngOnInit(); - component.activeTeams = [team2.id, - team3.id]; - fixture.detectChanges(); - expect(component.teams$.value) - .toStrictEqual(teamList); - teamServiceMock.getAllTeams.mockReturnValue(of([team2, - team1])); - fixture.detectChanges(); - expect(component.teams$.value) - .toStrictEqual(teamList); - refreshDataServiceMock.reloadOverviewSubject.next(null); - fixture.detectChanges(); - expect(component.teams$.value) - .toStrictEqual([team2, - team1]); - expect(component.activeTeams) - .toStrictEqual([team1.id]); - }); - - it("should use teams of user if no known teams are in url", - async () => { - const teamIds = [654, - 478]; - jest.spyOn(component.teams$, - "next"); - jest.spyOn(component, - "changeTeamFilterParams"); - const routerHarness = await RouterTestingHarness.create(); - - await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.activeTeams.length) - .toBe(1); - expect(component.activeTeams) - .toStrictEqual(extractTeamsFromUser(testUser) - .map((team) => team.id)); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - }); - - it("should use teams of user if no teams are in url", - async () => { - jest.spyOn(component.teams$, - "next"); - jest.spyOn(component, - "changeTeamFilterParams"); - const routerHarness = await RouterTestingHarness.create(); - - await routerHarness.navigateByUrl(""); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(component.activeTeams.length) - .toBe(1); - expect(component.activeTeams) - .toStrictEqual(extractTeamsFromUser(testUser) - .map((team) => team.id)); - expect(component.changeTeamFilterParams) - .toHaveBeenCalledTimes(1); - }); - - it.each([[[1, + [[1, + 2], + [1, + 2, + 3]], + [[1, 2, 3], - "1,2,3"], - [[], - null]])("changeTeamFilterParams", - async (currentTeams: number[], routingTeams: string | null) => { - component.activeTeams = currentTeams; - - jest.spyOn(router, - "navigate"); - - fixture.detectChanges(); - await component.changeTeamFilterParams(); - - expect(router.navigate) - .toHaveBeenCalledTimes(1); - expect(router.navigate) - .toHaveBeenCalledWith([], - { queryParams: { teams: routingTeams } }); - }); - - it("should filter teams by toggled priority and then by name", - async () => { - const teams = [ - { id: 1, - version: 0, - name: "Team D", - writeable: true }, - { id: 2, - version: 0, - name: "Team C", - writeable: true }, - { id: 3, - version: 0, - name: "Team B", - writeable: true }, - { id: 4, - version: 0, - name: "Team A", - writeable: true } - ]; - - component.teams$ = new BehaviorSubject(teams); - component.activeTeams = [3, - 4]; - - const sortedTeams = component.sortTeamsToggledPriority(); - - expect(sortedTeams) - .toEqual([ - { id: 4, - version: 0, - name: "Team A", - writeable: true }, - { id: 3, - version: 0, - name: "Team B", - writeable: true }, - { id: 2, - version: 0, - name: "Team C", - writeable: true }, - { id: 1, - version: 0, - name: "Team D", - writeable: true } - ]); - }); + []] + ])("select all", (currentTeams: number[], expectedTeams: number[]) => { + component.activeTeams = currentTeams; + jest.spyOn(component, "changeTeamFilterParams"); + component.toggleAll(); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + expect(component.activeTeams) + .toStrictEqual(expectedTeams); + }); + + it("should refresh teams on data refresh", () => { + component.ngOnInit(); + component.activeTeams = [team2.id, + team3.id]; + fixture.detectChanges(); + expect(component.teams$.value) + .toStrictEqual(teamList); + teamServiceMock.getAllTeams.mockReturnValue(of([team2, + team1])); + fixture.detectChanges(); + expect(component.teams$.value) + .toStrictEqual(teamList); + refreshDataServiceMock.reloadOverviewSubject.next(null); + fixture.detectChanges(); + expect(component.teams$.value) + .toStrictEqual([team2, + team1]); + expect(component.activeTeams) + .toStrictEqual([team1.id]); + }); + + it("should use teams of user if no known teams are in url", async () => { + const teamIds = [654, + 478]; + jest.spyOn(component.teams$, "next"); + jest.spyOn(component, "changeTeamFilterParams"); + const routerHarness = await RouterTestingHarness.create(); + + await routerHarness.navigateByUrl("/?teams=" + teamIds.join(",")); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.activeTeams.length) + .toBe(1); + expect(component.activeTeams) + .toStrictEqual(extractTeamsFromUser(testUser) + .map((team) => team.id)); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + }); + + it("should use teams of user if no teams are in url", async () => { + jest.spyOn(component.teams$, "next"); + jest.spyOn(component, "changeTeamFilterParams"); + const routerHarness = await RouterTestingHarness.create(); + + await routerHarness.navigateByUrl(""); + + component.ngOnInit(); + fixture.detectChanges(); + + expect(component.activeTeams.length) + .toBe(1); + expect(component.activeTeams) + .toStrictEqual(extractTeamsFromUser(testUser) + .map((team) => team.id)); + expect(component.changeTeamFilterParams) + .toHaveBeenCalledTimes(1); + }); + + it.each([[[1, + 2, + 3], + "1,2,3"], + [[], + null]])("changeTeamFilterParams", async (currentTeams: number[], routingTeams: string | null) => { + component.activeTeams = currentTeams; + + jest.spyOn(router, "navigate"); + + fixture.detectChanges(); + await component.changeTeamFilterParams(); + + expect(router.navigate) + .toHaveBeenCalledTimes(1); + expect(router.navigate) + .toHaveBeenCalledWith([], { queryParams: { teams: routingTeams } }); + }); + + it("should filter teams by toggled priority and then by name", async () => { + const teams = [ + { id: 1, + version: 0, + name: "Team D", + writeable: true }, + { id: 2, + version: 0, + name: "Team C", + writeable: true }, + { id: 3, + version: 0, + name: "Team B", + writeable: true }, + { id: 4, + version: 0, + name: "Team A", + writeable: true } + ]; + + component.teams$ = new BehaviorSubject(teams); + component.activeTeams = [3, + 4]; + + const sortedTeams = component.sortTeamsToggledPriority(); + + expect(sortedTeams) + .toEqual([ + { id: 4, + version: 0, + name: "Team A", + writeable: true }, + { id: 3, + version: 0, + name: "Team B", + writeable: true }, + { id: 2, + version: 0, + name: "Team C", + writeable: true }, + { id: 1, + version: 0, + name: "Team D", + writeable: true } + ]); }); +}); diff --git a/frontend/src/app/components/team-filter/team-filter.component.ts b/frontend/src/app/components/team-filter/team-filter.component.ts index c0b573bbb0..eb4025f337 100644 --- a/frontend/src/app/components/team-filter/team-filter.component.ts +++ b/frontend/src/app/components/team-filter/team-filter.component.ts @@ -61,8 +61,7 @@ export class TeamFilterComponent implements OnInit, OnDestroy { } this.subscription = this.teamService .getAllTeams() - .pipe(takeUntil(this.unsubscribe$), - filter((teams) => teams.length > 0)) + .pipe(takeUntil(this.unsubscribe$), filter((teams) => teams.length > 0)) .subscribe((teams: Team[]) => { this.teams$.next(teams); const teamQuery = this.route.snapshot.queryParams["teams"]; @@ -91,8 +90,7 @@ export class TeamFilterComponent implements OnInit, OnDestroy { const params = { teams: this.activeTeams.join(",") }; const optionalParams = optionalReplaceWithNulls(params); this.router - .navigate([], - { queryParams: optionalParams }) + .navigate([], { queryParams: optionalParams }) .then(() => this.refreshDataService.teamFilterReady.next()); } @@ -112,8 +110,7 @@ export class TeamFilterComponent implements OnInit, OnDestroy { } areAllTeamsShown () { - return areEqual(this.activeTeams, - this.getAllTeamIds()); + return areEqual(this.activeTeams, this.getAllTeamIds()); } toggleAll () { diff --git a/frontend/src/app/components/team/team.component.spec.ts b/frontend/src/app/components/team/team.component.spec.ts index 8b880c277f..73e0400362 100644 --- a/frontend/src/app/components/team/team.component.spec.ts +++ b/frontend/src/app/components/team/team.component.spec.ts @@ -45,129 +45,120 @@ const refreshDataServiceMock = { markDataRefresh: jest.fn() }; -describe("TeamComponent", - () => { - let component: TeamComponent; - let fixture: ComponentFixture; +describe("TeamComponent", () => { + let component: TeamComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule, - MatMenuModule, - MatDialogModule, - MatTooltipModule, - TranslateTestingModule.withTranslations({ - de: de - }), - MatIcon - ], - declarations: [ - TeamComponent, - ObjectiveComponent, - KeyresultComponent, - ConfidenceComponent, - ScoringComponent - ], - providers: [ - { - provide: DialogService, - useValue: dialogService - }, - { - provide: ConfigService, - useValue: configServiceDefined - }, - { - provide: RefreshDataService, - useValue: refreshDataServiceMock - }, - provideHttpClient(withInterceptorsFromDi()) - ] + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RouterTestingModule, + MatMenuModule, + MatDialogModule, + MatTooltipModule, + TranslateTestingModule.withTranslations({ + de: de + }), + MatIcon + ], + declarations: [ + TeamComponent, + ObjectiveComponent, + KeyresultComponent, + ConfidenceComponent, + ScoringComponent + ], + providers: [ + { + provide: DialogService, + useValue: dialogService + }, + { + provide: ConfigService, + useValue: configServiceDefined + }, + { + provide: RefreshDataService, + useValue: refreshDataServiceMock + }, + provideHttpClient(withInterceptorsFromDi()) + ] + }) + .overrideComponent(TeamComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } }) - .overrideComponent(TeamComponent, - { - set: { changeDetection: ChangeDetectionStrategy.Default } - }) - .compileComponents(); + .compileComponents(); - fixture = TestBed.createComponent(TeamComponent); - component = fixture.componentInstance; - component.overviewEntity = overViewEntity1; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TeamComponent); + component = fixture.componentInstance; + component.overviewEntity = overViewEntity1; + fixture.detectChanges(); + }); - it("should create", - () => { - fixture.detectChanges(); - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + fixture.detectChanges(); + expect(component) + .toBeTruthy(); + }); - it("should display add objective button if writeable is true", - async () => { - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"add-objective\"]")); - expect(button) - .toBeTruthy(); - }); + it("should display add objective button if writeable is true", async () => { + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"add-objective\"]")); + expect(button) + .toBeTruthy(); + }); - it("should not display add objective button if writeable is false", - () => { - component.overviewEntity = { ...overViewEntity2 }; - component.overviewEntity.writeable = false; - fixture.detectChanges(); - const button = fixture.debugElement.query(By.css("[data-testId=\"add-objective\"]")); - expect(button) - .toBeFalsy(); - }); + it("should not display add objective button if writeable is false", () => { + component.overviewEntity = { ...overViewEntity2 }; + component.overviewEntity.writeable = false; + fixture.detectChanges(); + const button = fixture.debugElement.query(By.css("[data-testId=\"add-objective\"]")); + expect(button) + .toBeFalsy(); + }); - it("should set value of addIconSrc if src from config service is defined", - () => { - expect(component.addIconSrc.value) - .toBe("new-icon-from-config-service.svg"); - const addObjectiveIcon = fixture.debugElement.query(By.css("[data-testId=\"add-objective-icon\"]")); - expect(addObjectiveIcon.attributes["src"]) - .toBe("new-icon-from-config-service.svg"); - }); + it("should set value of addIconSrc if src from config service is defined", () => { + expect(component.addIconSrc.value) + .toBe("new-icon-from-config-service.svg"); + const addObjectiveIcon = fixture.debugElement.query(By.css("[data-testId=\"add-objective-icon\"]")); + expect(addObjectiveIcon.attributes["src"]) + .toBe("new-icon-from-config-service.svg"); }); +}); -describe("TeamComponent undefined values in config service", - () => { - let component: TeamComponent; - let fixture: ComponentFixture; +describe("TeamComponent undefined values in config service", () => { + let component: TeamComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatMenuModule, - TranslateTestingModule.withTranslations({ - de: de - })], - declarations: [TeamComponent], - providers: [{ - provide: ConfigService, - useValue: configServiceUndefined - }, - provideHttpClient(withInterceptorsFromDi())] + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MatMenuModule, + TranslateTestingModule.withTranslations({ + de: de + })], + declarations: [TeamComponent], + providers: [{ + provide: ConfigService, + useValue: configServiceUndefined + }, + provideHttpClient(withInterceptorsFromDi())] + }) + .overrideComponent(TeamComponent, { + set: { changeDetection: ChangeDetectionStrategy.Default } }) - .overrideComponent(TeamComponent, - { - set: { changeDetection: ChangeDetectionStrategy.Default } - }) - .compileComponents(); + .compileComponents(); - fixture = TestBed.createComponent(TeamComponent); - component = fixture.componentInstance; - component.overviewEntity = overViewEntity1; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TeamComponent); + component = fixture.componentInstance; + component.overviewEntity = overViewEntity1; + fixture.detectChanges(); + }); - it("should keep default value of addIconSrc if src from config service is undefined", - () => { - expect(component.addIconSrc.value) - .toBe("assets/icons/new-icon.svg"); - const addObjectiveIcon = fixture.debugElement.query(By.css("[data-testId=\"add-objective-icon\"]")); - expect(addObjectiveIcon.attributes["src"]) - .toBe("assets/icons/new-icon.svg"); - }); + it("should keep default value of addIconSrc if src from config service is undefined", () => { + expect(component.addIconSrc.value) + .toBe("assets/icons/new-icon.svg"); + const addObjectiveIcon = fixture.debugElement.query(By.css("[data-testId=\"add-objective-icon\"]")); + expect(addObjectiveIcon.attributes["src"]) + .toBe("assets/icons/new-icon.svg"); }); +}); diff --git a/frontend/src/app/components/team/team.component.ts b/frontend/src/app/components/team/team.component.ts index 22a3e76812..022afe1b05 100644 --- a/frontend/src/app/components/team/team.component.ts +++ b/frontend/src/app/components/team/team.component.ts @@ -35,14 +35,13 @@ export class TeamComponent { trackByObjectiveId: TrackByFunction = (index, objective) => objective.id; createObjective () { - const matDialogRef = this.dialogService.open(ObjectiveFormComponent, - { - data: { - objective: { - teamId: this.overviewEntity.team.id - } + const matDialogRef = this.dialogService.open(ObjectiveFormComponent, { + data: { + objective: { + teamId: this.overviewEntity.team.id } - }); + } + }); matDialogRef.afterClosed() .subscribe((result) => { if (result?.addKeyResult) { @@ -54,13 +53,12 @@ export class TeamComponent { openAddKeyResultDialog (objective: Objective) { this.dialogService - .open(KeyresultDialogComponent, - { - data: { - objective: objective, - keyResult: null - } - }) + .open(KeyresultDialogComponent, { + data: { + objective: objective, + keyResult: null + } + }) .afterClosed() .subscribe((result) => { if (result?.openNew) { diff --git a/frontend/src/app/guards/auth.guard.spec.ts b/frontend/src/app/guards/auth.guard.spec.ts index efdeb55008..24619941de 100644 --- a/frontend/src/app/guards/auth.guard.spec.ts +++ b/frontend/src/app/guards/auth.guard.spec.ts @@ -18,100 +18,85 @@ const routerMock = { const route = { queryParamMap: new Map() }; -describe("authGuard", - () => { - const executeGuard: CanActivateFn = (...guardParameters) => TestBed.runInInjectionContext(() => authGuard(...guardParameters)); - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ - provide: OAuthService, - useValue: oAuthMock - }, - { - provide: Router, - useValue: routerMock - }] - }); - jest.spyOn(oAuthMock, - "initCodeFlow") - .mockReturnValue(true); - jest.spyOn(oAuthMock, - "loadDiscoveryDocumentAndTryLogin") - .mockReturnValue(Promise.resolve(true)); - jest.spyOn(oAuthMock, - "setupAutomaticSilentRefresh") - .mockReturnValue(true); - jest.spyOn(routerMock, - "navigateByUrl") - .mockReturnValue(of() - .toPromise()); - oAuthMock.initCodeFlow.mockReset(); - oAuthMock.setupAutomaticSilentRefresh.mockReset(); - routerMock.navigateByUrl.mockReset(); +describe("authGuard", () => { + const executeGuard: CanActivateFn = (...guardParameters) => TestBed.runInInjectionContext(() => authGuard(...guardParameters)); + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{ + provide: OAuthService, + useValue: oAuthMock + }, + { + provide: Router, + useValue: routerMock + }] }); + jest.spyOn(oAuthMock, "initCodeFlow") + .mockReturnValue(true); + jest.spyOn(oAuthMock, "loadDiscoveryDocumentAndTryLogin") + .mockReturnValue(Promise.resolve(true)); + jest.spyOn(oAuthMock, "setupAutomaticSilentRefresh") + .mockReturnValue(true); + jest.spyOn(routerMock, "navigateByUrl") + .mockReturnValue(of() + .toPromise()); + oAuthMock.initCodeFlow.mockReset(); + oAuthMock.setupAutomaticSilentRefresh.mockReset(); + routerMock.navigateByUrl.mockReset(); + }); - it("should be created", - () => { - expect(executeGuard) - .toBeTruthy(); - }); - - it("should not call initCodeFlow if token is valid and call router if state param exist", - async () => { - jest.spyOn(oAuthMock, - "hasValidIdToken") - .mockReturnValue(true); - route.queryParamMap.set("state", - 1234); - - const result = await runAuthGuardWithContext(authGuard); - - expect(result) - .toBe(false); - expect(oAuthMock.loadDiscoveryDocumentAndTryLogin) - .toHaveBeenCalled(); - expect(oAuthMock.initCodeFlow).not.toHaveBeenCalled(); - expect(oAuthMock.setupAutomaticSilentRefresh) - .toHaveBeenCalled(); - - expect(routerMock.navigateByUrl) - .toHaveBeenCalled(); - }); - - it("should not call router if state param does not exist", - async () => { - jest.spyOn(oAuthMock, - "hasValidIdToken") - .mockReturnValue(true); - route.queryParamMap.set("state", - null); - - const result = await runAuthGuardWithContext(authGuard); - - expect(result) - .toBeTruthy(); - expect(routerMock.navigateByUrl).not.toHaveBeenCalled(); - }); - - it("should call initCodeFlow if token is invalid", - async () => { - jest.spyOn(oAuthMock, - "hasValidIdToken") - .mockReturnValue(false); - const result = await runAuthGuardWithContext(authGuard); - - expect(result) - .toBe(false); - expect(oAuthMock.loadDiscoveryDocumentAndTryLogin) - .toHaveBeenCalled(); - expect(oAuthMock.initCodeFlow) - .toHaveBeenCalled(); - expect(oAuthMock.setupAutomaticSilentRefresh).not.toHaveBeenCalled(); - }); - - async function runAuthGuardWithContext (authGuard: any): Promise { - return await TestBed.runInInjectionContext(() => authGuard(route, - null)); - } + it("should be created", () => { + expect(executeGuard) + .toBeTruthy(); }); + + it("should not call initCodeFlow if token is valid and call router if state param exist", async () => { + jest.spyOn(oAuthMock, "hasValidIdToken") + .mockReturnValue(true); + route.queryParamMap.set("state", 1234); + + const result = await runAuthGuardWithContext(authGuard); + + expect(result) + .toBe(false); + expect(oAuthMock.loadDiscoveryDocumentAndTryLogin) + .toHaveBeenCalled(); + expect(oAuthMock.initCodeFlow).not.toHaveBeenCalled(); + expect(oAuthMock.setupAutomaticSilentRefresh) + .toHaveBeenCalled(); + + expect(routerMock.navigateByUrl) + .toHaveBeenCalled(); + }); + + it("should not call router if state param does not exist", async () => { + jest.spyOn(oAuthMock, "hasValidIdToken") + .mockReturnValue(true); + route.queryParamMap.set("state", null); + + const result = await runAuthGuardWithContext(authGuard); + + expect(result) + .toBeTruthy(); + expect(routerMock.navigateByUrl).not.toHaveBeenCalled(); + }); + + it("should call initCodeFlow if token is invalid", async () => { + jest.spyOn(oAuthMock, "hasValidIdToken") + .mockReturnValue(false); + const result = await runAuthGuardWithContext(authGuard); + + expect(result) + .toBe(false); + expect(oAuthMock.loadDiscoveryDocumentAndTryLogin) + .toHaveBeenCalled(); + expect(oAuthMock.initCodeFlow) + .toHaveBeenCalled(); + expect(oAuthMock.setupAutomaticSilentRefresh).not.toHaveBeenCalled(); + }); + + async function runAuthGuardWithContext (authGuard: any): Promise { + return await TestBed.runInInjectionContext(() => authGuard(route, null)); + } +}); diff --git a/frontend/src/app/interceptors/error-interceptor.service.ts b/frontend/src/app/interceptors/error-interceptor.service.ts index 5f16861476..b462435dfa 100644 --- a/frontend/src/app/interceptors/error-interceptor.service.ts +++ b/frontend/src/app/interceptors/error-interceptor.service.ts @@ -22,21 +22,18 @@ export class ErrorInterceptor implements HttpInterceptor { intercept (request: HttpRequest, next: HttpHandler): Observable> { return next.handle(request) - .pipe(filter((event) => event instanceof HttpResponse), - tap((response) => { - if (this.checkForToaster(response)) { - const method = HttpType[request.method as keyof typeof HttpType]; - this.handleSuccessToaster(response, - method); - } - }), - catchError((response) => { - if (this.checkForToaster(response)) { - this.handleErrorToaster(response); - } - this.handleDrawerError(request); - return throwError(() => new Error(response)); - })); + .pipe(filter((event) => event instanceof HttpResponse), tap((response) => { + if (this.checkForToaster(response)) { + const method = HttpType[request.method as keyof typeof HttpType]; + this.handleSuccessToaster(response, method); + } + }), catchError((response) => { + if (this.checkForToaster(response)) { + this.handleErrorToaster(response); + } + this.handleDrawerError(request); + return throwError(() => new Error(response)); + })); } handleErrorToaster (response: any) { @@ -53,9 +50,7 @@ export class ErrorInterceptor implements HttpInterceptor { } handleSuccessToaster (response: any, method: HttpType) { - const successMessageObj = this.getSuccessMessageKey(response.url, - response.status, - method); + const successMessageObj = this.getSuccessMessageKey(response.url, response.status, method); if (!successMessageObj) return; let messageKey = successMessageObj.key; @@ -64,8 +59,7 @@ export class ErrorInterceptor implements HttpInterceptor { messageKey += "_BACKLOG"; } const message = this.translate.instant(SUCCESS_MESSAGE_KEY_PREFIX + messageKey); - this.toasterService.showCustomToaster(message, - successMessageObj.toasterType); + this.toasterService.showCustomToaster(message, successMessageObj.toasterType); } getSuccessMessageKey (url: string, statusCode: number, method: HttpType) { diff --git a/frontend/src/app/interceptors/error.interceptor.spec.ts b/frontend/src/app/interceptors/error.interceptor.spec.ts index 3974cd88c1..f3fba4d646 100644 --- a/frontend/src/app/interceptors/error.interceptor.spec.ts +++ b/frontend/src/app/interceptors/error.interceptor.spec.ts @@ -8,364 +8,331 @@ import "../../global"; import { HttpType } from "../shared/types/enums/HttpType"; import { ToasterType } from "../shared/types/enums/ToasterType"; -describe("ErrorInterceptor", - () => { - let interceptor: ErrorInterceptor; - let router: Router; - let translator: TranslateService; - let toaster: ToasterService; +describe("ErrorInterceptor", () => { + let interceptor: ErrorInterceptor; + let router: Router; + let translator: TranslateService; + let toaster: ToasterService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ToastrModule.forRoot(), - TranslateModule.forRoot()], - providers: [ErrorInterceptor, - ToasterService, - TranslateService] - }); - interceptor = TestBed.inject(ErrorInterceptor); - router = TestBed.inject(Router); - translator = TestBed.inject(TranslateService); - toaster = TestBed.inject(ToasterService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ToastrModule.forRoot(), + TranslateModule.forRoot()], + providers: [ErrorInterceptor, + ToasterService, + TranslateService] }); + interceptor = TestBed.inject(ErrorInterceptor); + router = TestBed.inject(Router); + translator = TestBed.inject(TranslateService); + toaster = TestBed.inject(ToasterService); + }); + + it("should be created", () => { + expect(interceptor) + .toBeTruthy(); + }); + + it.each([["test", + 0], + ["objective", + 1], + ["keyresult", + 1]])("handleDrawerError on route %p should be called %p times", (url: string, isCalledTimes: number) => { + const requestMock = { url: url }; + jest.spyOn(router, "navigate"); + + interceptor.handleDrawerError(requestMock); + + expect(router.navigate) + .toHaveBeenCalledTimes(isCalledTimes); + }); + + it.each([["NOT_AUTHORIZED_TO_READ", + ["Objective"]], + ["NOT_AUTHORIZED_TO_WRITE", + ["Check-in"]]])("handleErrorToaster should show correct toaster", (key: string, params: string[]) => { + const ERROR_PREFIX = "ERROR."; + jest.spyOn(translator, "instant"); + jest.spyOn(toaster, "showError"); + jest.spyOn(String.prototype, "format"); + const requestMock = { + error: { + errors: [{ + errorKey: key, + params: params + }] + } + }; + + interceptor.handleErrorToaster(requestMock); + expect(translator.instant) + .toBeCalledWith(ERROR_PREFIX + key); + expect(String.prototype.format) + .toBeCalledWith(params); + expect(toaster.showError) + .toBeCalledTimes(1); + }); - it("should be created", - () => { - expect(interceptor) - .toBeTruthy(); - }); + it.each([[ + "/objective/1", + 200, + HttpType.POST, + "OBJECTIVE", + ToasterType.SUCCESS, + "Objective erstellt" + ], + [ + "/keyresult/1", + 200, + HttpType.PUT, + "KEYRESULT", + ToasterType.SUCCESS, + "Keyresult wurde aktualisiert" + ], + [ + "/keyresult/1", + 200, + HttpType.DELETE, + "KEYRESULT", + ToasterType.SUCCESS, + "Keyresult wurde gelöscht" + ]])("handleSuccessToaster should show toaster ", ( + url: string, code: number, method: HttpType, key: string, toasterType: ToasterType, message: string + ) => { + const SUCCESS_PREFIX = "SUCCESS."; + jest.spyOn(translator, "instant") + .mockReturnValue(message); + jest.spyOn(toaster, "showCustomToaster"); + jest.spyOn(interceptor, "getSuccessMessageKey") + .mockReturnValue({ key: key, + toasterType: toasterType }); - it.each([["test", - 0], - ["objective", - 1], - ["keyresult", - 1]])("handleDrawerError on route %p should be called %p times", - (url: string, isCalledTimes: number) => { - const requestMock = { url: url }; - jest.spyOn(router, - "navigate"); + const requestMock = { + url: url, + status: code + }; - interceptor.handleDrawerError(requestMock); + interceptor.handleSuccessToaster(requestMock, method); + expect(interceptor.getSuccessMessageKey) + .toBeCalledWith(url, code, method); + expect(translator.instant) + .toBeCalledWith(SUCCESS_PREFIX + key); + expect(toaster.showCustomToaster) + .toBeCalledWith(message, toasterType); + }); + + it.each([[ + "/objective/1", + 200, + HttpType.GET, + "OBJECTIVE" + ], + [ + "/keyresult/1", + 200, + HttpType.GET, + "KEYRESULT" + ], + [ + "/keyresult/1", + 200, + HttpType.GET, + "KEYRESULT" + ]])("handleSuccessToaster should not show toaster ", (url: string, code: number, method: HttpType) => { + jest.spyOn(translator, "instant"); + jest.spyOn(toaster, "showCustomToaster"); + jest.spyOn(interceptor, "getSuccessMessageKey") + .mockReturnValue(undefined); - expect(router.navigate) - .toHaveBeenCalledTimes(isCalledTimes); - }); + const requestMock = { + url: url, + status: code + }; - it.each([["NOT_AUTHORIZED_TO_READ", - ["Objective"]], - ["NOT_AUTHORIZED_TO_WRITE", - ["Check-in"]]])("handleErrorToaster should show correct toaster", - (key: string, params: string[]) => { - const ERROR_PREFIX = "ERROR."; - jest.spyOn(translator, - "instant"); - jest.spyOn(toaster, - "showError"); - jest.spyOn(String.prototype, - "format"); - const requestMock = { - error: { - errors: [{ - errorKey: key, - params: params - }] - } - }; + interceptor.handleSuccessToaster(requestMock, method); + expect(interceptor.getSuccessMessageKey) + .toBeCalledWith(url, code, method); - interceptor.handleErrorToaster(requestMock); - expect(translator.instant) - .toBeCalledWith(ERROR_PREFIX + key); - expect(String.prototype.format) - .toBeCalledWith(params); - expect(toaster.showError) - .toBeCalledTimes(1); - }); + expect(translator.instant) + .toBeCalledTimes(0); + expect(toaster.showCustomToaster) + .toBeCalledTimes(0); + }); - it.each([[ - "/objective/1", + it.each([ + [ + "/teams/1", 200, - HttpType.POST, - "OBJECTIVE", - ToasterType.SUCCESS, - "Objective erstellt" + HttpType.GET, + undefined ], [ - "/keyresult/1", + "/teams/1", 200, HttpType.PUT, - "KEYRESULT", - ToasterType.SUCCESS, - "Keyresult wurde aktualisiert" + { key: "TEAM.PUT", + toasterType: ToasterType.SUCCESS } + ], + [ + "/teams/1", + 200, + HttpType.POST, + { key: "TEAM.POST", + toasterType: ToasterType.SUCCESS } ], [ - "/keyresult/1", + "/teams/1", 200, HttpType.DELETE, - "KEYRESULT", - ToasterType.SUCCESS, - "Keyresult wurde gelöscht" - ]])("handleSuccessToaster should show toaster ", - ( - url: string, code: number, method: HttpType, key: string, toasterType: ToasterType, message: string - ) => { - const SUCCESS_PREFIX = "SUCCESS."; - jest.spyOn(translator, - "instant") - .mockReturnValue(message); - jest.spyOn(toaster, - "showCustomToaster"); - jest.spyOn(interceptor, - "getSuccessMessageKey") - .mockReturnValue({ key: key, - toasterType: toasterType }); - - const requestMock = { - url: url, - status: code - }; - - interceptor.handleSuccessToaster(requestMock, - method); - expect(interceptor.getSuccessMessageKey) - .toBeCalledWith(url, - code, - method); - expect(translator.instant) - .toBeCalledWith(SUCCESS_PREFIX + key); - expect(toaster.showCustomToaster) - .toBeCalledWith(message, - toasterType); - }); + { key: "TEAM.DELETE", + toasterType: ToasterType.SUCCESS } + ], - it.each([[ - "/objective/1", + [ + "/objectives/1", 200, HttpType.GET, - "OBJECTIVE" + undefined ], [ - "/keyresult/1", + "/objectives/1", 200, - HttpType.GET, - "KEYRESULT" + HttpType.PUT, + { key: "OBJECTIVE.PUT", + toasterType: ToasterType.SUCCESS } ], [ - "/keyresult/1", + "/objectives/1", 200, - HttpType.GET, - "KEYRESULT" - ]])("handleSuccessToaster should not show toaster ", - (url: string, code: number, method: HttpType) => { - jest.spyOn(translator, - "instant"); - jest.spyOn(toaster, - "showCustomToaster"); - jest.spyOn(interceptor, - "getSuccessMessageKey") - .mockReturnValue(undefined); - - const requestMock = { - url: url, - status: code - }; - - interceptor.handleSuccessToaster(requestMock, - method); - expect(interceptor.getSuccessMessageKey) - .toBeCalledWith(url, - code, - method); - - expect(translator.instant) - .toBeCalledTimes(0); - expect(toaster.showCustomToaster) - .toBeCalledTimes(0); - }); - - it.each([ - [ - "/teams/1", - 200, - HttpType.GET, - undefined - ], - [ - "/teams/1", - 200, - HttpType.PUT, - { key: "TEAM.PUT", - toasterType: ToasterType.SUCCESS } - ], - [ - "/teams/1", - 200, - HttpType.POST, - { key: "TEAM.POST", - toasterType: ToasterType.SUCCESS } - ], - [ - "/teams/1", - 200, - HttpType.DELETE, - { key: "TEAM.DELETE", - toasterType: ToasterType.SUCCESS } - ], - - [ - "/objectives/1", - 200, - HttpType.GET, - undefined - ], - [ - "/objectives/1", - 200, - HttpType.PUT, - { key: "OBJECTIVE.PUT", - toasterType: ToasterType.SUCCESS } - ], - [ - "/objectives/1", - 200, - HttpType.POST, - { key: "OBJECTIVE.POST", - toasterType: ToasterType.SUCCESS } - ], - [ - "/objectives/1", - 200, - HttpType.DELETE, - { key: "OBJECTIVE.DELETE", - toasterType: ToasterType.SUCCESS } - ], - [ - "/objectives/1", - 226, - HttpType.PUT, - { key: "OBJECTIVE.IM_USED", - toasterType: ToasterType.WARN } - ], + HttpType.POST, + { key: "OBJECTIVE.POST", + toasterType: ToasterType.SUCCESS } + ], + [ + "/objectives/1", + 200, + HttpType.DELETE, + { key: "OBJECTIVE.DELETE", + toasterType: ToasterType.SUCCESS } + ], + [ + "/objectives/1", + 226, + HttpType.PUT, + { key: "OBJECTIVE.IM_USED", + toasterType: ToasterType.WARN } + ], - [ - "/keyresults/1", - 200, - HttpType.GET, - undefined - ], - [ - "/keyresults/1", - 200, - HttpType.PUT, - { key: "KEY_RESULT.PUT", - toasterType: ToasterType.SUCCESS } - ], - [ - "/keyresults/1", - 200, - HttpType.POST, - { key: "KEY_RESULT.POST", - toasterType: ToasterType.SUCCESS } - ], - [ - "/keyresults/1", - 200, - HttpType.DELETE, - { key: "KEY_RESULT.DELETE", - toasterType: ToasterType.SUCCESS } - ], - [ - "/keyresults/1", - 226, - HttpType.PUT, - { key: "KEY_RESULT.IM_USED", - toasterType: ToasterType.WARN } - ], + [ + "/keyresults/1", + 200, + HttpType.GET, + undefined + ], + [ + "/keyresults/1", + 200, + HttpType.PUT, + { key: "KEY_RESULT.PUT", + toasterType: ToasterType.SUCCESS } + ], + [ + "/keyresults/1", + 200, + HttpType.POST, + { key: "KEY_RESULT.POST", + toasterType: ToasterType.SUCCESS } + ], + [ + "/keyresults/1", + 200, + HttpType.DELETE, + { key: "KEY_RESULT.DELETE", + toasterType: ToasterType.SUCCESS } + ], + [ + "/keyresults/1", + 226, + HttpType.PUT, + { key: "KEY_RESULT.IM_USED", + toasterType: ToasterType.WARN } + ], - [ - "/checkIns/1", - 200, - HttpType.GET, - undefined - ], - [ - "/checkIns/1", - 200, - HttpType.PUT, - { key: "CHECK_IN.PUT", - toasterType: ToasterType.SUCCESS } - ], - [ - "/checkIns/1", - 200, - HttpType.POST, - { key: "CHECK_IN.POST", - toasterType: ToasterType.SUCCESS } - ], - [ - "/checkIns/1", - 200, - HttpType.DELETE, - undefined - ] - ])("getSuccessMessageKey should work", - ( - url: string, code: number, method: HttpType, result: any - ) => { - const successMessageKey = interceptor.getSuccessMessageKey(url, - code, - method); - expect(successMessageKey) - .toStrictEqual(result); - }); + [ + "/checkIns/1", + 200, + HttpType.GET, + undefined + ], + [ + "/checkIns/1", + 200, + HttpType.PUT, + { key: "CHECK_IN.PUT", + toasterType: ToasterType.SUCCESS } + ], + [ + "/checkIns/1", + 200, + HttpType.POST, + { key: "CHECK_IN.POST", + toasterType: ToasterType.SUCCESS } + ], + [ + "/checkIns/1", + 200, + HttpType.DELETE, + undefined + ] + ])("getSuccessMessageKey should work", ( + url: string, code: number, method: HttpType, result: any + ) => { + const successMessageKey = interceptor.getSuccessMessageKey(url, code, method); + expect(successMessageKey) + .toStrictEqual(result); + }); - it.each([["http://localhost:4200/", - "http://localhost:4200/api/objecive/1", - true], - ["http://localhost:4200/", - "http://habasch:4200/api/objecive/1", - false], - ["http://localhost:4200/", - "http://habasch:4200/objecive/1", - false]])("checkIfSuccessToasterIsShown should work as intended", - (currentURL: string, requestURL: string, result: boolean) => { - const requestMock = { url: requestURL }; - window.location.assign(currentURL); + it.each([["http://localhost:4200/", + "http://localhost:4200/api/objecive/1", + true], + ["http://localhost:4200/", + "http://habasch:4200/api/objecive/1", + false], + ["http://localhost:4200/", + "http://habasch:4200/objecive/1", + false]])("checkIfSuccessToasterIsShown should work as intended", (currentURL: string, requestURL: string, result: boolean) => { + const requestMock = { url: requestURL }; + window.location.assign(currentURL); - const b = interceptor.checkForToaster(requestMock); - expect(b) - .toBe(result); - }); + const b = interceptor.checkForToaster(requestMock); + expect(b) + .toBe(result); + }); - it("should return custom success message on objective creation in backlog", - () => { - jest.spyOn(translator, - "instant") - .mockReturnValue("Das Objective wurde als Draft im Backlog gespeichert."); - jest.spyOn(toaster, - "showCustomToaster"); - jest.spyOn(interceptor, - "getSuccessMessageKey") - .mockReturnValue({ key: "OBJECTIVE.POST", - toasterType: undefined }); + it("should return custom success message on objective creation in backlog", () => { + jest.spyOn(translator, "instant") + .mockReturnValue("Das Objective wurde als Draft im Backlog gespeichert."); + jest.spyOn(toaster, "showCustomToaster"); + jest.spyOn(interceptor, "getSuccessMessageKey") + .mockReturnValue({ key: "OBJECTIVE.POST", + toasterType: undefined }); - const mockHttpResponse = { - url: "\"http://localhost:4200/api/v2/objectives\"", - status: 201, - statusText: "Created", - ok: true, - body: { - objectiveTitle: "Das ist der Titel", - quarterId: 999 - } - }; + const mockHttpResponse = { + url: "\"http://localhost:4200/api/v2/objectives\"", + status: 201, + statusText: "Created", + ok: true, + body: { + objectiveTitle: "Das ist der Titel", + quarterId: 999 + } + }; - interceptor.handleSuccessToaster(mockHttpResponse, - HttpType.POST); - expect(translator.instant) - .toBeCalledWith("SUCCESS.OBJECTIVE.POST_BACKLOG"); - expect(toaster.showCustomToaster) - .toBeCalledWith("Das Objective wurde als Draft im Backlog gespeichert.", - undefined); - }); + interceptor.handleSuccessToaster(mockHttpResponse, HttpType.POST); + expect(translator.instant) + .toBeCalledWith("SUCCESS.OBJECTIVE.POST_BACKLOG"); + expect(toaster.showCustomToaster) + .toBeCalledWith("Das Objective wurde als Draft im Backlog gespeichert.", undefined); }); +}); diff --git a/frontend/src/app/interceptors/oauth.interceptor.spec.ts b/frontend/src/app/interceptors/oauth.interceptor.spec.ts index ff7e3ed81c..65b11cdf3d 100644 --- a/frontend/src/app/interceptors/oauth.interceptor.spec.ts +++ b/frontend/src/app/interceptors/oauth.interceptor.spec.ts @@ -4,23 +4,21 @@ import { OauthInterceptor } from "./oauth.interceptor"; import { HttpClientTestingModule } from "@angular/common/http/testing"; import { DateTimeProvider, OAuthLogger, OAuthService, UrlHelperService } from "angular-oauth2-oidc"; -describe("OauthInterceptor", - () => { - beforeEach(() => TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - OAuthService, - UrlHelperService, - OAuthLogger, - DateTimeProvider, - OAuthService - ] - })); +describe("OauthInterceptor", () => { + beforeEach(() => TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + OAuthService, + UrlHelperService, + OAuthLogger, + DateTimeProvider, + OAuthService + ] + })); - it("should be created", - () => { - const interceptor: OauthInterceptor = TestBed.inject(OauthInterceptor); - expect(interceptor) - .toBeTruthy(); - }); + it("should be created", () => { + const interceptor: OauthInterceptor = TestBed.inject(OauthInterceptor); + expect(interceptor) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/interceptors/oauth.interceptor.ts b/frontend/src/app/interceptors/oauth.interceptor.ts index d6cafc498f..0d6066e1f0 100644 --- a/frontend/src/app/interceptors/oauth.interceptor.ts +++ b/frontend/src/app/interceptors/oauth.interceptor.ts @@ -15,21 +15,16 @@ export class OauthInterceptor implements HttpInterceptor { } return merge(of(this.oauthService.getAccessToken()) - .pipe(filter((token) => !!token)), - this.oauthService.events.pipe(filter((e) => e.type === "token_received"), - timeout(500), - map((_) => this.oauthService.getAccessToken()))) - .pipe(take(1), - mergeMap((token) => { - if (token) { - const header = "Bearer " + token; - const headers = req.headers.set("Authorization", - header); - req = req.clone({ headers }); - } + .pipe(filter((token) => !!token)), this.oauthService.events.pipe(filter((e) => e.type === "token_received"), timeout(500), map((_) => this.oauthService.getAccessToken()))) + .pipe(take(1), mergeMap((token) => { + if (token) { + const header = "Bearer " + token; + const headers = req.headers.set("Authorization", header); + req = req.clone({ headers }); + } - return next.handle(req); + return next.handle(req); // .pipe(catchError((err) => this.errorHandler.handleError(err))); - })); + })); } } diff --git a/frontend/src/app/services/action.service.spec.ts b/frontend/src/app/services/action.service.spec.ts index edbc7d4532..c2ff89b0e4 100644 --- a/frontend/src/app/services/action.service.spec.ts +++ b/frontend/src/app/services/action.service.spec.ts @@ -2,20 +2,18 @@ import { TestBed } from "@angular/core/testing"; import { HttpClientTestingModule } from "@angular/common/http/testing"; import { ActionService } from "./action.service"; -describe("ActionService", - () => { - let service: ActionService; +describe("ActionService", () => { + let service: ActionService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(ActionService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(ActionService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/action.service.ts b/frontend/src/app/services/action.service.ts index c0ebc14bd1..0cc56df75d 100644 --- a/frontend/src/app/services/action.service.ts +++ b/frontend/src/app/services/action.service.ts @@ -10,8 +10,7 @@ export class ActionService { constructor (private httpClient: HttpClient) {} updateActions (actionList: Action[]): Observable { - return this.httpClient.put("/api/v2/action", - actionList); + return this.httpClient.put("/api/v2/action", actionList); } deleteAction (actionId: number): Observable { diff --git a/frontend/src/app/services/check-in.service.spec.ts b/frontend/src/app/services/check-in.service.spec.ts index 63e00d6fdf..6cf2740cff 100644 --- a/frontend/src/app/services/check-in.service.spec.ts +++ b/frontend/src/app/services/check-in.service.spec.ts @@ -5,37 +5,34 @@ import { HttpClientTestingModule } from "@angular/common/http/testing"; import { firstCheckIn, keyResultMetricWithIdEight, secondCheckIn } from "../shared/testData"; import { CheckInMetricMin } from "../shared/types/model/CheckInMetricMin"; -describe("CheckInService", - () => { - let service: CheckInService; +describe("CheckInService", () => { + let service: CheckInService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(CheckInService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(CheckInService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - it("should map correctly", - () => { - service.getAllCheckInOfKeyResult(keyResultMetricWithIdEight.id) - .subscribe((checkIns) => { - // Check first CheckIn of this KeyResult - expect(checkIns[0].confidence) - .toBe(firstCheckIn.confidence); - expect((checkIns[0] as CheckInMetricMin).value) - .toBe(firstCheckIn.value); + it("should map correctly", () => { + service.getAllCheckInOfKeyResult(keyResultMetricWithIdEight.id) + .subscribe((checkIns) => { + // Check first CheckIn of this KeyResult + expect(checkIns[0].confidence) + .toBe(firstCheckIn.confidence); + expect((checkIns[0] as CheckInMetricMin).value) + .toBe(firstCheckIn.value); - expect(checkIns[1].confidence) - .toBe(secondCheckIn.confidence); - expect((checkIns[1] as CheckInMetricMin).value) - .toBe(secondCheckIn.value); - }); + expect(checkIns[1].confidence) + .toBe(secondCheckIn.confidence); + expect((checkIns[1] as CheckInMetricMin).value) + .toBe(secondCheckIn.value); }); }); +}); diff --git a/frontend/src/app/services/check-in.service.ts b/frontend/src/app/services/check-in.service.ts index 9dcd6a0267..710dfaf2c7 100644 --- a/frontend/src/app/services/check-in.service.ts +++ b/frontend/src/app/services/check-in.service.ts @@ -16,11 +16,9 @@ export class CheckInService { saveCheckIn (checkIn: CheckIn) { if (checkIn.id) { - return this.httpclient.put("/api/v2/checkIns/" + checkIn.id, - checkIn); + return this.httpclient.put("/api/v2/checkIns/" + checkIn.id, checkIn); } else { - return this.httpclient.post("/api/v2/checkIns", - checkIn); + return this.httpclient.post("/api/v2/checkIns", checkIn); } } } diff --git a/frontend/src/app/services/completed.servce.ts b/frontend/src/app/services/completed.servce.ts index 29c04c53fd..c17cbc0e94 100644 --- a/frontend/src/app/services/completed.servce.ts +++ b/frontend/src/app/services/completed.servce.ts @@ -10,8 +10,7 @@ export class CompletedService { constructor (private httpClient: HttpClient) {} createCompleted (completed: Completed): Observable { - return this.httpClient.post("/api/v2/completed", - completed); + return this.httpClient.post("/api/v2/completed", completed); } deleteCompleted (objectiveId: number): Observable { diff --git a/frontend/src/app/services/completed.service.spec.ts b/frontend/src/app/services/completed.service.spec.ts index 1a9bc5b8c3..d3e39f7979 100644 --- a/frontend/src/app/services/completed.service.spec.ts +++ b/frontend/src/app/services/completed.service.spec.ts @@ -2,20 +2,18 @@ import { TestBed } from "@angular/core/testing"; import { HttpClientTestingModule } from "@angular/common/http/testing"; import { CompletedService } from "./completed.servce"; -describe("CompletedService", - () => { - let service: CompletedService; +describe("CompletedService", () => { + let service: CompletedService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(CompletedService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(CompletedService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/config.service.spec.ts b/frontend/src/app/services/config.service.spec.ts index 8e30a489af..9299ee9424 100644 --- a/frontend/src/app/services/config.service.spec.ts +++ b/frontend/src/app/services/config.service.spec.ts @@ -3,20 +3,18 @@ import { TestBed } from "@angular/core/testing"; import { ConfigService } from "./config.service"; import { HttpClientTestingModule } from "@angular/common/http/testing"; -describe("ConfigService", - () => { - let service: ConfigService; +describe("ConfigService", () => { + let service: ConfigService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(ConfigService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(ConfigService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/customization.service.spec.ts b/frontend/src/app/services/customization.service.spec.ts index d106bd133c..1bac4f8240 100644 --- a/frontend/src/app/services/customization.service.spec.ts +++ b/frontend/src/app/services/customization.service.spec.ts @@ -26,167 +26,149 @@ class CallRecorder { } } -describe("CustomizationService", - () => { - const body: ClientConfig = { - activeProfile: "test", - issuer: "some-issuer.com", - clientId: "my-client-id", - title: "title", - favicon: "favicon", - logo: "logo", - triangles: "triangles", - backgroundLogo: "backgroundLogo", +describe("CustomizationService", () => { + const body: ClientConfig = { + activeProfile: "test", + issuer: "some-issuer.com", + clientId: "my-client-id", + title: "title", + favicon: "favicon", + logo: "logo", + triangles: "triangles", + backgroundLogo: "backgroundLogo", + helpSiteUrl: "https://wiki.puzzle.ch/Puzzle/OKRs", + customStyles: { cssVar1: "foo" } + }; + + let service: CustomizationService; + let configServiceMock: ConfigService; + let documentMock: Document; + const callRecorder = new CallRecorder(); + let configSubject: BehaviorSubject; + + beforeEach(() => { + configSubject = new BehaviorSubject(body); + configServiceMock = { config$: configSubject.asObservable() } as ConfigService; + callRecorder.clear(); + + documentMock = { + getElementById: (id: string) => { + return { + setAttribute: function () { + callRecorder.add(`${id}-setAttribute`, arguments); + } + } as unknown as HTMLElement; + }, + querySelector: (selector: string) => { + return { + set innerHTML (value: string) { + callRecorder.add(`${selector}.innerHTML`, arguments); + }, + get style () { + return { + setProperty: function () { + callRecorder.add(`${selector}.style.setProperty`, arguments); + }, + removeProperty: function () { + callRecorder.add(`${selector}.style.removeProperty`, arguments); + } + }; + } + }; + } + } as unknown as Document; + service = new CustomizationService(configServiceMock, documentMock); + }); + + it("should call correct apis when config is ready", () => { + const currentConfig = service.getCurrentConfig(); + expect(currentConfig?.title) + .toBe(body.title); + expect(currentConfig?.logo) + .toBe(body.logo); + expect(currentConfig?.favicon) + .toBe(body.favicon); + expect(currentConfig?.triangles) + .toBe(body.triangles); + expect(currentConfig?.backgroundLogo) + .toBe(body.backgroundLogo); + expect(currentConfig?.helpSiteUrl) + .toBe(body.helpSiteUrl); + expect(currentConfig?.customStyles["cssVar1"]) + .toBe(body.customStyles["cssVar1"]); + + expect(callRecorder.getCallCount("title.innerHTML")) + .toBe(1); + expect(callRecorder.getCallCount("favicon-setAttribute")) + .toBe(1); + expect(callRecorder.getCallCount("html.style.setProperty")) + .toBe(1); + expect(callRecorder.getCallCount("html.style.removeProperty")) + .toBe(0); + + expect(callRecorder.getCallByIdx("title.innerHTML", 0)[0]) + .toBe("title"); + expect(callRecorder.getCallByIdx("favicon-setAttribute", 0)[0]) + .toBe("href"); + expect(callRecorder.getCallByIdx("favicon-setAttribute", 0)[1]) + .toBe("favicon"); + expect(callRecorder.getCallByIdx("html.style.setProperty", 0)[0]) + .toBe("--cssVar1"); + expect(callRecorder.getCallByIdx("html.style.setProperty", 0)[1]) + .toBe("foo"); + }); + + it("should update if config changed afterwards", () => { + const bodySecond = { + activeProfile: "test-second", + issuer: "some-issuer.com-second", + clientId: "my-client-id-second", + title: "title-second", + favicon: "favicon-second", + logo: "logo-second", + triangles: "triangles-second", + backgroundLogo: "backgroundLogo-second", helpSiteUrl: "https://wiki.puzzle.ch/Puzzle/OKRs", - customStyles: { cssVar1: "foo" } + customStyles: { cssVarNew: "bar" } }; - - let service: CustomizationService; - let configServiceMock: ConfigService; - let documentMock: Document; - const callRecorder = new CallRecorder(); - let configSubject: BehaviorSubject; - - beforeEach(() => { - configSubject = new BehaviorSubject(body); - configServiceMock = { config$: configSubject.asObservable() } as ConfigService; - callRecorder.clear(); - - documentMock = { - getElementById: (id: string) => { - return { - setAttribute: function () { - callRecorder.add(`${id}-setAttribute`, - arguments); - } - } as unknown as HTMLElement; - }, - querySelector: (selector: string) => { - return { - set innerHTML (value: string) { - callRecorder.add(`${selector}.innerHTML`, - arguments); - }, - get style () { - return { - setProperty: function () { - callRecorder.add(`${selector}.style.setProperty`, - arguments); - }, - removeProperty: function () { - callRecorder.add(`${selector}.style.removeProperty`, - arguments); - } - }; - } - }; - } - } as unknown as Document; - service = new CustomizationService(configServiceMock, - documentMock); - }); - - it("should call correct apis when config is ready", - () => { - const currentConfig = service.getCurrentConfig(); - expect(currentConfig?.title) - .toBe(body.title); - expect(currentConfig?.logo) - .toBe(body.logo); - expect(currentConfig?.favicon) - .toBe(body.favicon); - expect(currentConfig?.triangles) - .toBe(body.triangles); - expect(currentConfig?.backgroundLogo) - .toBe(body.backgroundLogo); - expect(currentConfig?.helpSiteUrl) - .toBe(body.helpSiteUrl); - expect(currentConfig?.customStyles["cssVar1"]) - .toBe(body.customStyles["cssVar1"]); - - expect(callRecorder.getCallCount("title.innerHTML")) - .toBe(1); - expect(callRecorder.getCallCount("favicon-setAttribute")) - .toBe(1); - expect(callRecorder.getCallCount("html.style.setProperty")) - .toBe(1); - expect(callRecorder.getCallCount("html.style.removeProperty")) - .toBe(0); - - expect(callRecorder.getCallByIdx("title.innerHTML", - 0)[0]) - .toBe("title"); - expect(callRecorder.getCallByIdx("favicon-setAttribute", - 0)[0]) - .toBe("href"); - expect(callRecorder.getCallByIdx("favicon-setAttribute", - 0)[1]) - .toBe("favicon"); - expect(callRecorder.getCallByIdx("html.style.setProperty", - 0)[0]) - .toBe("--cssVar1"); - expect(callRecorder.getCallByIdx("html.style.setProperty", - 0)[1]) - .toBe("foo"); - }); - - it("should update if config changed afterwards", - () => { - const bodySecond = { - activeProfile: "test-second", - issuer: "some-issuer.com-second", - clientId: "my-client-id-second", - title: "title-second", - favicon: "favicon-second", - logo: "logo-second", - triangles: "triangles-second", - backgroundLogo: "backgroundLogo-second", - helpSiteUrl: "https://wiki.puzzle.ch/Puzzle/OKRs", - customStyles: { cssVarNew: "bar" } - }; - configSubject.next(bodySecond); - - const currentConfig = service.getCurrentConfig(); - expect(currentConfig?.title) - .toBe(bodySecond.title); - expect(currentConfig?.logo) - .toBe(bodySecond.logo); - expect(currentConfig?.favicon) - .toBe(bodySecond.favicon); - expect(currentConfig?.triangles) - .toBe(bodySecond.triangles); - expect(currentConfig?.backgroundLogo) - .toBe(bodySecond.backgroundLogo); - expect(currentConfig?.helpSiteUrl) - .toBe(bodySecond.helpSiteUrl); - expect(currentConfig?.customStyles["cssVarNew"]) - .toBe(bodySecond.customStyles["cssVarNew"]); - expect(currentConfig?.customStyles["cssVar1"]) - .toBe(undefined); - - expect(callRecorder.getCallCount("title.innerHTML")) - .toBe(2); - expect(callRecorder.getCallCount("favicon-setAttribute")) - .toBe(2); - expect(callRecorder.getCallCount("html.style.setProperty")) - .toBe(2); - expect(callRecorder.getCallCount("html.style.removeProperty")) - .toBe(1); - - expect(callRecorder.getCallByIdx("title.innerHTML", - 1)[0]) - .toBe("title-second"); - expect(callRecorder.getCallByIdx("favicon-setAttribute", - 1)[0]) - .toBe("href"); - expect(callRecorder.getCallByIdx("favicon-setAttribute", - 1)[1]) - .toBe("favicon-second"); - expect(callRecorder.getCallByIdx("html.style.setProperty", - 1)[0]) - .toBe("--cssVarNew"); - expect(callRecorder.getCallByIdx("html.style.setProperty", - 1)[1]) - .toBe("bar"); - }); + configSubject.next(bodySecond); + + const currentConfig = service.getCurrentConfig(); + expect(currentConfig?.title) + .toBe(bodySecond.title); + expect(currentConfig?.logo) + .toBe(bodySecond.logo); + expect(currentConfig?.favicon) + .toBe(bodySecond.favicon); + expect(currentConfig?.triangles) + .toBe(bodySecond.triangles); + expect(currentConfig?.backgroundLogo) + .toBe(bodySecond.backgroundLogo); + expect(currentConfig?.helpSiteUrl) + .toBe(bodySecond.helpSiteUrl); + expect(currentConfig?.customStyles["cssVarNew"]) + .toBe(bodySecond.customStyles["cssVarNew"]); + expect(currentConfig?.customStyles["cssVar1"]) + .toBe(undefined); + + expect(callRecorder.getCallCount("title.innerHTML")) + .toBe(2); + expect(callRecorder.getCallCount("favicon-setAttribute")) + .toBe(2); + expect(callRecorder.getCallCount("html.style.setProperty")) + .toBe(2); + expect(callRecorder.getCallCount("html.style.removeProperty")) + .toBe(1); + + expect(callRecorder.getCallByIdx("title.innerHTML", 1)[0]) + .toBe("title-second"); + expect(callRecorder.getCallByIdx("favicon-setAttribute", 1)[0]) + .toBe("href"); + expect(callRecorder.getCallByIdx("favicon-setAttribute", 1)[1]) + .toBe("favicon-second"); + expect(callRecorder.getCallByIdx("html.style.setProperty", 1)[0]) + .toBe("--cssVarNew"); + expect(callRecorder.getCallByIdx("html.style.setProperty", 1)[1]) + .toBe("bar"); }); +}); diff --git a/frontend/src/app/services/customization.service.ts b/frontend/src/app/services/customization.service.ts index 77b791c480..67b053176e 100644 --- a/frontend/src/app/services/customization.service.ts +++ b/frontend/src/app/services/customization.service.ts @@ -38,8 +38,7 @@ export class CustomizationService { } this.document.getElementById("favicon") - ?.setAttribute("href", - favicon); + ?.setAttribute("href", favicon); } private setTitle (title: string) { @@ -84,8 +83,7 @@ export class CustomizationService { Object.entries(customStylesMap) .forEach(([varName, varValue]) => { - styles.setProperty(`--${varName}`, - varValue); + styles.setProperty(`--${varName}`, varValue); }); } diff --git a/frontend/src/app/services/dialog.service.spec.ts b/frontend/src/app/services/dialog.service.spec.ts index bdbab0fb34..6c787dbf7f 100644 --- a/frontend/src/app/services/dialog.service.spec.ts +++ b/frontend/src/app/services/dialog.service.spec.ts @@ -9,236 +9,213 @@ import { provideHttpClientTesting } from "@angular/common/http/testing"; import { provideHttpClient } from "@angular/common/http"; import { ButtonState } from "../shared/types/enums/ButtonState"; -describe("DialogService", - () => { - let service: DialogService; - let matDialogSpy: MatDialog; - let translateServiceSpy: TranslateService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - providers: [provideHttpClient(), - provideHttpClientTesting(), - TranslateService] - }); - matDialogSpy = TestBed.inject(MatDialog); - service = TestBed.inject(DialogService); - translateServiceSpy = TestBed.inject(TranslateService); - jest.spyOn(matDialogSpy, - "open"); +describe("DialogService", () => { + let service: DialogService; + let matDialogSpy: MatDialog; + let translateServiceSpy: TranslateService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + providers: [provideHttpClient(), + provideHttpClientTesting(), + TranslateService] }); + matDialogSpy = TestBed.inject(MatDialog); + service = TestBed.inject(DialogService); + translateServiceSpy = TestBed.inject(TranslateService); + jest.spyOn(matDialogSpy, "open"); + }); - function expectData (current: ConfirmDialogData, expected: ConfirmDialogData) { - expect(current.title) - .toBe(expected.title); - expect(current.text) - .toBe(expected.text); - expect(current.yesButtonState) - .toBe(expected.yesButtonState); - expect(current.noButtonState) - .toBe(expected.noButtonState); - expect(current.closeButtonState) - .toBe(expected.closeButtonState); - } - - function expectYesButtonIsVisibleAndEnabled (dialog: ConfirmDialogComponent) { - expect(dialog.isYesButtonVisible()) - .toBe(true); - expect(dialog.isYesButtonDisabled()) - .toBe(false); - } - - function expectNoButtonIsVisibleAndEnabled (dialog: ConfirmDialogComponent) { - expect(dialog.isNoButtonVisible()) - .toBe(true); - expect(dialog.isNoButtonDisabled()) - .toBe(false); - } - - function expectCloseButtonIsHiddenAndEnabled (dialog: ConfirmDialogComponent) { - expect(dialog.isCloseButtonVisible()) - .toBe(false); - expect(dialog.isCloseButtonDisabled()) - .toBe(false); - } - - function expectNoButtonIsVisibleAndDisabled (dialog: ConfirmDialogComponent) { - expect(dialog.isNoButtonVisible()) - .toBe(true); - expect(dialog.isNoButtonDisabled()) - .toBe(true); - } - - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + function expectData (current: ConfirmDialogData, expected: ConfirmDialogData) { + expect(current.title) + .toBe(expected.title); + expect(current.text) + .toBe(expected.text); + expect(current.yesButtonState) + .toBe(expected.yesButtonState); + expect(current.noButtonState) + .toBe(expected.noButtonState); + expect(current.closeButtonState) + .toBe(expected.closeButtonState); + } + + function expectYesButtonIsVisibleAndEnabled (dialog: ConfirmDialogComponent) { + expect(dialog.isYesButtonVisible()) + .toBe(true); + expect(dialog.isYesButtonDisabled()) + .toBe(false); + } + + function expectNoButtonIsVisibleAndEnabled (dialog: ConfirmDialogComponent) { + expect(dialog.isNoButtonVisible()) + .toBe(true); + expect(dialog.isNoButtonDisabled()) + .toBe(false); + } + + function expectCloseButtonIsHiddenAndEnabled (dialog: ConfirmDialogComponent) { + expect(dialog.isCloseButtonVisible()) + .toBe(false); + expect(dialog.isCloseButtonDisabled()) + .toBe(false); + } + + function expectNoButtonIsVisibleAndDisabled (dialog: ConfirmDialogComponent) { + expect(dialog.isNoButtonVisible()) + .toBe(true); + expect(dialog.isNoButtonDisabled()) + .toBe(true); + } + + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - it("should open dialog", - () => { - const dialog = service.open(AddEditTeamDialogComponent, - { - data: { - aProperty: "aValue" - } - }); - expect(dialog) - .toBeInstanceOf(MatDialogRef); - expect(dialog.componentInstance) - .toBeInstanceOf(AddEditTeamDialogComponent); - - expect(matDialogSpy.open) - .toHaveBeenCalledWith(AddEditTeamDialogComponent, - { - panelClass: service.DIALOG_PANEL_CLASS_DEFAULT, - ...service.DIALOG_CONFIG, - data: { - aProperty: "aValue" - } - }); + it("should open dialog", () => { + const dialog = service.open(AddEditTeamDialogComponent, { + data: { + aProperty: "aValue" + } + }); + expect(dialog) + .toBeInstanceOf(MatDialogRef); + expect(dialog.componentInstance) + .toBeInstanceOf(AddEditTeamDialogComponent); + + expect(matDialogSpy.open) + .toHaveBeenCalledWith(AddEditTeamDialogComponent, { + panelClass: service.DIALOG_PANEL_CLASS_DEFAULT, + ...service.DIALOG_CONFIG, + data: { + aProperty: "aValue" + } }); + }); - it("should open confirm dialog", - () => { - const i18nData = { - team: "the a-team" - }; - jest.spyOn(service, - "open"); - jest.spyOn(translateServiceSpy, - "instant"); - const dialog = service.openConfirmDialog("DELETE.TEAM", - i18nData); - - // Call function of own service - expect(service.open) - .toHaveBeenCalledTimes(1); - expect(dialog) - .toBeInstanceOf(MatDialogRef); - expect(translateServiceSpy.instant) - .toHaveBeenCalledTimes(2); - expect(translateServiceSpy.instant) - .toHaveBeenCalledWith("DELETE.TEAM.TITLE", - i18nData); - expect(translateServiceSpy.instant) - .toHaveBeenCalledWith("DELETE.TEAM.TEXT", - i18nData); - - // Call function of angular material dialog - expect(matDialogSpy.open) - .toHaveBeenCalledTimes(1); - expect(dialog.componentInstance) - .toBeInstanceOf(ConfirmDialogComponent); - expect(dialog.componentInstance.data.title) - .toBe("DELETE.TEAM.TITLE"); - expect(dialog.componentInstance.data.text) - .toBe("DELETE.TEAM.TEXT"); - - expect(matDialogSpy.open) - .toHaveBeenCalledWith(ConfirmDialogComponent, - { - panelClass: service.DIALOG_PANEL_CLASS_SMALL, - ...service.DIALOG_CONFIG, - data: { - title: "DELETE.TEAM.TITLE", - text: "DELETE.TEAM.TEXT" - } - }); + it("should open confirm dialog", () => { + const i18nData = { + team: "the a-team" + }; + jest.spyOn(service, "open"); + jest.spyOn(translateServiceSpy, "instant"); + const dialog = service.openConfirmDialog("DELETE.TEAM", i18nData); + + // Call function of own service + expect(service.open) + .toHaveBeenCalledTimes(1); + expect(dialog) + .toBeInstanceOf(MatDialogRef); + expect(translateServiceSpy.instant) + .toHaveBeenCalledTimes(2); + expect(translateServiceSpy.instant) + .toHaveBeenCalledWith("DELETE.TEAM.TITLE", i18nData); + expect(translateServiceSpy.instant) + .toHaveBeenCalledWith("DELETE.TEAM.TEXT", i18nData); + + // Call function of angular material dialog + expect(matDialogSpy.open) + .toHaveBeenCalledTimes(1); + expect(dialog.componentInstance) + .toBeInstanceOf(ConfirmDialogComponent); + expect(dialog.componentInstance.data.title) + .toBe("DELETE.TEAM.TITLE"); + expect(dialog.componentInstance.data.text) + .toBe("DELETE.TEAM.TEXT"); + + expect(matDialogSpy.open) + .toHaveBeenCalledWith(ConfirmDialogComponent, { + panelClass: service.DIALOG_PANEL_CLASS_SMALL, + ...service.DIALOG_CONFIG, + data: { + title: "DELETE.TEAM.TITLE", + text: "DELETE.TEAM.TEXT" + } }); + }); - it("should open customized confirm dialog with default visibility properties", - () => { - // arrange - const data: ConfirmDialogData = { - title: "Test title", - text: "Test description", - yesButtonState: undefined, - noButtonState: undefined, - closeButtonState: undefined - }; - - jest.spyOn(service, - "open"); - jest.spyOn(translateServiceSpy, - "instant"); - - // act - const dialog = service.openCustomizedConfirmDialog(data); - dialog.componentInstance.ngOnInit(); // trigger ngOnInit() manually in the test - - // assert - expect(service.open) - .toHaveBeenCalledTimes(1); - expect(dialog) - .toBeInstanceOf(MatDialogRef); - expect(matDialogSpy.open) - .toHaveBeenCalledTimes(1); - - const confirmDialogInstance = dialog.componentInstance; - expect(confirmDialogInstance) - .toBeInstanceOf(ConfirmDialogComponent); - expectData(confirmDialogInstance.data, - data); - - expect(matDialogSpy.open) - .toHaveBeenCalledWith(ConfirmDialogComponent, - { - panelClass: service.DIALOG_PANEL_CLASS_SMALL, - ...service.DIALOG_CONFIG, - data - }); - - expectYesButtonIsVisibleAndEnabled(confirmDialogInstance); - expectNoButtonIsVisibleAndEnabled(confirmDialogInstance); - expectCloseButtonIsHiddenAndEnabled(confirmDialogInstance); + it("should open customized confirm dialog with default visibility properties", () => { + // arrange + const data: ConfirmDialogData = { + title: "Test title", + text: "Test description", + yesButtonState: undefined, + noButtonState: undefined, + closeButtonState: undefined + }; + + jest.spyOn(service, "open"); + jest.spyOn(translateServiceSpy, "instant"); + + // act + const dialog = service.openCustomizedConfirmDialog(data); + dialog.componentInstance.ngOnInit(); // trigger ngOnInit() manually in the test + + // assert + expect(service.open) + .toHaveBeenCalledTimes(1); + expect(dialog) + .toBeInstanceOf(MatDialogRef); + expect(matDialogSpy.open) + .toHaveBeenCalledTimes(1); + + const confirmDialogInstance = dialog.componentInstance; + expect(confirmDialogInstance) + .toBeInstanceOf(ConfirmDialogComponent); + expectData(confirmDialogInstance.data, data); + + expect(matDialogSpy.open) + .toHaveBeenCalledWith(ConfirmDialogComponent, { + panelClass: service.DIALOG_PANEL_CLASS_SMALL, + ...service.DIALOG_CONFIG, + data }); - it("should open customized confirm dialog with explicit visibility properties", - () => { - // arrange - const data: ConfirmDialogData = { - title: "Test title", - text: "Test description", - yesButtonState: ButtonState.VisibleEnabled, - noButtonState: ButtonState.VisibleDisabled, - closeButtonState: ButtonState.Hidden - }; - - jest.spyOn(service, - "open"); - jest.spyOn(translateServiceSpy, - "instant"); - - // act - const dialog = service.openCustomizedConfirmDialog(data); - dialog.componentInstance.ngOnInit(); // trigger ngOnInit() manually in the test - - // assert - expect(service.open) - .toHaveBeenCalledTimes(1); - expect(dialog) - .toBeInstanceOf(MatDialogRef); - expect(matDialogSpy.open) - .toHaveBeenCalledTimes(1); - - const confirmDialogInstance = dialog.componentInstance; - expect(confirmDialogInstance) - .toBeInstanceOf(ConfirmDialogComponent); - expectData(confirmDialogInstance.data, - data); - - expect(matDialogSpy.open) - .toHaveBeenCalledWith(ConfirmDialogComponent, - { - panelClass: service.DIALOG_PANEL_CLASS_SMALL, - ...service.DIALOG_CONFIG, - data - }); - - expectYesButtonIsVisibleAndEnabled(confirmDialogInstance); - expectNoButtonIsVisibleAndDisabled(confirmDialogInstance); - expectCloseButtonIsHiddenAndEnabled(confirmDialogInstance); + expectYesButtonIsVisibleAndEnabled(confirmDialogInstance); + expectNoButtonIsVisibleAndEnabled(confirmDialogInstance); + expectCloseButtonIsHiddenAndEnabled(confirmDialogInstance); + }); + + it("should open customized confirm dialog with explicit visibility properties", () => { + // arrange + const data: ConfirmDialogData = { + title: "Test title", + text: "Test description", + yesButtonState: ButtonState.VisibleEnabled, + noButtonState: ButtonState.VisibleDisabled, + closeButtonState: ButtonState.Hidden + }; + + jest.spyOn(service, "open"); + jest.spyOn(translateServiceSpy, "instant"); + + // act + const dialog = service.openCustomizedConfirmDialog(data); + dialog.componentInstance.ngOnInit(); // trigger ngOnInit() manually in the test + + // assert + expect(service.open) + .toHaveBeenCalledTimes(1); + expect(dialog) + .toBeInstanceOf(MatDialogRef); + expect(matDialogSpy.open) + .toHaveBeenCalledTimes(1); + + const confirmDialogInstance = dialog.componentInstance; + expect(confirmDialogInstance) + .toBeInstanceOf(ConfirmDialogComponent); + expectData(confirmDialogInstance.data, data); + + expect(matDialogSpy.open) + .toHaveBeenCalledWith(ConfirmDialogComponent, { + panelClass: service.DIALOG_PANEL_CLASS_SMALL, + ...service.DIALOG_CONFIG, + data }); + + expectYesButtonIsVisibleAndEnabled(confirmDialogInstance); + expectNoButtonIsVisibleAndDisabled(confirmDialogInstance); + expectCloseButtonIsHiddenAndEnabled(confirmDialogInstance); }); +}); diff --git a/frontend/src/app/services/dialog.service.ts b/frontend/src/app/services/dialog.service.ts index 896e22df4a..3d92a92d73 100644 --- a/frontend/src/app/services/dialog.service.ts +++ b/frontend/src/app/services/dialog.service.ts @@ -31,40 +31,35 @@ export class DialogService { private readonly translationService: TranslateService) {} open(component: ComponentType, config?: MatDialogConfig): MatDialogRef { - return this.dialog.open(component, - { - panelClass: this.DIALOG_PANEL_CLASS_DEFAULT, - ...this.DIALOG_CONFIG, - ...config - }); + return this.dialog.open(component, { + panelClass: this.DIALOG_PANEL_CLASS_DEFAULT, + ...this.DIALOG_CONFIG, + ...config + }); } openConfirmDialog (translationKey: string, i18nData?: object): MatDialogRef { - const title = this.translationService.instant(`${translationKey}.TITLE`, - i18nData); - const text = this.translationService.instant(`${translationKey}.TEXT`, - i18nData); - return this.open(ConfirmDialogComponent, - { - panelClass: this.DIALOG_PANEL_CLASS_SMALL, - data: { - title: title, - text: text - } - }); + const title = this.translationService.instant(`${translationKey}.TITLE`, i18nData); + const text = this.translationService.instant(`${translationKey}.TEXT`, i18nData); + return this.open(ConfirmDialogComponent, { + panelClass: this.DIALOG_PANEL_CLASS_SMALL, + data: { + title: title, + text: text + } + }); } openCustomizedConfirmDialog (data: ConfirmDialogData): MatDialogRef { - return this.open(ConfirmDialogComponent, - { - panelClass: this.DIALOG_PANEL_CLASS_SMALL, - data: { - title: data.title, - text: data.text, - yesButtonState: data.yesButtonState, - noButtonState: data.noButtonState, - closeButtonState: data.closeButtonState - } - }); + return this.open(ConfirmDialogComponent, { + panelClass: this.DIALOG_PANEL_CLASS_SMALL, + data: { + title: data.title, + text: data.text, + yesButtonState: data.yesButtonState, + noButtonState: data.noButtonState, + closeButtonState: data.closeButtonState + } + }); } } diff --git a/frontend/src/app/services/keyresult.service.spec.ts b/frontend/src/app/services/keyresult.service.spec.ts index 777836432d..e834ab3db5 100644 --- a/frontend/src/app/services/keyresult.service.spec.ts +++ b/frontend/src/app/services/keyresult.service.spec.ts @@ -3,18 +3,16 @@ import { TestBed } from "@angular/core/testing"; import { KeyresultService } from "./keyresult.service"; import { HttpClientTestingModule } from "@angular/common/http/testing"; -describe("KeyresultService", - () => { - let service: KeyresultService; +describe("KeyresultService", () => { + let service: KeyresultService; - beforeEach(() => { - TestBed.configureTestingModule({ imports: [HttpClientTestingModule] }); - service = TestBed.inject(KeyresultService); - }); + beforeEach(() => { + TestBed.configureTestingModule({ imports: [HttpClientTestingModule] }); + service = TestBed.inject(KeyresultService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/keyresult.service.ts b/frontend/src/app/services/keyresult.service.ts index 7a471cb735..23225130f8 100644 --- a/frontend/src/app/services/keyresult.service.ts +++ b/frontend/src/app/services/keyresult.service.ts @@ -20,11 +20,9 @@ export class KeyresultService { saveKeyResult (keyResultDTO: KeyResultDTO): Observable { if (keyResultDTO.id) { - return this.httpClient.put("/api/v2/keyresults/" + keyResultDTO.id, - keyResultDTO); + return this.httpClient.put("/api/v2/keyresults/" + keyResultDTO.id, keyResultDTO); } else { - return this.httpClient.post("/api/v2/keyresults", - keyResultDTO); + return this.httpClient.post("/api/v2/keyresults", keyResultDTO); } } diff --git a/frontend/src/app/services/objective-menu-actions.service.spec.ts b/frontend/src/app/services/objective-menu-actions.service.spec.ts index 1f58f4473c..91ec0340bf 100644 --- a/frontend/src/app/services/objective-menu-actions.service.spec.ts +++ b/frontend/src/app/services/objective-menu-actions.service.spec.ts @@ -9,113 +9,95 @@ import { ObjectiveMin } from "../shared/types/model/ObjectiveMin"; import { State } from "../shared/types/enums/State"; import { objectiveMin } from "../shared/testData"; -describe("ObjectiveMenuActionsService", - () => { - let service: ObjectiveMenuActionsService; - let specificMenuEntriesSpy: jest.SpyInstance; +describe("ObjectiveMenuActionsService", () => { + let service: ObjectiveMenuActionsService; + let specificMenuEntriesSpy: jest.SpyInstance; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - providers: [ - TranslateService, - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting() - ] - }); - service = TestBed.inject(ObjectiveMenuActionsService); - - specificMenuEntriesSpy = jest.spyOn(service as any, - "getSpecificMenuEntries"); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + providers: [ + TranslateService, + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting() + ] }); + service = TestBed.inject(ObjectiveMenuActionsService); + + specificMenuEntriesSpy = jest.spyOn(service as any, "getSpecificMenuEntries"); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - describe("getMenu", - () => { - it("should return default and specific menu entries for an ongoing objective", - () => { - const spyOn = jest.spyOn(service as any, - "getOngoingMenuActions"); + describe("getMenu", () => { + it("should return default and specific menu entries for an ongoing objective", () => { + const spyOn = jest.spyOn(service as any, "getOngoingMenuActions"); - const objectiveMinLocal: ObjectiveMin = objectiveMin; - objectiveMinLocal.state = State.ONGOING; - service.getMenu(objectiveMinLocal); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); + const objectiveMinLocal: ObjectiveMin = objectiveMin; + objectiveMinLocal.state = State.ONGOING; + service.getMenu(objectiveMinLocal); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); - it("should return draft menu entries for a draft objective", - () => { - const spyOn = jest.spyOn(service as any, - "getDraftMenuActions"); + it("should return draft menu entries for a draft objective", () => { + const spyOn = jest.spyOn(service as any, "getDraftMenuActions"); - const objectiveMinLocal: ObjectiveMin = objectiveMin; - objectiveMinLocal.state = State.DRAFT; - service.getMenu(objectiveMinLocal); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); + const objectiveMinLocal: ObjectiveMin = objectiveMin; + objectiveMinLocal.state = State.DRAFT; + service.getMenu(objectiveMinLocal); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); - it("should return completed menu entries for a successful objective", - () => { - const spyOn = jest.spyOn(service as any, - "getCompletedMenuActions"); + it("should return completed menu entries for a successful objective", () => { + const spyOn = jest.spyOn(service as any, "getCompletedMenuActions"); - const objectiveMinLocal: ObjectiveMin = objectiveMin; - objectiveMinLocal.state = State.SUCCESSFUL; - service.getMenu(objectiveMinLocal); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); + const objectiveMinLocal: ObjectiveMin = objectiveMin; + objectiveMinLocal.state = State.SUCCESSFUL; + service.getMenu(objectiveMinLocal); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); - it("should return completed menu entries for a non-successful objective", - () => { - const spyOn = jest.spyOn(service as any, - "getCompletedMenuActions"); + it("should return completed menu entries for a non-successful objective", () => { + const spyOn = jest.spyOn(service as any, "getCompletedMenuActions"); - const objectiveMinLocal: ObjectiveMin = objectiveMin; - objectiveMinLocal.state = State.NOTSUCCESSFUL; - service.getMenu(objectiveMinLocal); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); - afterEach(() => { - expect(specificMenuEntriesSpy) - .toHaveBeenCalledTimes(1); - }); - }); + const objectiveMinLocal: ObjectiveMin = objectiveMin; + objectiveMinLocal.state = State.NOTSUCCESSFUL; + service.getMenu(objectiveMinLocal); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); + afterEach(() => { + expect(specificMenuEntriesSpy) + .toHaveBeenCalledTimes(1); + }); + }); - describe("getReleaseAction", - () => { - it("should return release from backlog action for an objective in backlog quarter", - () => { - jest.spyOn(service as any, - "isInBacklogQuarter") - .mockReturnValue(true); - const spyOn = jest.spyOn(service as any, - "isInBacklogQuarter") - .mockReturnValue(true); - // @ts-expect-error - service.getReleaseAction(objectiveMin); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); + describe("getReleaseAction", () => { + it("should return release from backlog action for an objective in backlog quarter", () => { + jest.spyOn(service as any, "isInBacklogQuarter") + .mockReturnValue(true); + const spyOn = jest.spyOn(service as any, "isInBacklogQuarter") + .mockReturnValue(true); + // @ts-expect-error + service.getReleaseAction(objectiveMin); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); - it("should return release from quarter action for an objective in non-backlog quarter", - () => { - const spyOn = jest.spyOn(service as any, - "isInBacklogQuarter") - .mockReturnValue(false); - // @ts-expect-error - service.getReleaseAction(objectiveMin); - expect(spyOn) - .toHaveBeenCalledTimes(1); - }); - }); + it("should return release from quarter action for an objective in non-backlog quarter", () => { + const spyOn = jest.spyOn(service as any, "isInBacklogQuarter") + .mockReturnValue(false); + // @ts-expect-error + service.getReleaseAction(objectiveMin); + expect(spyOn) + .toHaveBeenCalledTimes(1); + }); }); +}); diff --git a/frontend/src/app/services/objective-menu-actions.service.ts b/frontend/src/app/services/objective-menu-actions.service.ts index 3ad7cdae9e..c88e5d3561 100644 --- a/frontend/src/app/services/objective-menu-actions.service.ts +++ b/frontend/src/app/services/objective-menu-actions.service.ts @@ -33,12 +33,8 @@ export class ObjectiveMenuActionsService { completedService: CompletedService, refreshDataService: RefreshDataService ) { - this.afterActions = new ObjectiveMenuAfterActions(objectiveService, - completedService, - refreshDataService); - this.actions = new ObjectiveMenuActions(dialogService, - refreshDataService, - this.afterActions); + this.afterActions = new ObjectiveMenuAfterActions(objectiveService, completedService, refreshDataService); + this.actions = new ObjectiveMenuActions(dialogService, refreshDataService, this.afterActions); } getMenu (objective: ObjectiveMin): ObjectiveMenuEntry[] { diff --git a/frontend/src/app/services/objective.service.spec.ts b/frontend/src/app/services/objective.service.spec.ts index 3533389d97..d9b770ed73 100644 --- a/frontend/src/app/services/objective.service.spec.ts +++ b/frontend/src/app/services/objective.service.spec.ts @@ -3,20 +3,18 @@ import { TestBed } from "@angular/core/testing"; import { ObjectiveService } from "./objective.service"; import { HttpClientTestingModule } from "@angular/common/http/testing"; -describe("ObjectiveService", - () => { - let service: ObjectiveService; +describe("ObjectiveService", () => { + let service: ObjectiveService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(ObjectiveService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(ObjectiveService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/objective.service.ts b/frontend/src/app/services/objective.service.ts index 67f209fdbc..5833da9f51 100644 --- a/frontend/src/app/services/objective.service.ts +++ b/frontend/src/app/services/objective.service.ts @@ -22,13 +22,11 @@ export class ObjectiveService { } createObjective (objectiveDTO: Objective): Observable { - return this.httpClient.post("/api/v2/objectives", - objectiveDTO); + return this.httpClient.post("/api/v2/objectives", objectiveDTO); } updateObjective (objectiveDTO: Objective): Observable { - return this.httpClient.put(`/api/v2/objectives/${objectiveDTO.id}`, - objectiveDTO); + return this.httpClient.put(`/api/v2/objectives/${objectiveDTO.id}`, objectiveDTO); } deleteObjective (objectiveId: number): Observable { @@ -52,7 +50,6 @@ export class ObjectiveService { }[]; objective: any; }): Observable { - return this.httpClient.post(`/api/v2/objectives/${objectiveId}`, - duplicateObjectiveDto); + return this.httpClient.post(`/api/v2/objectives/${objectiveId}`, duplicateObjectiveDto); } } diff --git a/frontend/src/app/services/overview.service.spec.ts b/frontend/src/app/services/overview.service.spec.ts index da16ffaed1..e3d478e56a 100644 --- a/frontend/src/app/services/overview.service.spec.ts +++ b/frontend/src/app/services/overview.service.spec.ts @@ -10,36 +10,32 @@ const httpClient = { get: jest.fn() }; -describe("OverviewService", - () => { - let service: OverviewService; +describe("OverviewService", () => { + let service: OverviewService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [{ provide: HttpClient, - useValue: httpClient }] - }) - .compileComponents(); - service = TestBed.inject(OverviewService); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [{ provide: HttpClient, + useValue: httpClient }] + }) + .compileComponents(); + service = TestBed.inject(OverviewService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - it("should set state of objectives correctly", - (done) => { - jest.spyOn(httpClient, - "get") - .mockReturnValue(of(overviews)); - service.getOverview() - .subscribe(() => { - overviews.forEach((overview) => overview.objectives.forEach((objective) => expect(typeof objective.state) - .toBe("string"))); - done(); - }); + it("should set state of objectives correctly", (done) => { + jest.spyOn(httpClient, "get") + .mockReturnValue(of(overviews)); + service.getOverview() + .subscribe(() => { + overviews.forEach((overview) => overview.objectives.forEach((objective) => expect(typeof objective.state) + .toBe("string"))); + done(); }); }); +}); diff --git a/frontend/src/app/services/overview.service.ts b/frontend/src/app/services/overview.service.ts index 10848ffa05..02865f3f81 100644 --- a/frontend/src/app/services/overview.service.ts +++ b/frontend/src/app/services/overview.service.ts @@ -17,8 +17,7 @@ export class OverviewService { team: teamIds, objectiveQuery: objectiveQuery }); - return this.http.get("/api/v2/overview", - { params: params }) + return this.http.get("/api/v2/overview", { params: params }) .pipe(map((overviews) => { overviews.forEach((overview) => { overview.objectives.forEach((objective) => { diff --git a/frontend/src/app/services/quarter.service.spec.ts b/frontend/src/app/services/quarter.service.spec.ts index 7ad7c20d62..c6f0e8d609 100644 --- a/frontend/src/app/services/quarter.service.spec.ts +++ b/frontend/src/app/services/quarter.service.spec.ts @@ -3,20 +3,18 @@ import { TestBed } from "@angular/core/testing"; import { QuarterService } from "./quarter.service"; import { HttpClientTestingModule } from "@angular/common/http/testing"; -describe("QuarterService", - () => { - let service: QuarterService; +describe("QuarterService", () => { + let service: QuarterService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(QuarterService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(QuarterService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/quarter.service.ts b/frontend/src/app/services/quarter.service.ts index f20d8d212b..a4f10444b6 100644 --- a/frontend/src/app/services/quarter.service.ts +++ b/frontend/src/app/services/quarter.service.ts @@ -13,10 +13,7 @@ export class QuarterService { return this.http .get("/api/v2/quarters") .pipe(map((quarters) => quarters.map((quarter) => new Quarter( - quarter.id, - quarter.label, - quarter.startDate, - quarter.endDate + quarter.id, quarter.label, quarter.startDate, quarter.endDate )))); } diff --git a/frontend/src/app/services/refresh-data.service.spec.ts b/frontend/src/app/services/refresh-data.service.spec.ts index c4a4d82aa2..633ca5cdec 100644 --- a/frontend/src/app/services/refresh-data.service.spec.ts +++ b/frontend/src/app/services/refresh-data.service.spec.ts @@ -2,18 +2,16 @@ import { TestBed } from "@angular/core/testing"; import { RefreshDataService } from "./refresh-data.service"; -describe("RefreshDataService", - () => { - let service: RefreshDataService; +describe("RefreshDataService", () => { + let service: RefreshDataService; - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(RefreshDataService); - }); + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(RefreshDataService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/team.service.spec.ts b/frontend/src/app/services/team.service.spec.ts index 4518b4f1fd..54903b2c9d 100644 --- a/frontend/src/app/services/team.service.spec.ts +++ b/frontend/src/app/services/team.service.spec.ts @@ -3,20 +3,18 @@ import { TestBed } from "@angular/core/testing"; import { TeamService } from "./team.service"; import { HttpClientTestingModule } from "@angular/common/http/testing"; -describe("TeamService", - () => { - let service: TeamService; +describe("TeamService", () => { + let service: TeamService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(TeamService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(TeamService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/services/team.service.ts b/frontend/src/app/services/team.service.ts index 87ab86cb7b..ac80fab71d 100644 --- a/frontend/src/app/services/team.service.ts +++ b/frontend/src/app/services/team.service.ts @@ -37,14 +37,12 @@ export class TeamService { } createTeam (team: Team): Observable { - return this.http.post(this.API_URL, - team) + return this.http.post(this.API_URL, team) .pipe(tap(() => this.reloadTeams())); } updateTeam (team: Team): Observable { - return this.http.put(`${this.API_URL}/${team.id}`, - team) + return this.http.put(`${this.API_URL}/${team.id}`, team) .pipe(tap(() => this.reloadTeams())); } @@ -54,21 +52,18 @@ export class TeamService { } addUsersToTeam (team: Team, selectedUsers: User[]): Observable { - return this.http.put(`${this.API_URL}/${team.id}/addusers`, - selectedUsers); + return this.http.put(`${this.API_URL}/${team.id}/addusers`, selectedUsers); } removeUserFromTeam (userId: number, team: Team): Observable { return this.http - .put(`${this.API_URL}/${team.id}/user/${userId}/removeuser`, - null) + .put(`${this.API_URL}/${team.id}/user/${userId}/removeuser`, null) .pipe(tap(() => this.reloadTeams())); } updateOrAddTeamMembership (userId: number, userTeam: UserTeam): Observable { return this.http - .put(`${this.API_URL}/${userTeam.team.id}/user/${userId}/updateaddteammembership/${userTeam.isTeamAdmin}`, - {}) + .put(`${this.API_URL}/${userTeam.team.id}/user/${userId}/updateaddteammembership/${userTeam.isTeamAdmin}`, {}) .pipe(tap(() => this.reloadTeams())); } } diff --git a/frontend/src/app/services/toaster.service.spec.ts b/frontend/src/app/services/toaster.service.spec.ts index 6d54a18693..29d2923260 100644 --- a/frontend/src/app/services/toaster.service.spec.ts +++ b/frontend/src/app/services/toaster.service.spec.ts @@ -4,78 +4,64 @@ import { ToasterService } from "./toaster.service"; import { ToastrModule, ToastrService } from "ngx-toastr"; import { ToasterType } from "../shared/types/enums/ToasterType"; -describe("ToasterService", - () => { - let service: ToasterService; - let toastr: ToastrService; +describe("ToasterService", () => { + let service: ToasterService; + let toastr: ToastrService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ToastrModule.forRoot()], - providers: [ToasterService] - }); - service = TestBed.inject(ToasterService); - toastr = TestBed.inject(ToastrService); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ToastrModule.forRoot()], + providers: [ToasterService] }); + service = TestBed.inject(ToasterService); + toastr = TestBed.inject(ToastrService); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - it("showSuccess should call right method", - () => { - jest.spyOn(toastr, - "success"); - service.showSuccess("test"); - expect(toastr.success) - .toBeCalledWith("test", - "Erfolgreich!"); - }); + it("showSuccess should call right method", () => { + jest.spyOn(toastr, "success"); + service.showSuccess("test"); + expect(toastr.success) + .toBeCalledWith("test", "Erfolgreich!"); + }); - it("showError should call right method", - () => { - jest.spyOn(toastr, - "error"); - service.showError("test"); - expect(toastr.error) - .toBeCalledWith("test", - "Fehler!"); - }); + it("showError should call right method", () => { + jest.spyOn(toastr, "error"); + service.showError("test"); + expect(toastr.error) + .toBeCalledWith("test", "Fehler!"); + }); - it("showWarn should call right method", - () => { - jest.spyOn(toastr, - "warning"); - service.showWarn("test"); - expect(toastr.warning) - .toBeCalledWith("test", - "Warnung!"); - }); + it("showWarn should call right method", () => { + jest.spyOn(toastr, "warning"); + service.showWarn("test"); + expect(toastr.warning) + .toBeCalledWith("test", "Warnung!"); + }); - it.each([ - [ToasterType.SUCCESS, - "message", - "showSuccess"], - [ToasterType.WARN, - "message", - "showWarn"], - [ToasterType.ERROR, - "message", - "showError"], - [999, - "message", - "showSuccess"] - ])("showWarn should call right method", - (toasterType: number, message: string, func: any) => { - const spy = jest.spyOn(service, - func); + it.each([ + [ToasterType.SUCCESS, + "message", + "showSuccess"], + [ToasterType.WARN, + "message", + "showWarn"], + [ToasterType.ERROR, + "message", + "showError"], + [999, + "message", + "showSuccess"] + ])("showWarn should call right method", (toasterType: number, message: string, func: any) => { + const spy = jest.spyOn(service, func); - service.showCustomToaster(message, - toasterType); + service.showCustomToaster(message, toasterType); - expect(spy) - .toBeCalledWith(message); - }); + expect(spy) + .toBeCalledWith(message); }); +}); diff --git a/frontend/src/app/services/toaster.service.ts b/frontend/src/app/services/toaster.service.ts index d21c57ecd1..1c6c9abace 100644 --- a/frontend/src/app/services/toaster.service.ts +++ b/frontend/src/app/services/toaster.service.ts @@ -9,18 +9,15 @@ export class ToasterService { constructor (private toastr: ToastrService) {} showSuccess (msg: string) { - this.toastr.success(msg, - "Erfolgreich!"); + this.toastr.success(msg, "Erfolgreich!"); } showError (msg: string) { - this.toastr.error(msg, - "Fehler!"); + this.toastr.error(msg, "Fehler!"); } showWarn (msg: string) { - this.toastr.warning(msg, - "Warnung!"); + this.toastr.warning(msg, "Warnung!"); } showCustomToaster (msg: string, type?: ToasterType) { diff --git a/frontend/src/app/services/user.service.spec.ts b/frontend/src/app/services/user.service.spec.ts index 572be80fa9..749e1a12ff 100644 --- a/frontend/src/app/services/user.service.spec.ts +++ b/frontend/src/app/services/user.service.spec.ts @@ -3,110 +3,100 @@ import { HttpClientTestingModule, HttpTestingController } from "@angular/common/ import { UserService } from "./user.service"; import { testUser, users } from "../shared/testData"; -describe("UserService", - () => { - let service: UserService; - let httpMock: HttpTestingController; - const URL = "api/v1/users"; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule] - }); - service = TestBed.inject(UserService); - const injector = getTestBed(); - httpMock = injector.get(HttpTestingController); +describe("UserService", () => { + let service: UserService; + let httpMock: HttpTestingController; + const URL = "api/v1/users"; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule] }); + service = TestBed.inject(UserService); + const injector = getTestBed(); + httpMock = injector.get(HttpTestingController); + }); - afterEach(() => { - httpMock.verify(); - }); + afterEach(() => { + httpMock.verify(); + }); - it("should be created", - () => { - expect(service) - .toBeTruthy(); - }); + it("should be created", () => { + expect(service) + .toBeTruthy(); + }); - it("getUsers should only reload users when they are not loaded yet", - (done) => { - const spy = jest.spyOn(service, - "reloadUsers"); + it("getUsers should only reload users when they are not loaded yet", (done) => { + const spy = jest.spyOn(service, "reloadUsers"); + service.getUsers() + .subscribe(() => { + expect(spy) + .toBeCalledTimes(1); + httpMock.expectOne(URL); service.getUsers() - .subscribe(() => { + .subscribe((users) => { expect(spy) .toBeCalledTimes(1); - httpMock.expectOne(URL); - service.getUsers() - .subscribe((users) => { - expect(spy) - .toBeCalledTimes(1); - expect(users) - .toStrictEqual([]); - done(); - }); + expect(users) + .toStrictEqual([]); + done(); }); }); + }); - it("get current user should throw error, when not loaded", - () => { - expect(() => service.getCurrentUser()) - .toThrowError("user should not be undefined here"); - }); + it("get current user should throw error, when not loaded", () => { + expect(() => service.getCurrentUser()) + .toThrowError("user should not be undefined here"); + }); - it("init current user should load user", - (done) => { - expect(() => service.getCurrentUser()) - .toThrowError("user should not be undefined here"); - service.getOrInitCurrentUser() - .subscribe(() => { - expect(service.getCurrentUser()) - .toBe(users[0]); - done(); - }); - const req = httpMock.expectOne("api/v1/users/current"); - req.flush(users[0]); + it("init current user should load user", (done) => { + expect(() => service.getCurrentUser()) + .toThrowError("user should not be undefined here"); + service.getOrInitCurrentUser() + .subscribe(() => { + expect(service.getCurrentUser()) + .toBe(users[0]); + done(); }); - - it("setIsOkrChampion should call put operation, reloadUsers and reloadCurrentUser", - fakeAsync(() => { - service.setIsOkrChampion(testUser, - true) - .subscribe(); - const req = httpMock.expectOne(`api/v1/users/${testUser.id}/isokrchampion/true`); - req.flush(users[0]); - - tick(); - - const req2 = httpMock.expectOne("api/v1/users"); - const req3 = httpMock.expectOne("api/v1/users/current"); - req2.flush({}); - req3.flush({}); - })); - - it("createUsers should call createAll and reloadUsers", - fakeAsync(() => { - service.createUsers(users) - .subscribe(); - const req = httpMock.expectOne("api/v1/users/createall"); - req.flush(users); - - tick(); - - const req2 = httpMock.expectOne("api/v1/users"); - req2.flush({}); - })); - - it("deleteUser should call /userId and reloadUsers", - fakeAsync(() => { - service.deleteUser(testUser) - .subscribe(); - const req = httpMock.expectOne(`api/v1/users/${testUser.id}`); - req.flush(users); - - tick(); - - const req2 = httpMock.expectOne("api/v1/users"); - req2.flush({}); - })); + const req = httpMock.expectOne("api/v1/users/current"); + req.flush(users[0]); }); + + it("setIsOkrChampion should call put operation, reloadUsers and reloadCurrentUser", fakeAsync(() => { + service.setIsOkrChampion(testUser, true) + .subscribe(); + const req = httpMock.expectOne(`api/v1/users/${testUser.id}/isokrchampion/true`); + req.flush(users[0]); + + tick(); + + const req2 = httpMock.expectOne("api/v1/users"); + const req3 = httpMock.expectOne("api/v1/users/current"); + req2.flush({}); + req3.flush({}); + })); + + it("createUsers should call createAll and reloadUsers", fakeAsync(() => { + service.createUsers(users) + .subscribe(); + const req = httpMock.expectOne("api/v1/users/createall"); + req.flush(users); + + tick(); + + const req2 = httpMock.expectOne("api/v1/users"); + req2.flush({}); + })); + + it("deleteUser should call /userId and reloadUsers", fakeAsync(() => { + service.deleteUser(testUser) + .subscribe(); + const req = httpMock.expectOne(`api/v1/users/${testUser.id}`); + req.flush(users); + + tick(); + + const req2 = httpMock.expectOne("api/v1/users"); + req2.flush({}); + })); +}); diff --git a/frontend/src/app/services/user.service.ts b/frontend/src/app/services/user.service.ts index 4f8a61b943..f1a53c0a2d 100644 --- a/frontend/src/app/services/user.service.ts +++ b/frontend/src/app/services/user.service.ts @@ -56,8 +56,7 @@ export class UserService { } setIsOkrChampion (user: User, isOkrChampion: boolean) { - return this.httpClient.put(`${this.API_URL}/${user.id}/isokrchampion/${isOkrChampion}`, - {}) + return this.httpClient.put(`${this.API_URL}/${user.id}/isokrchampion/${isOkrChampion}`, {}) .pipe(tap(() => { this.reloadUsers(); this.reloadCurrentUser() @@ -66,24 +65,20 @@ export class UserService { } createUsers (userList: NewUser[]) { - return this.httpClient.post(`${this.API_URL}/createall`, - userList) + return this.httpClient.post(`${this.API_URL}/createall`, userList) .pipe(tap(() => this.reloadUsers())); } deleteUser (user: User) { - return this.httpClient.delete(`${this.API_URL}/${user.id}`, - {}) + return this.httpClient.delete(`${this.API_URL}/${user.id}`, {}) .pipe(tap(() => this.reloadUsers())); } getUserOkrData (user: User): Observable { - return this.httpClient.get(`${this.API_URL}/${user.id}/userokrdata`, - {}); + return this.httpClient.get(`${this.API_URL}/${user.id}/userokrdata`, {}); } isUserMemberOfTeams (user: User): Observable { - return this.httpClient.get(`${this.API_URL}/${user.id}/ismemberofteams`, - {}); + return this.httpClient.get(`${this.API_URL}/${user.id}/ismemberofteams`, {}); } } diff --git a/frontend/src/app/shared/common.spec.ts b/frontend/src/app/shared/common.spec.ts index 99652660c2..a526a223f6 100644 --- a/frontend/src/app/shared/common.spec.ts +++ b/frontend/src/app/shared/common.spec.ts @@ -13,403 +13,378 @@ import { FormControl, FormGroup, Validators } from "@angular/forms"; import { keyResultMetricMinScoring, keyResultOrdinalMinScoring } from "./testData"; import { KeyResultMetricMin } from "./types/model/KeyResultMetricMin"; -describe("test common functions", - () => { - describe("getNumberOrNull", - () => { - test("should get simple number correctly", - () => { - expect(getNumberOrNull("-123456789")) - .toBe(-123456789); - expect(getNumberOrNull("-5")) - .toBe(-5); - expect(getNumberOrNull("-0")) - .toBe(-0); - expect(getNumberOrNull("0")) - .toBe(0); - expect(getNumberOrNull("+0")) - .toBe(0); - expect(getNumberOrNull("3")) - .toBe(3); - expect(getNumberOrNull("123456789")) - .toBe(123456789); - }); +describe("test common functions", () => { + describe("getNumberOrNull", () => { + test("should get simple number correctly", () => { + expect(getNumberOrNull("-123456789")) + .toBe(-123456789); + expect(getNumberOrNull("-5")) + .toBe(-5); + expect(getNumberOrNull("-0")) + .toBe(-0); + expect(getNumberOrNull("0")) + .toBe(0); + expect(getNumberOrNull("+0")) + .toBe(0); + expect(getNumberOrNull("3")) + .toBe(3); + expect(getNumberOrNull("123456789")) + .toBe(123456789); + }); - test("should get special number correctly", - () => { - expect(getNumberOrNull("03")) - .toBe(3); - expect(getNumberOrNull(" 3")) - .toBe(3); - expect(getNumberOrNull(" 3 ")) - .toBe(3); - expect(getNumberOrNull("3 ")) - .toBe(3); - expect(getNumberOrNull("+3 ")) - .toBe(3); - expect(getNumberOrNull("-3 ")) - .toBe(-3); - expect(getNumberOrNull("3foo")) - .toBe(3); - expect(getNumberOrNull("+3foo")) - .toBe(3); - expect(getNumberOrNull("-3foo")) - .toBe(-3); - expect(getNumberOrNull(" 3foo")) - .toBe(3); - expect(getNumberOrNull(" +3foo")) - .toBe(3); - expect(getNumberOrNull(" -3foo")) - .toBe(-3); - expect(getNumberOrNull("03.2")) - .toBe(3); - expect(getNumberOrNull("03,2")) - .toBe(3); - expect(getNumberOrNull("3+2")) - .toBe(3); - }); + test("should get special number correctly", () => { + expect(getNumberOrNull("03")) + .toBe(3); + expect(getNumberOrNull(" 3")) + .toBe(3); + expect(getNumberOrNull(" 3 ")) + .toBe(3); + expect(getNumberOrNull("3 ")) + .toBe(3); + expect(getNumberOrNull("+3 ")) + .toBe(3); + expect(getNumberOrNull("-3 ")) + .toBe(-3); + expect(getNumberOrNull("3foo")) + .toBe(3); + expect(getNumberOrNull("+3foo")) + .toBe(3); + expect(getNumberOrNull("-3foo")) + .toBe(-3); + expect(getNumberOrNull(" 3foo")) + .toBe(3); + expect(getNumberOrNull(" +3foo")) + .toBe(3); + expect(getNumberOrNull(" -3foo")) + .toBe(-3); + expect(getNumberOrNull("03.2")) + .toBe(3); + expect(getNumberOrNull("03,2")) + .toBe(3); + expect(getNumberOrNull("3+2")) + .toBe(3); + }); - test("should get null if the argument has no digit", - () => { - expect(getNumberOrNull(null)) - .toBe(null); - expect(getNumberOrNull("")) - .toBe(null); - expect(getNumberOrNull(" ")) - .toBe(null); - expect(getNumberOrNull("foo")) - .toBe(null); - expect(getNumberOrNull("null")) - .toBe(null); - expect(getNumberOrNull("undefined")) - .toBe(null); - }); + test("should get null if the argument has no digit", () => { + expect(getNumberOrNull(null)) + .toBe(null); + expect(getNumberOrNull("")) + .toBe(null); + expect(getNumberOrNull(" ")) + .toBe(null); + expect(getNumberOrNull("foo")) + .toBe(null); + expect(getNumberOrNull("null")) + .toBe(null); + expect(getNumberOrNull("undefined")) + .toBe(null); + }); - test("should get null if the argument more that spaces, + or - a the beginning", - () => { - expect(getNumberOrNull("foo3")) - .toBe(null); - expect(getNumberOrNull("foo+3")) - .toBe(null); - expect(getNumberOrNull("+foo3")) - .toBe(null); - expect(getNumberOrNull(" + 3")) - .toBe(null); - expect(getNumberOrNull("+ 3")) - .toBe(null); - expect(getNumberOrNull("+ 3 ")) - .toBe(null); - expect(getNumberOrNull(" - 3")) - .toBe(null); - expect(getNumberOrNull("- 3")) - .toBe(null); - expect(getNumberOrNull("- 3 ")) - .toBe(null); - }); - }); + test("should get null if the argument more that spaces, + or - a the beginning", () => { + expect(getNumberOrNull("foo3")) + .toBe(null); + expect(getNumberOrNull("foo+3")) + .toBe(null); + expect(getNumberOrNull("+foo3")) + .toBe(null); + expect(getNumberOrNull(" + 3")) + .toBe(null); + expect(getNumberOrNull("+ 3")) + .toBe(null); + expect(getNumberOrNull("+ 3 ")) + .toBe(null); + expect(getNumberOrNull(" - 3")) + .toBe(null); + expect(getNumberOrNull("- 3")) + .toBe(null); + expect(getNumberOrNull("- 3 ")) + .toBe(null); + }); + }); - it.each([ - [[], - [], - true], - [[1], - [], - false], - [[1, - 2], + it.each([ + [[], [], - false], - [[1], - [1], - true], - [[1, - 2], - [1, - 2], - true], - [[1, - 2, - 3], - [1, - 2, - 3], true], - [[1, - 2, - 3], - [ - 1, - 2, - 3, - 4 - ], - false], - [[1, - 2, - 3], - [ - 1, - 2, - 3, - 3 - ], + [[1], + [], false], - [[1, - 2, - 3], - [3, - 2, - 1], - true] - ])("should give correct output for deep equal", - (arr1: number[], arr2: number[], output: boolean) => { - expect(areEqual(arr1, - arr2)) - .toBe(output); - expect(areEqual(arr2, - arr1)) - .toBe(output); - }); + [[1, + 2], + [], + false], + [[1], + [1], + true], + [[1, + 2], + [1, + 2], + true], + [[1, + 2, + 3], + [1, + 2, + 3], + true], + [[1, + 2, + 3], + [ + 1, + 2, + 3, + 4 + ], + false], + [[1, + 2, + 3], + [ + 1, + 2, + 3, + 3 + ], + false], + [[1, + 2, + 3], + [3, + 2, + 1], + true] + ])("should give correct output for deep equal", (arr1: number[], arr2: number[], output: boolean) => { + expect(areEqual(arr1, arr2)) + .toBe(output); + expect(areEqual(arr2, arr1)) + .toBe(output); + }); - it.each([ - [[], - undefined, - []], - [undefined, - undefined, - []], - ["", - undefined, - []], - [[1], - undefined, - [1]], - [[1, - NaN], + it.each([ + [[], + undefined, + []], + [undefined, + undefined, + []], + ["", + undefined, + []], + [[1], + undefined, + [1]], + [[1, + NaN], + undefined, + [1]], + [[1, + "", + 3], + undefined, + [1, + 3]], + ["1,3", + undefined, + [1, + 3]], + ["1,3.5", undefined, [1]], - [[1, - "", - 3], + ["1,3.5,3", undefined, [1, 3]], - ["1,3", - undefined, - [1, - 3]], - ["1,3.5", - undefined, - [1]], - ["1,3.5,3", - undefined, - [1, - 3]], - ["1,nonsense,3", - undefined, - [1, - 3]], + ["1,nonsense,3", + undefined, + [1, + 3]], + [0, + undefined, + [0]], + [[0], + undefined, + [0]], + ["0", + undefined, + [0]], + ["1,0", + undefined, + [1, + 0]], + ["0,1", + undefined, [0, - undefined, - [0]], - [[0], - undefined, - [0]], - ["0", - undefined, - [0]], - ["1,0", - undefined, - [1, - 0]], - ["0,1", - undefined, - [0, - 1]], - ["", - 1, - [1]], - [[], - 1, - [1]] - ])("should give correct output for getValueFromQuery", - (value: any, fallback: number | undefined, arr2: number[]) => { - expect(getValueFromQuery(value, - fallback)) - .toStrictEqual(arr2); - }); + 1]], + ["", + 1, + [1]], + [[], + 1, + [1]] + ])("should give correct output for getValueFromQuery", (value: any, fallback: number | undefined, arr2: number[]) => { + expect(getValueFromQuery(value, fallback)) + .toStrictEqual(arr2); + }); - it.each([ - [{ v: undefined }, - {}], - [{ v: "" }, - {}], - [{ v: [] }, - {}], - [{ v: [1] }, - { v: [1] }], - [{ v: 1 }, - { v: 1 }], - [{ v: 1, - v2: undefined }, + it.each([ + [{ v: undefined }, + {}], + [{ v: "" }, + {}], + [{ v: [] }, + {}], + [{ v: [1] }, + { v: [1] }], + [{ v: 1 }, { v: 1 }], - [{ v: undefined, - v2: 1 }, - { v2: 1 }] - ])("should give correct output for optionalValue", - (value: Record, expected: Record) => { - expect(optionalValue(value)) - .toStrictEqual(expected); - }); + [{ v: 1, + v2: undefined }, + { v: 1 }], + [{ v: undefined, + v2: 1 }, + { v2: 1 }] + ])("should give correct output for optionalValue", (value: Record, expected: Record) => { + expect(optionalValue(value)) + .toStrictEqual(expected); + }); - it.each([[" test ", - "test"], - ["ffF", - "fff"]])("test sanitize function", - (str: any, expected: string) => { - expect(sanitize(str)) - .toBe(expected); - }); + it.each([[" test ", + "test"], + ["ffF", + "fff"]])("test sanitize function", (str: any, expected: string) => { + expect(sanitize(str)) + .toBe(expected); + }); - it.each([ - [ - 0, - 100, - 20, - 20 - ], - [ - 100, - 0, - 20, - 80 - ], - [ - 500, - 400, - 460, - 40 - ], - [ - 100, - 10, - 110, - 0 - ], - [ - 0, - 100, - -10, - 0 - ], - [ - 0, - 100, - -10, - 0 - ], - [ - 0, - 100, - -10, - 0 - ] - ])("should calculate progress correctly", - async ( - baseline: number, stretchGoal: number, value: number, filledPercentage: number - ) => { - const keyResult = { - ...keyResultMetricMinScoring, - baseline: baseline, - stretchGoal: stretchGoal, - lastCheckIn: { ...keyResultOrdinalMinScoring.lastCheckIn, - value: value } - } as KeyResultMetricMin; - const percentage = calculateCurrentPercentage(keyResult); - expect(percentage) - .toBe(filledPercentage); - }); + it.each([ + [ + 0, + 100, + 20, + 20 + ], + [ + 100, + 0, + 20, + 80 + ], + [ + 500, + 400, + 460, + 40 + ], + [ + 100, + 10, + 110, + 0 + ], + [ + 0, + 100, + -10, + 0 + ], + [ + 0, + 100, + -10, + 0 + ], + [ + 0, + 100, + -10, + 0 + ] + ])("should calculate progress correctly", async ( + baseline: number, stretchGoal: number, value: number, filledPercentage: number + ) => { + const keyResult = { + ...keyResultMetricMinScoring, + baseline: baseline, + stretchGoal: stretchGoal, + lastCheckIn: { ...keyResultOrdinalMinScoring.lastCheckIn, + value: value } + } as KeyResultMetricMin; + const percentage = calculateCurrentPercentage(keyResult); + expect(percentage) + .toBe(filledPercentage); + }); - it.each([ - ["t%20t", - "t t"], - ["%20", - ""], - ["f%20", - "f"], - ["%20f", - "f"], - ["test", - "test"] - ])("test getQueryString function", - (str: any, expected: string) => { - expect(getQueryString(str)) - .toBe(expected); - }); + it.each([ + ["t%20t", + "t t"], + ["%20", + ""], + ["f%20", + "f"], + ["%20f", + "f"], + ["test", + "test"] + ])("test getQueryString function", (str: any, expected: string) => { + expect(getQueryString(str)) + .toBe(expected); + }); - it.each([ - [{ v: undefined }, - { v: null }], - [{ v: "" }, - { v: null }], - [{ v: [] }, - { v: null }], - [{ v: [1] }, - { v: [1] }], - [{ v: 1 }, - { v: 1 }], - [{ v: 1, - v2: undefined }, - { v: 1, - v2: null }], - [{ v: undefined, - v2: 1 }, - { v: null, - v2: 1 }] - ])("should give correct output for optionalReplaceWithNulls", - (obj1: Record, obj2: Record) => { - expect(optionalReplaceWithNulls(obj1)) - .toStrictEqual(obj2); - }); + it.each([ + [{ v: undefined }, + { v: null }], + [{ v: "" }, + { v: null }], + [{ v: [] }, + { v: null }], + [{ v: [1] }, + { v: [1] }], + [{ v: 1 }, + { v: 1 }], + [{ v: 1, + v2: undefined }, + { v: 1, + v2: null }], + [{ v: undefined, + v2: 1 }, + { v: null, + v2: 1 }] + ])("should give correct output for optionalReplaceWithNulls", (obj1: Record, obj2: Record) => { + expect(optionalReplaceWithNulls(obj1)) + .toStrictEqual(obj2); + }); - test("should return correct class", - () => { - const testForm = new FormGroup({ - title: new FormControl(undefined, - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("", - [Validators.maxLength(4096)]), - code: new FormControl(0, - [Validators.min(5), - Validators.max(10)]) - }); - testForm.controls["code"].markAsDirty(); - testForm.controls["title"].markAsTouched(); - testForm.controls["description"].markAsDirty(); + test("should return correct class", () => { + const testForm = new FormGroup({ + title: new FormControl(undefined, [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("", [Validators.maxLength(4096)]), + code: new FormControl(0, [Validators.min(5), + Validators.max(10)]) + }); + testForm.controls["code"].markAsDirty(); + testForm.controls["title"].markAsTouched(); + testForm.controls["description"].markAsDirty(); - // False check - expect(formInputCheck(testForm, - "code")) - .toBe("dialog-form-field-error"); - expect(formInputCheck(testForm, - "title")) - .toBe("dialog-form-field-error"); + // False check + expect(formInputCheck(testForm, "code")) + .toBe("dialog-form-field-error"); + expect(formInputCheck(testForm, "title")) + .toBe("dialog-form-field-error"); - // Fill in value to match validation - testForm.controls.code.setValue(8); - testForm.controls.title.setValue("Test"); + // Fill in value to match validation + testForm.controls.code.setValue(8); + testForm.controls.title.setValue("Test"); - // True check - expect(formInputCheck(testForm, - "description")) - .toBe("dialog-form-field"); - expect(formInputCheck(testForm, - "code")) - .toBe("dialog-form-field"); - expect(formInputCheck(testForm, - "title")) - .toBe("dialog-form-field"); - }); + // True check + expect(formInputCheck(testForm, "description")) + .toBe("dialog-form-field"); + expect(formInputCheck(testForm, "code")) + .toBe("dialog-form-field"); + expect(formInputCheck(testForm, "title")) + .toBe("dialog-form-field"); }); +}); diff --git a/frontend/src/app/shared/common.ts b/frontend/src/app/shared/common.ts index 580bbc74df..f02410e113 100644 --- a/frontend/src/app/shared/common.ts +++ b/frontend/src/app/shared/common.ts @@ -6,8 +6,7 @@ export function getNumberOrNull (str: string | null | undefined): number | null .trim() === "") { return null; } - const number: number = parseInt(str, - 10); + const number: number = parseInt(str, 10); return Number.isNaN(number) ? null : number; } @@ -16,7 +15,7 @@ export function getValueFromQuery (query: any, fallback?: number): number[] { .flat() .filter((e) => e !== "") .map((e) => { - return typeof e == 'string' ? e.split(',') : e; + return typeof e == "string" ? e.split(",") : e; }) .flat() .map((id: any) => Number(id)) @@ -48,9 +47,7 @@ export function calculateCurrentPercentage (keyResultMetric: KeyResultMetricMin) const value: number = +(keyResultMetric.lastCheckIn?.value ?? 0); const baseline: number = +keyResultMetric.baseline; const stretchGoal: number = +keyResultMetric.stretchGoal; - if (isLastCheckInNegative(baseline, - stretchGoal, - value)) return 0; + if (isLastCheckInNegative(baseline, stretchGoal, value)) return 0; if (value == stretchGoal) return 100; return Math.abs(value - baseline) / Math.abs(stretchGoal - baseline) * 100; diff --git a/frontend/src/app/shared/custom/scoring/scoring.component.spec.ts b/frontend/src/app/shared/custom/scoring/scoring.component.spec.ts index 5a1083f577..c0ed1de80b 100644 --- a/frontend/src/app/shared/custom/scoring/scoring.component.spec.ts +++ b/frontend/src/app/shared/custom/scoring/scoring.component.spec.ts @@ -6,183 +6,173 @@ import { HttpClientTestingModule } from "@angular/common/http/testing"; import { Zone } from "../../types/enums/Zone"; import { CheckInOrdinalMin } from "../../types/model/CheckInOrdinalMin"; -describe("ScoringComponent", - () => { - let component: ScoringComponent; - let fixture: ComponentFixture; - - describe("Basic function tests", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ScoringComponent], - providers: [{ - provide: Router, - useValue: { - url: "/okr/overview" - } - }], - imports: [HttpClientTestingModule] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ScoringComponent); - component = fixture.componentInstance; - component.keyResult = keyResultMetricMinScoring; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should fill out star if target percentage is over 100", - () => { - component.stretched = true; - component.ngAfterViewInit(); - expect(component.iconPath) - .toBe("filled"); - }); - - it.each([ - [{ fail: 0, - commit: 0, - target: 0, - className: null, - borderClass: "none" }], - [{ fail: 99, - commit: 0, - target: 0, - className: "score-red", - borderClass: "fail" }], - [{ fail: 100, - commit: 0, - target: 0, - className: "score-yellow", - borderClass: "commit" }], - [{ fail: 100, - commit: 99, - target: 0, - className: "score-yellow", - borderClass: "commit" }], - [{ fail: 100, - commit: 100, - target: 0, - className: "score-green", - borderClass: "target" }], - [{ fail: 100, - commit: 100, - target: 99, - className: "score-green", - borderClass: "target" }], - [{ fail: 100, - commit: 100, - target: 100, - className: "score-green", - borderClass: "target" }], - [{ fail: 100, - commit: 100, - target: 101, - className: "score-stretch", - borderClass: "none" }] - ])("should set styles correctly", - async (object: any) => { - component.targetPercent = object.target; - component.commitPercent = object.commit; - component.failPercent = object.fail; - - const color: string | null = component.getScoringColorClassAndSetBorder(); - expect(color) - .toBe(object.className); - }); - }); - - describe("KeyResult metric", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ScoringComponent], - providers: [{ - provide: Router, - useValue: { - url: "/okr/overview" - } - }], - imports: [HttpClientTestingModule] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ScoringComponent); - component = fixture.componentInstance; - component.keyResult = keyResultMetricMinScoring; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - }); - - describe("KeyResult ordinal", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ScoringComponent], - providers: [{ - provide: Router, - useValue: { - url: "/okr/overview" - } - }], - imports: [HttpClientTestingModule] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ScoringComponent); - component = fixture.componentInstance; - component.keyResult = keyResultOrdinalMinScoring; - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it.each([[{ zoneValue: Zone.FAIL, - fail: 100, - commit: 0, - target: 0 }], - [{ zoneValue: Zone.COMMIT, - fail: 100, - commit: 100, - target: 0 }], - [{ zoneValue: Zone.TARGET, - fail: 100, - commit: 100, - target: 100 }]])("should set percentages correctly", - (object: any) => { - // Reset component - component.targetPercent = 0; - component.commitPercent = 0; - component.failPercent = 0; - - // Set zonen - (component.keyResult.lastCheckIn as CheckInOrdinalMin).zone = object.zoneValue; - component.calculatePercentageOrdinal(); - - // Verify if percentage was set correctly - expect(component.failPercent) - .toBe(object.fail); - expect(component.commitPercent) - .toBe(object.commit); - expect(component.targetPercent) - .toBe(object.target); - }); - }); +describe("ScoringComponent", () => { + let component: ScoringComponent; + let fixture: ComponentFixture; + + describe("Basic function tests", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ScoringComponent], + providers: [{ + provide: Router, + useValue: { + url: "/okr/overview" + } + }], + imports: [HttpClientTestingModule] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ScoringComponent); + component = fixture.componentInstance; + component.keyResult = keyResultMetricMinScoring; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should fill out star if target percentage is over 100", () => { + component.stretched = true; + component.ngAfterViewInit(); + expect(component.iconPath) + .toBe("filled"); + }); + + it.each([ + [{ fail: 0, + commit: 0, + target: 0, + className: null, + borderClass: "none" }], + [{ fail: 99, + commit: 0, + target: 0, + className: "score-red", + borderClass: "fail" }], + [{ fail: 100, + commit: 0, + target: 0, + className: "score-yellow", + borderClass: "commit" }], + [{ fail: 100, + commit: 99, + target: 0, + className: "score-yellow", + borderClass: "commit" }], + [{ fail: 100, + commit: 100, + target: 0, + className: "score-green", + borderClass: "target" }], + [{ fail: 100, + commit: 100, + target: 99, + className: "score-green", + borderClass: "target" }], + [{ fail: 100, + commit: 100, + target: 100, + className: "score-green", + borderClass: "target" }], + [{ fail: 100, + commit: 100, + target: 101, + className: "score-stretch", + borderClass: "none" }] + ])("should set styles correctly", async (object: any) => { + component.targetPercent = object.target; + component.commitPercent = object.commit; + component.failPercent = object.fail; + + const color: string | null = component.getScoringColorClassAndSetBorder(); + expect(color) + .toBe(object.className); + }); }); + + describe("KeyResult metric", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ScoringComponent], + providers: [{ + provide: Router, + useValue: { + url: "/okr/overview" + } + }], + imports: [HttpClientTestingModule] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ScoringComponent); + component = fixture.componentInstance; + component.keyResult = keyResultMetricMinScoring; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + }); + + describe("KeyResult ordinal", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ScoringComponent], + providers: [{ + provide: Router, + useValue: { + url: "/okr/overview" + } + }], + imports: [HttpClientTestingModule] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ScoringComponent); + component = fixture.componentInstance; + component.keyResult = keyResultOrdinalMinScoring; + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it.each([[{ zoneValue: Zone.FAIL, + fail: 100, + commit: 0, + target: 0 }], + [{ zoneValue: Zone.COMMIT, + fail: 100, + commit: 100, + target: 0 }], + [{ zoneValue: Zone.TARGET, + fail: 100, + commit: 100, + target: 100 }]])("should set percentages correctly", (object: any) => { + // Reset component + component.targetPercent = 0; + component.commitPercent = 0; + component.failPercent = 0; + + // Set zonen + (component.keyResult.lastCheckIn as CheckInOrdinalMin).zone = object.zoneValue; + component.calculatePercentageOrdinal(); + + // Verify if percentage was set correctly + expect(component.failPercent) + .toBe(object.fail); + expect(component.commitPercent) + .toBe(object.commit); + expect(component.targetPercent) + .toBe(object.target); + }); + }); +}); diff --git a/frontend/src/app/shared/customRouter.ts b/frontend/src/app/shared/customRouter.ts index d0996c927d..56337d0dd5 100644 --- a/frontend/src/app/shared/customRouter.ts +++ b/frontend/src/app/shared/customRouter.ts @@ -10,7 +10,6 @@ export class CustomRouter extends Router { override navigate (commands: any[], extras?: NavigationExtras | undefined): Promise { const customExtras = { ...extras, queryParamsHandling: "merge" } as NavigationExtras; - return super.navigate(commands, - customExtras); + return super.navigate(commands, customExtras); } } diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts index 606ecc197f..7e159e1011 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.spec.ts @@ -23,126 +23,120 @@ const matDataMock: { objective: { objectiveId: number | undefined; } }; -describe("CompleteDialogComponent", - () => { - let component: CompleteDialogComponent; - let fixture: ComponentFixture; - let debugElement: any; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - FormsModule, - ReactiveFormsModule, - MatDialogModule, - MatIconModule, - MatDividerModule - ], - declarations: [CompleteDialogComponent, - DialogTemplateCoreComponent], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: MatDialogRef, - useValue: dialogMock }, - { provide: MAT_DIALOG_DATA, - useValue: matDataMock }, - { provide: TranslateService, - useValue: {} } - ] - }); - fixture = TestBed.createComponent(CompleteDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - debugElement = fixture.debugElement.nativeElement; +describe("CompleteDialogComponent", () => { + let component: CompleteDialogComponent; + let fixture: ComponentFixture; + let debugElement: any; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + FormsModule, + ReactiveFormsModule, + MatDialogModule, + MatIconModule, + MatDividerModule + ], + declarations: [CompleteDialogComponent, + DialogTemplateCoreComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: MatDialogRef, + useValue: dialogMock }, + { provide: MAT_DIALOG_DATA, + useValue: matDataMock }, + { provide: TranslateService, + useValue: {} } + ] }); + fixture = TestBed.createComponent(CompleteDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + debugElement = fixture.debugElement.nativeElement; + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should set right classes on init", - () => { - const elements = document.querySelectorAll(".valuation-card"); - const successful = document.querySelectorAll(".card-hover-successful"); - const notSuccessful = document.querySelectorAll(".card-hover-not-successful"); - const submitButton = debugElement.querySelector("[data-testid=\"submit\"]"); - - expect(elements.length) - .toEqual(2); - expect(successful.length) - .toEqual(1); - expect(notSuccessful.length) - .toEqual(1); - expect(component.completeForm.value.isSuccessful) - .toBeNull(); - expect(component.completeForm.value.comment) - .toBeNull(); - expect(component.completeForm.invalid) - .toBeTruthy(); - expect(submitButton!.hasAttribute("disabled")) - .toBeTruthy(); - }); + it("should set right classes on init", () => { + const elements = document.querySelectorAll(".valuation-card"); + const successful = document.querySelectorAll(".card-hover-successful"); + const notSuccessful = document.querySelectorAll(".card-hover-not-successful"); + const submitButton = debugElement.querySelector("[data-testid=\"submit\"]"); + + expect(elements.length) + .toEqual(2); + expect(successful.length) + .toEqual(1); + expect(notSuccessful.length) + .toEqual(1); + expect(component.completeForm.value.isSuccessful) + .toBeNull(); + expect(component.completeForm.value.comment) + .toBeNull(); + expect(component.completeForm.invalid) + .toBeTruthy(); + expect(submitButton!.hasAttribute("disabled")) + .toBeTruthy(); + }); - it("should change isSuccessful value on card click and remove class card-hover", - () => { - component.switchSuccessState("successful"); - let elements = document.querySelectorAll(".card-hover"); - const submitButton = debugElement.querySelector("[data-testid=\"submit\"]"); - - expect(component.completeForm.value.isSuccessful) - .toBeTruthy(); - expect(component.completeForm.invalid) - .toBeFalsy(); - expect(elements.length) - .toEqual(0); - expect(submitButton!.hasAttribute("disabled")) - .toBeTruthy(); - - component.completeForm.patchValue({ isSuccessful: null }); - component.switchSuccessState("notSuccessful"); - elements = document.querySelectorAll(".card-hover"); - - expect(component.completeForm.value.isSuccessful) - .toBeFalsy(); - expect(elements.length) - .toEqual(0); - }); + it("should change isSuccessful value on card click and remove class card-hover", () => { + component.switchSuccessState("successful"); + let elements = document.querySelectorAll(".card-hover"); + const submitButton = debugElement.querySelector("[data-testid=\"submit\"]"); + + expect(component.completeForm.value.isSuccessful) + .toBeTruthy(); + expect(component.completeForm.invalid) + .toBeFalsy(); + expect(elements.length) + .toEqual(0); + expect(submitButton!.hasAttribute("disabled")) + .toBeTruthy(); + + component.completeForm.patchValue({ isSuccessful: null }); + component.switchSuccessState("notSuccessful"); + elements = document.querySelectorAll(".card-hover"); + + expect(component.completeForm.value.isSuccessful) + .toBeFalsy(); + expect(elements.length) + .toEqual(0); + }); - it("should set active and non-active classes on switch", - () => { - component.switchSuccessState("successful"); - fixture.detectChanges(); - let nonActiveElement = document.querySelector(".active-successful"); + it("should set active and non-active classes on switch", () => { + component.switchSuccessState("successful"); + fixture.detectChanges(); + let nonActiveElement = document.querySelector(".active-successful"); - expect(nonActiveElement!.innerHTML) - .toContain("Objective erreicht"); + expect(nonActiveElement!.innerHTML) + .toContain("Objective erreicht"); - component.switchSuccessState("notSuccessful"); - fixture.detectChanges(); - nonActiveElement = document.querySelector(".active-not-successful"); + component.switchSuccessState("notSuccessful"); + fixture.detectChanges(); + nonActiveElement = document.querySelector(".active-not-successful"); - expect(nonActiveElement!.innerHTML) - .toContain("Objective nicht erreicht"); - }); + expect(nonActiveElement!.innerHTML) + .toContain("Objective nicht erreicht"); + }); - it("should close dialog with right data", - () => { - component.completeForm.patchValue({ - isSuccessful: true, - comment: "My new comment" - }); - component.closeDialog(); - - expect(dialogMock.close) - .toHaveBeenCalledTimes(1); - expect(dialogMock.close) - .toHaveBeenCalledWith({ - endState: "SUCCESSFUL", - comment: "My new comment" - }); + it("should close dialog with right data", () => { + component.completeForm.patchValue({ + isSuccessful: true, + comment: "My new comment" + }); + component.closeDialog(); + + expect(dialogMock.close) + .toHaveBeenCalledTimes(1); + expect(dialogMock.close) + .toHaveBeenCalledWith({ + endState: "SUCCESSFUL", + comment: "My new comment" }); }); +}); diff --git a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts index 0bb0ab7c03..ae385d863c 100644 --- a/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts +++ b/frontend/src/app/shared/dialog/complete-dialog/complete-dialog.component.ts @@ -11,10 +11,8 @@ import { TranslateService } from "@ngx-translate/core"; }) export class CompleteDialogComponent { completeForm = new FormGroup({ - isSuccessful: new FormControl(null, - [Validators.required]), - comment: new FormControl(null, - [Validators.maxLength(4096)]) + isSuccessful: new FormControl(null, [Validators.required]), + comment: new FormControl(null, [Validators.maxLength(4096)]) }); protected readonly formInputCheck = formInputCheck; diff --git a/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.spec.ts b/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.spec.ts index 8184c852d7..fe6be2551b 100644 --- a/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.spec.ts +++ b/frontend/src/app/shared/dialog/confirm-dialog/confirm-dialog.component.spec.ts @@ -20,63 +20,59 @@ const dialogRefMock = { close: jest.fn() }; -describe("ConfirmDialogComponent", - () => { - let component: ConfirmDialogComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; +describe("ConfirmDialogComponent", () => { + let component: ConfirmDialogComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule, - TranslateModule.forRoot(), - MatIconModule, - MatDividerModule - ], - declarations: [ConfirmDialogComponent, - DialogTemplateCoreComponent], - providers: [TranslateService, - { provide: MAT_DIALOG_DATA, - useValue: { title: "", - text: "" } as ConfirmDialogData }, - { provide: MatDialogRef, - useValue: dialogRefMock }] - }); - fixture = TestBed.createComponent(ConfirmDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule, + TranslateModule.forRoot(), + MatIconModule, + MatDividerModule + ], + declarations: [ConfirmDialogComponent, + DialogTemplateCoreComponent], + providers: [TranslateService, + { provide: MAT_DIALOG_DATA, + useValue: { title: "", + text: "" } as ConfirmDialogData }, + { provide: MatDialogRef, + useValue: dialogRefMock }] }); + fixture = TestBed.createComponent(ConfirmDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should call close method with parameter: true if clicked to submit button", - async () => { - const buttons = await loader.getAllHarnesses(MatButtonHarness); - const submitButton = buttons[1]; - await submitButton.click(); + it("should call close method with parameter: true if clicked to submit button", async () => { + const buttons = await loader.getAllHarnesses(MatButtonHarness); + const submitButton = buttons[1]; + await submitButton.click(); - expect(dialogRefMock.close) - .toHaveBeenCalledWith(true); - }); + expect(dialogRefMock.close) + .toHaveBeenCalledWith(true); + }); - it("should call close method with parameter: \"\" if clicked to cancel button", - async () => { - const buttons = await loader.getAllHarnesses(MatButtonHarness); - const cancelButton = buttons[0]; - await cancelButton.click(); + it("should call close method with parameter: \"\" if clicked to cancel button", async () => { + const buttons = await loader.getAllHarnesses(MatButtonHarness); + const cancelButton = buttons[0]; + await cancelButton.click(); - expect(dialogRefMock.close) - .toHaveBeenCalledWith(""); - }); + expect(dialogRefMock.close) + .toHaveBeenCalledWith(""); }); +}); diff --git a/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.spec.ts b/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.spec.ts index 75f8fd1b29..2f46a91246 100644 --- a/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.spec.ts +++ b/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.spec.ts @@ -17,199 +17,191 @@ import * as errorData from "../../../../assets/errors/error-messages.json"; import { ObjectiveComponent } from "../../../components/objective/objective.component"; import { MatOptionHarness } from "@angular/material/core/testing"; -describe("ExampleDialogComponent", - () => { - let component: ExampleDialogComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; - - const errors = errorData; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - NoopAnimationsModule, - MatSelectModule, - MatInputModule, - MatRadioModule, - ReactiveFormsModule - ], - providers: [{ - provide: MatDialogRef, - useValue: {} - }, - { - provide: MAT_DIALOG_DATA, - useValue: {} - }], - declarations: [ExampleDialogComponent, - ObjectiveComponent] - }) - .compileComponents(); - fixture = TestBed.createComponent(ExampleDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); - }); - - it("should create", - fakeAsync(() => { - expect(component) - .toBeTruthy(); - })); +describe("ExampleDialogComponent", () => { + let component: ExampleDialogComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + + const errors = errorData; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoopAnimationsModule, + MatSelectModule, + MatInputModule, + MatRadioModule, + ReactiveFormsModule + ], + providers: [{ + provide: MatDialogRef, + useValue: {} + }, + { + provide: MAT_DIALOG_DATA, + useValue: {} + }], + declarations: [ExampleDialogComponent, + ObjectiveComponent] + }) + .compileComponents(); + fixture = TestBed.createComponent(ExampleDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + }); - it("should be able to set name", - waitForAsync(async () => { - // Insert values into name input - const nameInput = await loader.getHarness(MatInputHarness); - await nameInput.setValue("Name"); - - // Check if save button is disabled - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.disabled) - .toBeTruthy(); - - // Validate if object was created correctly - const formObject = fixture.componentInstance.dialogForm.value; - expect(formObject.name) - .toBe("Name"); + it("should create", fakeAsync(() => { + expect(component) + .toBeTruthy(); + })); + + it("should be able to set name", waitForAsync(async () => { + // Insert values into name input + const nameInput = await loader.getHarness(MatInputHarness); + await nameInput.setValue("Name"); + + // Check if save button is disabled + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.disabled) + .toBeTruthy(); + + // Validate if object was created correctly + const formObject = fixture.componentInstance.dialogForm.value; + expect(formObject.name) + .toBe("Name"); + })); + + it("should be able to set buttons", waitForAsync(async () => { + // Check radio button + const buttons = await loader.getAllHarnesses(MatRadioButtonHarness); + await buttons[0].check(); + + // Check if save button is disabled + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.disabled) + .toBeTruthy(); + + // Validate if object was created correctly + const formObject = fixture.componentInstance.dialogForm.value; + expect(formObject.name) + .toBe(""); + expect(formObject.gender) + .toBe(await buttons[0].getValue()); + })); + + it("should be able to set select", async () => { + let option = ""; + // Get mat-select element and click it (dropdown) + await loader.getHarness(MatSelectHarness) + .then(fakeAsync((matSelect: MatSelectHarness) => { + matSelect.open(); + advance(); + matSelect.getOptions() + .then((selectOptions) => { + selectOptions[0].click(); + advance(); + selectOptions[0].getText() + .then((value) => option = value); + }); })); - it("should be able to set buttons", - waitForAsync(async () => { - // Check radio button - const buttons = await loader.getAllHarnesses(MatRadioButtonHarness); - await buttons[0].check(); - - // Check if save button is disabled - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.disabled) - .toBeTruthy(); - - // Validate if object was created correctly - const formObject = fixture.componentInstance.dialogForm.value; - expect(formObject.name) - .toBe(""); - expect(formObject.gender) - .toBe(await buttons[0].getValue()); - })); + // Check if save button is disabled + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(await submitButton.nativeElement.disabled) + .toBeTruthy(); + + // Validate if object was created correctly + const formObject = fixture.componentInstance.dialogForm.value; + expect(formObject.name) + .toBe(""); + expect(option) + .toBe(formObject.hobby); + }); - it("should be able to set select", - async () => { - let option = ""; - // Get mat-select element and click it (dropdown) - await loader.getHarness(MatSelectHarness) - .then(fakeAsync((matSelect: MatSelectHarness) => { - matSelect.open(); - advance(); + it("should display error message of too short input", waitForAsync(async () => { + // Insert values into name input which don't match length validator + const nameInput = await loader.getHarness(MatInputHarness); + await nameInput.setValue("Na"); + + // Verify error message + const errorMessage = fixture.debugElement.query(By.css("mat-error")); + expect(errorMessage.nativeElement.textContent) + .toContain(errors.MINLENGTH); + + // Check if submit button is disabled + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(submitButton.nativeElement.disabled) + .toBeTruthy(); + })); + + it("should display error message of required dropdown", waitForAsync(async () => { + // Open and close mat-select element to trigger validation + const matSelect = await loader.getHarness(MatSelectHarness); + await matSelect.open(); + await matSelect.close(); + + // Verify error message + const errorMessage = fixture.debugElement.query(By.css("mat-error")); + expect(errorMessage.nativeElement.textContent) + .toContain(errors.REQUIRED); + + // Check if submit button is disabled + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(submitButton.nativeElement.disabled) + .toBeTruthy(); + })); + + it("should not save form unless radio button is checked", async () => { + // Insert value into input + const nameInput = loader.getHarness(MatInputHarness); + const matSelect = loader.getHarness(MatSelectHarness); + const radioButtons = loader.getAllHarnesses(MatRadioButtonHarness); + + // Verify that the submit button is disabled because the radio button is not checked yet + const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); + expect(submitButton.nativeElement.disabled) + .toBeTruthy(); + + await Promise.all([nameInput, + matSelect, + radioButtons]) + .then(fakeAsync(([nameInput, + matSelect, + radioButtons]: [MatInputHarness, MatSelectHarness, MatRadioButtonHarness[]]) => { + nameInput.setValue("Name"); + advance(); + matSelect.open() + .then(() => { matSelect.getOptions() - .then((selectOptions) => { - selectOptions[0].click(); + .then((options: MatOptionHarness[]) => { + options[1].click(); + radioButtons[1].check(); advance(); - selectOptions[0].getText() - .then((value) => option = value); - }); - })); - - // Check if save button is disabled - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(await submitButton.nativeElement.disabled) - .toBeTruthy(); - - // Validate if object was created correctly - const formObject = fixture.componentInstance.dialogForm.value; - expect(formObject.name) - .toBe(""); - expect(option) - .toBe(formObject.hobby); - }); - - it("should display error message of too short input", - waitForAsync(async () => { - // Insert values into name input which don't match length validator - const nameInput = await loader.getHarness(MatInputHarness); - await nameInput.setValue("Na"); - - // Verify error message - const errorMessage = fixture.debugElement.query(By.css("mat-error")); - expect(errorMessage.nativeElement.textContent) - .toContain(errors.MINLENGTH); - - // Check if submit button is disabled - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(submitButton.nativeElement.disabled) - .toBeTruthy(); - })); - - it("should display error message of required dropdown", - waitForAsync(async () => { - // Open and close mat-select element to trigger validation - const matSelect = await loader.getHarness(MatSelectHarness); - await matSelect.open(); - await matSelect.close(); - - // Verify error message - const errorMessage = fixture.debugElement.query(By.css("mat-error")); - expect(errorMessage.nativeElement.textContent) - .toContain(errors.REQUIRED); - - // Check if submit button is disabled - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(submitButton.nativeElement.disabled) - .toBeTruthy(); - })); - - it("should not save form unless radio button is checked", - async () => { - // Insert value into input - const nameInput = loader.getHarness(MatInputHarness); - const matSelect = loader.getHarness(MatSelectHarness); - const radioButtons = loader.getAllHarnesses(MatRadioButtonHarness); - - // Verify that the submit button is disabled because the radio button is not checked yet - const submitButton = fixture.debugElement.query(By.css("[data-testId=\"submit\"]")); - expect(submitButton.nativeElement.disabled) - .toBeTruthy(); - - await Promise.all([nameInput, - matSelect, - radioButtons]) - .then(fakeAsync(([nameInput, - matSelect, - radioButtons]: [MatInputHarness, MatSelectHarness, MatRadioButtonHarness[]]) => { - nameInput.setValue("Name"); - advance(); - matSelect.open() - .then(() => { - matSelect.getOptions() - .then((options: MatOptionHarness[]) => { - options[1].click(); - radioButtons[1].check(); - advance(); - // Check submit button and form output - Promise.all([radioButtons[1].getValue(), - options[1].getText()]) - .then(([gender, - hobby]) => { - const formObject = fixture.componentInstance.dialogForm.value; - expect(submitButton.nativeElement.disabled) - .toBeFalsy(); - expect(formObject.name) - .toBe("Name"); - expect(gender) - .toBe("female"); - expect(hobby) - .toBe(formObject.hobby); - }); + // Check submit button and form output + Promise.all([radioButtons[1].getValue(), + options[1].getText()]) + .then(([gender, + hobby]) => { + const formObject = fixture.componentInstance.dialogForm.value; + expect(submitButton.nativeElement.disabled) + .toBeFalsy(); + expect(formObject.name) + .toBe("Name"); + expect(gender) + .toBe("female"); + expect(hobby) + .toBe(formObject.hobby); }); }); - })); - }); - - function advance (duration = 100) { - tick(duration); - fixture.detectChanges(); - tick(duration); - } + }); + })); }); + + function advance (duration = 100) { + tick(duration); + fixture.detectChanges(); + tick(duration); + } +}); diff --git a/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.ts b/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.ts index 1bb491ef46..4ff965cb90 100644 --- a/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.ts +++ b/frontend/src/app/shared/dialog/example-dialog/example-dialog.component.ts @@ -22,14 +22,11 @@ export class ExampleDialogComponent { protected readonly formInputCheck = formInputCheck; dialogForm = new FormGroup({ - name: new FormControl("", - [Validators.required, - Validators.minLength(3), - Validators.maxLength(50)]), - gender: new FormControl("", - [Validators.required]), - hobby: new FormControl("", - [Validators.required]) + name: new FormControl("", [Validators.required, + Validators.minLength(3), + Validators.maxLength(50)]), + gender: new FormControl("", [Validators.required]), + hobby: new FormControl("", [Validators.required]) }); constructor (public dialog: MatDialogRef, diff --git a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts index a83cff9f2d..13b4bdc621 100644 --- a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts +++ b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.spec.ts @@ -47,30 +47,18 @@ interface MatDialogDataInterface { const quarterService = { getAllQuarters (): Observable { return of([new Quarter( - 1, - quarter.label, - quarter.startDate, - quarter.endDate + 1, quarter.label, quarter.startDate, quarter.endDate ), new Quarter( - 2, - quarter.label, - quarter.startDate, - quarter.endDate + 2, quarter.label, quarter.startDate, quarter.endDate ), new Quarter( - 999, - "Backlog", - null, - null + 999, "Backlog", null, null )]); }, getCurrentQuarter (): Observable { return of(new Quarter( - 2, - quarter.label, - quarter.startDate, - quarter.endDate + 2, quarter.label, quarter.startDate, quarter.endDate )); } }; @@ -110,435 +98,415 @@ const mockActivatedRoute = { } }; -describe("ObjectiveDialogComponent", - () => { - let component: ObjectiveFormComponent; - let fixture: ComponentFixture; - let loader: HarnessLoader; - - describe("Normal Objective dialog", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - MatIconModule, - MatFormFieldModule, - MatSelectModule, - ReactiveFormsModule, - MatInputModule, - NoopAnimationsModule, - MatCheckboxModule, - TranslateTestingModule.withTranslations({ - de: de - }), - MatDividerModule - ], - declarations: [ObjectiveFormComponent, - DialogTemplateCoreComponent], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: MatDialogRef, - useValue: dialogMock }, - { provide: MAT_DIALOG_DATA, - useValue: matDataMock }, - { provide: ObjectiveService, - useValue: objectiveService }, - { provide: QuarterService, - useValue: quarterService }, - { provide: TeamService, - useValue: teamService } - ] - }); - fixture = TestBed.createComponent(ObjectiveFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); +describe("ObjectiveDialogComponent", () => { + let component: ObjectiveFormComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + + describe("Normal Objective dialog", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + ReactiveFormsModule, + MatInputModule, + NoopAnimationsModule, + MatCheckboxModule, + TranslateTestingModule.withTranslations({ + de: de + }), + MatDividerModule + ], + declarations: [ObjectiveFormComponent, + DialogTemplateCoreComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: MatDialogRef, + useValue: dialogMock }, + { provide: MAT_DIALOG_DATA, + useValue: matDataMock }, + { provide: ObjectiveService, + useValue: objectiveService }, + { provide: QuarterService, + useValue: quarterService }, + { provide: TeamService, + useValue: teamService } + ] + }); + fixture = TestBed.createComponent(ObjectiveFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it.each([["DRAFT"], + ["ONGOING"]])("onSubmit create", fakeAsync((state: string) => { + // Prepare data + const title = "title"; + const description = "description"; + const createKeyresults = true; + let quarter = 0; + let team = 0; + teamService.getAllTeams() + .subscribe((teams: { id: number }[]) => { + team = teams[0].id; + }); + quarterService.getAllQuarters() + .subscribe((quarters) => { + quarter = quarters[1].id; }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it.each([["DRAFT"], - ["ONGOING"]])("onSubmit create", - fakeAsync((state: string) => { - // Prepare data - const title = "title"; - const description = "description"; - const createKeyresults = true; - let quarter = 0; - let team = 0; - teamService.getAllTeams() - .subscribe((teams: { id: number }[]) => { - team = teams[0].id; - }); - quarterService.getAllQuarters() - .subscribe((quarters) => { - quarter = quarters[1].id; - }); - - // Get input elements and set values - const titleInput: HTMLInputElement = fixture.debugElement.query(By.css("[data-testId=\"title\"]")).nativeElement; - titleInput.value = title; - const descriptionInput: HTMLInputElement = fixture.debugElement.query(By.css("[data-testId=\"description\"]")).nativeElement; - descriptionInput.value = description; - loader.getHarness(MatCheckboxHarness) - .then((checkBox) => checkBox.check()); - tick(200); - const quarterSelect: HTMLSelectElement = fixture.debugElement.query(By.css("[data-testId=\"quarterSelect\"]")).nativeElement; - quarterSelect.value = quarter.toString(); - // Trigger update of form - fixture.detectChanges(); - titleInput.dispatchEvent(new Event("input")); - descriptionInput.dispatchEvent(new Event("input")); - quarterSelect.dispatchEvent(new Event("change")); - - const rawFormValue = component.objectiveForm.getRawValue(); - expect(rawFormValue.description) - .toBe(description); - expect(rawFormValue.quarter) - .toBe(quarter.toString()); - expect(rawFormValue.team) - .toBe(team); - expect(rawFormValue.title) - .toBe(title); - expect(rawFormValue.createKeyResults) - .toBe(createKeyresults); - - objectiveService.createObjective.mockReturnValue(of({ ...objective, - state: state })); - component.onSubmit(state); - - expect(dialogMock.close) - .toHaveBeenCalledWith({ - addKeyResult: createKeyresults, - delete: false, - objective: { - description: description, - id: 5, - version: 1, - quarterId: 2, - quarterLabel: "GJ 22/23-Q2", - state: State[state as keyof typeof State], - teamId: 2, - title: title, - writeable: true - }, - teamId: 1 - }); - })); - - it("should create objective", - () => { - matDataMock.objective.objectiveId = undefined; - component.objectiveForm.setValue({ - title: "Test title", - description: "Test description", - quarter: 0, - team: 0, - relation: 0, - createKeyResults: false, - keyResults: [] - }); - - objectiveService.createObjective.mockReturnValue(of({ ...objective, - state: "DRAFT" })); - component.onSubmit("DRAFT"); - - fixture.detectChanges(); - - expect(objectiveService.createObjective) - .toHaveBeenCalledWith({ - description: "Test description", - id: undefined, - state: "DRAFT", - title: "Test title", - quarterId: 0, - teamId: 0 - }); - }); - - it("should update objective", - () => { - matDataMock.objective.objectiveId = 1; - component.objectiveForm.setValue({ - title: "Test title", - description: "Test description", - quarter: 1, - team: 1, - relation: 0, - createKeyResults: false, - keyResults: [] - }); - - objectiveService.updateObjective.mockReturnValue(of({ ...objective, - state: "ONGOING" })); - component.onSubmit("DRAFT"); - - fixture.detectChanges(); - - expect(objectiveService.updateObjective) - .toHaveBeenCalledWith({ - description: "Test description", - id: 1, - state: "DRAFT", - title: "Test title", - quarterId: 1, - teamId: 1 - }); - }); - - it("should load default values into form onInit with undefined objectiveId", - () => { - matDataMock.objective.objectiveId = undefined; - matDataMock.objective.teamId = 1; - component.ngOnInit(); - const rawFormValue = component.objectiveForm.getRawValue(); - const defaultComponent = component.getDefaultObjective(); - expect(rawFormValue.title) - .toBe(defaultComponent.title); - expect(rawFormValue.description) - .toBe(defaultComponent.description); - expect(rawFormValue.team) - .toBe(matDataMock.objective.teamId); - quarterService.getAllQuarters() - .subscribe((quarters) => { - expect(rawFormValue.quarter) - .toBe([quarters[0].id]); - }); - }); - - it("should load default values into form onInit with defined objectiveId", - async () => { - matDataMock.objective.objectiveId = 1; - const routerHarness = await RouterTestingHarness.create(); - await routerHarness.navigateByUrl("/?quarter=2"); - objectiveService.getFullObjective.mockReturnValue(of(objective)); - objectiveService.getAllKeyResultsByObjective.mockReturnValue(of(keyResult)); - component.ngOnInit(); - const rawFormValue = component.objectiveForm.getRawValue(); - expect(rawFormValue.title) - .toBe(objective.title); - expect(rawFormValue.description) - .toBe(objective.description); - expect(rawFormValue.team) - .toBe(objective.teamId); - expect(rawFormValue.quarter) - .toBe(objective.quarterId); - }); - - it("should set teams$ observable correctly on ngOnInit", - () => { - const mockTeams = [{ id: 1, - name: "Team A" }, - { id: 2, - name: "Team B" }]; - teamService.getAllTeams.mockReturnValue(of(mockTeams)); - - component.ngOnInit(); - - component.teams$.subscribe((teams: Team[]) => { - expect(teams) - .toEqual(mockTeams); - }); - }); - - it("should set keyResults$ observable correctly when objectiveId is defined", - () => { - const mockKeyResults = [{ id: 1, - name: "Key Result A" }]; - matDataMock.objective.objectiveId = 1; - objectiveService.getAllKeyResultsByObjective.mockReturnValue(of(mockKeyResults)); - - component.ngOnInit(); - - component.keyResults$.subscribe((keyResults) => { - expect(keyResults) - .toEqual(mockKeyResults); - }); - }); - - it("should return correct value if allowed to save to backlog", - async () => { - component.quarters = quarterList; - const isBacklogQuarterSpy = jest.spyOn(component, - "isBacklogQuarter"); - isBacklogQuarterSpy.mockReturnValue(false); - - component.data.action = "duplicate"; - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeTruthy(); - - component.objectiveForm.controls.quarter.setValue(999); - component.data.action = ""; - component.data.objective.objectiveId = 5; - component.state = "DRAFT"; - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeTruthy(); - - component.state = "ONGOING"; - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeFalsy(); - - component.objectiveForm.controls.quarter.setValue(2); - isBacklogQuarterSpy.mockReturnValue(true); - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeTruthy(); - - component.objectiveForm.controls.quarter.setValue(999); - component.data.objective.objectiveId = undefined; - isBacklogQuarterSpy.mockReturnValue(false); - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeFalsy(); - - component.objectiveForm.controls.quarter.setValue(2); - isBacklogQuarterSpy.mockReturnValue(true); - fixture.detectChanges(); - expect(component.allowedToSaveBacklog()) - .toBeTruthy(); - }); - - it("should return if option is allowed for quarter select", - async () => { - const quarter: Quarter = new Quarter( - 1, - "Backlog", - null, - null - ); - - const data = { - action: "duplicate", - objective: { - objectiveId: 22 - } - }; - component.data = data; - component.state = "DRAFT"; - fixture.detectChanges(); - - expect(component.allowedOption(quarter)) - .toBeTruthy(); - - expect(component.allowedOption(quarter)) - .toBeTruthy(); - data.action = "releaseBacklog"; - fixture.detectChanges(); - expect(component.allowedOption(quarter)) - .toBeFalsy(); - - data.action = "edit"; - fixture.detectChanges(); - - expect(component.allowedOption(quarter)) - .toBeTruthy(); - - component.state = "ONGOING"; - fixture.detectChanges(); - expect(component.allowedOption(quarter)) - .toBeFalsy(); - - component.data = { - action: "duplicate", - objective: {} - }; - - fixture.detectChanges(); - expect(component.allowedOption(quarter)) - .toBeTruthy(); - }); + // Get input elements and set values + const titleInput: HTMLInputElement = fixture.debugElement.query(By.css("[data-testId=\"title\"]")).nativeElement; + titleInput.value = title; + const descriptionInput: HTMLInputElement = fixture.debugElement.query(By.css("[data-testId=\"description\"]")).nativeElement; + descriptionInput.value = description; + loader.getHarness(MatCheckboxHarness) + .then((checkBox) => checkBox.check()); + tick(200); + const quarterSelect: HTMLSelectElement = fixture.debugElement.query(By.css("[data-testId=\"quarterSelect\"]")).nativeElement; + quarterSelect.value = quarter.toString(); + // Trigger update of form + fixture.detectChanges(); + titleInput.dispatchEvent(new Event("input")); + descriptionInput.dispatchEvent(new Event("input")); + quarterSelect.dispatchEvent(new Event("change")); + + const rawFormValue = component.objectiveForm.getRawValue(); + expect(rawFormValue.description) + .toBe(description); + expect(rawFormValue.quarter) + .toBe(quarter.toString()); + expect(rawFormValue.team) + .toBe(team); + expect(rawFormValue.title) + .toBe(title); + expect(rawFormValue.createKeyResults) + .toBe(createKeyresults); + + objectiveService.createObjective.mockReturnValue(of({ ...objective, + state: state })); + component.onSubmit(state); + + expect(dialogMock.close) + .toHaveBeenCalledWith({ + addKeyResult: createKeyresults, + delete: false, + objective: { + description: description, + id: 5, + version: 1, + quarterId: 2, + quarterLabel: "GJ 22/23-Q2", + state: State[state as keyof typeof State], + teamId: 2, + title: title, + writeable: true + }, + teamId: 1 + }); + })); + + it("should create objective", () => { + matDataMock.objective.objectiveId = undefined; + component.objectiveForm.setValue({ + title: "Test title", + description: "Test description", + quarter: 0, + team: 0, + relation: 0, + createKeyResults: false, + keyResults: [] }); - describe("Backlog quarter", - () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - MatIconModule, - MatFormFieldModule, - MatSelectModule, - ReactiveFormsModule, - MatInputModule, - NoopAnimationsModule, - MatCheckboxModule, - TranslateTestingModule.withTranslations({ - de: de - }), - MatDividerModule - ], - declarations: [ObjectiveFormComponent, - DialogTemplateCoreComponent], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: MatDialogRef, - useValue: dialogMock }, - { provide: MAT_DIALOG_DATA, - useValue: matDataMock }, - { provide: ObjectiveService, - useValue: objectiveService }, - { provide: QuarterService, - useValue: quarterService }, - { provide: TeamService, - useValue: teamService }, - { provide: ActivatedRoute, - useValue: mockActivatedRoute } - ] - }); - fixture = TestBed.createComponent(ObjectiveFormComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - loader = TestbedHarnessEnvironment.loader(fixture); + objectiveService.createObjective.mockReturnValue(of({ ...objective, + state: "DRAFT" })); + component.onSubmit("DRAFT"); + + fixture.detectChanges(); + + expect(objectiveService.createObjective) + .toHaveBeenCalledWith({ + description: "Test description", + id: undefined, + state: "DRAFT", + title: "Test title", + quarterId: 0, + teamId: 0 }); + }); + + it("should update objective", () => { + matDataMock.objective.objectiveId = 1; + component.objectiveForm.setValue({ + title: "Test title", + description: "Test description", + quarter: 1, + team: 1, + relation: 0, + createKeyResults: false, + keyResults: [] + }); + + objectiveService.updateObjective.mockReturnValue(of({ ...objective, + state: "ONGOING" })); + component.onSubmit("DRAFT"); + + fixture.detectChanges(); + + expect(objectiveService.updateObjective) + .toHaveBeenCalledWith({ + description: "Test description", + id: 1, + state: "DRAFT", + title: "Test title", + quarterId: 1, + teamId: 1 + }); + }); + + it("should load default values into form onInit with undefined objectiveId", () => { + matDataMock.objective.objectiveId = undefined; + matDataMock.objective.teamId = 1; + component.ngOnInit(); + const rawFormValue = component.objectiveForm.getRawValue(); + const defaultComponent = component.getDefaultObjective(); + expect(rawFormValue.title) + .toBe(defaultComponent.title); + expect(rawFormValue.description) + .toBe(defaultComponent.description); + expect(rawFormValue.team) + .toBe(matDataMock.objective.teamId); + quarterService.getAllQuarters() + .subscribe((quarters) => { + expect(rawFormValue.quarter) + .toBe([quarters[0].id]); + }); + }); + + it("should load default values into form onInit with defined objectiveId", async () => { + matDataMock.objective.objectiveId = 1; + const routerHarness = await RouterTestingHarness.create(); + await routerHarness.navigateByUrl("/?quarter=2"); + objectiveService.getFullObjective.mockReturnValue(of(objective)); + objectiveService.getAllKeyResultsByObjective.mockReturnValue(of(keyResult)); + component.ngOnInit(); + const rawFormValue = component.objectiveForm.getRawValue(); + expect(rawFormValue.title) + .toBe(objective.title); + expect(rawFormValue.description) + .toBe(objective.description); + expect(rawFormValue.team) + .toBe(objective.teamId); + expect(rawFormValue.quarter) + .toBe(objective.quarterId); + }); + + it("should set teams$ observable correctly on ngOnInit", () => { + const mockTeams = [{ id: 1, + name: "Team A" }, + { id: 2, + name: "Team B" }]; + teamService.getAllTeams.mockReturnValue(of(mockTeams)); + + component.ngOnInit(); + + component.teams$.subscribe((teams: Team[]) => { + expect(teams) + .toEqual(mockTeams); + }); + }); + + it("should set keyResults$ observable correctly when objectiveId is defined", () => { + const mockKeyResults = [{ id: 1, + name: "Key Result A" }]; + matDataMock.objective.objectiveId = 1; + objectiveService.getAllKeyResultsByObjective.mockReturnValue(of(mockKeyResults)); + + component.ngOnInit(); + + component.keyResults$.subscribe((keyResults) => { + expect(keyResults) + .toEqual(mockKeyResults); + }); + }); + + it("should return correct value if allowed to save to backlog", async () => { + component.quarters = quarterList; + const isBacklogQuarterSpy = jest.spyOn(component, "isBacklogQuarter"); + isBacklogQuarterSpy.mockReturnValue(false); + + component.data.action = "duplicate"; + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeTruthy(); + + component.objectiveForm.controls.quarter.setValue(999); + component.data.action = ""; + component.data.objective.objectiveId = 5; + component.state = "DRAFT"; + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeTruthy(); + + component.state = "ONGOING"; + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeFalsy(); + + component.objectiveForm.controls.quarter.setValue(2); + isBacklogQuarterSpy.mockReturnValue(true); + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeTruthy(); + + component.objectiveForm.controls.quarter.setValue(999); + component.data.objective.objectiveId = undefined; + isBacklogQuarterSpy.mockReturnValue(false); + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeFalsy(); + + component.objectiveForm.controls.quarter.setValue(2); + isBacklogQuarterSpy.mockReturnValue(true); + fixture.detectChanges(); + expect(component.allowedToSaveBacklog()) + .toBeTruthy(); + }); + + it("should return if option is allowed for quarter select", async () => { + const quarter: Quarter = new Quarter( + 1, "Backlog", null, null + ); + + const data = { + action: "duplicate", + objective: { + objectiveId: 22 + } + }; + component.data = data; + component.state = "DRAFT"; + fixture.detectChanges(); + + expect(component.allowedOption(quarter)) + .toBeTruthy(); + + expect(component.allowedOption(quarter)) + .toBeTruthy(); + data.action = "releaseBacklog"; + fixture.detectChanges(); + expect(component.allowedOption(quarter)) + .toBeFalsy(); + + data.action = "edit"; + fixture.detectChanges(); + + expect(component.allowedOption(quarter)) + .toBeTruthy(); + + component.state = "ONGOING"; + fixture.detectChanges(); + expect(component.allowedOption(quarter)) + .toBeFalsy(); + + component.data = { + action: "duplicate", + objective: {} + }; + + fixture.detectChanges(); + expect(component.allowedOption(quarter)) + .toBeTruthy(); + }); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should set correct default value if objective is released in backlog", - async () => { - component.data = { - objective: { - objectiveId: 1, - teamId: 1 - }, - action: "releaseBacklog" - }; - - const isBacklogQuarterSpy = jest.spyOn(component, - "isBacklogQuarter"); - isBacklogQuarterSpy.mockReturnValue(false); - - const routerHarness = await RouterTestingHarness.create(); - await routerHarness.navigateByUrl("/?quarter=999"); - objectiveService.getFullObjective.mockReturnValue(of(objective)); - fixture.detectChanges(); - component.ngOnInit(); - - const rawFormValue = component.objectiveForm.getRawValue(); - expect(rawFormValue.title) - .toBe(objective.title); - expect(rawFormValue.description) - .toBe(objective.description); - expect(rawFormValue.team) - .toBe(objective.teamId); - expect(rawFormValue.quarter).not.toBe(999); - expect(rawFormValue.quarter) - .toBe(2); - }); + describe("Backlog quarter", () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + ReactiveFormsModule, + MatInputModule, + NoopAnimationsModule, + MatCheckboxModule, + TranslateTestingModule.withTranslations({ + de: de + }), + MatDividerModule + ], + declarations: [ObjectiveFormComponent, + DialogTemplateCoreComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: MatDialogRef, + useValue: dialogMock }, + { provide: MAT_DIALOG_DATA, + useValue: matDataMock }, + { provide: ObjectiveService, + useValue: objectiveService }, + { provide: QuarterService, + useValue: quarterService }, + { provide: TeamService, + useValue: teamService }, + { provide: ActivatedRoute, + useValue: mockActivatedRoute } + ] }); + fixture = TestBed.createComponent(ObjectiveFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + loader = TestbedHarnessEnvironment.loader(fixture); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should set correct default value if objective is released in backlog", async () => { + component.data = { + objective: { + objectiveId: 1, + teamId: 1 + }, + action: "releaseBacklog" + }; + + const isBacklogQuarterSpy = jest.spyOn(component, "isBacklogQuarter"); + isBacklogQuarterSpy.mockReturnValue(false); + + const routerHarness = await RouterTestingHarness.create(); + await routerHarness.navigateByUrl("/?quarter=999"); + objectiveService.getFullObjective.mockReturnValue(of(objective)); + fixture.detectChanges(); + component.ngOnInit(); + + const rawFormValue = component.objectiveForm.getRawValue(); + expect(rawFormValue.title) + .toBe(objective.title); + expect(rawFormValue.description) + .toBe(objective.description); + expect(rawFormValue.team) + .toBe(objective.teamId); + expect(rawFormValue.quarter).not.toBe(999); + expect(rawFormValue.quarter) + .toBe(2); + }); }); +}); diff --git a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts index 66a92459a7..628d406e4d 100644 --- a/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts +++ b/frontend/src/app/shared/dialog/objective-dialog/objective-form.component.ts @@ -25,19 +25,15 @@ import { KeyResultDTO } from "../../types/DTOs/KeyResultDTO"; }) export class ObjectiveFormComponent implements OnInit, OnDestroy { objectiveForm = new FormGroup({ - title: new FormControl("", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]), - description: new FormControl("", - [Validators.maxLength(4096)]), - quarter: new FormControl(0, - [Validators.required]), + title: new FormControl("", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]), + description: new FormControl("", [Validators.maxLength(4096)]), + quarter: new FormControl(0, [Validators.required]), team: new FormControl({ value: 0, disabled: true - }, - [Validators.required]), + }, [Validators.required]), relation: new FormControl({ value: 0, disabled: true @@ -104,9 +100,7 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { const submitFunction = this.getSubmitFunction(this.data.objective.objectiveId, objectiveDTO); submitFunction.subscribe((savedObjective: Objective) => { - this.closeDialog(savedObjective, - false, - value.createKeyResults ?? undefined); + this.closeDialog(savedObjective, false, value.createKeyResults ?? undefined); }); } @@ -135,11 +129,7 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { keyResults]: [Objective, Quarter[], Quarter, KeyResultDTO[] ]) => { this.handleDataInitialization( - objective, - quarters, - currentQuarter, - keyResults, - this.data.objective.objectiveId != null + objective, quarters, currentQuarter, keyResults, this.data.objective.objectiveId != null ); }); } @@ -156,8 +146,7 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { // Determine the team ID to set in the form: existing team for editing or default team for new objectives const teamId = isEditing ? objective.teamId : this.data.objective.teamId; const newEditQuarter = isEditing ? currentQuarter.id : objective.quarterId; - let quarterId = getValueFromQuery(this.route.snapshot.queryParams["quarter"], - newEditQuarter)[0]; + let quarterId = getValueFromQuery(this.route.snapshot.queryParams["quarter"], newEditQuarter)[0]; if (currentQuarter && !this.isBacklogQuarter(currentQuarter.label) && this.data.action == "releaseBacklog") { quarterId = quarters[1].id; @@ -194,16 +183,15 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { if (this.data.action == "duplicate" && id) { objectiveDTO.id = null; objectiveDTO.state = "DRAFT" as State; - return this.objectiveService.duplicateObjective(id, - { - objective: objectiveDTO, - keyResults: this.keyResults - .filter((keyResult, index) => this.objectiveForm.value.keyResults?.[index] ?? false) - .map((result) => ({ - ...result, - id: undefined - })) - }); + return this.objectiveService.duplicateObjective(id, { + objective: objectiveDTO, + keyResults: this.keyResults + .filter((keyResult, index) => this.objectiveForm.value.keyResults?.[index] ?? false) + .map((result) => ({ + ...result, + id: undefined + })) + }); } else { if (this.data.action == "releaseBacklog") objectiveDTO.state = "ONGOING" as State; if (this.data.objective.objectiveId && id) { @@ -223,8 +211,7 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { .subscribe({ next: () => { const objectiveDTO: Objective = { id: this.data.objective.objectiveId } as unknown as Objective; - this.closeDialog(objectiveDTO, - true); + this.closeDialog(objectiveDTO, true); }, error: () => { this.dialogRef.close(); @@ -256,8 +243,7 @@ export class ObjectiveFormComponent implements OnInit, OnDestroy { error: string, field: string, firstNumber: number | null, secondNumber: number | null ): string { return field + this.translate.instant("DIALOG_ERRORS." + error) - .format(firstNumber, - secondNumber); + .format(firstNumber, secondNumber); } getDefaultObjective () { diff --git a/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.spec.ts b/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.spec.ts index 617c35de5c..a3641f2e1e 100644 --- a/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.spec.ts +++ b/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.spec.ts @@ -1,84 +1,64 @@ import { UnitTransformationPipe } from "./unit-transformation.pipe"; import { Unit } from "../../types/enums/Unit"; -describe("UnitTransformationPipe", - () => { - it("create an instance", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe) - .toBeTruthy(); - }); +describe("UnitTransformationPipe", () => { + it("create an instance", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe) + .toBeTruthy(); + }); - it("Format Percent label", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(1, - Unit.PERCENT)) - .toBe("1%"); - }); + it("Format Percent label", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(1, Unit.PERCENT)) + .toBe("1%"); + }); - it("Format FTE label", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(1, - Unit.FTE)) - .toBe("1 " + Unit.FTE); - }); + it("Format FTE label", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(1, Unit.FTE)) + .toBe("1 " + Unit.FTE); + }); - it("Format CHF label", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(1, - Unit.CHF)) - .toBe("1 " + Unit.CHF); - }); + it("Format CHF label", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(1, Unit.CHF)) + .toBe("1 " + Unit.CHF); + }); - it("Format EUR label", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(1, - Unit.EUR)) - .toBe("1 " + Unit.EUR); - }); + it("Format EUR label", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(1, Unit.EUR)) + .toBe("1 " + Unit.EUR); + }); - it("Format Number label", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(1, - Unit.NUMBER)) - .toBe("1"); - }); + it("Format Number label", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(1, Unit.NUMBER)) + .toBe("1"); + }); - it("should format as Percent", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(38, - Unit.PERCENT)) - .toBe("38%"); - }); + it("should format as Percent", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(38, Unit.PERCENT)) + .toBe("38%"); + }); - it("should format as Number", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(38000, - Unit.NUMBER)) - .toBe("38'000"); - }); + it("should format as Number", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(38000, Unit.NUMBER)) + .toBe("38'000"); + }); - it("should format as CHF as double value", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(380.987, - Unit.NUMBER)) - .toBe("380.99"); - }); + it("should format as CHF as double value", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(380.987, Unit.NUMBER)) + .toBe("380.99"); + }); - it("should return with no format if unit is not known", - () => { - const pipe = new UnitTransformationPipe(); - expect(pipe.transform(134, - "Some Unit")) - .toBe("134"); - }); + it("should return with no format if unit is not known", () => { + const pipe = new UnitTransformationPipe(); + expect(pipe.transform(134, "Some Unit")) + .toBe("134"); }); +}); diff --git a/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.ts b/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.ts index c94486123d..3d3ca8f5cf 100644 --- a/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.ts +++ b/frontend/src/app/shared/pipes/unit-transformation/unit-transformation.pipe.ts @@ -15,8 +15,7 @@ export class UnitTransformationPipe implements PipeTransform { roundAndAddThousandSplitSign (value: number): string { return (+value.toFixed(2)).toLocaleString("en-US") - .replace(/,/g, - "'"); + .replace(/,/g, "'"); } transformLabel (label: string): string { diff --git a/frontend/src/app/shared/routeUtils.spec.ts b/frontend/src/app/shared/routeUtils.spec.ts index 9681253a95..1bae11ab22 100644 --- a/frontend/src/app/shared/routeUtils.spec.ts +++ b/frontend/src/app/shared/routeUtils.spec.ts @@ -1,42 +1,32 @@ import { getRouteToTeam, getRouteToUserDetails } from "./routeUtils"; -describe("routeUtils", - () => { - describe("getRouteToUserDetails", - () => { - it("should not include team fragment when teamId is missing", - () => { - expect(getRouteToUserDetails(1)) - .toBe("/team-management/details/member/1"); - }); +describe("routeUtils", () => { + describe("getRouteToUserDetails", () => { + it("should not include team fragment when teamId is missing", () => { + expect(getRouteToUserDetails(1)) + .toBe("/team-management/details/member/1"); + }); - it("should include team fragment when teamId is missing", - () => { - expect(getRouteToUserDetails(1, - 11)) - .toBe("/team-management/11/details/member/1"); - }); + it("should include team fragment when teamId is missing", () => { + expect(getRouteToUserDetails(1, 11)) + .toBe("/team-management/11/details/member/1"); + }); - it("should work with id=0", - () => { - expect(getRouteToUserDetails(0, - 0)) - .toBe("/team-management/0/details/member/0"); - }); - }); + it("should work with id=0", () => { + expect(getRouteToUserDetails(0, 0)) + .toBe("/team-management/0/details/member/0"); + }); + }); - describe("getRouteToTeam", - () => { - it("should work with normal id", - () => { - expect(getRouteToTeam(1)) - .toBe("/team-management/1"); - }); + describe("getRouteToTeam", () => { + it("should work with normal id", () => { + expect(getRouteToTeam(1)) + .toBe("/team-management/1"); + }); - it("should work with id=0", - () => { - expect(getRouteToTeam(0)) - .toBe("/team-management/0"); - }); - }); + it("should work with id=0", () => { + expect(getRouteToTeam(0)) + .toBe("/team-management/0"); + }); }); +}); diff --git a/frontend/src/app/shared/sidepanel/sidepanel.component.ts b/frontend/src/app/shared/sidepanel/sidepanel.component.ts index 36a4e8110c..dd9bb2f2ba 100644 --- a/frontend/src/app/shared/sidepanel/sidepanel.component.ts +++ b/frontend/src/app/shared/sidepanel/sidepanel.component.ts @@ -49,8 +49,7 @@ export class SidepanelComponent implements AfterContentInit, OnDestroy { } close () { - this.router.navigate(["../"], - { relativeTo: this.route }); + this.router.navigate(["../"], { relativeTo: this.route }); } closeOnKeydown ($event: KeyboardEvent) { diff --git a/frontend/src/app/shared/testData.ts b/frontend/src/app/shared/testData.ts index df0a1f5302..b9f1bcb3d4 100644 --- a/frontend/src/app/shared/testData.ts +++ b/frontend/src/app/shared/testData.ts @@ -95,31 +95,19 @@ export const addedAction: Action = { } as Action; export const quarterMin: Quarter = new Quarter( - 1, - "GJ 23/24-Q1", - null, - null + 1, "GJ 23/24-Q1", null, null ); export const quarter1: Quarter = new Quarter( - 1, - "GJ 22/23-Q4", - new Date("2023-04-01"), - new Date("2023-07-30") + 1, "GJ 22/23-Q4", new Date("2023-04-01"), new Date("2023-07-30") ); export const quarter2: Quarter = new Quarter( - 2, - "GJ 22/23-Q3", - new Date("2023-01-01"), - new Date("2023-03-31") + 2, "GJ 22/23-Q3", new Date("2023-01-01"), new Date("2023-03-31") ); export const quarterBacklog: Quarter = new Quarter( - 999, - "GJ 23/24-Q1", - null, - null + 999, "GJ 23/24-Q1", null, null ); export const quarterList: Quarter[] = [quarter1, @@ -329,10 +317,7 @@ export const overviews: OverviewEntity[] = [overViewEntityResponse1, overViewEntityResponse2]; export const quarter: Quarter = new Quarter( - 1, - "23.02.2025", - new Date(), - new Date() + 1, "23.02.2025", new Date(), new Date() ); export const keyResultObjective: KeyResultObjective = { @@ -454,10 +439,7 @@ export const keyResult: KeyResultOrdinal = { version: 1, state: State.DRAFT, quarter: new Quarter( - 1, - "GJ 23/24-Q1", - new Date(), - new Date() + 1, "GJ 23/24-Q1", new Date(), new Date() ), writeable: true } as KeyResultObjective, @@ -493,10 +475,7 @@ export const keyResultOrdinal: KeyResultOrdinal = { version: 1, state: State.DRAFT, quarter: new Quarter( - 1, - "GJ 23/24-Q1", - new Date(), - new Date() + 1, "GJ 23/24-Q1", new Date(), new Date() ), writeable: true } as KeyResultObjective, @@ -532,10 +511,7 @@ export const keyResultWriteableFalse: KeyResultOrdinal = { version: 1, state: State.DRAFT, quarter: new Quarter( - 1, - "GJ 23/24-Q1", - new Date(), - new Date() + 1, "GJ 23/24-Q1", new Date(), new Date() ), writeable: false } as KeyResultObjective, @@ -571,10 +547,7 @@ export const keyResultMetric: KeyResultMetric = { version: 1, state: State.DRAFT, quarter: new Quarter( - 1, - "GJ 23/24-Q1", - new Date(), - new Date() + 1, "GJ 23/24-Q1", new Date(), new Date() ), writeable: true } as KeyResultObjective, @@ -610,10 +583,7 @@ export const keyResultActions: KeyResultMetric = { id: 302, state: State.DRAFT, quarter: new Quarter( - 1, - "GJ 23/24-Q1", - new Date(), - new Date() + 1, "GJ 23/24-Q1", new Date(), new Date() ), writeable: true } as KeyResultObjective, diff --git a/frontend/src/app/shared/validators.ts b/frontend/src/app/shared/validators.ts index 35e532f7a9..2a99af0777 100644 --- a/frontend/src/app/shared/validators.ts +++ b/frontend/src/app/shared/validators.ts @@ -17,20 +17,16 @@ export class UnitValueValidator implements Validator { const value: string = control.value; switch (this.unit) { case "PERCENT": { - return this.proceedRegex(value, - PERCENT_REGEX); + return this.proceedRegex(value, PERCENT_REGEX); } case "CHF": { - return this.proceedRegex(value, - NUMBER_REGEX); + return this.proceedRegex(value, NUMBER_REGEX); } case "EUR": { - return this.proceedRegex(value, - NUMBER_REGEX); + return this.proceedRegex(value, NUMBER_REGEX); } case "NUMBER": { - return this.proceedRegex(value, - NUMBER_REGEX); + return this.proceedRegex(value, NUMBER_REGEX); } default: { return null; diff --git a/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.spec.ts b/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.spec.ts index a3f3ad0e85..f64fe628db 100644 --- a/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.spec.ts +++ b/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.spec.ts @@ -34,99 +34,92 @@ const teamServiceMock = { deleteTeam: jest.fn() }; -describe("TeamManagementComponent", - () => { - let component: AddEditTeamDialogComponent; - let fixture: ComponentFixture; +describe("TeamManagementComponent", () => { + let component: AddEditTeamDialogComponent; + let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - MatIconModule, - MatFormFieldModule, - MatSelectModule, - ReactiveFormsModule, - MatInputModule, - NoopAnimationsModule, - MatCheckboxModule, - MatDividerModule - ], - declarations: [AddEditTeamDialogComponent, - DialogTemplateCoreComponent], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { - provide: DialogService, - useValue: dialogServiceMock - }, - { - provide: MatDialogRef, - useValue: dialogRefMock - }, - { - provide: TeamService, - useValue: teamServiceMock - }, - { - provide: MAT_DIALOG_DATA, - useValue: null - }, - { provide: TranslateService, - useValue: {} } - ] - }); - fixture = TestBed.createComponent(AddEditTeamDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + ReactiveFormsModule, + MatInputModule, + NoopAnimationsModule, + MatCheckboxModule, + MatDividerModule + ], + declarations: [AddEditTeamDialogComponent, + DialogTemplateCoreComponent], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { + provide: DialogService, + useValue: dialogServiceMock + }, + { + provide: MatDialogRef, + useValue: dialogRefMock + }, + { + provide: TeamService, + useValue: teamServiceMock + }, + { + provide: MAT_DIALOG_DATA, + useValue: null + }, + { provide: TranslateService, + useValue: {} } + ] }); + fixture = TestBed.createComponent(AddEditTeamDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should call service method to save team", - async () => { - component.teamForm.setValue(teamFormObject); - jest.spyOn(teamServiceMock, - "createTeam") - .mockReturnValue(of(teamFormObject)); - fixture.detectChanges(); - component.saveTeam(); - expect(teamServiceMock.createTeam) - .toHaveBeenCalled(); - expect(teamServiceMock.createTeam) - .toHaveBeenCalledWith(teamFormObject as Team); - }); + it("should call service method to save team", async () => { + component.teamForm.setValue(teamFormObject); + jest.spyOn(teamServiceMock, "createTeam") + .mockReturnValue(of(teamFormObject)); + fixture.detectChanges(); + component.saveTeam(); + expect(teamServiceMock.createTeam) + .toHaveBeenCalled(); + expect(teamServiceMock.createTeam) + .toHaveBeenCalledWith(teamFormObject as Team); + }); - it("should call service method to update team if data input is not null", - async () => { - component.data = { team: marketingTeamWriteable }; - component.teamForm.setValue(teamFormObject); - jest.spyOn(teamServiceMock, - "updateTeam") - .mockReturnValue(of(teamFormObject)); - fixture.detectChanges(); - component.saveTeam(); - expect(teamServiceMock.updateTeam) - .toHaveBeenCalled(); - expect(teamServiceMock.updateTeam) - .toHaveBeenCalledWith({ - ...teamFormObject, - id: marketingTeamWriteable.id, - version: marketingTeamWriteable.version - } as Team); - }); + it("should call service method to update team if data input is not null", async () => { + component.data = { team: marketingTeamWriteable }; + component.teamForm.setValue(teamFormObject); + jest.spyOn(teamServiceMock, "updateTeam") + .mockReturnValue(of(teamFormObject)); + fixture.detectChanges(); + component.saveTeam(); + expect(teamServiceMock.updateTeam) + .toHaveBeenCalled(); + expect(teamServiceMock.updateTeam) + .toHaveBeenCalledWith({ + ...teamFormObject, + id: marketingTeamWriteable.id, + version: marketingTeamWriteable.version + } as Team); + }); - it("should set team values in from on init if data is not null", - async () => { - component.data = { team: marketingTeamWriteable }; - component.ngOnInit(); - expect(component.teamForm.controls.name.value) - .toBe(marketingTeamWriteable.name); - }); + it("should set team values in from on init if data is not null", async () => { + component.data = { team: marketingTeamWriteable }; + component.ngOnInit(); + expect(component.teamForm.controls.name.value) + .toBe(marketingTeamWriteable.name); }); +}); diff --git a/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.ts b/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.ts index 17c6edcd00..4e50b1d32e 100644 --- a/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.ts +++ b/frontend/src/app/team-management/add-edit-team-dialog/add-edit-team-dialog.component.ts @@ -15,10 +15,9 @@ import { Router } from "@angular/router"; }) export class AddEditTeamDialogComponent implements OnInit { teamForm = new FormGroup({ - name: new FormControl("", - [Validators.required, - Validators.minLength(2), - Validators.maxLength(250)]) + name: new FormControl("", [Validators.required, + Validators.minLength(2), + Validators.maxLength(250)]) }); protected readonly formInputCheck = formInputCheck; @@ -86,8 +85,7 @@ export class AddEditTeamDialogComponent implements OnInit { error: string, field: string, firstNumber: number | null, secondNumber: number | null ): string { return field + this.translate.instant("DIALOG_ERRORS." + error) - .format(firstNumber, - secondNumber); + .format(firstNumber, secondNumber); } getDialogTitle (): string { diff --git a/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.spec.ts b/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.spec.ts index 9e7dce26b0..045cde0406 100644 --- a/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.spec.ts +++ b/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.spec.ts @@ -11,149 +11,140 @@ import { MatAutocompleteModule } from "@angular/material/autocomplete"; import { User } from "../../shared/types/model/User"; import { MatTable } from "@angular/material/table"; -describe("AddMemberToTeamDialogComponent", - () => { - let component: AddMemberToTeamDialogComponent; - let fixture: ComponentFixture; - - const userServiceMock = { - getUsers: jest.fn(), - reloadUsers: jest.fn() - }; - - const teamServiceMock = { - addUsersToTeam: jest.fn() - }; - - const matDialogRefMock = {}; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AddMemberToTeamDialogComponent], - imports: [ - SharedModule, - MatDialogModule, - MatFormFieldModule, - MatAutocompleteModule - ], - providers: [ - { provide: UserService, - useValue: userServiceMock }, - { provide: TeamService, - useValue: teamServiceMock }, - { - provide: MatDialogRef, - useValue: matDialogRefMock - }, - { - provide: MAT_DIALOG_DATA, - useValue: { team: team1, - currentUsersOfTeam: [users[0]] } - } - ] - }) - .compileComponents(); - - userServiceMock.getUsers.mockReturnValue(of(users)); - - fixture = TestBed.createComponent(AddMemberToTeamDialogComponent); - component = fixture.componentInstance; - - component.table = { - renderRows: () => undefined - } as MatTable; - - component.selectedUsers$ = new BehaviorSubject([]); +describe("AddMemberToTeamDialogComponent", () => { + let component: AddMemberToTeamDialogComponent; + let fixture: ComponentFixture; + + const userServiceMock = { + getUsers: jest.fn(), + reloadUsers: jest.fn() + }; + + const teamServiceMock = { + addUsersToTeam: jest.fn() + }; + + const matDialogRefMock = {}; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AddMemberToTeamDialogComponent], + imports: [ + SharedModule, + MatDialogModule, + MatFormFieldModule, + MatAutocompleteModule + ], + providers: [ + { provide: UserService, + useValue: userServiceMock }, + { provide: TeamService, + useValue: teamServiceMock }, + { + provide: MatDialogRef, + useValue: matDialogRefMock + }, + { + provide: MAT_DIALOG_DATA, + useValue: { team: team1, + currentUsersOfTeam: [users[0]] } + } + ] + }) + .compileComponents(); + + userServiceMock.getUsers.mockReturnValue(of(users)); + + fixture = TestBed.createComponent(AddMemberToTeamDialogComponent); + component = fixture.componentInstance; + + component.table = { + renderRows: () => undefined + } as MatTable; + + component.selectedUsers$ = new BehaviorSubject([]); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should set allPossibleUsers correctly", () => { + component.ngOnInit(); + component.usersForSelection$!.subscribe((filteredUsers) => { + expect(filteredUsers.length) + .toBe(users.length - 1); + expect(filteredUsers).not.toContain(users[0]); }); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should set filteredUsers correctly: search by PaCo", (done) => { + component.search = { + valueChanges: of("PaCo") + } as any; - it("should set allPossibleUsers correctly", - () => { - component.ngOnInit(); - component.usersForSelection$!.subscribe((filteredUsers) => { - expect(filteredUsers.length) - .toBe(users.length - 1); - expect(filteredUsers).not.toContain(users[0]); - }); - }); + component.ngOnInit(); - it("should set filteredUsers correctly: search by PaCo", - (done) => { - component.search = { - valueChanges: of("PaCo") - } as any; - - component.ngOnInit(); - - component.usersForSelection$!.subscribe((filteredUsers) => { - expect(filteredUsers.length) - .toBe(1); - expect(filteredUsers[0].email) - .toBe("peggimann@puzzle.ch"); - done(); - }); - }); + component.usersForSelection$!.subscribe((filteredUsers) => { + expect(filteredUsers.length) + .toBe(1); + expect(filteredUsers[0].email) + .toBe("peggimann@puzzle.ch"); + done(); + }); + }); - it("should set filteredUsers correctly: dont show already selected users", - (done) => { - component.search = { - valueChanges: of("puzzle.ch") - } as any; + it("should set filteredUsers correctly: dont show already selected users", (done) => { + component.search = { + valueChanges: of("puzzle.ch") + } as any; - component.selectedUsers$.next([users[1]]); + component.selectedUsers$.next([users[1]]); - component.ngOnInit(); + component.ngOnInit(); - component.usersForSelection$!.pipe(skip(1)) - .subscribe((filteredUsers) => { - expect(filteredUsers.length) - .toBe(users.length - 2); - expect(filteredUsers.map((u) => u.id)).not.toContain(users[1].id); - done(); - }); + component.usersForSelection$!.pipe(skip(1)) + .subscribe((filteredUsers) => { + expect(filteredUsers.length) + .toBe(users.length - 2); + expect(filteredUsers.map((u) => u.id)).not.toContain(users[1].id); + done(); }); + }); - it("should set teamname correctly", - () => { - expect(component.getDialogTitle()) - .toBe(`Members zu Team ${team1.name} hinzufügen`); - }); + it("should set teamname correctly", () => { + expect(component.getDialogTitle()) + .toBe(`Members zu Team ${team1.name} hinzufügen`); + }); - it("should return correct display value", - () => { - expect(component.getDisplayValue(users[0])) - .toBe(`${users[0].firstname} ${users[0].lastname} (${users[0].email})`); - }); + it("should return correct display value", () => { + expect(component.getDisplayValue(users[0])) + .toBe(`${users[0].firstname} ${users[0].lastname} (${users[0].email})`); + }); - it("should add user to selected users and restore search value", - () => { - component.search.setValue("test"); - component.selectedUsers$.next([users[1], - users[2]]); - component.selectUser(users[3]); - expect(component.search.value) - .toBe(""); - expect(component.selectedUsers$.getValue().length) - .toBe(3); - expect(component.selectedUsers$.getValue() - .map((u) => u.id)) - .toStrictEqual([users[1].id, - users[2].id, - users[3].id]); - }); + it("should add user to selected users and restore search value", () => { + component.search.setValue("test"); + component.selectedUsers$.next([users[1], + users[2]]); + component.selectUser(users[3]); + expect(component.search.value) + .toBe(""); + expect(component.selectedUsers$.getValue().length) + .toBe(3); + expect(component.selectedUsers$.getValue() + .map((u) => u.id)) + .toStrictEqual([users[1].id, + users[2].id, + users[3].id]); + }); - it("should remove user from selected users", - () => { - component.selectedUsers$.next([...users]); - component.remove(users[0]); - expect(component.selectedUsers$.getValue().length) - .toBe(users.length - 1); - expect(component.selectedUsers$.getValue() - .map((u) => u.id)).not.toContain(users[0].id); - }); + it("should remove user from selected users", () => { + component.selectedUsers$.next([...users]); + component.remove(users[0]); + expect(component.selectedUsers$.getValue().length) + .toBe(users.length - 1); + expect(component.selectedUsers$.getValue() + .map((u) => u.id)).not.toContain(users[0].id); }); +}); diff --git a/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.ts b/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.ts index 0238133aea..d2350917e4 100644 --- a/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.ts +++ b/frontend/src/app/team-management/add-member-to-team-dialog/add-member-to-team-dialog.component.ts @@ -48,17 +48,13 @@ export class AddMemberToTeamDialogComponent implements OnInit, OnDestroy { public ngOnInit (): void { this.usersForSelection$ = combineLatest([this.userService.getUsers(), this.selectedUsers$, - this.search.valueChanges.pipe(startWith(""), - // directly after selecting object, filtervalue is an object. - filter((searchValue) => typeof searchValue === "string"))]) - .pipe(takeUntil(this.unsubscribe$), - map(([allPossibleUsers, - selectedUsers, - filterValue]) => { - return this.filter(allPossibleUsers, - filterValue || "", - selectedUsers); - })); + // directly after selecting object, filter value is an object. + this.search.valueChanges.pipe(startWith(""), filter((searchValue) => typeof searchValue === "string"))]) + .pipe(takeUntil(this.unsubscribe$), map(([allPossibleUsers, + selectedUsers, + filterValue]) => { + return this.filter(allPossibleUsers, filterValue || "", selectedUsers); + })); } public ngOnDestroy () { @@ -71,8 +67,7 @@ export class AddMemberToTeamDialogComponent implements OnInit, OnDestroy { } addUsersToTeam (): void { - this.teamService.addUsersToTeam(this.data.team, - this.selectedUsers$.getValue()) + this.teamService.addUsersToTeam(this.data.team, this.selectedUsers$.getValue()) .subscribe(() => { this.userService.reloadUsers(); this.userService.reloadCurrentUser() diff --git a/frontend/src/app/team-management/add-user-team/add-user-team.component.spec.ts b/frontend/src/app/team-management/add-user-team/add-user-team.component.spec.ts index 3eacd20ef5..3514afe8bf 100644 --- a/frontend/src/app/team-management/add-user-team/add-user-team.component.spec.ts +++ b/frontend/src/app/team-management/add-user-team/add-user-team.component.spec.ts @@ -4,129 +4,120 @@ import { TeamService } from "../../services/team.service"; import { team1, team2, team3, testUser } from "../../shared/testData"; import { of } from "rxjs"; -describe("AddUserTeamComponent", - () => { - let component: AddUserTeamComponent; - let fixture: ComponentFixture; - const team1Copy = { ...team1 }; - const team2Copy = { ...team2 }; - const team3Copy = { ...team3 }; +describe("AddUserTeamComponent", () => { + let component: AddUserTeamComponent; + let fixture: ComponentFixture; + const team1Copy = { ...team1 }; + const team2Copy = { ...team2 }; + const team3Copy = { ...team3 }; - const teamServiceMock = { - getAllTeams: jest.fn() - }; + const teamServiceMock = { + getAllTeams: jest.fn() + }; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AddUserTeamComponent], - providers: [{ provide: TeamService, - useValue: teamServiceMock }] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AddUserTeamComponent], + providers: [{ provide: TeamService, + useValue: teamServiceMock }] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(AddUserTeamComponent); - component = fixture.componentInstance; + beforeEach(() => { + fixture = TestBed.createComponent(AddUserTeamComponent); + component = fixture.componentInstance; - teamServiceMock.getAllTeams.mockReturnValue(of([team1Copy, - team2Copy, - team3Copy])); - component.currentTeams$ = of(testUser.userTeamList); + teamServiceMock.getAllTeams.mockReturnValue(of([team1Copy, + team2Copy, + team3Copy])); + component.currentTeams$ = of(testUser.userTeamList); - fixture.detectChanges(); - }); + fixture.detectChanges(); + }); - it("should create the component", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create the component", () => { + expect(component) + .toBeTruthy(); + }); - it("should filter selectableAdminTeams correctly", - (done) => { - team1Copy.writeable = true; - team2Copy.writeable = true; - team3Copy.writeable = false; - component.ngOnInit(); - component.selectableAdminTeams$!.subscribe((teams) => { - expect(teams.length) - .toBe(1); - expect(teams[0].id) - .toBe(team2Copy.id); - done(); - }); - }); + it("should filter selectableAdminTeams correctly", (done) => { + team1Copy.writeable = true; + team2Copy.writeable = true; + team3Copy.writeable = false; + component.ngOnInit(); + component.selectableAdminTeams$!.subscribe((teams) => { + expect(teams.length) + .toBe(1); + expect(teams[0].id) + .toBe(team2Copy.id); + done(); + }); + }); - it("should filter allAdminTeams correctly", - (done) => { - team1Copy.writeable = true; - team2Copy.writeable = true; - team3Copy.writeable = false; - component.ngOnInit(); - component.allAdminTeams$!.subscribe((teams) => { - expect(teams.length) - .toBe(2); - expect(teams[0].id) - .toBe(team1Copy.id); - expect(teams[1].id) - .toBe(team2Copy.id); - expect(component.showAddButton(teams)) - .toBeTruthy(); - done(); - }); - }); + it("should filter allAdminTeams correctly", (done) => { + team1Copy.writeable = true; + team2Copy.writeable = true; + team3Copy.writeable = false; + component.ngOnInit(); + component.allAdminTeams$!.subscribe((teams) => { + expect(teams.length) + .toBe(2); + expect(teams[0].id) + .toBe(team1Copy.id); + expect(teams[1].id) + .toBe(team2Copy.id); + expect(component.showAddButton(teams)) + .toBeTruthy(); + done(); + }); + }); - it("createUserTeam should create the userTeam", - () => { - component.createUserTeam(team1Copy); - expect(component.userTeam) - .toStrictEqual({ - team: team1Copy, - isTeamAdmin: false - }); + it("createUserTeam should create the userTeam", () => { + component.createUserTeam(team1Copy); + expect(component.userTeam) + .toStrictEqual({ + team: team1Copy, + isTeamAdmin: false }); + }); - it("save should throw exception if userTeam is undefined", - () => { - expect(() => component.save()) - .toThrowError("UserTeam should be defined here"); - }); + it("save should throw exception if userTeam is undefined", () => { + expect(() => component.save()) + .toThrowError("UserTeam should be defined here"); + }); - it("save should emit addUserTeam event and set userTeam to undefined", - (done) => { - component.userTeam = testUser.userTeamList[0]; - component.addUserTeam.subscribe(() => { - done(); - }); - component.save(); - expect(component.userTeam) - .toBe(undefined); - }); + it("save should emit addUserTeam event and set userTeam to undefined", (done) => { + component.userTeam = testUser.userTeamList[0]; + component.addUserTeam.subscribe(() => { + done(); + }); + component.save(); + expect(component.userTeam) + .toBe(undefined); + }); - it("should test showAddButton", - () => { - component.userTeam = testUser.userTeamList[0]; - expect(component.showAddButton(null)) - .toBeFalsy(); - expect(component.showAddButton([team1Copy, - team2Copy])) - .toBeFalsy(); - component.userTeam = undefined; - expect(component.showAddButton([])) - .toBeFalsy(); - expect(component.showAddButton([team1Copy, - team2Copy])) - .toBeTruthy(); - }); + it("should test showAddButton", () => { + component.userTeam = testUser.userTeamList[0]; + expect(component.showAddButton(null)) + .toBeFalsy(); + expect(component.showAddButton([team1Copy, + team2Copy])) + .toBeFalsy(); + component.userTeam = undefined; + expect(component.showAddButton([])) + .toBeFalsy(); + expect(component.showAddButton([team1Copy, + team2Copy])) + .toBeTruthy(); + }); - it("should test addButtonDisabled", - () => { - expect(component.addButtonDisabled([team1Copy])) - .toBeFalsy(); - expect(component.addButtonDisabled([])) - .toBeTruthy(); - expect(component.addButtonDisabled(null)) - .toBeTruthy(); - }); + it("should test addButtonDisabled", () => { + expect(component.addButtonDisabled([team1Copy])) + .toBeFalsy(); + expect(component.addButtonDisabled([])) + .toBeTruthy(); + expect(component.addButtonDisabled(null)) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/team-management/add-user-team/add-user-team.component.ts b/frontend/src/app/team-management/add-user-team/add-user-team.component.ts index 9d67f29c86..95fb9d9d44 100644 --- a/frontend/src/app/team-management/add-user-team/add-user-team.component.ts +++ b/frontend/src/app/team-management/add-user-team/add-user-team.component.ts @@ -29,21 +29,19 @@ export class AddUserTeamComponent implements OnInit, OnDestroy { ngOnInit () { this.allAdminTeams$ = this.teamService.getAllTeams() - .pipe(takeUntil(this.unsubscribe$), - map((teams) => { - return teams.filter((t) => t.writeable); - })); + .pipe(takeUntil(this.unsubscribe$), map((teams) => { + return teams.filter((t) => t.writeable); + })); this.selectableAdminTeams$ = combineLatest([this.allAdminTeams$, this.currentTeams$]) - .pipe(takeUntil(this.unsubscribe$), - map(([allTeams, - userTeams]) => { - const currentTeamIds = userTeams.map((ut) => ut.team.id); - return allTeams.filter((t) => { - return !currentTeamIds.includes(t.id); - }); - })); + .pipe(takeUntil(this.unsubscribe$), map(([allTeams, + userTeams]) => { + const currentTeamIds = userTeams.map((ut) => ut.team.id); + return allTeams.filter((t) => { + return !currentTeamIds.includes(t.id); + }); + })); } ngOnDestroy () { diff --git a/frontend/src/app/team-management/delete-user/delete-user.component.spec.ts b/frontend/src/app/team-management/delete-user/delete-user.component.spec.ts index d9af77d59b..47f404f731 100644 --- a/frontend/src/app/team-management/delete-user/delete-user.component.spec.ts +++ b/frontend/src/app/team-management/delete-user/delete-user.component.spec.ts @@ -9,237 +9,226 @@ import { DialogService } from "../../services/dialog.service"; import { Location } from "@angular/common"; import { ButtonState } from "../../shared/types/enums/ButtonState"; -describe("DeleteUserComponent", - () => { - let component: DeleteUserComponent; - let fixture: ComponentFixture; - - const dialogRefMock: jest.Mocked> = { afterClosed: jest.fn() } as any; - const userServiceMock = { - deleteUser: jest.fn(), - getOrInitCurrentUser: jest.fn(), // the okrUser - reloadUsers: jest.fn(), - getUserOkrData: jest.fn(), - isUserMemberOfTeams: jest.fn() +describe("DeleteUserComponent", () => { + let component: DeleteUserComponent; + let fixture: ComponentFixture; + + const dialogRefMock: jest.Mocked> = { afterClosed: jest.fn() } as any; + const userServiceMock = { + deleteUser: jest.fn(), + getOrInitCurrentUser: jest.fn(), // the okrUser + reloadUsers: jest.fn(), + getUserOkrData: jest.fn(), + isUserMemberOfTeams: jest.fn() + }; + const dialogServiceMock = { openCustomizedConfirmDialog: jest.fn() }; + const mockLocation: jest.Mocked = { back: jest.fn() } as any; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DeleteUserComponent], + providers: [{ provide: UserService, + useValue: userServiceMock }, + { provide: DialogService, + useValue: dialogServiceMock }, + { provide: Location, + useValue: mockLocation }] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DeleteUserComponent); + component = fixture.componentInstance; + component.user = { + id: 2, + firstname: "Hans", + lastname: "Muster", + isOkrChampion: false, + userTeamList: [], + email: "hans.muster@puzzle.ch" }; - const dialogServiceMock = { openCustomizedConfirmDialog: jest.fn() }; - const mockLocation: jest.Mocked = { back: jest.fn() } as any; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [DeleteUserComponent], - providers: [{ provide: UserService, - useValue: userServiceMock }, - { provide: DialogService, - useValue: dialogServiceMock }, - { provide: Location, - useValue: mockLocation }] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DeleteUserComponent); - component = fixture.componentInstance; - component.user = { - id: 2, - firstname: "Hans", - lastname: "Muster", - isOkrChampion: false, - userTeamList: [], - email: "hans.muster@puzzle.ch" - }; - component.currentTeams$ = new Subject(); - userServiceMock.getOrInitCurrentUser.mockReturnValue(of(testUser)); - userServiceMock.getUserOkrData.mockReturnValue(of({ keyResults: [] })); - userServiceMock.isUserMemberOfTeams.mockReturnValue(of(true)); - fixture.detectChanges(); - }); - - afterEach(() => { - userServiceMock.reloadUsers.mockReset(); - mockLocation.back.mockReset(); - dialogServiceMock.openCustomizedConfirmDialog.mockReset(); - }); - - it("should create component", - () => { - expect(component) - .toBeTruthy(); - }); + component.currentTeams$ = new Subject(); + userServiceMock.getOrInitCurrentUser.mockReturnValue(of(testUser)); + userServiceMock.getUserOkrData.mockReturnValue(of({ keyResults: [] })); + userServiceMock.isUserMemberOfTeams.mockReturnValue(of(true)); + fixture.detectChanges(); + }); - it("deleteUser() should delete user and reload users", - () => { - // arrange - userServiceMock.deleteUser.mockReturnValue(of(userServiceMock.deleteUser)); - dialogRefMock.afterClosed.mockReturnValue(of("some data")); - dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); - - // act - component.deleteUser(); - - // assert - setTimeout(() => expect(userServiceMock.deleteUser) - .toHaveBeenCalledWith(component.user), - 0); - expect(userServiceMock.reloadUsers) - .toHaveBeenCalledTimes(1); - expect(mockLocation.back) - .toHaveBeenCalledTimes(1); - }); + afterEach(() => { + userServiceMock.reloadUsers.mockReset(); + mockLocation.back.mockReset(); + dialogServiceMock.openCustomizedConfirmDialog.mockReset(); + }); - it("deleteUser() should not reload users when UserService throws an error", - () => { - // arrange - function createErrorSubject () { - const myError = new Subject(); - myError.error("uups"); - return myError; - } - - userServiceMock.deleteUser.mockReturnValue(createErrorSubject()); - dialogRefMock.afterClosed.mockReturnValue(of("some data")); - dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); - - // act - component.deleteUser(); - - // assert - setTimeout(() => expect(userServiceMock.deleteUser) - .toHaveBeenCalledWith(component.user), - 0); - expect(userServiceMock.reloadUsers) - .toHaveBeenCalledTimes(0); - expect(mockLocation.back) - .toHaveBeenCalledTimes(0); - }); + it("should create component", () => { + expect(component) + .toBeTruthy(); + }); + + it("deleteUser() should delete user and reload users", () => { + // arrange + userServiceMock.deleteUser.mockReturnValue(of(userServiceMock.deleteUser)); + dialogRefMock.afterClosed.mockReturnValue(of("some data")); + dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); + + // act + component.deleteUser(); + + // assert + setTimeout(() => expect(userServiceMock.deleteUser) + .toHaveBeenCalledWith(component.user), 0); + expect(userServiceMock.reloadUsers) + .toHaveBeenCalledTimes(1); + expect(mockLocation.back) + .toHaveBeenCalledTimes(1); + }); - it("deleteUserWithChecks() should not delete user which is member of a Team", - () => { - // arrange (user is member of team Lorem) - component.userIsMemberOfTeams = true; - component.user.userTeamList = [{ - id: 100, - team: { - id: 1, - version: 2, - name: "Lorem", - writeable: true - }, - isTeamAdmin: false - }]; - - // act - component.deleteUserWithChecks(); - - // assert - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledTimes(1); - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledWith({ - title: "User kann nicht gelöscht werden", - text: "Hans Muster ist in folgenden Teams und kann daher nicht gelöscht werden: Lorem", - yesButtonState: ButtonState.Hidden, - noButtonState: ButtonState.Hidden, - closeButtonState: ButtonState.VisibleEnabled - }); + it("deleteUser() should not reload users when UserService throws an error", () => { + // arrange + function createErrorSubject () { + const myError = new Subject(); + myError.error("uups"); + return myError; + } + + userServiceMock.deleteUser.mockReturnValue(createErrorSubject()); + dialogRefMock.afterClosed.mockReturnValue(of("some data")); + dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); + + // act + component.deleteUser(); + + // assert + setTimeout(() => expect(userServiceMock.deleteUser) + .toHaveBeenCalledWith(component.user), 0); + expect(userServiceMock.reloadUsers) + .toHaveBeenCalledTimes(0); + expect(mockLocation.back) + .toHaveBeenCalledTimes(0); + }); + + it("deleteUserWithChecks() should not delete user which is member of a Team", () => { + // arrange (user is member of team Lorem) + component.userIsMemberOfTeams = true; + component.user.userTeamList = [{ + id: 100, + team: { + id: 1, + version: 2, + name: "Lorem", + writeable: true + }, + isTeamAdmin: false + }]; + + // act + component.deleteUserWithChecks(); + + // assert + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledTimes(1); + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledWith({ + title: "User kann nicht gelöscht werden", + text: "Hans Muster ist in folgenden Teams und kann daher nicht gelöscht werden: Lorem", + yesButtonState: ButtonState.Hidden, + noButtonState: ButtonState.Hidden, + closeButtonState: ButtonState.VisibleEnabled }); + }); + + it("deleteUserWithChecks() should not delete user which has KeyResults", () => { + // arrange (user has KeyResult one) + component.userIsMemberOfTeams = false; + component.userOkrData = { + keyResults: [{ + keyResultId: 1, + keyResultName: "one", + objectiveId: 2, + objectiveName: "two" + }] + }; - it("deleteUserWithChecks() should not delete user which has KeyResults", - () => { - // arrange (user has KeyResult one) - component.userIsMemberOfTeams = false; - component.userOkrData = { - keyResults: [{ - keyResultId: 1, - keyResultName: "one", - objectiveId: 2, - objectiveName: "two" - }] - }; - - // act - component.deleteUserWithChecks(); - - // assert - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledTimes(1); - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledWith({ - title: "User kann nicht gelöscht werden", - text: "Hans Muster ist Owner folgender KeyResults und kann daher nicht gelöscht werden: \n\none\n(Objective: two)", - yesButtonState: ButtonState.Hidden, - noButtonState: ButtonState.Hidden, - closeButtonState: ButtonState.VisibleEnabled - }); + // act + component.deleteUserWithChecks(); + + // assert + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledTimes(1); + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledWith({ + title: "User kann nicht gelöscht werden", + text: "Hans Muster ist Owner folgender KeyResults und kann daher nicht gelöscht werden: \n\none\n(Objective: two)", + yesButtonState: ButtonState.Hidden, + noButtonState: ButtonState.Hidden, + closeButtonState: ButtonState.VisibleEnabled }); + }); - it("deleteUserWithChecks() should delete user which is not member of a Team and has no KeyResults", - () => { - // arrange - component.userIsMemberOfTeams = false; - component.userOkrData = { keyResults: [] }; - - userServiceMock.deleteUser.mockReturnValue(of(userServiceMock.deleteUser)); - dialogRefMock.afterClosed.mockReturnValue(of("some data")); - dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); - - // act - component.deleteUserWithChecks(); - - // assert - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledTimes(1); - expect(dialogServiceMock.openCustomizedConfirmDialog) - .toHaveBeenCalledWith({ - title: "User löschen", - text: "Möchtest du den User Hans Muster wirklich löschen?", - yesButtonState: ButtonState.VisibleEnabled, - noButtonState: ButtonState.VisibleEnabled, - closeButtonState: ButtonState.Hidden - }); + it("deleteUserWithChecks() should delete user which is not member of a Team and has no KeyResults", () => { + // arrange + component.userIsMemberOfTeams = false; + component.userOkrData = { keyResults: [] }; + + userServiceMock.deleteUser.mockReturnValue(of(userServiceMock.deleteUser)); + dialogRefMock.afterClosed.mockReturnValue(of("some data")); + dialogServiceMock.openCustomizedConfirmDialog.mockReturnValue(dialogRefMock); + + // act + component.deleteUserWithChecks(); + + // assert + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledTimes(1); + expect(dialogServiceMock.openCustomizedConfirmDialog) + .toHaveBeenCalledWith({ + title: "User löschen", + text: "Möchtest du den User Hans Muster wirklich löschen?", + yesButtonState: ButtonState.VisibleEnabled, + noButtonState: ButtonState.VisibleEnabled, + closeButtonState: ButtonState.Hidden }); + }); - it("updateUserTeamsStatusWhenTeamOfUserChanges() does not update userIsMemberOfTeams property if currentTeams$ does not emit a value ", - () => { - // arrange (currentTeams$ does not emit a value) - component.currentTeams$ = of(); + it("updateUserTeamsStatusWhenTeamOfUserChanges() does not update userIsMemberOfTeams property if currentTeams$ does not emit a value ", () => { + // arrange (currentTeams$ does not emit a value) + component.currentTeams$ = of(); - // pre-condition - expect(component.userIsMemberOfTeams) - .toBe(undefined); + // pre-condition + expect(component.userIsMemberOfTeams) + .toBe(undefined); - // act - component.updateUserTeamsStatusWhenTeamOfUserChanges(); + // act + component.updateUserTeamsStatusWhenTeamOfUserChanges(); - // assert - expect(component.userIsMemberOfTeams) - .toBe(undefined); - }); + // assert + expect(component.userIsMemberOfTeams) + .toBe(undefined); + }); - it("updateUserTeamsStatusWhenTeamOfUserChanges() does update userIsMemberOfTeams property if currentTeams$ does emit a value ", - () => { - // arrange (currentTeams$ does emit a value) - component.currentTeams$ = of([{ - id: 100, - team: { - id: 1, - version: 2, - name: "Lorem", - writeable: true - }, - isTeamAdmin: false - }]); - - // pre-condition - expect(component.userIsMemberOfTeams) - .toBe(undefined); - - // act - component.updateUserTeamsStatusWhenTeamOfUserChanges(); - - // assert - expect(component.userIsMemberOfTeams) - .toBe(true); - }); + it("updateUserTeamsStatusWhenTeamOfUserChanges() does update userIsMemberOfTeams property if currentTeams$ does emit a value ", () => { + // arrange (currentTeams$ does emit a value) + component.currentTeams$ = of([{ + id: 100, + team: { + id: 1, + version: 2, + name: "Lorem", + writeable: true + }, + isTeamAdmin: false + }]); + + // pre-condition + expect(component.userIsMemberOfTeams) + .toBe(undefined); + + // act + component.updateUserTeamsStatusWhenTeamOfUserChanges(); + + // assert + expect(component.userIsMemberOfTeams) + .toBe(true); }); +}); diff --git a/frontend/src/app/team-management/delete-user/delete-user.component.ts b/frontend/src/app/team-management/delete-user/delete-user.component.ts index 3bd5668abe..6bd8a9e26c 100644 --- a/frontend/src/app/team-management/delete-user/delete-user.component.ts +++ b/frontend/src/app/team-management/delete-user/delete-user.component.ts @@ -44,16 +44,14 @@ export class DeleteUserComponent implements OnInit, OnDestroy { private loadOkrUser () { this.userService .getOrInitCurrentUser() - .pipe(takeUntil(this.unsubscribe$), - tap((user) => this.okrUser = user)) + .pipe(takeUntil(this.unsubscribe$), tap((user) => this.okrUser = user)) .subscribe(); } loadUserOkrData () { this.userService .getUserOkrData(this.user) - .pipe(takeUntil(this.unsubscribe$), - tap((okrData) => this.userOkrData = okrData)) + .pipe(takeUntil(this.unsubscribe$), tap((okrData) => this.userOkrData = okrData)) .subscribe(); } @@ -66,8 +64,7 @@ export class DeleteUserComponent implements OnInit, OnDestroy { loadUserMemberOfTeamsStatus () { this.userService .isUserMemberOfTeams(this.user) - .pipe(takeUntil(this.unsubscribe$), - tap((isMemberOfTeams) => this.userIsMemberOfTeams = isMemberOfTeams)) + .pipe(takeUntil(this.unsubscribe$), tap((isMemberOfTeams) => this.userIsMemberOfTeams = isMemberOfTeams)) .subscribe(); } @@ -80,14 +77,12 @@ export class DeleteUserComponent implements OnInit, OnDestroy { if (this.isUserMemberOfTeams()) { const dialogTitle = "User kann nicht gelöscht werden"; const dialogText = `${getFullNameFromUser(this.user)} ist in folgenden Teams und kann daher nicht gelöscht werden: ${this.dialogDetailsUserTeams()}`; - this.showUnableToDeleteUserDialog(dialogTitle, - dialogText); + this.showUnableToDeleteUserDialog(dialogTitle, dialogText); return; } else if (this.isUserOwnerOfKeyResults()) { const dialogTitle = "User kann nicht gelöscht werden"; const dialogText = `${getFullNameFromUser(this.user)} ist Owner folgender KeyResults und kann daher nicht gelöscht werden: \n\n${this.dialogDetailsUserKeyResults()}`; - this.showUnableToDeleteUserDialog(dialogTitle, - dialogText); + this.showUnableToDeleteUserDialog(dialogTitle, dialogText); return; } this.deleteUser(); @@ -145,16 +140,15 @@ export class DeleteUserComponent implements OnInit, OnDestroy { if (result) { this.userService .deleteUser(this.user) - .pipe(takeUntil(this.unsubscribe$), - tap({ - next: () => { - this.userService.reloadUsers(); - this.location.back(); - }, - error: () => { - throw Error(`unable to delete user ${getFullNameFromUser(this.user)} (with id ${this.user.id})`); - } - })) + .pipe(takeUntil(this.unsubscribe$), tap({ + next: () => { + this.userService.reloadUsers(); + this.location.back(); + }, + error: () => { + throw Error(`unable to delete user ${getFullNameFromUser(this.user)} (with id ${this.user.id})`); + } + })) .subscribe(); } }); diff --git a/frontend/src/app/team-management/edit-okr-champion/edit-okr-champion.component.ts b/frontend/src/app/team-management/edit-okr-champion/edit-okr-champion.component.ts index 9ab93c943c..c15336cbe7 100644 --- a/frontend/src/app/team-management/edit-okr-champion/edit-okr-champion.component.ts +++ b/frontend/src/app/team-management/edit-okr-champion/edit-okr-champion.component.ts @@ -22,8 +22,7 @@ export class EditOkrChampionComponent { private elementRef: ElementRef ) {} - @HostListener("document:click", - ["$event"]) + @HostListener("document:click", ["$event"]) clickOutside (event: MouseEvent) { if (this.elementRef.nativeElement.contains(event.target)) { return; @@ -39,8 +38,7 @@ export class EditOkrChampionComponent { setTimeout(() => { this.edit = edit; this.cd.markForCheck(); - }, - 0); + }, 0); } okrChampionEditable (): boolean { diff --git a/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.spec.ts b/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.spec.ts index 477d0def74..c5a8df5cd8 100644 --- a/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.spec.ts +++ b/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.spec.ts @@ -14,126 +14,120 @@ import { UniqueEmailValidator } from "../new-user/unique-mail.validator"; import { MatFormFieldModule } from "@angular/material/form-field"; import { NO_ERRORS_SCHEMA } from "@angular/core"; -describe("InviteUserDialogComponent", - () => { - let component: InviteUserDialogComponent; - let fixture: ComponentFixture; - - const user1 = { firstname: "user1", - lastname: "1user", - email: "user1@user.ch" }; - const user2 = { firstname: "user2", - lastname: "2user", - email: "user2@user.ch" }; - const user3 = { firstname: "user3", - lastname: "3user", - email: "user3@user.ch" }; - - const userServiceMock = { - createUsers: jest.fn(), - getUsers: jest.fn() - }; - - const dialogRefMock = { - close: jest.fn() - }; - - const uniqueMailValidatorMock = { - setAddedMails: jest.fn(), - validate: () => null - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - InviteUserDialogComponent, - NewUserComponent, - PuzzleIconComponent, - PuzzleIconButtonComponent - ], - imports: [ - MatDialogModule, - FormsModule, - ReactiveFormsModule, - MatFormFieldModule - ], - providers: [{ provide: UserService, - useValue: userServiceMock }, - { provide: DialogRef, - useValue: dialogRefMock }, - { provide: UniqueEmailValidator, - useValue: uniqueMailValidatorMock }], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - - fixture = TestBed.createComponent(InviteUserDialogComponent); - component = fixture.componentInstance; - - userServiceMock.createUsers.mockReset(); - dialogRefMock.close.mockReset(); - - userServiceMock.getUsers.mockReturnValue(of([])); - - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("addUser should add a user to the existing users", - () => { - component.addUser(); - expect(component.form.controls.length) - .toBe(2); - }); - - it("removeUser should remove given user from users array", - () => { - component.addUser(); - component.addUser(); - component.addUser(); - - component.form.controls[0].setValue(user1); - component.form.controls[1].setValue(user2); - component.form.controls[2].setValue(user3); - - component.removeUser(1); - - expect(component.form.controls[0].value) - .toStrictEqual(user1); - expect(component.form.controls[1].value) - .toStrictEqual(user3); - }); - - it("registerUsers should call createUsers and close dialog if form is valid", - fakeAsync(() => { - userServiceMock.createUsers.mockReturnValue(of([testUser])); - - component.form.controls[0].setValue(user1); - - component.registerUsers(); - tick(); - - expect(userServiceMock.createUsers) - .toBeCalledTimes(1); - expect(userServiceMock.createUsers) - .toBeCalledWith(component.form.value); - expect(dialogRefMock.close) - .toBeCalledTimes(1); - })); - - it("registerUsers should not call createUsers form is not valid", - fakeAsync(() => { - component.registerUsers(); - tick(); - - expect(userServiceMock.createUsers) - .toBeCalledTimes(0); - expect(dialogRefMock.close) - .toBeCalledTimes(0); - })); +describe("InviteUserDialogComponent", () => { + let component: InviteUserDialogComponent; + let fixture: ComponentFixture; + + const user1 = { firstname: "user1", + lastname: "1user", + email: "user1@user.ch" }; + const user2 = { firstname: "user2", + lastname: "2user", + email: "user2@user.ch" }; + const user3 = { firstname: "user3", + lastname: "3user", + email: "user3@user.ch" }; + + const userServiceMock = { + createUsers: jest.fn(), + getUsers: jest.fn() + }; + + const dialogRefMock = { + close: jest.fn() + }; + + const uniqueMailValidatorMock = { + setAddedMails: jest.fn(), + validate: () => null + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + InviteUserDialogComponent, + NewUserComponent, + PuzzleIconComponent, + PuzzleIconButtonComponent + ], + imports: [ + MatDialogModule, + FormsModule, + ReactiveFormsModule, + MatFormFieldModule + ], + providers: [{ provide: UserService, + useValue: userServiceMock }, + { provide: DialogRef, + useValue: dialogRefMock }, + { provide: UniqueEmailValidator, + useValue: uniqueMailValidatorMock }], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + + fixture = TestBed.createComponent(InviteUserDialogComponent); + component = fixture.componentInstance; + + userServiceMock.createUsers.mockReset(); + dialogRefMock.close.mockReset(); + + userServiceMock.getUsers.mockReturnValue(of([])); + + fixture.detectChanges(); }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("addUser should add a user to the existing users", () => { + component.addUser(); + expect(component.form.controls.length) + .toBe(2); + }); + + it("removeUser should remove given user from users array", () => { + component.addUser(); + component.addUser(); + component.addUser(); + + component.form.controls[0].setValue(user1); + component.form.controls[1].setValue(user2); + component.form.controls[2].setValue(user3); + + component.removeUser(1); + + expect(component.form.controls[0].value) + .toStrictEqual(user1); + expect(component.form.controls[1].value) + .toStrictEqual(user3); + }); + + it("registerUsers should call createUsers and close dialog if form is valid", fakeAsync(() => { + userServiceMock.createUsers.mockReturnValue(of([testUser])); + + component.form.controls[0].setValue(user1); + + component.registerUsers(); + tick(); + + expect(userServiceMock.createUsers) + .toBeCalledTimes(1); + expect(userServiceMock.createUsers) + .toBeCalledWith(component.form.value); + expect(dialogRefMock.close) + .toBeCalledTimes(1); + })); + + it("registerUsers should not call createUsers form is not valid", fakeAsync(() => { + component.registerUsers(); + tick(); + + expect(userServiceMock.createUsers) + .toBeCalledTimes(0); + expect(dialogRefMock.close) + .toBeCalledTimes(0); + })); +}); diff --git a/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.ts b/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.ts index 8d701d6118..38f64b0e3b 100644 --- a/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.ts +++ b/frontend/src/app/team-management/invite-user-dialog/invite-user-dialog.component.ts @@ -52,19 +52,16 @@ export class InviteUserDialogComponent { private createUserFormGroup () { return this.formBuilder.group({ - firstname: this.formBuilder.control("", - [Validators.required, - Validators.minLength(1)]), - lastname: this.formBuilder.control("", - [Validators.required, - Validators.minLength(1)]), - email: this.formBuilder.control("", - [ - Validators.required, - Validators.minLength(1), - Validators.email, - this.uniqueMailValidator.validate.bind(this.uniqueMailValidator) - ]) + firstname: this.formBuilder.control("", [Validators.required, + Validators.minLength(1)]), + lastname: this.formBuilder.control("", [Validators.required, + Validators.minLength(1)]), + email: this.formBuilder.control("", [ + Validators.required, + Validators.minLength(1), + Validators.email, + this.uniqueMailValidator.validate.bind(this.uniqueMailValidator) + ]) }); } diff --git a/frontend/src/app/team-management/member-detail/member-detail.component.spec.ts b/frontend/src/app/team-management/member-detail/member-detail.component.spec.ts index 7c608ed4ed..367bf41198 100644 --- a/frontend/src/app/team-management/member-detail/member-detail.component.spec.ts +++ b/frontend/src/app/team-management/member-detail/member-detail.component.spec.ts @@ -21,212 +21,194 @@ import { provideHttpClient } from "@angular/common/http"; import { provideHttpClientTesting } from "@angular/common/http/testing"; import { DialogTemplateCoreComponent } from "../../shared/custom/dialog-template-core/dialog-template-core.component"; -describe("MemberDetailComponent", - () => { - let component: MemberDetailComponent; - let fixture: ComponentFixture; - - const activatedRouteMock = { - paramMap: of({ - get: (): any => 1 - }) - }; - - const userServiceMock = { - getUserById: jest.fn(), - getCurrentUser: jest.fn(), - reloadUsers: jest.fn(), - reloadCurrentUser: jest.fn() - }; - - const teamServiceMock = { - removeUserFromTeam: jest.fn(), - updateOrAddTeamMembership: jest.fn(), - getAllTeams: () => of([]) - }; - - const dialogServiceMock = { - open: jest.fn(), - openConfirmDialog: jest.fn() - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - MemberDetailComponent, - AddUserTeamComponent, - ShowEditRoleComponent, - PuzzleIconButtonComponent, - PuzzleIconComponent, - DialogTemplateCoreComponent - ], - imports: [ - TranslateModule.forRoot(), - BrowserModule, - SharedModule, - MatTableModule, - MatIconModule, - CommonModule - ], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: ActivatedRoute, - useValue: activatedRouteMock }, - { provide: UserService, - useValue: userServiceMock }, - { provide: TeamService, - useValue: teamServiceMock }, - { provide: DialogService, - useValue: dialogServiceMock } - ], - schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); - }); +describe("MemberDetailComponent", () => { + let component: MemberDetailComponent; + let fixture: ComponentFixture; + + const activatedRouteMock = { + paramMap: of({ + get: (): any => 1 + }) + }; + + const userServiceMock = { + getUserById: jest.fn(), + getCurrentUser: jest.fn(), + reloadUsers: jest.fn(), + reloadCurrentUser: jest.fn() + }; + + const teamServiceMock = { + removeUserFromTeam: jest.fn(), + updateOrAddTeamMembership: jest.fn(), + getAllTeams: () => of([]) + }; + + const dialogServiceMock = { + open: jest.fn(), + openConfirmDialog: jest.fn() + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + MemberDetailComponent, + AddUserTeamComponent, + ShowEditRoleComponent, + PuzzleIconButtonComponent, + PuzzleIconComponent, + DialogTemplateCoreComponent + ], + imports: [ + TranslateModule.forRoot(), + BrowserModule, + SharedModule, + MatTableModule, + MatIconModule, + CommonModule + ], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: ActivatedRoute, + useValue: activatedRouteMock }, + { provide: UserService, + useValue: userServiceMock }, + { provide: TeamService, + useValue: teamServiceMock }, + { provide: DialogService, + useValue: dialogServiceMock } + ], + schemas: [NO_ERRORS_SCHEMA] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(MemberDetailComponent); + component = fixture.componentInstance; + + userServiceMock.getUserById.mockReturnValue(of(testUser)); + userServiceMock.getCurrentUser.mockReturnValue(testUser); + userServiceMock.reloadCurrentUser.mockReturnValue(of(testUser)); + + fixture.detectChanges(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(MemberDetailComponent); - component = fixture.componentInstance; + afterEach(() => { + userServiceMock.getUserById.mockReset(); + userServiceMock.reloadUsers.mockReset(); + teamServiceMock.updateOrAddTeamMembership.mockReset(); + dialogServiceMock.open.mockReset(); + teamServiceMock.removeUserFromTeam.mockReset(); + }); + + it("should create the component", () => { + expect(component) + .toBeTruthy(); + }); - userServiceMock.getUserById.mockReturnValue(of(testUser)); - userServiceMock.getCurrentUser.mockReturnValue(testUser); - userServiceMock.reloadCurrentUser.mockReturnValue(of(testUser)); + it("should set selectedUserIsLoggedInUser and currentUserTeams correctly", (done) => { + component.ngOnInit(); + component.currentUserTeams$.subscribe((userTeams) => { + expect(userTeams) + .toStrictEqual(testUser.userTeamList); + expect(component.user) + .toStrictEqual(testUser); + expect(component.selectedUserIsLoggedInUser) + .toBeTruthy(); + done(); + }); + }); - fixture.detectChanges(); + it("removeUserFromTeam should call removeUserFromTeam and loadUser", fakeAsync(() => { + const user = testUser; + const userTeam = testUser.userTeamList[0]; + teamServiceMock.removeUserFromTeam.mockReturnValue(of()); + userServiceMock.getUserById.mockReturnValue(of(user)); + dialogServiceMock.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(true) }); - afterEach(() => { - userServiceMock.getUserById.mockReset(); - userServiceMock.reloadUsers.mockReset(); - teamServiceMock.updateOrAddTeamMembership.mockReset(); - dialogServiceMock.open.mockReset(); - teamServiceMock.removeUserFromTeam.mockReset(); + component.removeUserFromTeam(userTeam, user); + tick(); + + expect(teamServiceMock.removeUserFromTeam) + .toHaveBeenCalledTimes(1); + expect(teamServiceMock.removeUserFromTeam) + .toHaveBeenCalledWith(user.id, userTeam.team); + expect(userServiceMock.getUserById) + .toHaveBeenCalledWith(user.id); + })); + + it("removeUserFromTeam should not call removeUserFromTeam if dialog canceled", fakeAsync(() => { + const user = testUser; + const userTeam = testUser.userTeamList[0]; + teamServiceMock.removeUserFromTeam.mockReturnValue(of()); + userServiceMock.getUserById.mockReturnValue(of(user)); + dialogServiceMock.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(false) }); - it("should create the component", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should set selectedUserIsLoggedInUser and currentUserTeams correctly", - (done) => { - component.ngOnInit(); - component.currentUserTeams$.subscribe((userTeams) => { - expect(userTeams) - .toStrictEqual(testUser.userTeamList); - expect(component.user) - .toStrictEqual(testUser); - expect(component.selectedUserIsLoggedInUser) - .toBeTruthy(); - done(); - }); - }); - - it("removeUserFromTeam should call removeUserFromTeam and loadUser", - fakeAsync(() => { - const user = testUser; - const userTeam = testUser.userTeamList[0]; - teamServiceMock.removeUserFromTeam.mockReturnValue(of()); - userServiceMock.getUserById.mockReturnValue(of(user)); - dialogServiceMock.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(true) - }); - - component.removeUserFromTeam(userTeam, - user); - tick(); - - expect(teamServiceMock.removeUserFromTeam) - .toHaveBeenCalledTimes(1); - expect(teamServiceMock.removeUserFromTeam) - .toHaveBeenCalledWith(user.id, - userTeam.team); - expect(userServiceMock.getUserById) - .toHaveBeenCalledWith(user.id); - })); - - it("removeUserFromTeam should not call removeUserFromTeam if dialog canceled", - fakeAsync(() => { - const user = testUser; - const userTeam = testUser.userTeamList[0]; - teamServiceMock.removeUserFromTeam.mockReturnValue(of()); - userServiceMock.getUserById.mockReturnValue(of(user)); - dialogServiceMock.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(false) - }); - - component.removeUserFromTeam(userTeam, - user); - tick(); - - expect(teamServiceMock.removeUserFromTeam) - .toHaveBeenCalledTimes(0); - })); - - it("addTeamRole should call updateOrAddTeamMembership, loadUser, reloadUsers and set userTeamEditId to null", - fakeAsync(() => { - const user = testUser; - const userTeam = testUser.userTeamList[0]; - - teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); - userServiceMock.getUserById.mockReturnValue(of(user)); - - component.addTeamMembership(userTeam, - user); - tick(); - - expect(teamServiceMock.updateOrAddTeamMembership) - .toHaveBeenCalledTimes(1); - expect(teamServiceMock.updateOrAddTeamMembership) - .toHaveBeenCalledWith(user.id, - userTeam); - expect(userServiceMock.getUserById) - .toHaveBeenCalledWith(user.id); - })); - - it("updateTeamRole should call updateOrAddTeamMembership, loadUser, reloadUsers and set userTeamEditId to null", - fakeAsync(() => { - const user = testUser; - const userTeam = testUser.userTeamList[0]; - - teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); - userServiceMock.getUserById.mockReturnValue(of(user)); - - component.updateTeamMembership(false, - userTeam, - user); - tick(); - - expect(teamServiceMock.updateOrAddTeamMembership) - .toHaveBeenCalledTimes(1); - expect(teamServiceMock.updateOrAddTeamMembership) - .toHaveBeenCalledWith(user.id, - userTeam); - expect(userServiceMock.getUserById) - .toHaveBeenCalledWith(user.id); - })); - - it("updateTeamRole should set isAdmin only after successfull request", - fakeAsync(() => { - const user = testUser; - const userTeam = { ...testUser.userTeamList[0] }; - userTeam.isTeamAdmin = false; - - teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null) - .pipe(delay(10))); - userServiceMock.getUserById.mockReturnValue(of(user)); - - component.updateTeamMembership(true, - userTeam, - user); - - expect(userTeam.isTeamAdmin) - .toBeFalsy(); - tick(11); - expect(userTeam.isTeamAdmin) - .toBeTruthy(); - })); - }); + component.removeUserFromTeam(userTeam, user); + tick(); + + expect(teamServiceMock.removeUserFromTeam) + .toHaveBeenCalledTimes(0); + })); + + it("addTeamRole should call updateOrAddTeamMembership, loadUser, reloadUsers and set userTeamEditId to null", fakeAsync(() => { + const user = testUser; + const userTeam = testUser.userTeamList[0]; + + teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); + userServiceMock.getUserById.mockReturnValue(of(user)); + + component.addTeamMembership(userTeam, user); + tick(); + + expect(teamServiceMock.updateOrAddTeamMembership) + .toHaveBeenCalledTimes(1); + expect(teamServiceMock.updateOrAddTeamMembership) + .toHaveBeenCalledWith(user.id, userTeam); + expect(userServiceMock.getUserById) + .toHaveBeenCalledWith(user.id); + })); + + it("updateTeamRole should call updateOrAddTeamMembership, loadUser, reloadUsers and set userTeamEditId to null", fakeAsync(() => { + const user = testUser; + const userTeam = testUser.userTeamList[0]; + + teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); + userServiceMock.getUserById.mockReturnValue(of(user)); + + component.updateTeamMembership(false, userTeam, user); + tick(); + + expect(teamServiceMock.updateOrAddTeamMembership) + .toHaveBeenCalledTimes(1); + expect(teamServiceMock.updateOrAddTeamMembership) + .toHaveBeenCalledWith(user.id, userTeam); + expect(userServiceMock.getUserById) + .toHaveBeenCalledWith(user.id); + })); + + it("updateTeamRole should set isAdmin only after successfull request", fakeAsync(() => { + const user = testUser; + const userTeam = { ...testUser.userTeamList[0] }; + userTeam.isTeamAdmin = false; + + teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null) + .pipe(delay(10))); + userServiceMock.getUserById.mockReturnValue(of(user)); + + component.updateTeamMembership(true, userTeam, user); + + expect(userTeam.isTeamAdmin) + .toBeFalsy(); + tick(11); + expect(userTeam.isTeamAdmin) + .toBeTruthy(); + })); +}); diff --git a/frontend/src/app/team-management/member-detail/member-detail.component.ts b/frontend/src/app/team-management/member-detail/member-detail.component.ts index a98c5e2ecf..58a8c7ec09 100644 --- a/frontend/src/app/team-management/member-detail/member-detail.component.ts +++ b/frontend/src/app/team-management/member-detail/member-detail.component.ts @@ -48,11 +48,10 @@ export class MemberDetailComponent implements OnInit, OnDestroy { ngOnInit (): void { this.route.paramMap - .pipe(takeUntil(this.unsubscribe$), - tap((params) => { - const id = this.getIdFromParams(params); - this.loadUser(id); - })) + .pipe(takeUntil(this.unsubscribe$), tap((params) => { + const id = this.getIdFromParams(params); + this.loadUser(id); + })) .subscribe(); } @@ -90,12 +89,9 @@ export class MemberDetailComponent implements OnInit, OnDestroy { team: userTeam.team.name }; this.dialogService - .openConfirmDialog("CONFIRMATION.DELETE.USER_FROM_TEAM", - i18nData) + .openConfirmDialog("CONFIRMATION.DELETE.USER_FROM_TEAM", i18nData) .afterClosed() - .pipe(filter((confirm) => confirm), - mergeMap(() => this.teamService.removeUserFromTeam(user.id, - userTeam.team))) + .pipe(filter((confirm) => confirm), mergeMap(() => this.teamService.removeUserFromTeam(user.id, userTeam.team))) .subscribe(() => { this.loadUser(user.id); this.userService.reloadUsers(); @@ -107,8 +103,7 @@ export class MemberDetailComponent implements OnInit, OnDestroy { // make a copy and set value of real object after successful request const newUserTeam = { ...userTeam }; newUserTeam.isTeamAdmin = isAdmin; - this.teamService.updateOrAddTeamMembership(user.id, - newUserTeam) + this.teamService.updateOrAddTeamMembership(user.id, newUserTeam) .subscribe(() => { userTeam.isTeamAdmin = isAdmin; this.loadUser(user.id); @@ -120,8 +115,7 @@ export class MemberDetailComponent implements OnInit, OnDestroy { addTeamMembership (userTeam: UserTeam, user: User) { this.userTeamEditId = undefined; - this.teamService.updateOrAddTeamMembership(user.id, - userTeam) + this.teamService.updateOrAddTeamMembership(user.id, userTeam) .subscribe(() => { this.loadUser(user.id); this.userService.reloadUsers(); @@ -135,13 +129,11 @@ export class MemberDetailComponent implements OnInit, OnDestroy { } navigateBack () { - this.router.navigate(["../"], - { relativeTo: this.route.parent }); + this.router.navigate(["../"], { relativeTo: this.route.parent }); } isOkrChampionChange (okrChampion: boolean, user: User) { - this.userService.setIsOkrChampion(user, - okrChampion) + this.userService.setIsOkrChampion(user, okrChampion) .subscribe(() => { this.loadUser(user.id); this.teamService.reloadTeams(); diff --git a/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.spec.ts b/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.spec.ts index 711ac0669c..e1df822c4a 100644 --- a/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.spec.ts +++ b/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.spec.ts @@ -7,48 +7,44 @@ import { team1 } from "../../../shared/testData"; import { UserTableEntry } from "../../../shared/types/model/UserTableEntry"; import { MatTableDataSource } from "@angular/material/table"; -describe("MemberListMobileComponent", - () => { - let component: MemberListMobileComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [MemberListMobileComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(MemberListMobileComponent); - component = fixture.componentInstance; - - component.dataSource = new MatTableDataSource([]); - - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should navigate to correct path if no team is selected", - () => { - component.selectedTeam$ = new BehaviorSubject(undefined); - const userTableEntry: any = { - id: 1 - }; - expect(component.getMemberDetailsLink(userTableEntry)) - .toStrictEqual("/team-management/details/member/1"); - }); - - it("should navigate to correct path team is selected", - () => { - component.selectedTeam$ = new BehaviorSubject(team1); - const userTableEntry: any = { - id: 1 - }; - expect(component.getMemberDetailsLink(userTableEntry)) - .toStrictEqual(`/team-management/${team1.id}/details/member/1`); - }); +describe("MemberListMobileComponent", () => { + let component: MemberListMobileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [MemberListMobileComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MemberListMobileComponent); + component = fixture.componentInstance; + + component.dataSource = new MatTableDataSource([]); + + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should navigate to correct path if no team is selected", () => { + component.selectedTeam$ = new BehaviorSubject(undefined); + const userTableEntry: any = { + id: 1 + }; + expect(component.getMemberDetailsLink(userTableEntry)) + .toStrictEqual("/team-management/details/member/1"); + }); + + it("should navigate to correct path team is selected", () => { + component.selectedTeam$ = new BehaviorSubject(team1); + const userTableEntry: any = { + id: 1 + }; + expect(component.getMemberDetailsLink(userTableEntry)) + .toStrictEqual(`/team-management/${team1.id}/details/member/1`); }); +}); diff --git a/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.ts b/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.ts index 56f52940fd..bd3e9d8a91 100644 --- a/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.ts +++ b/frontend/src/app/team-management/member-list/member-list-mobile/member-list-mobile.component.ts @@ -19,8 +19,7 @@ export class MemberListMobileComponent { constructor () {} getMemberDetailsLink (userTableEntry: UserTableEntry) { - return getRouteToUserDetails(userTableEntry.id, - this.selectedTeam$.value?.id); + return getRouteToUserDetails(userTableEntry.id, this.selectedTeam$.value?.id); } protected readonly getFullNameFromUser = getFullNameFromUser; diff --git a/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.spec.ts b/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.spec.ts index db426b131a..6e4c238ce1 100644 --- a/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.spec.ts +++ b/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.spec.ts @@ -10,202 +10,185 @@ import { Team } from "../../../shared/types/model/Team"; import { MatTableModule } from "@angular/material/table"; import { DialogService } from "../../../services/dialog.service"; -describe("MemberListTableComponent", - () => { - let component: MemberListTableComponent; - let fixture: ComponentFixture; - - const userServiceMock = { - getUsers: jest.fn(), - reloadUsers: jest.fn(), - reloadCurrentUser: jest.fn() - }; +describe("MemberListTableComponent", () => { + let component: MemberListTableComponent; + let fixture: ComponentFixture; + + const userServiceMock = { + getUsers: jest.fn(), + reloadUsers: jest.fn(), + reloadCurrentUser: jest.fn() + }; + + const teamServiceMock = { + getAllTeams: jest.fn(), + deleteTeam: jest.fn(), + removeUserFromTeam: jest.fn(), + updateOrAddTeamMembership: jest.fn() + }; + + const dialogService = { + open: jest.fn(), + openConfirmDialog: jest.fn() + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MatTableModule], + declarations: [MemberListTableComponent], + providers: [{ provide: UserService, + useValue: userServiceMock }, + { provide: TeamService, + useValue: teamServiceMock }, + { provide: DialogService, + useValue: dialogService }] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MemberListTableComponent); + + component = fixture.componentInstance; + + component.selectedTeam$ = new BehaviorSubject(undefined); + teamServiceMock.removeUserFromTeam.mockReset(); + userServiceMock.reloadUsers.mockReset(); + userServiceMock.reloadCurrentUser.mockReset(); + + fixture.detectChanges(); + }); - const teamServiceMock = { - getAllTeams: jest.fn(), - deleteTeam: jest.fn(), - removeUserFromTeam: jest.fn(), - updateOrAddTeamMembership: jest.fn() - }; + afterEach(() => { + teamServiceMock.removeUserFromTeam.mockReset(); + }); - const dialogService = { - open: jest.fn(), - openConfirmDialog: jest.fn() - }; + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [MatTableModule], - declarations: [MemberListTableComponent], - providers: [{ provide: UserService, - useValue: userServiceMock }, - { provide: TeamService, - useValue: teamServiceMock }, - { provide: DialogService, - useValue: dialogService }] - }) - .compileComponents(); - - fixture = TestBed.createComponent(MemberListTableComponent); - - component = fixture.componentInstance; - - component.selectedTeam$ = new BehaviorSubject(undefined); - teamServiceMock.removeUserFromTeam.mockReset(); - userServiceMock.reloadUsers.mockReset(); - userServiceMock.reloadCurrentUser.mockReset(); - - fixture.detectChanges(); + it("should set displayedColumns for all teams correctly", fakeAsync(() => { + component.selectedTeam$.next(undefined); + tick(); + expect(component.displayedColumns) + .toStrictEqual([ + "icon", + "name", + "roles", + "teams", + "okr_champion" + ]); + })); + + it("should set displayedColumns for admin team correctly", fakeAsync(() => { + component.selectedTeam$.next(team1); + tick(); + expect(component.displayedColumns) + .toStrictEqual(["icon", + "name", + "role"]); + })); + + it("should set displayedColumns for admin team correctly", fakeAsync(() => { + const team = { ...team1 }; + team.writeable = true; + component.selectedTeam$.next(team); + tick(); + expect(component.displayedColumns) + .toStrictEqual([ + "icon", + "name", + "role", + "menu" + ]); + })); + + it("should return correct memberDetailsLink", () => { + expect(component.getMemberDetailsLink(testUser)) + .toStrictEqual("/team-management/details/member/" + testUser.id); + }); + + it("removeMemberFromTeam should call removeUserFromTeam and reloadUsers if confirmed", fakeAsync(() => { + const entry = { + id: 1 + }; + component.selectedTeam$.next(team1); + teamServiceMock.removeUserFromTeam.mockReturnValue(of(null)); + userServiceMock.reloadUsers.mockReturnValue(of()); + userServiceMock.reloadCurrentUser.mockReturnValue(of()); + dialogService.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(true) }); - afterEach(() => { - teamServiceMock.removeUserFromTeam.mockReset(); + component.removeMemberFromTeam(entry as UserTableEntry, new MouseEvent("click")); + tick(); + + expect(teamServiceMock.removeUserFromTeam) + .toBeCalledTimes(1); + expect(teamServiceMock.removeUserFromTeam) + .toBeCalledWith(entry.id, component.selectedTeam$.value); + expect(userServiceMock.reloadUsers) + .toBeCalledTimes(1); + expect(userServiceMock.reloadCurrentUser) + .toBeCalledTimes(1); + })); + + it("removeMemberFromTeam should not call removeUserFromTeam and reloadUsers if not confirmed", fakeAsync(() => { + const entry = { + id: 1 + }; + component.selectedTeam$.next(team1); + teamServiceMock.removeUserFromTeam.mockReturnValue(of(null)); + userServiceMock.reloadUsers.mockReturnValue(of()); + userServiceMock.reloadCurrentUser.mockReturnValue(of()); + dialogService.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(false) }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should set displayedColumns for all teams correctly", - fakeAsync(() => { - component.selectedTeam$.next(undefined); - tick(); - expect(component.displayedColumns) - .toStrictEqual([ - "icon", - "name", - "roles", - "teams", - "okr_champion" - ]); - })); - - it("should set displayedColumns for admin team correctly", - fakeAsync(() => { - component.selectedTeam$.next(team1); - tick(); - expect(component.displayedColumns) - .toStrictEqual(["icon", - "name", - "role"]); - })); - - it("should set displayedColumns for admin team correctly", - fakeAsync(() => { - const team = { ...team1 }; - team.writeable = true; - component.selectedTeam$.next(team); - tick(); - expect(component.displayedColumns) - .toStrictEqual([ - "icon", - "name", - "role", - "menu" - ]); - })); - - it("should return correct memberDetailsLink", - () => { - expect(component.getMemberDetailsLink(testUser)) - .toStrictEqual("/team-management/details/member/" + testUser.id); - }); - - it("removeMemberFromTeam should call removeUserFromTeam and reloadUsers if confirmed", - fakeAsync(() => { - const entry = { - id: 1 - }; - component.selectedTeam$.next(team1); - teamServiceMock.removeUserFromTeam.mockReturnValue(of(null)); - userServiceMock.reloadUsers.mockReturnValue(of()); - userServiceMock.reloadCurrentUser.mockReturnValue(of()); - dialogService.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(true) - }); - - component.removeMemberFromTeam(entry as UserTableEntry, - new MouseEvent("click")); - tick(); - - expect(teamServiceMock.removeUserFromTeam) - .toBeCalledTimes(1); - expect(teamServiceMock.removeUserFromTeam) - .toBeCalledWith(entry.id, - component.selectedTeam$.value); - expect(userServiceMock.reloadUsers) - .toBeCalledTimes(1); - expect(userServiceMock.reloadCurrentUser) - .toBeCalledTimes(1); - })); - - it("removeMemberFromTeam should not call removeUserFromTeam and reloadUsers if not confirmed", - fakeAsync(() => { - const entry = { - id: 1 - }; - component.selectedTeam$.next(team1); - teamServiceMock.removeUserFromTeam.mockReturnValue(of(null)); - userServiceMock.reloadUsers.mockReturnValue(of()); - userServiceMock.reloadCurrentUser.mockReturnValue(of()); - dialogService.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(false) - }); - - component.removeMemberFromTeam(entry as UserTableEntry, - new MouseEvent("click")); - tick(); - - expect(teamServiceMock.removeUserFromTeam) - .toBeCalledTimes(0); - expect(userServiceMock.reloadUsers) - .toBeCalledTimes(0); - expect(userServiceMock.reloadCurrentUser) - .toBeCalledTimes(0); - })); - - it("saveUserTeamRole should call updateOrAddTeamMembership and reload users", - fakeAsync(() => { - teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); - userServiceMock.reloadCurrentUser.mockReturnValue(of()); - const entry = { - id: 1 - } as any; - const ut = testUser.userTeamList[0]; - component.saveUserTeamMembership(true, - entry, - ut); - tick(); - expect(teamServiceMock.updateOrAddTeamMembership) - .toHaveBeenCalledWith(entry.id, - ut); - expect(userServiceMock.reloadUsers) - .toHaveBeenCalledTimes(1); - expect(userServiceMock.reloadCurrentUser) - .toHaveBeenCalledTimes(1); - })); - - it("getSingleUserTeam should return first userTeam uf userTableEntry", - () => { - const ut = { - userTeamList: [testUser.userTeamList[0]] - } as any; - expect(component.getSingleUserTeam(ut)) - .toStrictEqual(testUser.userTeamList[0]); - }); - - it("getSingleUserTeam should throw error if userTeamList.length is not 1", - () => { - const ut = { - userTeamList: [testUser.userTeamList[0], - testUser.userTeamList[0]] - } as any; - expect(() => component.getSingleUserTeam(ut)) - .toThrowError("it should have exactly one UserTeam at this point"); - ut.userTeamList = []; - expect(() => component.getSingleUserTeam(ut)) - .toThrowError("it should have exactly one UserTeam at this point"); - }); + component.removeMemberFromTeam(entry as UserTableEntry, new MouseEvent("click")); + tick(); + + expect(teamServiceMock.removeUserFromTeam) + .toBeCalledTimes(0); + expect(userServiceMock.reloadUsers) + .toBeCalledTimes(0); + expect(userServiceMock.reloadCurrentUser) + .toBeCalledTimes(0); + })); + + it("saveUserTeamRole should call updateOrAddTeamMembership and reload users", fakeAsync(() => { + teamServiceMock.updateOrAddTeamMembership.mockReturnValue(of(null)); + userServiceMock.reloadCurrentUser.mockReturnValue(of()); + const entry = { + id: 1 + } as any; + const ut = testUser.userTeamList[0]; + component.saveUserTeamMembership(true, entry, ut); + tick(); + expect(teamServiceMock.updateOrAddTeamMembership) + .toHaveBeenCalledWith(entry.id, ut); + expect(userServiceMock.reloadUsers) + .toHaveBeenCalledTimes(1); + expect(userServiceMock.reloadCurrentUser) + .toHaveBeenCalledTimes(1); + })); + + it("getSingleUserTeam should return first userTeam uf userTableEntry", () => { + const ut = { + userTeamList: [testUser.userTeamList[0]] + } as any; + expect(component.getSingleUserTeam(ut)) + .toStrictEqual(testUser.userTeamList[0]); + }); + + it("getSingleUserTeam should throw error if userTeamList.length is not 1", () => { + const ut = { + userTeamList: [testUser.userTeamList[0], + testUser.userTeamList[0]] + } as any; + expect(() => component.getSingleUserTeam(ut)) + .toThrowError("it should have exactly one UserTeam at this point"); + ut.userTeamList = []; + expect(() => component.getSingleUserTeam(ut)) + .toThrowError("it should have exactly one UserTeam at this point"); }); +}); diff --git a/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.ts b/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.ts index fb4efac147..e471eac7b4 100644 --- a/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.ts +++ b/frontend/src/app/team-management/member-list/member-list-table/member-list-table.component.ts @@ -72,12 +72,9 @@ export class MemberListTableComponent implements OnInit, OnDestroy { team: this.selectedTeam$.value?.name }; this.dialogService - .openConfirmDialog("CONFIRMATION.DELETE.USER_FROM_TEAM", - i18nData) + .openConfirmDialog("CONFIRMATION.DELETE.USER_FROM_TEAM", i18nData) .afterClosed() - .pipe(filter((confirm) => confirm), - mergeMap(() => this.teamService.removeUserFromTeam(entry.id, - this.selectedTeam$.value as Team))) + .pipe(filter((confirm) => confirm), mergeMap(() => this.teamService.removeUserFromTeam(entry.id, this.selectedTeam$.value as Team))) .subscribe(() => { this.userService.reloadUsers(); this.userService.reloadCurrentUser() @@ -89,8 +86,7 @@ export class MemberListTableComponent implements OnInit, OnDestroy { // make a copy and set value only after successful request const newUserTeam = { ...userTeam }; newUserTeam.isTeamAdmin = isAdmin; - this.teamService.updateOrAddTeamMembership(userTableEntry.id, - newUserTeam) + this.teamService.updateOrAddTeamMembership(userTableEntry.id, newUserTeam) .subscribe(() => { userTeam.isTeamAdmin = isAdmin; this.userService.reloadUsers(); @@ -100,8 +96,7 @@ export class MemberListTableComponent implements OnInit, OnDestroy { } getMemberDetailsLink (user: User, team?: Team) { - return getRouteToUserDetails(user.id, - team?.id); + return getRouteToUserDetails(user.id, team?.id); } /* diff --git a/frontend/src/app/team-management/member-list/member-list.component.spec.ts b/frontend/src/app/team-management/member-list/member-list.component.spec.ts index 77f2cb3fd4..93b942fd07 100644 --- a/frontend/src/app/team-management/member-list/member-list.component.spec.ts +++ b/frontend/src/app/team-management/member-list/member-list.component.spec.ts @@ -46,279 +46,263 @@ const dialogService = { openConfirmDialog: jest.fn() }; -describe("MemberListComponent", - () => { - let component: MemberListComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [MemberListComponent, - MemberListTableComponent, - MemberListMobileComponent], - imports: [TranslateTestingModule, - BrowserAnimationsModule], - providers: [ - provideRouter([]), - provideHttpClient(), - provideHttpClientTesting(), - { provide: UserService, - useValue: userServiceMock }, - { provide: ActivatedRoute, - useValue: activatedRouteMock }, - { provide: TeamService, - useValue: teamServiceMock }, - { provide: Router, - useValue: routerMock }, - { provide: DialogService, - useValue: dialogService }, - ChangeDetectorRef - ] - }); - - fixture = TestBed.createComponent(MemberListComponent); - component = fixture.componentInstance; - - activatedRouteMock.paramMap = of({ - get: () => team1.id - }); - - userServiceMock.reloadCurrentUser.mockReset(); - userServiceMock.reloadUsers.mockReset(); - - jest.spyOn(userServiceMock, - "getUsers") - .mockReturnValue(of([])); - userServiceMock.reloadCurrentUser.mockReturnValue(of(testUser)); - userServiceMock.getCurrentUser.mockReturnValue(of(testUser)); +describe("MemberListComponent", () => { + let component: MemberListComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [MemberListComponent, + MemberListTableComponent, + MemberListMobileComponent], + imports: [TranslateTestingModule, + BrowserAnimationsModule], + providers: [ + provideRouter([]), + provideHttpClient(), + provideHttpClientTesting(), + { provide: UserService, + useValue: userServiceMock }, + { provide: ActivatedRoute, + useValue: activatedRouteMock }, + { provide: TeamService, + useValue: teamServiceMock }, + { provide: Router, + useValue: routerMock }, + { provide: DialogService, + useValue: dialogService }, + ChangeDetectorRef + ] }); - afterEach(() => { - teamServiceMock.deleteTeam.mockReset(); + fixture = TestBed.createComponent(MemberListComponent); + component = fixture.componentInstance; + + activatedRouteMock.paramMap = of({ + get: () => team1.id }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should test method convertFromUser", - () => { - const user: User = { ...testUser }; - let userTableEntry = convertFromUser(user); - - expect(userTableEntry.id) - .toBe(user.id); - expect(userTableEntry.firstname) - .toBe(user.firstname); - expect(userTableEntry.lastname) - .toBe(user.lastname); - expect(userTableEntry.email) - .toBe(user.email); - expect(userTableEntry.roles) - .toStrictEqual([UserRole.TEAM_MEMBER]); - expect(userTableEntry.isOkrChampion) - .toBeFalsy(); - expect(userTableEntry.teams) - .toStrictEqual([team1.name]); - expect(userTableEntry.userTeamList) - .toStrictEqual(user.userTeamList); - - user.userTeamList.push({ - id: 2, - team: team2, - isTeamAdmin: true - }); - user.isOkrChampion = true; - - userTableEntry = convertFromUser(user); - - expect(userTableEntry.roles) - .toStrictEqual([UserRole.TEAM_ADMIN, - UserRole.TEAM_MEMBER]); - expect(userTableEntry.isOkrChampion) - .toBeTruthy(); - expect(userTableEntry.teams) - .toStrictEqual([team1.name, - team2.name]); - expect(userTableEntry.userTeamList) - .toStrictEqual(user.userTeamList); - }); - - it("should test method convertFromUsers", - () => { - const usersCopy: User[] = JSON.parse(JSON.stringify(users)); - usersCopy[0].userTeamList.push({ - id: 1, - team: team1, - isTeamAdmin: true - }); - usersCopy[0].isOkrChampion = true; - usersCopy[1].userTeamList.push({ - id: 2, - team: team1, - isTeamAdmin: false - }); - usersCopy[2].userTeamList.push({ - id: 3, - team: team2, - isTeamAdmin: false - }); - usersCopy[3].userTeamList.push({ - id: 4, - team: team1, - isTeamAdmin: false - }, - { - id: 5, - team: team2, - isTeamAdmin: true - }); - - const userTableEntries = convertFromUsers(usersCopy, - null); - expect(userTableEntries.length) - .toBe(4); - // test that it makes a deep copy - expect(userTableEntries).not.toBe(usersCopy); - // should be sorted - expect(userTableEntries.map((ut) => ut.firstname)) - .toStrictEqual([ - "Bob", - "Key Result", - "Paco", - "Robin" - ]); - }); - - it("ngAfterViewInit should load all Users, set teamId, selectedTeam and update data source correctly", - fakeAsync(() => { - userServiceMock.getUsers.mockReturnValue(of(users)); - teamServiceMock.getAllTeams.mockReturnValue(of([team1, - team2, - team3])); - component.ngAfterViewInit(); - tick(); - expect(teamServiceMock.getAllTeams) - .toHaveBeenCalledTimes(1); - expect(component.selectedTeam$.value) - .toBe(team1); - expect(component.dataSource.data.length) - .toBe(1); - expect(component.dataSource.data[0].teams[0]) - .toBe(team1.name); - })); + userServiceMock.reloadCurrentUser.mockReset(); + userServiceMock.reloadUsers.mockReset(); - it("ngAfterViewInit should load all Users, set teamId, selectedTeam and update data source correctly if teamIdParam is null", - fakeAsync(() => { - activatedRouteMock.paramMap = of({ - get: () => null - }); - TestBed.runInInjectionContext(() => { - userServiceMock.getUsers.mockReturnValue(of(users)); - teamServiceMock.getAllTeams.mockReturnValue(of([team1, - team2, - team3])); - component.ngAfterViewInit(); - tick(); - expect(component.selectedTeam$.value) - .toBe(undefined); - expect(component.dataSource.data.length) - .toBe(users.length); - }); - })); + jest.spyOn(userServiceMock, "getUsers") + .mockReturnValue(of([])); + userServiceMock.reloadCurrentUser.mockReturnValue(of(testUser)); + userServiceMock.getCurrentUser.mockReturnValue(of(testUser)); + }); - it("deleteTeam should trigger teamService.deleteTeam and navigate", - fakeAsync(() => { - routerMock.navigateByUrl.mockReturnValue(of(null)); - teamServiceMock.deleteTeam.mockReturnValue(of(null)); - dialogService.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(true) - }); - - const team = team1; - - component.deleteTeam(team); - tick(); - - expect(teamServiceMock.deleteTeam) - .toBeCalledTimes(1); - expect(teamServiceMock.deleteTeam) - .toBeCalledWith(team.id); - expect(routerMock.navigateByUrl) - .toBeCalledWith("team-management"); - expect(routerMock.navigateByUrl) - .toBeCalledTimes(1); - expect(userServiceMock.reloadUsers) - .toBeCalledTimes(1); - expect(userServiceMock.reloadCurrentUser) - .toBeCalledTimes(1); - })); + afterEach(() => { + teamServiceMock.deleteTeam.mockReset(); + }); - it("deleteTeam should not trigger teamService.deleteTeam if dialog is canceled", - fakeAsync(() => { - routerMock.navigateByUrl.mockReturnValue(of(null)); - teamServiceMock.deleteTeam.mockReturnValue(of(null)); - dialogService.openConfirmDialog.mockReturnValue({ - afterClosed: () => of(false) - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - component.deleteTeam(team1); - tick(); + it("should test method convertFromUser", () => { + const user: User = { ...testUser }; + let userTableEntry = convertFromUser(user); + + expect(userTableEntry.id) + .toBe(user.id); + expect(userTableEntry.firstname) + .toBe(user.firstname); + expect(userTableEntry.lastname) + .toBe(user.lastname); + expect(userTableEntry.email) + .toBe(user.email); + expect(userTableEntry.roles) + .toStrictEqual([UserRole.TEAM_MEMBER]); + expect(userTableEntry.isOkrChampion) + .toBeFalsy(); + expect(userTableEntry.teams) + .toStrictEqual([team1.name]); + expect(userTableEntry.userTeamList) + .toStrictEqual(user.userTeamList); + + user.userTeamList.push({ + id: 2, + team: team2, + isTeamAdmin: true + }); + user.isOkrChampion = true; + + userTableEntry = convertFromUser(user); + + expect(userTableEntry.roles) + .toStrictEqual([UserRole.TEAM_ADMIN, + UserRole.TEAM_MEMBER]); + expect(userTableEntry.isOkrChampion) + .toBeTruthy(); + expect(userTableEntry.teams) + .toStrictEqual([team1.name, + team2.name]); + expect(userTableEntry.userTeamList) + .toStrictEqual(user.userTeamList); + }); + + it("should test method convertFromUsers", () => { + const usersCopy: User[] = JSON.parse(JSON.stringify(users)); + usersCopy[0].userTeamList.push({ + id: 1, + team: team1, + isTeamAdmin: true + }); + usersCopy[0].isOkrChampion = true; + usersCopy[1].userTeamList.push({ + id: 2, + team: team1, + isTeamAdmin: false + }); + usersCopy[2].userTeamList.push({ + id: 3, + team: team2, + isTeamAdmin: false + }); + usersCopy[3].userTeamList.push({ + id: 4, + team: team1, + isTeamAdmin: false + }, { + id: 5, + team: team2, + isTeamAdmin: true + }); + + const userTableEntries = convertFromUsers(usersCopy, null); + expect(userTableEntries.length) + .toBe(4); + // test that it makes a deep copy + expect(userTableEntries).not.toBe(usersCopy); + // should be sorted + expect(userTableEntries.map((ut) => ut.firstname)) + .toStrictEqual([ + "Bob", + "Key Result", + "Paco", + "Robin" + ]); + }); - expect(teamServiceMock.deleteTeam) - .toBeCalledTimes(0); + it("ngAfterViewInit should load all Users, set teamId, selectedTeam and update data source correctly", fakeAsync(() => { + userServiceMock.getUsers.mockReturnValue(of(users)); + teamServiceMock.getAllTeams.mockReturnValue(of([team1, + team2, + team3])); + component.ngAfterViewInit(); + tick(); + expect(teamServiceMock.getAllTeams) + .toHaveBeenCalledTimes(1); + expect(component.selectedTeam$.value) + .toBe(team1); + expect(component.dataSource.data.length) + .toBe(1); + expect(component.dataSource.data[0].teams[0]) + .toBe(team1.name); + })); + + it("ngAfterViewInit should load all Users, set teamId, selectedTeam and update data source correctly if teamIdParam is null", fakeAsync(() => { + activatedRouteMock.paramMap = of({ + get: () => null + }); + TestBed.runInInjectionContext(() => { + userServiceMock.getUsers.mockReturnValue(of(users)); + teamServiceMock.getAllTeams.mockReturnValue(of([team1, + team2, + team3])); + component.ngAfterViewInit(); + tick(); + expect(component.selectedTeam$.value) + .toBe(undefined); + expect(component.dataSource.data.length) + .toBe(users.length); + }); + })); + + it("deleteTeam should trigger teamService.deleteTeam and navigate", fakeAsync(() => { + routerMock.navigateByUrl.mockReturnValue(of(null)); + teamServiceMock.deleteTeam.mockReturnValue(of(null)); + dialogService.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(true) + }); + + const team = team1; + + component.deleteTeam(team); + tick(); + + expect(teamServiceMock.deleteTeam) + .toBeCalledTimes(1); + expect(teamServiceMock.deleteTeam) + .toBeCalledWith(team.id); + expect(routerMock.navigateByUrl) + .toBeCalledWith("team-management"); + expect(routerMock.navigateByUrl) + .toBeCalledTimes(1); + expect(userServiceMock.reloadUsers) + .toBeCalledTimes(1); + expect(userServiceMock.reloadCurrentUser) + .toBeCalledTimes(1); + })); + + it("deleteTeam should not trigger teamService.deleteTeam if dialog is canceled", fakeAsync(() => { + routerMock.navigateByUrl.mockReturnValue(of(null)); + teamServiceMock.deleteTeam.mockReturnValue(of(null)); + dialogService.openConfirmDialog.mockReturnValue({ + afterClosed: () => of(false) + }); + + component.deleteTeam(team1); + tick(); + + expect(teamServiceMock.deleteTeam) + .toBeCalledTimes(0); + })); + + it("addMemberToTeam should open dialog", () => { + component.selectedTeam$.next(team1); + component.dataSource = new MatTableDataSource([]); + dialogService.open.mockReturnValue({ + afterClosed: () => of(null) + }); + component.addMemberToTeam(); + + expect(dialogService.open) + .toBeCalledWith(AddMemberToTeamDialogComponent, expect.objectContaining({ + data: { + team: team1, + currentUsersOfTeam: component.dataSource.filteredData + } })); + }); - it("addMemberToTeam should open dialog", - () => { - component.selectedTeam$.next(team1); - component.dataSource = new MatTableDataSource([]); - dialogService.open.mockReturnValue({ - afterClosed: () => of(null) - }); - component.addMemberToTeam(); - - expect(dialogService.open) - .toBeCalledWith(AddMemberToTeamDialogComponent, - expect.objectContaining({ - data: { - team: team1, - currentUsersOfTeam: component.dataSource.filteredData - } - })); - }); - - it("should showAddMemberToTeam if selectedTeam is set and selectedTeam is writable", - () => { - component.selectedTeam$.next(undefined); - expect(component.showAddMemberToTeam()) - .toBeFalsy(); - const teamCopy = { ...team1 }; - teamCopy.writeable = false; - component.selectedTeam$.next(teamCopy); - expect(component.showAddMemberToTeam()) - .toBeFalsy(); - teamCopy.writeable = true; - expect(component.showAddMemberToTeam()) - .toBeTruthy(); - }); - - it("edit team should open dialog", - () => { - component.selectedTeam$.next(team1); - dialogService.open.mockReturnValue({ - afterClosed: () => of(null) - }); - component.editTeam(); - - expect(dialogService.open) - .toBeCalledWith(AddEditTeamDialogComponent, - expect.objectContaining({ - data: { - team: team1 - } - })); - }); + it("should showAddMemberToTeam if selectedTeam is set and selectedTeam is writable", () => { + component.selectedTeam$.next(undefined); + expect(component.showAddMemberToTeam()) + .toBeFalsy(); + const teamCopy = { ...team1 }; + teamCopy.writeable = false; + component.selectedTeam$.next(teamCopy); + expect(component.showAddMemberToTeam()) + .toBeFalsy(); + teamCopy.writeable = true; + expect(component.showAddMemberToTeam()) + .toBeTruthy(); + }); + + it("edit team should open dialog", () => { + component.selectedTeam$.next(team1); + dialogService.open.mockReturnValue({ + afterClosed: () => of(null) + }); + component.editTeam(); + + expect(dialogService.open) + .toBeCalledWith(AddEditTeamDialogComponent, expect.objectContaining({ + data: { + team: team1 + } + })); }); +}); diff --git a/frontend/src/app/team-management/member-list/member-list.component.ts b/frontend/src/app/team-management/member-list/member-list.component.ts index 214c947573..38a0cb747e 100644 --- a/frontend/src/app/team-management/member-list/member-list.component.ts +++ b/frontend/src/app/team-management/member-list/member-list.component.ts @@ -48,10 +48,8 @@ export class MemberListComponent implements OnDestroy, AfterViewInit { .subscribe(([users, teamIdParam, teams]) => { - this.setSelectedTeam(teams, - teamIdParam); - this.setDataSourceForTeamOrAll(users, - teamIdParam); + this.setSelectedTeam(teams, teamIdParam); + this.setDataSourceForTeamOrAll(users, teamIdParam); }); } @@ -76,20 +74,17 @@ export class MemberListComponent implements OnDestroy, AfterViewInit { this.cd.markForCheck(); return; } - this.setDataSourceForTeam(teamIdParam, - users); + this.setDataSourceForTeam(teamIdParam, users); this.cd.markForCheck(); } private setDataSourceForAllTeams (users: User[]) { - this.dataSource.data = convertFromUsers(users, - null); + this.dataSource.data = convertFromUsers(users, null); } private setDataSourceForTeam (teamIdParam: string, users: User[]) { const teamId = parseInt(teamIdParam); - this.dataSource.data = convertFromUsers(users, - teamId); + this.dataSource.data = convertFromUsers(users, teamId); } deleteTeam (selectedTeam: Team) { @@ -98,11 +93,9 @@ export class MemberListComponent implements OnDestroy, AfterViewInit { }; this.dialogService - .openConfirmDialog("CONFIRMATION.DELETE.TEAM", - data) + .openConfirmDialog("CONFIRMATION.DELETE.TEAM", data) .afterClosed() - .pipe(filter((confirm) => confirm), - mergeMap(() => this.teamService.deleteTeam(selectedTeam.id))) + .pipe(filter((confirm) => confirm), mergeMap(() => this.teamService.deleteTeam(selectedTeam.id))) .subscribe(() => { this.userService.reloadUsers(); this.userService.reloadCurrentUser() @@ -112,13 +105,12 @@ export class MemberListComponent implements OnDestroy, AfterViewInit { } addMemberToTeam () { - const dialogRef = this.dialogService.open(AddMemberToTeamDialogComponent, - { - data: { - team: this.selectedTeam$.value, - currentUsersOfTeam: this.dataSource.data - } - }); + const dialogRef = this.dialogService.open(AddMemberToTeamDialogComponent, { + data: { + team: this.selectedTeam$.value, + currentUsersOfTeam: this.dataSource.data + } + }); dialogRef.afterClosed() .subscribe(() => this.cd.markForCheck()); } @@ -138,8 +130,7 @@ export class MemberListComponent implements OnDestroy, AfterViewInit { } editTeam (): void { - const dialogRef = this.dialogService.open(AddEditTeamDialogComponent, - { data: { team: this.selectedTeam$.value } }); + const dialogRef = this.dialogService.open(AddEditTeamDialogComponent, { data: { team: this.selectedTeam$.value } }); dialogRef.afterClosed() .subscribe(() => this.cd.markForCheck()); } diff --git a/frontend/src/app/team-management/new-user/new-user.component.spec.ts b/frontend/src/app/team-management/new-user/new-user.component.spec.ts index 1b034dcbc6..b22e99e03b 100644 --- a/frontend/src/app/team-management/new-user/new-user.component.spec.ts +++ b/frontend/src/app/team-management/new-user/new-user.component.spec.ts @@ -8,41 +8,39 @@ import { PuzzleIconComponent } from "../../shared/custom/puzzle-icon/puzzle-icon import { CommonModule } from "@angular/common"; import { NewUserForm } from "../../shared/types/model/NewUserForm"; -describe("NewUserComponent", - () => { - let component: NewUserComponent; - let fixture: ComponentFixture; +describe("NewUserComponent", () => { + let component: NewUserComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [NewUserComponent, - PuzzleIconButtonComponent, - PuzzleIconComponent], - imports: [ - FormsModule, - ReactiveFormsModule, - SharedModule, - CommonModule - ], - providers: [NgForm] - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [NewUserComponent, + PuzzleIconButtonComponent, + PuzzleIconComponent], + imports: [ + FormsModule, + ReactiveFormsModule, + SharedModule, + CommonModule + ], + providers: [NgForm] + }) + .compileComponents(); - fixture = TestBed.createComponent(NewUserComponent); - component = fixture.componentInstance; + fixture = TestBed.createComponent(NewUserComponent); + component = fixture.componentInstance; - component.userFormGroup = new FormGroup>({ - firstname: new FormControl("user1"), - lastname: new FormControl("user"), - email: new FormControl("test@test.ch") - }); - - fixture.detectChanges(); + component.userFormGroup = new FormGroup>({ + firstname: new FormControl("user1"), + lastname: new FormControl("user"), + email: new FormControl("test@test.ch") }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + fixture.detectChanges(); + }); + + it("should create", () => { + expect(component) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/team-management/new-user/unique-mail.directive.spec.ts b/frontend/src/app/team-management/new-user/unique-mail.directive.spec.ts index 9d72fb0f29..105345963d 100644 --- a/frontend/src/app/team-management/new-user/unique-mail.directive.spec.ts +++ b/frontend/src/app/team-management/new-user/unique-mail.directive.spec.ts @@ -4,45 +4,42 @@ import { TestBed } from "@angular/core/testing"; import { of } from "rxjs"; import { AbstractControl } from "@angular/forms"; -describe("UniqueMailDirective", - () => { - const userServiceMock = { - getUsers: jest.fn() - } as any; - - beforeEach(() => { - userServiceMock.getUsers.mockReturnValue(of(users)); +describe("UniqueMailDirective", () => { + const userServiceMock = { + getUsers: jest.fn() + } as any; + + beforeEach(() => { + userServiceMock.getUsers.mockReturnValue(of(users)); + }); + + it("should create an instance", () => { + TestBed.runInInjectionContext(() => { + const directive = new UniqueEmailValidator(userServiceMock); + expect(directive) + .toBeTruthy(); }); + }); + + it("should return validationError if user exists, otherwise null", () => { + TestBed.runInInjectionContext(() => { + const directive = new UniqueEmailValidator(userServiceMock); - it("should create an instance", - () => { - TestBed.runInInjectionContext(() => { - const directive = new UniqueEmailValidator(userServiceMock); - expect(directive) - .toBeTruthy(); - }); - }); - - it("should return validationError if user exists, otherwise null", - () => { - TestBed.runInInjectionContext(() => { - const directive = new UniqueEmailValidator(userServiceMock); - - let control = { value: users[0].email } as AbstractControl; - expect(directive.validate(control)) - .toStrictEqual({ notUniqueMail: { value: users[0].email } }); - - const notExistingMail = "notexistinguser@test.com"; - control = { value: notExistingMail } as AbstractControl; - expect(directive.validate(control)) - .toStrictEqual(null); - - directive.setAddedMails([notExistingMail]); - expect(directive.validate(control)) - .toStrictEqual({ notUniqueMail: { value: notExistingMail } }); - - expect(directive) - .toBeTruthy(); - }); - }); + let control = { value: users[0].email } as AbstractControl; + expect(directive.validate(control)) + .toStrictEqual({ notUniqueMail: { value: users[0].email } }); + + const notExistingMail = "notexistinguser@test.com"; + control = { value: notExistingMail } as AbstractControl; + expect(directive.validate(control)) + .toStrictEqual(null); + + directive.setAddedMails([notExistingMail]); + expect(directive.validate(control)) + .toStrictEqual({ notUniqueMail: { value: notExistingMail } }); + + expect(directive) + .toBeTruthy(); + }); }); +}); diff --git a/frontend/src/app/team-management/okr-champion.pipe.spec.ts b/frontend/src/app/team-management/okr-champion.pipe.spec.ts index b7d3931897..f3c3d0e8c8 100644 --- a/frontend/src/app/team-management/okr-champion.pipe.spec.ts +++ b/frontend/src/app/team-management/okr-champion.pipe.spec.ts @@ -1,29 +1,25 @@ import { OkrChampionPipe } from "./okr-champion.pipe"; -describe("OkrChampionPipe", - () => { - const translateMock = { - instant: () => "Ja" - } as any; +describe("OkrChampionPipe", () => { + const translateMock = { + instant: () => "Ja" + } as any; - it("create an instance", - () => { - const pipe = new OkrChampionPipe(translateMock); - expect(pipe) - .toBeTruthy(); - }); + it("create an instance", () => { + const pipe = new OkrChampionPipe(translateMock); + expect(pipe) + .toBeTruthy(); + }); - it("should display \"Ja\" if user is okrChampion", - () => { - const pipe = new OkrChampionPipe(translateMock); - expect(pipe.transform(true)) - .toBe("Ja"); - }); + it("should display \"Ja\" if user is okrChampion", () => { + const pipe = new OkrChampionPipe(translateMock); + expect(pipe.transform(true)) + .toBe("Ja"); + }); - it("should display \"-\" if user is not okrChampion", - () => { - const pipe = new OkrChampionPipe(translateMock); - expect(pipe.transform(false)) - .toBe("-"); - }); + it("should display \"-\" if user is not okrChampion", () => { + const pipe = new OkrChampionPipe(translateMock); + expect(pipe.transform(false)) + .toBe("-"); }); +}); diff --git a/frontend/src/app/team-management/search-team-management/search-team-management.component.spec.ts b/frontend/src/app/team-management/search-team-management/search-team-management.component.spec.ts index a7d9d9e74f..e99eaf3f9d 100644 --- a/frontend/src/app/team-management/search-team-management/search-team-management.component.spec.ts +++ b/frontend/src/app/team-management/search-team-management/search-team-management.component.spec.ts @@ -70,157 +70,149 @@ const users: User[] = [{ isOkrChampion: false }]; -describe("SearchTeamManagementComponent", - () => { - let component: SearchTeamManagementComponent; - let fixture: ComponentFixture; - - let teamServiceMock: Partial; - let userServiceMock: Partial; - let activatedRouteMock: Partial; - let navigateSpy: Spy; - beforeEach(async () => { - jest.useFakeTimers(); - - teamServiceMock = { - getAllTeams: () => { - return of(teams); - } - }; - - userServiceMock = { - getUsers: () => { - return of(users); - } - }; - - activatedRouteMock = { - snapshot: { - params: {} - } as unknown as ActivatedRouteSnapshot - }; - - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - RouterTestingModule.withRoutes([]), - BrowserAnimationsModule, - MatAutocompleteModule, - ReactiveFormsModule, - MatInputModule, - MatIconModule, - TranslateTestingModule.withTranslations({ - de: de - }), - SharedModule - ], - declarations: [SearchTeamManagementComponent], - providers: [{ - provide: TeamService, - useValue: teamServiceMock - }, - { - provide: UserService, - useValue: userServiceMock - }, - { - provide: ActivatedRoute, - useValue: activatedRouteMock - }] - }) - .compileComponents(); - }); - beforeEach(() => { - navigateSpy = jest.spyOn(TestBed.inject(Router), - "navigateByUrl") as unknown as Spy; - fixture = TestBed.createComponent(SearchTeamManagementComponent); - component = fixture.componentInstance; - - fixture.detectChanges(); - }); - - afterEach(() => { - jest.clearAllTimers(); - }); - - const getDisplayValues = (value: FilteredUser | FilteredTeam) => value.displayValue; - const getHTMLValues = (value: FilteredUser | FilteredTeam) => value.htmlValue; - - it("should filter out entries and order them according to the position in which the search value occurs", - () => { - component.search.setValue("puz"); - fixture.detectChanges(); - jest.advanceTimersByTime(250); - - const filteredUsers = component.filteredUsers$.getValue(); - const filteredTeams = component.filteredTeams$.getValue(); - expect(filteredUsers.map(getDisplayValues)) - .toEqual(["Pete Parrot (parrot@puzzle.ch)", - "Martin Käser (kaeser@puzzle.ch)"]); - - expect(filteredTeams.map(getDisplayValues)) - .toEqual(["Puzzle Team - No", - "The Puzzle Team - Keyword", - "ZZ the Puzzle Team - Keyword"]); - }); - - it("should generate html values correctly", - () => { - component.search.setValue("Ruedi"); - fixture.detectChanges(); - jest.advanceTimersByTime(250); - - const filteredUsers = component.filteredUsers$.getValue(); - const filteredTeams = component.filteredTeams$.getValue(); - - expect(filteredUsers.map(getHTMLValues)) - .toEqual(["Ruedi Peters (rpeter@gmail.com)"]); - - expect(filteredTeams.map(getHTMLValues)) - .toEqual(["Team Ruedi - Noname"]); - }); - - it("should debounce inputs correctly", - () => { - component.search.setValue("Ruedi"); - fixture.detectChanges(); - - jest.advanceTimersByTime(100); // After 100ms - expect(component.filteredUsers$.getValue()) - .toHaveLength(0); - expect(component.filteredTeams$.getValue()) - .toHaveLength(0); - - jest.advanceTimersByTime(110); // After 210ms - expect(component.filteredUsers$.getValue()).not.toHaveLength(0); - expect(component.filteredTeams$.getValue()).not.toHaveLength(0); - }); - - it("should stay on current team page when a user is selected", - () => { - activatedRouteMock!.snapshot!.params["teamId"] = "42"; - - component.selectUser(users[1]); - - expect(navigateSpy) - .toHaveBeenCalledWith("/team-management/42/details/member/2"); - }); - - it("should stay on current root page when a user is selected", - () => { - activatedRouteMock!.snapshot!.params = {}; - - component.selectUser(users[1]); - - expect(navigateSpy) - .toHaveBeenCalledWith("/team-management/details/member/2"); - }); - - it("should switch to teams page when selected", - () => { - component.selectTeam(teams[0]); - - expect(navigateSpy) - .toHaveBeenCalledWith("/team-management/1"); - }); +describe("SearchTeamManagementComponent", () => { + let component: SearchTeamManagementComponent; + let fixture: ComponentFixture; + + let teamServiceMock: Partial; + let userServiceMock: Partial; + let activatedRouteMock: Partial; + let navigateSpy: Spy; + beforeEach(async () => { + jest.useFakeTimers(); + + teamServiceMock = { + getAllTeams: () => { + return of(teams); + } + }; + + userServiceMock = { + getUsers: () => { + return of(users); + } + }; + + activatedRouteMock = { + snapshot: { + params: {} + } as unknown as ActivatedRouteSnapshot + }; + + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + RouterTestingModule.withRoutes([]), + BrowserAnimationsModule, + MatAutocompleteModule, + ReactiveFormsModule, + MatInputModule, + MatIconModule, + TranslateTestingModule.withTranslations({ + de: de + }), + SharedModule + ], + declarations: [SearchTeamManagementComponent], + providers: [{ + provide: TeamService, + useValue: teamServiceMock + }, + { + provide: UserService, + useValue: userServiceMock + }, + { + provide: ActivatedRoute, + useValue: activatedRouteMock + }] + }) + .compileComponents(); }); + beforeEach(() => { + navigateSpy = jest.spyOn(TestBed.inject(Router), "navigateByUrl") as unknown as Spy; + fixture = TestBed.createComponent(SearchTeamManagementComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + afterEach(() => { + jest.clearAllTimers(); + }); + + const getDisplayValues = (value: FilteredUser | FilteredTeam) => value.displayValue; + const getHTMLValues = (value: FilteredUser | FilteredTeam) => value.htmlValue; + + it("should filter out entries and order them according to the position in which the search value occurs", () => { + component.search.setValue("puz"); + fixture.detectChanges(); + jest.advanceTimersByTime(250); + + const filteredUsers = component.filteredUsers$.getValue(); + const filteredTeams = component.filteredTeams$.getValue(); + expect(filteredUsers.map(getDisplayValues)) + .toEqual(["Pete Parrot (parrot@puzzle.ch)", + "Martin Käser (kaeser@puzzle.ch)"]); + + expect(filteredTeams.map(getDisplayValues)) + .toEqual(["Puzzle Team - No", + "The Puzzle Team - Keyword", + "ZZ the Puzzle Team - Keyword"]); + }); + + it("should generate html values correctly", () => { + component.search.setValue("Ruedi"); + fixture.detectChanges(); + jest.advanceTimersByTime(250); + + const filteredUsers = component.filteredUsers$.getValue(); + const filteredTeams = component.filteredTeams$.getValue(); + + expect(filteredUsers.map(getHTMLValues)) + .toEqual(["Ruedi Peters (rpeter@gmail.com)"]); + + expect(filteredTeams.map(getHTMLValues)) + .toEqual(["Team Ruedi - Noname"]); + }); + + it("should debounce inputs correctly", () => { + component.search.setValue("Ruedi"); + fixture.detectChanges(); + + jest.advanceTimersByTime(100); // After 100ms + expect(component.filteredUsers$.getValue()) + .toHaveLength(0); + expect(component.filteredTeams$.getValue()) + .toHaveLength(0); + + jest.advanceTimersByTime(110); // After 210ms + expect(component.filteredUsers$.getValue()).not.toHaveLength(0); + expect(component.filteredTeams$.getValue()).not.toHaveLength(0); + }); + + it("should stay on current team page when a user is selected", () => { + activatedRouteMock!.snapshot!.params["teamId"] = "42"; + + component.selectUser(users[1]); + + expect(navigateSpy) + .toHaveBeenCalledWith("/team-management/42/details/member/2"); + }); + + it("should stay on current root page when a user is selected", () => { + activatedRouteMock!.snapshot!.params = {}; + + component.selectUser(users[1]); + + expect(navigateSpy) + .toHaveBeenCalledWith("/team-management/details/member/2"); + }); + + it("should switch to teams page when selected", () => { + component.selectTeam(teams[0]); + + expect(navigateSpy) + .toHaveBeenCalledWith("/team-management/1"); + }); +}); diff --git a/frontend/src/app/team-management/search-team-management/search-team-management.component.ts b/frontend/src/app/team-management/search-team-management/search-team-management.component.ts index 228ac88f1a..3cc42476b0 100644 --- a/frontend/src/app/team-management/search-team-management/search-team-management.component.ts +++ b/frontend/src/app/team-management/search-team-management/search-team-management.component.ts @@ -50,17 +50,13 @@ export class SearchTeamManagementComponent { .pipe(takeUntilDestroyed()) .subscribe(([teams, users]) => { - this.updateTeamsAndUsers(teams, - users); + this.updateTeamsAndUsers(teams, users); this.applyFilter(this.searchValue$.getValue()); }); this.search.valueChanges .pipe( - takeUntilDestroyed(), - debounceTime(200), - map((v) => (v ?? "").trim()), - distinctUntilChanged() + takeUntilDestroyed(), debounceTime(200), map((v) => (v ?? "").trim()), distinctUntilChanged() ) .subscribe((searchValue) => { this.searchValue$.next(searchValue); @@ -75,8 +71,7 @@ export class SearchTeamManagementComponent { selectUser (user: User) { this.search.setValue(""); const teamId: number = this.activatedRoute.snapshot.params["teamId"]; - this.router.navigateByUrl(getRouteToUserDetails(user.id, - teamId)) + this.router.navigateByUrl(getRouteToUserDetails(user.id, teamId)) .then(); } @@ -93,20 +88,12 @@ export class SearchTeamManagementComponent { return; } - this.filteredTeams$.next(this.filterTeams(this.teams, - filterValue) - .sort((a, b) => this.sortByStringPosition(a.displayValue, - b.displayValue, - filterValue)) - .slice(0, - SearchTeamManagementComponent.MAX_SUGGESTIONS)); - this.filteredUsers$.next(this.filterUsers(this.users, - filterValue) - .sort((a, b) => this.sortByStringPosition(a.displayValue, - b.displayValue, - filterValue)) - .slice(0, - SearchTeamManagementComponent.MAX_SUGGESTIONS)); + this.filteredTeams$.next(this.filterTeams(this.teams, filterValue) + .sort((a, b) => this.sortByStringPosition(a.displayValue, b.displayValue, filterValue)) + .slice(0, SearchTeamManagementComponent.MAX_SUGGESTIONS)); + this.filteredUsers$.next(this.filterUsers(this.users, filterValue) + .sort((a, b) => this.sortByStringPosition(a.displayValue, b.displayValue, filterValue)) + .slice(0, SearchTeamManagementComponent.MAX_SUGGESTIONS)); } private sortByStringPosition (a: string, b: string, value: string): number { @@ -137,26 +124,22 @@ export class SearchTeamManagementComponent { private filterTeams (teams: Team[], filterValue: string): FilteredTeam[] { return teams - .filter((team) => this.containsText(team.name, - filterValue)) + .filter((team) => this.containsText(team.name, filterValue)) .map((team) => ({ ...team, displayValue: team.name, - htmlValue: this.formatText(team.name, - filterValue) + htmlValue: this.formatText(team.name, filterValue) })); } private filterUsers (users: User[], filterValue: string): FilteredUser[] { return users - .filter((user) => this.containsText(user.firstname + user.lastname + user.email, - filterValue)) + .filter((user) => this.containsText(user.firstname + user.lastname + user.email, filterValue)) .map((user) => ({ ...user, displayValue: `${user.firstname} ${user.lastname} (${user.email})`, - htmlValue: this.formatText(`${user.firstname} ${user.lastname} (${user.email})`, - filterValue) + htmlValue: this.formatText(`${user.firstname} ${user.lastname} (${user.email})`, filterValue) })); } @@ -166,8 +149,6 @@ export class SearchTeamManagementComponent { } private formatText (value: string, text: string): string { - return value.replaceAll(new RegExp(`(${text})`, - "ig"), - "$1"); + return value.replaceAll(new RegExp(`(${text})`, "ig"), "$1"); } } diff --git a/frontend/src/app/team-management/show-edit-role/show-edit-role.component.spec.ts b/frontend/src/app/team-management/show-edit-role/show-edit-role.component.spec.ts index 73387dc35f..af6e82bf05 100644 --- a/frontend/src/app/team-management/show-edit-role/show-edit-role.component.spec.ts +++ b/frontend/src/app/team-management/show-edit-role/show-edit-role.component.spec.ts @@ -5,51 +5,46 @@ import { testUser } from "../../shared/testData"; import { TranslateTestingModule } from "ngx-translate-testing"; import * as de from "../../../assets/i18n/de.json"; -describe("ShowEditRoleComponent", - () => { - let component: ShowEditRoleComponent; - let fixture: ComponentFixture; - const userTeam = { ...testUser.userTeamList[0] }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ShowEditRoleComponent], - imports: [TranslateTestingModule.withTranslations({ de: de })] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ShowEditRoleComponent); - component = fixture.componentInstance; - - component.userTeam = userTeam; - - fixture.detectChanges(); - }); - - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("saveIsAdmin should set edit to false", - () => { - component.edit = true; - component.saveIsAdmin(true); - expect(component.edit) - .toBeFalsy(); - }); - - it("setEditAsync should set edit to given value", - fakeAsync(() => { - component.edit = false; - const mouseEvent = { - stopPropagation: () => undefined - } as any; - component.setEditAsync(mouseEvent, - true); - tick(); - expect(component.edit) - .toBeTruthy(); - })); +describe("ShowEditRoleComponent", () => { + let component: ShowEditRoleComponent; + let fixture: ComponentFixture; + const userTeam = { ...testUser.userTeamList[0] }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ShowEditRoleComponent], + imports: [TranslateTestingModule.withTranslations({ de: de })] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShowEditRoleComponent); + component = fixture.componentInstance; + + component.userTeam = userTeam; + + fixture.detectChanges(); }); + + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("saveIsAdmin should set edit to false", () => { + component.edit = true; + component.saveIsAdmin(true); + expect(component.edit) + .toBeFalsy(); + }); + + it("setEditAsync should set edit to given value", fakeAsync(() => { + component.edit = false; + const mouseEvent = { + stopPropagation: () => undefined + } as any; + component.setEditAsync(mouseEvent, true); + tick(); + expect(component.edit) + .toBeTruthy(); + })); +}); diff --git a/frontend/src/app/team-management/show-edit-role/show-edit-role.component.ts b/frontend/src/app/team-management/show-edit-role/show-edit-role.component.ts index bf8c5d1039..06270bb044 100644 --- a/frontend/src/app/team-management/show-edit-role/show-edit-role.component.ts +++ b/frontend/src/app/team-management/show-edit-role/show-edit-role.component.ts @@ -19,8 +19,7 @@ export class ShowEditRoleComponent { private readonly elementRef: ElementRef, private readonly cd: ChangeDetectorRef) {} - @HostListener("document:click", - ["$event"]) + @HostListener("document:click", ["$event"]) clickOutside (event: MouseEvent) { if (this.elementRef.nativeElement.contains(event.target)) { return; @@ -37,8 +36,7 @@ export class ShowEditRoleComponent { setTimeout(() => { this.edit = edit; this.cd.markForCheck(); - }, - 0); + }, 0); } saveIsAdmin (isAdmin: boolean) { diff --git a/frontend/src/app/team-management/team-list/team-list.component.spec.ts b/frontend/src/app/team-management/team-list/team-list.component.spec.ts index 0c23bd17b0..b00a3651ed 100644 --- a/frontend/src/app/team-management/team-list/team-list.component.spec.ts +++ b/frontend/src/app/team-management/team-list/team-list.component.spec.ts @@ -4,60 +4,56 @@ import { ActivatedRoute } from "@angular/router"; import { TeamService } from "../../services/team.service"; import { TeamListComponent } from "./team-list.component"; -describe("TeamListComponent", - () => { - let component: TeamListComponent; - let fixture: ComponentFixture; - const paramTeamId = 1; - - const teamServiceMock = { - getAllTeams: jest.fn() - .mockReturnValue(of()) - }; - - const activatedRouteMock: any = { - paramMap: of({ - get: () => paramTeamId - }) - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TeamListComponent], - providers: [{ provide: TeamService, - useValue: teamServiceMock }, - { provide: ActivatedRoute, - useValue: activatedRouteMock }] - }) - .compileComponents(); - }); +describe("TeamListComponent", () => { + let component: TeamListComponent; + let fixture: ComponentFixture; + const paramTeamId = 1; + + const teamServiceMock = { + getAllTeams: jest.fn() + .mockReturnValue(of()) + }; + + const activatedRouteMock: any = { + paramMap: of({ + get: () => paramTeamId + }) + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TeamListComponent], + providers: [{ provide: TeamService, + useValue: teamServiceMock }, + { provide: ActivatedRoute, + useValue: activatedRouteMock }] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TeamListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TeamListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); - - it("should set selected teamid", - () => { - component.ngOnInit(); - expect(component.selectedTeamId) - .toBe(paramTeamId); - }); - - it("should set selected teamid", - () => { - activatedRouteMock.paramMap = of({ - get: () => undefined - }); - component.ngOnInit(); - expect(component.selectedTeamId) - .toBe(undefined); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); + + it("should set selected teamid", () => { + component.ngOnInit(); + expect(component.selectedTeamId) + .toBe(paramTeamId); + }); + + it("should set selected teamid", () => { + activatedRouteMock.paramMap = of({ + get: () => undefined + }); + component.ngOnInit(); + expect(component.selectedTeamId) + .toBe(undefined); }); +}); diff --git a/frontend/src/app/team-management/team-management-banner/team-management-banner.component.spec.ts b/frontend/src/app/team-management/team-management-banner/team-management-banner.component.spec.ts index fb4f92aa9e..3b02fe25e2 100644 --- a/frontend/src/app/team-management/team-management-banner/team-management-banner.component.spec.ts +++ b/frontend/src/app/team-management/team-management-banner/team-management-banner.component.spec.ts @@ -13,57 +13,54 @@ import { ActivatedRoute } from "@angular/router"; import { DialogService } from "../../services/dialog.service"; import { OkrTangramComponent } from "../../shared/custom/okr-tangram/okr-tangram.component"; -describe("TeamManagementBannerComponent", - () => { - let component: TeamManagementBannerComponent; - let fixture: ComponentFixture; +describe("TeamManagementBannerComponent", () => { + let component: TeamManagementBannerComponent; + let fixture: ComponentFixture; - const dialogServiceMock = { - open: jest.fn() - }; + const dialogServiceMock = { + open: jest.fn() + }; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - MatDialogModule, - MatFormFieldModule, - MatIconModule, - HttpClientTestingModule, - TranslateModule.forRoot(), - MatAutocompleteModule - ], - declarations: [TeamManagementBannerComponent, - SearchTeamManagementComponent, - OkrTangramComponent], - providers: [{ provide: DialogService, - useValue: dialogServiceMock }, - { provide: ActivatedRoute, - useValue: {} }] - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TeamManagementBannerComponent); - component = fixture.componentInstance; - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatFormFieldModule, + MatIconModule, + HttpClientTestingModule, + TranslateModule.forRoot(), + MatAutocompleteModule + ], + declarations: [TeamManagementBannerComponent, + SearchTeamManagementComponent, + OkrTangramComponent], + providers: [{ provide: DialogService, + useValue: dialogServiceMock }, + { provide: ActivatedRoute, + useValue: {} }] + }) + .compileComponents(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TeamManagementBannerComponent); + component = fixture.componentInstance; + }); - it("createTeam should open dialog", - fakeAsync(() => { - dialogServiceMock.open.mockReturnValue({ - afterClosed: () => of() - }); - component.createTeam(); - tick(); - expect(dialogServiceMock.open) - .toBeCalledTimes(1); - expect(dialogServiceMock.open) - .toBeCalledWith(AddEditTeamDialogComponent); - })); + it("should create", () => { + expect(component) + .toBeTruthy(); }); + + it("createTeam should open dialog", fakeAsync(() => { + dialogServiceMock.open.mockReturnValue({ + afterClosed: () => of() + }); + component.createTeam(); + tick(); + expect(dialogServiceMock.open) + .toBeCalledTimes(1); + expect(dialogServiceMock.open) + .toBeCalledWith(AddEditTeamDialogComponent); + })); +}); diff --git a/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.spec.ts b/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.spec.ts index 24847c1e9b..a13036c8f9 100644 --- a/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.spec.ts +++ b/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.spec.ts @@ -19,108 +19,102 @@ import { MatInputModule } from "@angular/material/input"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { getRouteToAllTeams, getRouteToTeam } from "../../shared/routeUtils"; -describe("TeamManagementMobileFilterComponent", - () => { - let component: TeamManagementMobileFilterComponent; - let fixture: ComponentFixture; +describe("TeamManagementMobileFilterComponent", () => { + let component: TeamManagementMobileFilterComponent; + let fixture: ComponentFixture; - const teamIdSubj = new BehaviorSubject({ - get: (): string | undefined => "1" - }); + const teamIdSubj = new BehaviorSubject({ + get: (): string | undefined => "1" + }); - const teamServiceMock = { - getAllTeams: jest.fn() - }; + const teamServiceMock = { + getAllTeams: jest.fn() + }; - const activatedRouteMock = { - paramMap: teamIdSubj.asObservable() - }; + const activatedRouteMock = { + paramMap: teamIdSubj.asObservable() + }; - const routerMock = { - navigateByUrl: jest.fn() - }; + const routerMock = { + navigateByUrl: jest.fn() + }; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientModule, - MatFormFieldModule, - MatSelectModule, - FormsModule, - ReactiveFormsModule, - TranslateTestingModule.withTranslations({ - de: de - }), - MatAutocompleteModule, - MatIconModule, - BrowserModule, - MatInputModule, - NoopAnimationsModule - ], - declarations: [TeamManagementMobileFilterComponent, - SearchTeamManagementComponent], - providers: [{ provide: TeamService, - useValue: teamServiceMock }, - { provide: ActivatedRoute, - useValue: activatedRouteMock }, - { provide: Router, - useValue: routerMock }] - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientModule, + MatFormFieldModule, + MatSelectModule, + FormsModule, + ReactiveFormsModule, + TranslateTestingModule.withTranslations({ + de: de + }), + MatAutocompleteModule, + MatIconModule, + BrowserModule, + MatInputModule, + NoopAnimationsModule + ], + declarations: [TeamManagementMobileFilterComponent, + SearchTeamManagementComponent], + providers: [{ provide: TeamService, + useValue: teamServiceMock }, + { provide: ActivatedRoute, + useValue: activatedRouteMock }, + { provide: Router, + useValue: routerMock }] + }) + .compileComponents(); - teamServiceMock.getAllTeams.mockReturnValue(of(teamList)); + teamServiceMock.getAllTeams.mockReturnValue(of(teamList)); - fixture = TestBed.createComponent(TeamManagementMobileFilterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TeamManagementMobileFilterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - afterEach(() => { - routerMock.navigateByUrl.mockReset(); - }); + afterEach(() => { + routerMock.navigateByUrl.mockReset(); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("should set allTeams and selectedTeam correctly", - fakeAsync(() => { - tick(); - expect(component.selectedTeam) - .toStrictEqual(team1); - expect(component.teams) - .toStrictEqual(teamList); - })); + it("should set allTeams and selectedTeam correctly", fakeAsync(() => { + tick(); + expect(component.selectedTeam) + .toStrictEqual(team1); + expect(component.teams) + .toStrictEqual(teamList); + })); - it("should set allTeams and selectedTeam correctly if no teamId given", - fakeAsync(() => { - teamIdSubj.next({ - get: () => undefined - }); - tick(); - expect(component.selectedTeam) - .toBe(component.ALL_TEAMS); - expect(component.teams) - .toStrictEqual(teamList); - })); + it("should set allTeams and selectedTeam correctly if no teamId given", fakeAsync(() => { + teamIdSubj.next({ + get: () => undefined + }); + tick(); + expect(component.selectedTeam) + .toBe(component.ALL_TEAMS); + expect(component.teams) + .toStrictEqual(teamList); + })); - it("navigate should navigate to team ", - () => { - component.navigate(team1); - expect(routerMock.navigateByUrl) - .toBeCalledTimes(1); - expect(routerMock.navigateByUrl) - .toBeCalledWith(getRouteToTeam(team1.id)); - }); + it("navigate should navigate to team ", () => { + component.navigate(team1); + expect(routerMock.navigateByUrl) + .toBeCalledTimes(1); + expect(routerMock.navigateByUrl) + .toBeCalledWith(getRouteToTeam(team1.id)); + }); - it("navigate should navigate to all teams ", - () => { - component.navigate(component.ALL_TEAMS); - expect(routerMock.navigateByUrl) - .toBeCalledTimes(1); - expect(routerMock.navigateByUrl) - .toBeCalledWith(getRouteToAllTeams()); - }); + it("navigate should navigate to all teams ", () => { + component.navigate(component.ALL_TEAMS); + expect(routerMock.navigateByUrl) + .toBeCalledTimes(1); + expect(routerMock.navigateByUrl) + .toBeCalledWith(getRouteToAllTeams()); }); +}); diff --git a/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.ts b/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.ts index b8cfd851a3..cfeb0d5405 100644 --- a/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.ts +++ b/frontend/src/app/team-management/team-management-mobile-filter/team-management-mobile-filter.component.ts @@ -24,8 +24,7 @@ export class TeamManagementMobileFilterComponent { this.route.paramMap]) .pipe(takeUntilDestroyed()) .subscribe(([teams, - params]) => this.setTeamsAndSelectedTeam(teams, - params)); + params]) => this.setTeamsAndSelectedTeam(teams, params)); } navigate (team: Team | "alle") { diff --git a/frontend/src/app/team-management/team-management.component.spec.ts b/frontend/src/app/team-management/team-management.component.spec.ts index 983b38f173..898f88f53f 100644 --- a/frontend/src/app/team-management/team-management.component.spec.ts +++ b/frontend/src/app/team-management/team-management.component.spec.ts @@ -25,74 +25,72 @@ import { testUser, users } from "../shared/testData"; import { UserService } from "../services/user.service"; import { ConfigService } from "../services/config.service"; -describe("TeamManagementComponent", - () => { - let component: TeamManagementComponent; - let fixture: ComponentFixture; +describe("TeamManagementComponent", () => { + let component: TeamManagementComponent; + let fixture: ComponentFixture; - const activatedRouteMock = { - paramMap: of({}) - }; + const activatedRouteMock = { + paramMap: of({}) + }; - const userServiceMock = { - getCurrentUser: () => of(testUser), - getUsers: () => of(users) - }; + const userServiceMock = { + getCurrentUser: () => of(testUser), + getUsers: () => of(users) + }; - const configServiceMock = { - config$: of({}) - }; + const configServiceMock = { + config$: of({}) + }; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - HttpClientTestingModule, - MatFormFieldModule, - MatIconModule, - SharedModule, - MatInputModule, - BrowserAnimationsModule, - MatListModule, - RouterModule, - MatAutocompleteModule, - ReactiveFormsModule, - TranslateModule.forRoot(), - MatSelectModule, - FormsModule, - ReactiveFormsModule, - MatTableModule - ], - declarations: [ - TeamManagementComponent, - TeamManagementBannerComponent, - TeamListComponent, - MemberListComponent, - SearchTeamManagementComponent, - TeamManagementMobileFilterComponent, - MemberListTableComponent, - MemberListMobileComponent - ], - providers: [{ provide: ActivatedRoute, - useValue: activatedRouteMock }, - { provide: UserService, - useValue: userServiceMock }, - { provide: ConfigService, - useValue: configServiceMock }] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + MatFormFieldModule, + MatIconModule, + SharedModule, + MatInputModule, + BrowserAnimationsModule, + MatListModule, + RouterModule, + MatAutocompleteModule, + ReactiveFormsModule, + TranslateModule.forRoot(), + MatSelectModule, + FormsModule, + ReactiveFormsModule, + MatTableModule + ], + declarations: [ + TeamManagementComponent, + TeamManagementBannerComponent, + TeamListComponent, + MemberListComponent, + SearchTeamManagementComponent, + TeamManagementMobileFilterComponent, + MemberListTableComponent, + MemberListMobileComponent + ], + providers: [{ provide: ActivatedRoute, + useValue: activatedRouteMock }, + { provide: UserService, + useValue: userServiceMock }, + { provide: ConfigService, + useValue: configServiceMock }] + }) + .compileComponents(); + }); - beforeEach(() => { - TestBed.runInInjectionContext(() => { - fixture = TestBed.createComponent(TeamManagementComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + TestBed.runInInjectionContext(() => { + fixture = TestBed.createComponent(TeamManagementComponent); + component = fixture.componentInstance; + fixture.detectChanges(); }); + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); }); +}); diff --git a/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.spec.ts b/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.spec.ts index 363172e0d2..127112f8b0 100644 --- a/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.spec.ts +++ b/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.spec.ts @@ -6,55 +6,50 @@ import { MatOptionModule } from "@angular/material/core"; import { TranslateModule } from "@ngx-translate/core"; import { takeLast } from "rxjs"; -describe("TeamRoleDropdownComponent", - () => { - let component: TeamRoleDropdownComponent; - let fixture: ComponentFixture; +describe("TeamRoleDropdownComponent", () => { + let component: TeamRoleDropdownComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - ReactiveFormsModule, - CommonModule, - FormsModule, - MatOptionModule, - TranslateModule.forRoot() - ], - declarations: [TeamRoleDropdownComponent] - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + ReactiveFormsModule, + CommonModule, + FormsModule, + MatOptionModule, + TranslateModule.forRoot() + ], + declarations: [TeamRoleDropdownComponent] + }) + .compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TeamRoleDropdownComponent); - component = fixture.componentInstance; - }); + beforeEach(() => { + fixture = TestBed.createComponent(TeamRoleDropdownComponent); + component = fixture.componentInstance; + }); - it("should create", - () => { - expect(component) - .toBeTruthy(); - }); + it("should create", () => { + expect(component) + .toBeTruthy(); + }); - it("component onInit should create formControl", - () => { - component.isAdmin = false; - component.ngOnInit(); - expect(JSON.stringify(component.adminControl)) - .toStrictEqual(JSON.stringify(new FormControl(component.isAdmin, - [Validators.required]))); - }); + it("component onInit should create formControl", () => { + component.isAdmin = false; + component.ngOnInit(); + expect(JSON.stringify(component.adminControl)) + .toStrictEqual(JSON.stringify(new FormControl(component.isAdmin, [Validators.required]))); + }); - it("triggerIsAdminChange should submit next value", - (done) => { - component.isAdminChange.pipe(takeLast(1)) - .subscribe((val) => { - expect(val) - .toBeFalsy(); - done(); - }); - component.isAdminChange.next(false); - component.triggerIsAdminChange(); - component.isAdminChange.complete(); + it("triggerIsAdminChange should submit next value", (done) => { + component.isAdminChange.pipe(takeLast(1)) + .subscribe((val) => { + expect(val) + .toBeFalsy(); + done(); }); + component.isAdminChange.next(false); + component.triggerIsAdminChange(); + component.isAdminChange.complete(); }); +}); diff --git a/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.ts b/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.ts index 7df33df31f..8e2421a704 100644 --- a/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.ts +++ b/frontend/src/app/team-management/team-role-dropdown/team-role-dropdown.component.ts @@ -16,8 +16,7 @@ export class TeamRoleDropdownComponent implements OnInit { adminControl!: FormControl; ngOnInit (): void { - this.adminControl = new FormControl(this.isAdmin, - [Validators.required]); + this.adminControl = new FormControl(this.isAdmin, [Validators.required]); } public triggerIsAdminChange (): void { diff --git a/frontend/src/app/team-management/teams.pipe.spec.ts b/frontend/src/app/team-management/teams.pipe.spec.ts index b227d2587f..11fc091b57 100644 --- a/frontend/src/app/team-management/teams.pipe.spec.ts +++ b/frontend/src/app/team-management/teams.pipe.spec.ts @@ -1,50 +1,40 @@ import { TeamsPipe } from "./teams.pipe"; -describe("TeamsPipe", - () => { - let pipe: TeamsPipe; - const translateMock: any = { - instant: jest.fn() - }; +describe("TeamsPipe", () => { + let pipe: TeamsPipe; + const translateMock: any = { + instant: jest.fn() + }; - beforeEach(() => { - pipe = new TeamsPipe(translateMock); - }); + beforeEach(() => { + pipe = new TeamsPipe(translateMock); + }); - it("should return an empty string if teams array is empty", - () => { - expect(pipe.transform([], - 2)) - .toEqual(""); - }); + it("should return an empty string if teams array is empty", () => { + expect(pipe.transform([], 2)) + .toEqual(""); + }); - it("should join all team names if maxEntries is not defined", - () => { - expect(pipe.transform(["team1", - "team2", - "team3"], - undefined)) - .toEqual("team1, team2, team3"); - }); + it("should join all team names if maxEntries is not defined", () => { + expect(pipe.transform(["team1", + "team2", + "team3"], undefined)) + .toEqual("team1, team2, team3"); + }); - it("should limit the number of teams if maxEntries is defined", - () => { - translateMock.instant.mockReturnValue("+ 1 Weitere"); - expect(pipe.transform(["team1", - "team2", - "team3"], - 2)) - .toEqual("team1, team2, + 1 Weitere"); - expect(translateMock.instant) - .toBeCalledWith("TEAM_MANAGEMENT.WEITERE", - { overflow: 1 }); - }); + it("should limit the number of teams if maxEntries is defined", () => { + translateMock.instant.mockReturnValue("+ 1 Weitere"); + expect(pipe.transform(["team1", + "team2", + "team3"], 2)) + .toEqual("team1, team2, + 1 Weitere"); + expect(translateMock.instant) + .toBeCalledWith("TEAM_MANAGEMENT.WEITERE", { overflow: 1 }); + }); - it("should join all of teams if maxEntries is defined and matched", - () => { - expect(pipe.transform(["team1", - "team2"], - 2)) - .toEqual("team1, team2"); - }); + it("should join all of teams if maxEntries is defined and matched", () => { + expect(pipe.transform(["team1", + "team2"], 2)) + .toEqual("team1, team2"); }); +}); diff --git a/frontend/src/app/team-management/teams.pipe.ts b/frontend/src/app/team-management/teams.pipe.ts index d26d05114c..a2233fe4d5 100644 --- a/frontend/src/app/team-management/teams.pipe.ts +++ b/frontend/src/app/team-management/teams.pipe.ts @@ -19,12 +19,10 @@ export class TeamsPipe implements PipeTransform { const overflow = teams.length - maxEntries; if (overflow > 0) { return ( - teams.slice(0, - maxEntries) + teams.slice(0, maxEntries) .join(this.SEPARATOR) + ", " + - this.translate.instant("TEAM_MANAGEMENT.WEITERE", - { overflow }) + this.translate.instant("TEAM_MANAGEMENT.WEITERE", { overflow }) ); } return teams.join(this.SEPARATOR); diff --git a/frontend/src/global.ts b/frontend/src/global.ts index 5ec436766d..0c4db9d634 100644 --- a/frontend/src/global.ts +++ b/frontend/src/global.ts @@ -7,8 +7,7 @@ declare global { String.prototype.format = function (...args: any[]): string { args.flat(); - return this.replace(/{(\d+)}/g, - function (match, index) { - return typeof args[index] == "undefined" ? match : args[index]; - }); + return this.replace(/{(\d+)}/g, function (match, index) { + return typeof args[index] == "undefined" ? match : args[index]; + }); };