diff --git a/frontend/src/e2e-test/pages/admin/application-details-page.ts b/frontend/src/e2e-test/pages/admin/application-details-page.ts deleted file mode 100644 index c19105ee14d..00000000000 --- a/frontend/src/e2e-test/pages/admin/application-details-page.ts +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -import { Page, TextInput, Element, ElementCollection } from '../../utils/page' - -export default class ApplicationDetailsPage { - #guardianName: Element - #vtjGuardianName: Element - #otherGuardianAgreementStatus: Element - #otherGuardianSameAddress: Element - #noOtherVtjGuardianText: Element - #applicationStatus: Element - #notes: ElementCollection - constructor(private page: Page) { - this.#guardianName = page.findByDataQa('guardian-name') - this.#vtjGuardianName = page.findByDataQa('vtj-guardian-name') - this.#otherGuardianAgreementStatus = page.findByDataQa('agreement-status') - this.#otherGuardianSameAddress = page.findByDataQa( - 'other-vtj-guardian-lives-in-same-address' - ) - this.#noOtherVtjGuardianText = page.findByDataQa('no-other-vtj-guardian') - this.#applicationStatus = page.findByDataQa('application-status') - this.#notes = page.findAllByDataQa('note-container') - } - - async assertGuardianName(expectedName: string) { - await this.#guardianName.findText(expectedName).waitUntilVisible() - } - - async assertNoOtherVtjGuardian() { - await this.#noOtherVtjGuardianText.waitUntilVisible() - } - - async assertVtjGuardianName(expectedName: string) { - await this.#vtjGuardianName.findText(expectedName).waitUntilVisible() - } - - async assertOtherGuardianSameAddress(status: boolean) { - await this.#otherGuardianSameAddress - .findText(status ? 'Kyllä' : 'Ei') - .waitUntilVisible() - } - - async assertOtherGuardianAgreementStatus(_status: false) { - const expectedText = 'Ei ole sovittu yhdessä' - await this.#otherGuardianAgreementStatus - .findText(expectedText) - .waitUntilVisible() - } - - async assertApplicationStatus(text: string) { - await this.#applicationStatus.findText(text).waitUntilVisible() - } - - async assertNote(index: number, note: string) { - await this.#notes - .nth(index) - .findByDataQa('application-note-content') - .assertTextEquals(note) - } - - async assertNoNote(index: number) { - await this.#notes.nth(index).waitUntilHidden() - } - - async addNote(note: string) { - await this.page.findByDataQa('add-note').click() - const noteTextArea = new TextInput(this.#notes.nth(0).find('textarea')) - await noteTextArea.fill(note) - await this.page.findByDataQa('save-note').click() - } - - async editNote(index: number, note: string) { - const noteContainer = this.#notes.nth(index) - await noteContainer.findByDataQa('edit-note').click() - const input = new TextInput(noteContainer.find('textarea')) - await input.fill(note) - await noteContainer.findByDataQa('save-note').click() - } - - async deleteNote(index: number) { - await this.#notes.nth(index).findByDataQa('delete-note').click() - await this.page.findByDataQa('modal-okBtn').click() - } -} diff --git a/frontend/src/e2e-test/pages/admin/application-workbench-page.ts b/frontend/src/e2e-test/pages/admin/application-workbench-page.ts deleted file mode 100644 index 2156b4883d3..00000000000 --- a/frontend/src/e2e-test/pages/admin/application-workbench-page.ts +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -import { ApplicationStatus } from 'lib-common/generated/api-types/application' -import { DecisionType } from 'lib-common/generated/api-types/decision' -import LocalDate from 'lib-common/local-date' -import { UUID } from 'lib-common/types' - -import { waitUntilTrue } from '../../utils' -import { Checkbox, Combobox, Page, Element } from '../../utils/page' -import { PlacementDraftPage } from '../employee/placement-draft-page' - -import ApplicationDetailsPage from './application-details-page' - -export class SearchFilter { - #statusRadioAll: Element - constructor(private page: Page) { - this.#statusRadioAll = page.findByDataQa('application-status-filter-ALL') - } - - async filterByTransferOnly() { - await this.page.findByDataQa('filter-transfer-only').click() - } - - async filterByTransferExclude() { - await this.page.findByDataQa('filter-transfer-exclude').click() - } - - async filterByApplicationStatus(status: ApplicationStatus) { - await this.#statusRadioAll.click() - await this.#statusRadioAll.click() - await new Checkbox( - this.page.findByDataQa(`application-status-filter-all-${status}`) - ).click() - } -} - -export class DecisionEditorPage { - constructor(private page: Page) {} - - async waitUntilLoaded() { - await this.page.findByDataQa('save-decisions-button').waitUntilVisible() - } - - async selectUnit(type: DecisionType, unitId: UUID) { - const selector = new Combobox( - this.page.findByDataQa(`unit-selector-${type}`) - ) - await selector.fillAndSelectItem('', unitId) - } - - async save() { - await this.page.findByDataQa('save-decisions-button').click() - } - - async cancel() { - await this.page.findByDataQa('cancel-decisions-button').click() - } -} - -export class ApplicationWorkbenchPage { - applicationsSent: Element - #applicationsWaitingPlacement: Element - #applicationsWaitingDecision: Element - #applicationsWaitingUnitConfirmation: Element - applicationsAll: Element - #applicationList: Element - #btnCloseApplication: Element - #agreementStatus: Element - #otherGuardianTel: Element - #otherGuardianEmail: Element - #withdrawPlacementProposalsButton: Element - constructor(private page: Page) { - this.applicationsSent = page.findByDataQa('application-status-filter-SENT') - this.#applicationsWaitingPlacement = page.findByDataQa( - 'application-status-filter-WAITING_PLACEMENT' - ) - this.#applicationsWaitingDecision = page.findByDataQa( - 'application-status-filter-WAITING_DECISION' - ) - this.#applicationsWaitingUnitConfirmation = page.findByDataQa( - 'application-status-filter-WAITING_UNIT_CONFIRMATION' - ) - this.applicationsAll = page.findByDataQa('application-status-filter-ALL') - this.#applicationList = page.findByDataQa('applications-list') - this.#btnCloseApplication = page.findByDataQa('close-application') - this.#agreementStatus = page.findByDataQa('agreement-status') - this.#otherGuardianTel = page.findByDataQa('second-guardian-phone') - this.#otherGuardianEmail = page.findByDataQa('second-guardian-email') - this.#withdrawPlacementProposalsButton = page.findByDataQa( - 'action-bar-withdrawPlacementProposal' - ) - } - - getApplicationListItem(applicationId: string) { - return this.#applicationList.find( - `tr[data-application-id="${applicationId}"]` - ) - } - - async openApplicationById(id: string) { - const popup = await this.page.capturePopup(async () => { - await this.getApplicationListItem(id).click() - }) - return new ApplicationDetailsPage(popup) - } - - getPrimaryActionCheck(id: string) { - return this.getApplicationById(id).findByDataQa('primary-action-check') - } - - getPrimaryActionCreatePlacementPlan(id: string) { - return this.getApplicationById(id).findByDataQa( - 'primary-action-create-placement-plan' - ) - } - - async openDaycarePlacementDialogById(id: string) { - await this.getPrimaryActionCreatePlacementPlan(id).click() - return new PlacementDraftPage(this.page) - } - - async clickApplicationCheckbox(applicationId: string) { - await new Checkbox( - this.page.findByDataQa(`application-row-checkbox-${applicationId}`) - ).click() - } - - async moveToWaitingPlacement(applicationId: string) { - await this.clickApplicationCheckbox(applicationId) - await this.page.findByDataQa('action-bar-moveToWaitingPlacement').click() - } - - async sendDecisionsWithoutProposal(applicationId: string) { - await this.clickApplicationCheckbox(applicationId) - await this.page - .findByDataQa('action-bar-sendDecisionsWithoutProposal') - .click() - } - - async withdrawPlacementProposal(applicationId: string) { - await this.clickApplicationCheckbox(applicationId) - await this.#withdrawPlacementProposalsButton.click() - } - - async assertWithdrawPlacementProposalsButtonDisabled() { - await waitUntilTrue(() => this.#withdrawPlacementProposalsButton.disabled) - } - - getApplicationById(id: string) { - return this.page.find( - `[data-qa="table-application-row"][data-application-id="${id}"]` - ) - } - - async closeApplication() { - if (await this.#btnCloseApplication.hasAttribute('disabled')) { - // Application was opened in new window/tab - throw new Error('close the window here somehow') - } else { - await this.#btnCloseApplication.click() - } - } - - async waitUntilLoaded() { - await this.#applicationList.waitUntilVisible() - } - - async openPlacementQueue() { - await this.#applicationsWaitingPlacement.click() - await this.waitUntilLoaded() - } - - async openDecisionQueue() { - await this.#applicationsWaitingDecision.click() - await this.waitUntilLoaded() - } - - async openPlacementProposalQueue() { - await this.#applicationsWaitingUnitConfirmation.click() - await this.waitUntilLoaded() - } - - async assertApplicationStartDate(index: number, date: LocalDate) { - const rows = this.page.findAllByDataQa('table-application-row') - const row = rows.nth(index) - await row.findByDataQa('start-date').assertTextEquals(date.format()) - } - - async assertServiceWorkerNoteMatches(index: number, matchingText: string) { - const note = this.page.findAllByDataQa('service-worker-note').nth(index) - await note.hover() - const tooltip = await note.text - const match = tooltip.match(matchingText) - return match ? match.length > 0 : false - } - - async openDecisionEditorById(applicationId: string) { - await this.getApplicationById(applicationId) - .findByDataQa('primary-action-edit-decisions') - .click() - return new DecisionEditorPage(this.page) - } - - async assertAgreementStatusNotAgreed() { - await this.#agreementStatus.assertText((text) => - text.includes('Ei ole sovittu yhdessä') - ) - } - - async assertContactDetails(expectedTel: string, expectedEmail: string) { - await this.#otherGuardianTel.assertTextEquals(expectedTel) - await this.#otherGuardianEmail.assertTextEquals(expectedEmail) - } - - async assertDecisionGuardians( - expectedGuardian: string, - expectedOtherGuardian?: string - ) { - await this.page - .findByDataQa('guardian-name') - .assertTextEquals(expectedGuardian) - if (expectedOtherGuardian !== undefined) { - await this.page - .findByDataQa('other-guardian-name') - .assertTextEquals(expectedOtherGuardian) - } - } -} diff --git a/frontend/src/e2e-test/pages/employee/applications.ts b/frontend/src/e2e-test/pages/employee/applications.ts deleted file mode 100644 index aaad8e2a59a..00000000000 --- a/frontend/src/e2e-test/pages/employee/applications.ts +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -import { Element, Page } from '../../utils/page' - -import ApplicationReadView from './applications/application-read-view' - -export default class ApplicationsPage { - details: { - applicantDeadIndicator: Element - } - constructor(private readonly page: Page) { - this.details = { - applicantDeadIndicator: page.findByDataQa('applicant-dead') - } - } - - applicationStatusFilter(status: 'ALL') { - return this.page.findByDataQa(`application-status-filter-${status}`) - } - - async toggleApplicationStatusFilter(status: 'ALL') { - await this.applicationStatusFilter(status).click() - } - - applicationRow(id: string) { - const element = this.page.find(`[data-application-id="${id}"]`) - return new ApplicationRow(this.page, element) - } -} - -export class ApplicationRow extends Element { - constructor( - private page: Page, - root: Element - ) { - super(root) - } - - status = this.find('[data-qa="application-status"]') - - async openApplication() { - const applicationDetails = new Promise((res) => { - this.page.onPopup((page) => res(new ApplicationReadView(page))) - }) - await this.click() - return applicationDetails - } -} diff --git a/frontend/src/e2e-test/pages/employee/applications/application-list-view.ts b/frontend/src/e2e-test/pages/employee/applications/application-list-view.ts index 8eb4fed168f..fb4821b10da 100644 --- a/frontend/src/e2e-test/pages/employee/applications/application-list-view.ts +++ b/frontend/src/e2e-test/pages/employee/applications/application-list-view.ts @@ -1,8 +1,14 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo +// SPDX-FileCopyrightText: 2017-2024 City of Espoo // // SPDX-License-Identifier: LGPL-2.1-or-later -import { ApplicationTypeToggle } from 'lib-common/generated/api-types/application' +import { + ApplicationStatusOption, + ApplicationTypeToggle +} from 'lib-common/generated/api-types/application' +import { DecisionType } from 'lib-common/generated/api-types/decision' +import LocalDate from 'lib-common/local-date' +import { UUID } from 'lib-common/types' import config from '../../../config' import { waitUntilEqual } from '../../../utils' @@ -11,21 +17,21 @@ import { Page, Element, ElementCollection, - Radio + Radio, + Checkbox, + Combobox } from '../../../utils/page' +import { PlacementDraftPage } from '../placement-draft-page' + +import ApplicationReadView from './application-read-view' export default class ApplicationListView { applicationStatus: Element allApplications: Element #areaFilter: MultiSelect #unitFilter: MultiSelect + searchButton: Element #applications: ElementCollection - actionsMenuItems: { - createPlacement: Element - createDecision: Element - acceptPlacementWithoutDecision: Element - cancelApplication: Element - } cancelConfirmation: { confidentialRadioYes: Radio confidentialRadioNo: Radio @@ -40,22 +46,19 @@ export default class ApplicationListView { voucherHide: Element noFilter: Element } + actionBar: { + sendDecisionsWithoutProposal: Element + withdrawPlacementProposal: Element + } constructor(private page: Page) { this.applicationStatus = page.findByDataQa('application-status') this.allApplications = page.findByDataQa('application-status-filter-ALL') this.#areaFilter = new MultiSelect(page.findByDataQa('area-filter')) this.#unitFilter = new MultiSelect(page.findByDataQa('unit-selector')) + this.searchButton = page.findByDataQa('search-button') this.#applications = page .find('[data-qa="table-of-applications"]') .findAll('[data-qa="table-application-row"]') - this.actionsMenuItems = { - createPlacement: this.#actionsMenuItemSelector('placement-draft'), - createDecision: this.#actionsMenuItemSelector('decision'), - acceptPlacementWithoutDecision: this.#actionsMenuItemSelector( - 'placement-without-decision' - ), - cancelApplication: this.#actionsMenuItemSelector('cancel-application') - } this.cancelConfirmation = { confidentialRadioYes: new Radio(page.findByDataQa('confidential-yes')), confidentialRadioNo: new Radio(page.findByDataQa('confidential-no')), @@ -70,18 +73,19 @@ export default class ApplicationListView { voucherHide: page.findByDataQa('filter-voucher-hide'), noFilter: page.findByDataQa('filter-voucher-no-filter') } + const actionBarRoot = page.findByDataQa('action-bar') + this.actionBar = { + sendDecisionsWithoutProposal: actionBarRoot.findByDataQa( + 'action-bar-sendDecisionsWithoutProposal' + ), + withdrawPlacementProposal: actionBarRoot.findByDataQa( + 'action-bar-withdrawPlacementProposal' + ) + } } static url = `${config.employeeUrl}/applications` - actionsMenu = (applicationId: string) => - this.page - .find(`[data-application-id="${applicationId}"]`) - .find('[data-qa="application-actions-menu"]') - - #actionsMenuItemSelector = (id: string) => - this.page.findByDataQa(`menu-item-${id}`) - async toggleArea(areaName: string) { await this.#areaFilter.fillAndSelectFirst(areaName) } @@ -90,8 +94,21 @@ export default class ApplicationListView { await this.#unitFilter.fillAndSelectFirst(unitName) } + async filterByApplicationType(type: ApplicationTypeToggle) { + await this.page.findByDataQa(`application-type-filter-${type}`).click() + } + + async filterByApplicationStatus(type: ApplicationStatusOption | 'ALL') { + await this.page.findByDataQa(`application-status-filter-${type}`).click() + } + #application = (id: string) => this.page.find(`[data-application-id="${id}"]`) + applicationRow(id: string) { + const element = this.#application(id) + return new ApplicationRow(this.page, element) + } + async assertApplicationIsVisible(applicationId: string) { await this.#application(applicationId).waitUntilVisible() } @@ -99,8 +116,87 @@ export default class ApplicationListView { async assertApplicationCount(n: number) { await waitUntilEqual(() => this.#applications.count(), n) } +} - async filterByApplicationType(type: ApplicationTypeToggle) { - await this.page.findByDataQa(`application-type-filter-${type}`).click() +export class ApplicationRow extends Element { + status: Element + actionsMenuButton: Element + actionsMenuItems: { + sendDecisionsWithoutProposal: Element + cancelApplication: Element + } + checkbox: Checkbox + constructor( + private page: Page, + private root: Element + ) { + super(root) + this.status = this.find('[data-qa="application-status"]') + this.actionsMenuButton = root.findByDataQa('application-actions-menu') + this.actionsMenuItems = { + sendDecisionsWithoutProposal: root.findByDataQa( + 'menu-item-send-decisions-without-proposal' + ), + cancelApplication: root.findByDataQa('menu-item-cancel-application') + } + this.checkbox = new Checkbox(root.findByDataQa('application-row-checkbox')) + } + + async openApplication() { + const applicationDetails = new Promise((res) => { + this.page.onPopup((page) => res(new ApplicationReadView(page))) + }) + await this.click() + return applicationDetails + } + + async primaryActionCheck() { + await this.root.findByDataQa('primary-action-check').click() + return new ApplicationReadView(this.page) + } + + async primaryActionCreatePlacementPlan() { + await this.root.findByDataQa('primary-action-create-placement-plan').click() + return new PlacementDraftPage(this.page) + } + + async primaryActionEditDecisions() { + await this.root.findByDataQa('primary-action-edit-decisions').click() + return new DecisionEditorPage(this.page) + } + + async assertStartDate(date: LocalDate) { + await this.root.findByDataQa('start-date').assertTextEquals(date.format()) + } + + async assertServiceWorkerNoteMatches(matchingText: string) { + const note = this.root.findByDataQa('service-worker-note') + await note.hover() + const tooltip = await note.text + const match = tooltip.match(matchingText) + return match ? match.length > 0 : false + } +} + +export class DecisionEditorPage { + constructor(private page: Page) {} + + async waitUntilLoaded() { + await this.page.findByDataQa('save-decisions-button').waitUntilVisible() + } + + async selectUnit(type: DecisionType, unitId: UUID) { + const selector = new Combobox( + this.page.findByDataQa(`unit-selector-${type}`) + ) + await selector.fillAndSelectItem('', unitId) + } + + async save() { + await this.page.findByDataQa('save-decisions-button').click() + } + + async cancel() { + await this.page.findByDataQa('cancel-decisions-button').click() } } diff --git a/frontend/src/e2e-test/pages/employee/applications/application-read-view.ts b/frontend/src/e2e-test/pages/employee/applications/application-read-view.ts index 959d8a7ae8a..827b99fb3fe 100644 --- a/frontend/src/e2e-test/pages/employee/applications/application-read-view.ts +++ b/frontend/src/e2e-test/pages/employee/applications/application-read-view.ts @@ -13,7 +13,8 @@ import { Page, Radio, Element, - ElementCollection + ElementCollection, + TextInput } from '../../../utils/page' import MessagesPage from '../messages/messages-page' @@ -21,6 +22,7 @@ import ApplicationEditView from './application-edit-view' export default class ApplicationReadView { #editButton: Element + #guardianName: Element #vtjGuardianName: Element #vtjGuardianPhone: Element #vtjGuardianEmail: Element @@ -28,7 +30,6 @@ export default class ApplicationReadView { #giveOtherGuardianEmail: Element #applicationStatus: Element #sendMessageButton: Element - notesList: Element #title: Element confidentialRadioYes: Radio confidentialRadioNo: Radio @@ -36,6 +37,7 @@ export default class ApplicationReadView { private notes: ElementCollection constructor(private page: Page) { this.#editButton = page.findByDataQa('edit-application') + this.#guardianName = page.findByDataQa('guardian-name') this.#vtjGuardianName = page.findByDataQa('vtj-guardian-name') this.#vtjGuardianPhone = page.findByDataQa('vtj-guardian-phone') this.#vtjGuardianEmail = page.findByDataQa('vtj-guardian-email') @@ -43,9 +45,8 @@ export default class ApplicationReadView { this.#giveOtherGuardianEmail = page.findByDataQa('second-guardian-email') this.#applicationStatus = page.findByDataQa('application-status') this.#sendMessageButton = page.findByDataQa('send-message-button') - this.notesList = page.findByDataQa('application-notes-list') this.#title = this.page.findByDataQa('application-title').find('h1') - this.notes = this.notesList.findAllByDataQa('note-container') + this.notes = this.page.findAllByDataQa('note-container') this.confidentialRadioYes = new Radio( this.page.findByDataQa('confidential-yes') ) @@ -84,6 +85,14 @@ export default class ApplicationReadView { await this.#title.assertTextEquals(expectedTitle) } + async assertGuardianName(expectedName: string) { + await this.#guardianName.findText(expectedName).waitUntilVisible() + } + + async assertOtherVtjGuardianName(expectedName: string) { + await this.#vtjGuardianName.assertTextEquals(expectedName) + } + async assertOtherVtjGuardian( expectedName: string, expectedPhone: string, @@ -95,9 +104,25 @@ export default class ApplicationReadView { } async assertOtherVtjGuardianMissing() { + await this.page.findByDataQa('no-other-vtj-guardian').waitUntilVisible() await this.#vtjGuardianName.waitUntilHidden() } + async assertOtherGuardianSameAddress(status: boolean) { + await this.page + .findByDataQa('other-vtj-guardian-lives-in-same-address') + .findText(status ? 'Kyllä' : 'Ei') + .waitUntilVisible() + } + + async assertOtherGuardianAgreementStatus(_status: false) { + const expectedText = 'Ei ole sovittu yhdessä' + await this.page + .findByDataQa('agreement-status') + .findText(expectedText) + .waitUntilVisible() + } + async assertGivenOtherGuardianInfo( expectedPhone: string, expectedEmail: string @@ -200,6 +225,25 @@ export default class ApplicationReadView { return new MessagesPage(popup) } + async addNote(note: string) { + await this.page.findByDataQa('add-note').click() + const noteTextArea = new TextInput(this.notes.nth(0).find('textarea')) + await noteTextArea.fill(note) + await this.page.findByDataQa('save-note').click() + } + + async assertNote(index: number, note: string) { + await this.notes + .nth(index) + .findByDataQa('application-note-content') + .assertTextEquals(note) + } + + async assertNoNotes() { + await this.page.findByDataQa('application-notes-list').waitUntilAttached() + await this.notes.nth(0).waitUntilHidden() + } + async clickMessageThreadLinkInNote(index: number): Promise { const popup = await this.page.capturePopup(async () => { await this.notes @@ -210,24 +254,25 @@ export default class ApplicationReadView { return new MessagesPage(popup) } - async assertNote(index: number, note: string) { - await this.notes - .nth(index) - .findByDataQa('application-note-content') - .assertTextEquals(note) - } - async assertNoteNotEditable(index: number) { await this.notes.nth(index).findByDataQa('edit-note').waitUntilHidden() } + async editNote(index: number, note: string) { + const noteContainer = this.notes.nth(index) + await noteContainer.findByDataQa('edit-note').click() + const input = new TextInput(noteContainer.find('textarea')) + await input.fill(note) + await noteContainer.findByDataQa('save-note').click() + } + async assertNoteNotDeletable(index: number) { await this.notes.nth(index).findByDataQa('delete-note').waitUntilHidden() } - async assertNoNotes() { - await this.notesList.waitUntilAttached() - await this.notes.nth(0).waitUntilHidden() + async deleteNote(index: number) { + await this.notes.nth(index).findByDataQa('delete-note').click() + await this.page.findByDataQa('modal-okBtn').click() } async reload() { diff --git a/frontend/src/e2e-test/specs/5_employee/application-attachments.spec.ts b/frontend/src/e2e-test/specs/5_employee/application-attachments.spec.ts index 89da025eef2..7d2afbbb3ce 100644 --- a/frontend/src/e2e-test/specs/5_employee/application-attachments.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/application-attachments.spec.ts @@ -22,7 +22,7 @@ import { createApplications, resetServiceState } from '../../generated/api-clients' -import ApplicationsPage from '../../pages/employee/applications' +import ApplicationListView from '../../pages/employee/applications/application-list-view' import ApplicationReadView from '../../pages/employee/applications/application-read-view' import EmployeeNav from '../../pages/employee/employee-nav' import { UnitPage } from '../../pages/employee/units/unit' @@ -30,7 +30,7 @@ import { Page } from '../../utils/page' import { employeeLogin } from '../../utils/user' let page: Page -let applicationsPage: ApplicationsPage +let applicationListView: ApplicationListView const testFileName = 'test_file.png' const testFilePath = `src/e2e-test/assets/${testFileName}` @@ -49,7 +49,7 @@ beforeEach(async () => { const serviceWorker = await Fixture.employee().serviceWorker().save() page = await Page.open() - applicationsPage = new ApplicationsPage(page) + applicationListView = new ApplicationListView(page) await employeeLogin(page, serviceWorker) await page.goto(config.employeeUrl) @@ -57,7 +57,8 @@ beforeEach(async () => { }) async function addAttachmentToApplication(applicationId: string) { - const applicationView = await applicationsPage + await applicationListView.searchButton.click() + const applicationView = await applicationListView .applicationRow(applicationId) .openApplication() const applicationEditView = await applicationView.startEditing() @@ -69,7 +70,8 @@ async function addAttachmentToApplication(applicationId: string) { describe('Employee application attachments', () => { test('Employee can add and remove attachments', async () => { - let applicationView = await applicationsPage + await applicationListView.searchButton.click() + const applicationView = await applicationListView .applicationRow(applicationFixtureId) .openApplication() const applicationEditView = await applicationView.startEditing() @@ -86,10 +88,13 @@ describe('Employee application attachments', () => { await applicationEditView.assertShiftCareAttachmentsDeleted() await applicationEditView.saveApplication() - applicationView = await applicationsPage + await applicationListView.searchButton.click() + const applicationView2 = await applicationListView .applicationRow(applicationFixtureId) .openApplication() - await applicationView.assertUrgencyAttachmentReceivedAtVisible(testFileName) + await applicationView2.assertUrgencyAttachmentReceivedAtVisible( + testFileName + ) }) test('Extended care attachment is visible to appropriate unit supervisor', async () => { diff --git a/frontend/src/e2e-test/specs/5_employee/application-details.spec.ts b/frontend/src/e2e-test/specs/5_employee/application-details.spec.ts index 34216a8daef..33612d085d8 100644 --- a/frontend/src/e2e-test/specs/5_employee/application-details.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/application-details.spec.ts @@ -29,15 +29,13 @@ import { resetServiceState } from '../../generated/api-clients' import { DevApplicationWithForm, DevEmployee } from '../../generated/api-types' -import ApplicationDetailsPage from '../../pages/admin/application-details-page' -import { ApplicationWorkbenchPage } from '../../pages/admin/application-workbench-page' +import ApplicationListView from '../../pages/employee/applications/application-list-view' import ApplicationReadView from '../../pages/employee/applications/application-read-view' import { Page } from '../../utils/page' import { employeeLogin } from '../../utils/user' let page: Page -let applicationWorkbench: ApplicationWorkbenchPage -let applicationDetailsPage: ApplicationDetailsPage +let applicationListView: ApplicationListView let applicationReadView: ApplicationReadView let admin: DevEmployee @@ -99,8 +97,7 @@ beforeEach(async () => { admin = await Fixture.employee().admin().save() page = await Page.open() - applicationWorkbench = new ApplicationWorkbenchPage(page) - applicationDetailsPage = new ApplicationDetailsPage(page) + applicationListView = new ApplicationListView(page) applicationReadView = new ApplicationReadView(page) }) @@ -109,9 +106,10 @@ describe('Application details', () => { await employeeLogin(page, admin) await page.goto(config.adminUrl) - const application = await applicationWorkbench.openApplicationById( - singleParentApplication.id - ) + await applicationListView.searchButton.click() + const application = await applicationListView + .applicationRow(singleParentApplication.id) + .openApplication() await application.assertGuardianName( `${testAdult.lastName} ${testAdult.firstName}` ) @@ -121,20 +119,22 @@ describe('Application details', () => { await employeeLogin(page, admin) await page.goto(config.adminUrl) - const application = await applicationWorkbench.openApplicationById( - singleParentApplication.id - ) - await application.assertNoOtherVtjGuardian() + await applicationListView.searchButton.click() + const application = await applicationListView + .applicationRow(singleParentApplication.id) + .openApplication() + await application.assertOtherVtjGuardianMissing() }) test('Other VTJ guardian in same address is shown', async () => { await employeeLogin(page, admin) await page.goto(config.adminUrl) - const application = await applicationWorkbench.openApplicationById( - familyWithTwoGuardiansApplication.id - ) - await application.assertVtjGuardianName( + await applicationListView.searchButton.click() + const application = await applicationListView + .applicationRow(familyWithTwoGuardiansApplication.id) + .openApplication() + await application.assertOtherVtjGuardianName( `${familyWithTwoGuardians.otherGuardian.lastName} ${familyWithTwoGuardians.otherGuardian.firstName}` ) await application.assertOtherGuardianSameAddress(true) @@ -144,10 +144,11 @@ describe('Application details', () => { await employeeLogin(page, admin) await page.goto(config.adminUrl) - const application = await applicationWorkbench.openApplicationById( - separatedFamilyApplication.id - ) - await application.assertVtjGuardianName( + await applicationListView.searchButton.click() + const application = await applicationListView + .applicationRow(separatedFamilyApplication.id) + .openApplication() + await application.assertOtherVtjGuardianName( `${familyWithSeparatedGuardians.otherGuardian.lastName} ${familyWithSeparatedGuardians.otherGuardian.firstName}` ) await application.assertOtherGuardianSameAddress(false) @@ -183,7 +184,7 @@ describe('Application details', () => { await applicationReadView.navigateToApplication( restrictedDetailsGuardianApplication.id ) - await applicationDetailsPage.assertApplicationStatus( + await applicationReadView.assertApplicationStatus( 'Vahvistettavana huoltajalla' ) @@ -226,11 +227,11 @@ describe('Application details', () => { await employeeLogin(page, unitSupervisor) await applicationReadView.navigateToApplication(singleParentApplication.id) - await applicationDetailsPage.assertApplicationStatus( + await applicationReadView.assertApplicationStatus( 'Vahvistettavana huoltajalla' ) await applicationReadView.acceptDecision('DAYCARE') - await applicationDetailsPage.assertApplicationStatus('Paikka vastaanotettu') + await applicationReadView.assertApplicationStatus('Paikka vastaanotettu') }) test('Service worker can create, edit and delete application notes', async () => { @@ -238,9 +239,10 @@ describe('Application details', () => { await employeeLogin(page, serviceWorker) await page.goto(config.employeeUrl) - const application = await applicationWorkbench.openApplicationById( - singleParentApplication.id - ) + await applicationListView.searchButton.click() + const application = await applicationListView + .applicationRow(singleParentApplication.id) + .openApplication() const newNote = 'New note.' await application.addNote(newNote) await application.assertNote(0, newNote) @@ -248,6 +250,6 @@ describe('Application details', () => { await application.editNote(0, editedNote) await application.assertNote(0, editedNote) await application.deleteNote(0) - await application.assertNoNote(0) + await application.assertNoNotes() }) }) diff --git a/frontend/src/e2e-test/specs/5_employee/application-search.spec.ts b/frontend/src/e2e-test/specs/5_employee/application-search.spec.ts index b17161b79f0..df65d696a02 100644 --- a/frontend/src/e2e-test/specs/5_employee/application-search.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/application-search.spec.ts @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo +// SPDX-FileCopyrightText: 2017-2024 City of Espoo // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -66,6 +66,7 @@ describe('Employee searches applications', () => { const applicationListView = await openPage() await applicationListView.specialFilterItems.duplicate.click() + await applicationListView.searchButton.click() await applicationListView.assertApplicationIsVisible(applicationFixtureId) await applicationListView.assertApplicationIsVisible(duplicateFixture.id) await applicationListView.assertApplicationCount(2) @@ -93,13 +94,16 @@ describe('Employee searches applications', () => { await createApplications({ body: [app1, app2, app3] }) const applicationListView = await openPage() + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(3) await applicationListView.toggleArea(careArea1.name) + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(1) await applicationListView.assertApplicationIsVisible(app1.id) await applicationListView.toggleArea(careArea2.name) + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(2) await applicationListView.assertApplicationIsVisible(app1.id) await applicationListView.assertApplicationIsVisible(app2.id) @@ -123,9 +127,11 @@ describe('Employee searches applications', () => { await createApplications({ body: [app1, app2] }) const applicationListView = await openPage() + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(2) await applicationListView.toggleUnit(daycare1.name) + await applicationListView.searchButton.click() await applicationListView.assertApplicationIsVisible(app1.id) await applicationListView.assertApplicationCount(1) }) @@ -177,6 +183,7 @@ describe('Employee searches applications', () => { ] }) const applicationListView = await openPage(specialEducationTeacher) + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(1) }) @@ -221,15 +228,18 @@ describe('Employee searches applications', () => { const applicationListView = await openPage() await applicationListView.voucherUnitFilter.noFilter.click() + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(3) await applicationListView.voucherUnitFilter.firstChoice.click() + await applicationListView.searchButton.click() await applicationListView.assertApplicationIsVisible( applicationWithVoucherUnitFirst.id ) await applicationListView.assertApplicationCount(1) await applicationListView.voucherUnitFilter.voucherOnly.click() + await applicationListView.searchButton.click() await applicationListView.assertApplicationIsVisible( applicationWithVoucherUnitFirst.id ) @@ -239,6 +249,7 @@ describe('Employee searches applications', () => { await applicationListView.assertApplicationCount(2) await applicationListView.voucherUnitFilter.voucherHide.click() + await applicationListView.searchButton.click() await applicationListView.assertApplicationIsVisible( applicationWithNoVoucherUnit.id ) @@ -287,17 +298,21 @@ describe('Employee searches applications', () => { const applicationListView = await openPage() await applicationListView.filterByApplicationType('ALL') + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(3) await applicationListView.filterByApplicationType('CLUB') + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(1) await applicationListView.assertApplicationIsVisible(clubApplication.id) await applicationListView.filterByApplicationType('DAYCARE') + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(1) await applicationListView.assertApplicationIsVisible(daycareApplication.id) await applicationListView.filterByApplicationType('PRESCHOOL') + await applicationListView.searchButton.click() await applicationListView.assertApplicationCount(1) await applicationListView.assertApplicationIsVisible( preschoolApplication.id diff --git a/frontend/src/e2e-test/specs/5_employee/application-transitions.spec.ts b/frontend/src/e2e-test/specs/5_employee/application-transitions.spec.ts index 83651f56870..ca69856cfee 100755 --- a/frontend/src/e2e-test/specs/5_employee/application-transitions.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/application-transitions.spec.ts @@ -36,7 +36,6 @@ import { resetServiceState } from '../../generated/api-clients' import { DevApplicationWithForm, DevEmployee } from '../../generated/api-types' -import { ApplicationWorkbenchPage } from '../../pages/admin/application-workbench-page' import ApplicationListView from '../../pages/employee/applications/application-list-view' import ApplicationReadView from '../../pages/employee/applications/application-read-view' import { UnitPage } from '../../pages/employee/units/unit' @@ -45,7 +44,7 @@ import { employeeLogin } from '../../utils/user' const mockedTime = LocalDate.of(2021, 8, 16) let page: Page -let applicationWorkbench: ApplicationWorkbenchPage +let applicationListView: ApplicationListView let applicationReadView: ApplicationReadView let serviceWorker: DevEmployee @@ -72,7 +71,7 @@ beforeEach(async () => { page = await Page.open({ mockedTime: mockedTime.toHelsinkiDateTime(LocalTime.of(12, 0)) }) - applicationWorkbench = new ApplicationWorkbenchPage(page) + applicationListView = new ApplicationListView(page) applicationReadView = new ApplicationReadView(page) }) @@ -149,10 +148,11 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - await applicationWorkbench.sendDecisionsWithoutProposal(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + await applicationListView.applicationRow(applicationId).checkbox.check() + await applicationListView.actionBar.sendDecisionsWithoutProposal.click() await applicationReadView.navigateToApplication(applicationId) await applicationReadView.waitUntilLoaded() @@ -177,10 +177,15 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - await applicationWorkbench.sendDecisionsWithoutProposal(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + await applicationListView + .applicationRow(applicationId) + .actionsMenuButton.click() + await applicationListView + .applicationRow(applicationId) + .actionsMenuItems.sendDecisionsWithoutProposal.click() await applicationReadView.navigateToApplication(applicationId) await applicationReadView.waitUntilLoaded() @@ -216,19 +221,14 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - await applicationWorkbench - .getPrimaryActionCheck(applicationId) - .waitUntilVisible() - await applicationWorkbench - .getPrimaryActionCreatePlacementPlan(applicationId) - .waitUntilHidden() + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() - await applicationWorkbench.getPrimaryActionCheck(applicationId).click() + const applicationReadView = await applicationListView + .applicationRow(applicationId) + .primaryActionCheck() - const applicationReadView = new ApplicationReadView(page) await applicationReadView.setVerifiedButton.waitUntilVisible() // confidentiality has been set automatically await applicationReadView.confidentialRadioYes.waitUntilHidden() @@ -237,15 +237,9 @@ describe('Application transitions', () => { await applicationReadView.setVerifiedButton.click() await page.goBack() - await applicationWorkbench - .getPrimaryActionCreatePlacementPlan(applicationId) - .waitUntilVisible() - await applicationWorkbench - .getPrimaryActionCheck(applicationId) - .waitUntilHidden() - - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() }) @@ -278,19 +272,14 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - await applicationWorkbench - .getPrimaryActionCheck(applicationId) - .waitUntilVisible() - await applicationWorkbench - .getPrimaryActionCreatePlacementPlan(applicationId) - .waitUntilHidden() + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() - await applicationWorkbench.getPrimaryActionCheck(applicationId).click() + const applicationReadView = await applicationListView + .applicationRow(applicationId) + .primaryActionCheck() - const applicationReadView = new ApplicationReadView(page) await applicationReadView.setVerifiedButton.waitUntilVisible() await applicationReadView.setVerifiedButton.assertDisabled(true) @@ -301,15 +290,9 @@ describe('Application transitions', () => { await applicationReadView.setVerifiedButton.click() await page.goBack() - await applicationWorkbench - .getPrimaryActionCreatePlacementPlan(applicationId) - .waitUntilVisible() - await applicationWorkbench - .getPrimaryActionCheck(applicationId) - .waitUntilHidden() - - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() }) @@ -336,20 +319,26 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - const applicationList = new ApplicationListView(page) - await applicationList.actionsMenu(applicationId).click() - await applicationList.actionsMenuItems.cancelApplication.click() + await applicationListView.searchButton.click() + await applicationListView + .applicationRow(applicationId) + .actionsMenuButton.click() + await applicationListView + .applicationRow(applicationId) + .actionsMenuItems.cancelApplication.click() - await applicationList.cancelConfirmation.submitButton.assertDisabled(true) - await applicationList.cancelConfirmation.confidentialRadioYes.check() - await applicationList.cancelConfirmation.submitButton.click() - - await applicationWorkbench.applicationsAll.click() - await applicationWorkbench - .getApplicationListItem(applicationId) - .assertText((text) => text.includes('Poistettu käsittelystä')) + await applicationListView.cancelConfirmation.submitButton.assertDisabled( + true + ) + await applicationListView.cancelConfirmation.confidentialRadioYes.check() + await applicationListView.cancelConfirmation.submitButton.click() + + await applicationListView.filterByApplicationStatus('ALL') + await applicationListView.searchButton.click() + await applicationListView + .applicationRow(applicationId) + .status.assertText((text) => text.includes('Poistettu käsittelystä')) }) test('Placement dialog works', async () => { @@ -411,11 +400,13 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() const planStartDate = preferredStartDate.addDays(1) @@ -439,9 +430,11 @@ describe('Application transitions', () => { await placementDraftPage.placeToUnit(testPreschool.id) await placementDraftPage.submit() - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - await applicationWorkbench.assertApplicationStartDate(0, planStartDate) + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + await applicationListView + .applicationRow(applicationId) + .assertStartDate(planStartDate) }) test('Placement dialog shows warning if guardian has restricted details', async () => { @@ -467,12 +460,13 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() await placementDraftPage.assertRestrictedDetailsWarning() }) @@ -503,24 +497,27 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() await placementDraftPage.placeToUnit(testPreschool.id) await placementDraftPage.submit() - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - const decisionEditorPage = - await applicationWorkbench.openDecisionEditorById(applicationId) - await decisionEditorPage.waitUntilLoaded() + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + const decisionEditorPage = await applicationListView + .applicationRow(applicationId) + .primaryActionEditDecisions() + await decisionEditorPage.waitUntilLoaded() await decisionEditorPage.save() - await applicationWorkbench.waitUntilLoaded() + await applicationListView.searchButton.click() await execSimpleApplicationActions( applicationId, @@ -565,25 +562,29 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() await placementDraftPage.placeToUnit(testPreschool.id) await placementDraftPage.submit() - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - const decisionEditorPage = - await applicationWorkbench.openDecisionEditorById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + + const decisionEditorPage = await applicationListView + .applicationRow(applicationId) + .primaryActionEditDecisions() await decisionEditorPage.waitUntilLoaded() await decisionEditorPage.selectUnit('PRESCHOOL_DAYCARE', testDaycare.id) await decisionEditorPage.save() - await applicationWorkbench.waitUntilLoaded() + await applicationListView.searchButton.click() await execSimpleApplicationActions( applicationId, @@ -646,51 +647,39 @@ describe('Application transitions', () => { .save() await employeeLogin(page2, unitSupervisor) - // unit supervisor + // unit supervisor accepts application1 proposal, does not respond to application2 proposal await unitPage.navigateToUnit(testDaycare.id) - let placementProposals = (await unitPage.openApplicationProcessTab()) + const placementProposals = (await unitPage.openApplicationProcessTab()) .placementProposals - await placementProposals.assertAcceptButtonDisabled() await placementProposals.clickProposalAccept(applicationId) - await placementProposals.assertAcceptButtonEnabled() - await placementProposals.clickProposalAccept(applicationId2) - - await placementProposals.clickProposalReject(applicationId2) - await placementProposals.selectProposalRejectionReason(0) - await placementProposals.submitProposalRejectionReason() + await placementProposals.clickAcceptButton() - // service worker + // service worker withdraws application2 proposal, mails application1 decision await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - - await applicationWorkbench.openPlacementProposalQueue() - await applicationWorkbench.withdrawPlacementProposal(applicationId2) - await applicationWorkbench.assertWithdrawPlacementProposalsButtonDisabled() - - // unit supervisor - await unitPage.navigateToUnit(testDaycare.id) - const applicationProcessPage = await unitPage.openApplicationProcessTab() - placementProposals = applicationProcessPage.placementProposals - await placementProposals.assertAcceptButtonEnabled() - await placementProposals.clickAcceptButton() - await placementProposals.assertPlacementProposalRowCount(0) - await applicationProcessPage.waitUntilLoaded() - + await applicationListView.filterByApplicationStatus( + 'WAITING_UNIT_CONFIRMATION' + ) + await applicationListView.searchButton.click() + await applicationListView.applicationRow(applicationId2).checkbox.check() + await applicationListView.actionBar.withdrawPlacementProposal.click() await execSimpleApplicationActions( applicationId, ['CONFIRM_DECISION_MAILED'], mockedTime.toHelsinkiDateTime(LocalTime.of(12, 0)) ) + // unit supervisor sees application1 as waiting confirmation from guardian, no longer sees proposal for application2 await unitPage.navigateToUnit(testDaycare.id) - const waitingConfirmation = (await unitPage.openApplicationProcessTab()) - .waitingConfirmation - await waitingConfirmation.assertRowCount(1) + const applicationProcessPage = await unitPage.openApplicationProcessTab() + await applicationProcessPage.placementProposals.assertPlacementProposalRowCount( + 0 + ) + await applicationProcessPage.waitingConfirmation.assertRowCount(1) }) - test('Placement proposal rejection status', async () => { + test('Placement proposal rejection returns status to WAITING_PLACEMENT and reason is shown in note', async () => { const fixture1 = { ...applicationFixture(testChild, familyWithTwoGuardians.guardian), status: 'SENT' as const @@ -731,10 +720,11 @@ describe('Application transitions', () => { // service worker await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - - await applicationWorkbench.assertServiceWorkerNoteMatches(0, 'TILARAJOITE') + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + await applicationListView + .applicationRow(applicationId) + .assertServiceWorkerNoteMatches('TILARAJOITE') }) test('Decision cannot be accepted on behalf of guardian if application is in placement proposal state', async () => { diff --git a/frontend/src/e2e-test/specs/5_employee/applications.spec.ts b/frontend/src/e2e-test/specs/5_employee/applications.spec.ts index c709977419c..37679ab7cba 100644 --- a/frontend/src/e2e-test/specs/5_employee/applications.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/applications.spec.ts @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo +// SPDX-FileCopyrightText: 2017-2024 City of Espoo // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -17,13 +17,13 @@ import { createApplications, resetServiceState } from '../../generated/api-clients' -import ApplicationsPage from '../../pages/employee/applications' +import ApplicationListView from '../../pages/employee/applications/application-list-view' import EmployeeNav from '../../pages/employee/employee-nav' import { Page } from '../../utils/page' import { employeeLogin } from '../../utils/user' let page: Page -let applicationsPage: ApplicationsPage +let applicationsPage: ApplicationListView beforeEach(async () => { await resetServiceState() @@ -33,7 +33,7 @@ beforeEach(async () => { const serviceWorker = await Fixture.employee().serviceWorker().save() page = await Page.open() - applicationsPage = new ApplicationsPage(page) + applicationsPage = new ApplicationListView(page) await employeeLogin(page, serviceWorker) await page.goto(config.employeeUrl) @@ -59,7 +59,8 @@ describe('Applications', () => { HelsinkiDateTime.now() // TODO: use mock clock ) - await applicationsPage.toggleApplicationStatusFilter('ALL') + await applicationsPage.filterByApplicationStatus('ALL') + await applicationsPage.searchButton.click() await applicationsPage .applicationRow(application.id) .status.assertTextEquals('Odottaa postitusta') @@ -74,7 +75,8 @@ describe('Applications', () => { ) await createApplications({ body: [application] }) - await applicationsPage.toggleApplicationStatusFilter('ALL') + await applicationsPage.filterByApplicationStatus('ALL') + await applicationsPage.searchButton.click() const applicationDetails = await applicationsPage .applicationRow(application.id) .openApplication() diff --git a/frontend/src/e2e-test/specs/5_employee/feature-flag-decision-draft-multiple-units.spec.ts b/frontend/src/e2e-test/specs/5_employee/feature-flag-decision-draft-multiple-units.spec.ts index 3e9b4fca75a..17c82afa761 100755 --- a/frontend/src/e2e-test/specs/5_employee/feature-flag-decision-draft-multiple-units.spec.ts +++ b/frontend/src/e2e-test/specs/5_employee/feature-flag-decision-draft-multiple-units.spec.ts @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017-2022 City of Espoo +// SPDX-FileCopyrightText: 2017-2024 City of Espoo // // SPDX-License-Identifier: LGPL-2.1-or-later @@ -28,14 +28,13 @@ import { resetServiceState } from '../../generated/api-clients' import { DevEmployee } from '../../generated/api-types' -import { ApplicationWorkbenchPage } from '../../pages/admin/application-workbench-page' import ApplicationListView from '../../pages/employee/applications/application-list-view' import { Page } from '../../utils/page' import { employeeLogin } from '../../utils/user' const mockedTime = LocalDate.of(2021, 8, 16) let page: Page -let applicationWorkbench: ApplicationWorkbenchPage +let applicationListView: ApplicationListView let serviceWorker: DevEmployee @@ -58,7 +57,7 @@ beforeEach(async () => { featureFlags: { decisionDraftMultipleUnits: true } } }) - applicationWorkbench = new ApplicationWorkbenchPage(page) + applicationListView = new ApplicationListView(page) }) describe('Application transitions', () => { @@ -88,24 +87,25 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() - await placementDraftPage.placeToUnit(testPreschool.id) await placementDraftPage.submit() - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openDecisionQueue() - const decisionEditorPage = - await applicationWorkbench.openDecisionEditorById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + const decisionEditorPage = await applicationListView + .applicationRow(applicationId) + .primaryActionEditDecisions() await decisionEditorPage.waitUntilLoaded() - await decisionEditorPage.save() - await applicationWorkbench.waitUntilLoaded() + + await applicationListView.searchButton.click() await execSimpleApplicationActions( applicationId, @@ -150,25 +150,25 @@ describe('Application transitions', () => { await employeeLogin(page, serviceWorker) await page.goto(ApplicationListView.url) - await applicationWorkbench.waitUntilLoaded() - await applicationWorkbench.openPlacementQueue() - const placementDraftPage = - await applicationWorkbench.openDaycarePlacementDialogById(applicationId) + await applicationListView.filterByApplicationStatus('WAITING_PLACEMENT') + await applicationListView.searchButton.click() + const placementDraftPage = await applicationListView + .applicationRow(applicationId) + .primaryActionCreatePlacementPlan() await placementDraftPage.waitUntilLoaded() - await placementDraftPage.placeToUnit(testPreschool.id) await placementDraftPage.submit() - await applicationWorkbench.waitUntilLoaded() - - await applicationWorkbench.openDecisionQueue() - const decisionEditorPage = - await applicationWorkbench.openDecisionEditorById(applicationId) - await decisionEditorPage.waitUntilLoaded() + await applicationListView.filterByApplicationStatus('WAITING_DECISION') + await applicationListView.searchButton.click() + const decisionEditorPage = await applicationListView + .applicationRow(applicationId) + .primaryActionEditDecisions() await decisionEditorPage.selectUnit('PRESCHOOL_DAYCARE', testDaycare.id) await decisionEditorPage.save() - await applicationWorkbench.waitUntilLoaded() + + await applicationListView.searchButton.click() await execSimpleApplicationActions( applicationId, diff --git a/frontend/src/e2e-test/specs/7_messaging/service-worker-messaging.spec.ts b/frontend/src/e2e-test/specs/7_messaging/service-worker-messaging.spec.ts index 68bb87c9655..423ac724c9a 100644 --- a/frontend/src/e2e-test/specs/7_messaging/service-worker-messaging.spec.ts +++ b/frontend/src/e2e-test/specs/7_messaging/service-worker-messaging.spec.ts @@ -25,7 +25,7 @@ import { import { DevEmployee } from '../../generated/api-types' import CitizenHeader from '../../pages/citizen/citizen-header' import CitizenMessagesPage from '../../pages/citizen/citizen-messages' -import ApplicationsPage from '../../pages/employee/applications' +import ApplicationReadView from '../../pages/employee/applications/application-read-view' import EmployeeNav from '../../pages/employee/employee-nav' import MessagesPage from '../../pages/employee/messages/messages-page' import { Page } from '../../utils/page' @@ -88,11 +88,8 @@ describe('Service Worker Messaging', () => { it('should be possible for service workers to send messages relating to an application', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -114,11 +111,8 @@ describe('Service Worker Messaging', () => { it('should NOT be possible for a citizen without placed children to send new messages', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -136,11 +130,8 @@ describe('Service Worker Messaging', () => { it('should prefill the receiver and title fields when sending a new message', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -155,11 +146,8 @@ describe('Service Worker Messaging', () => { it('should create an application note with the message contents when sending a new message', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -175,11 +163,8 @@ describe('Service Worker Messaging', () => { it('should create an application note with a clickable link to the message thread', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -199,11 +184,8 @@ describe('Service Worker Messaging', () => { it('should create an application note when the citizen answers a message', async () => { await openStaffPage(mockedTime, serviceWorker) - let applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - let applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -225,21 +207,14 @@ describe('Service Worker Messaging', () => { await citizenMessagesPage.replyToFirstThread(replyContent) await openStaffPage(mockedTime.addHours(2), serviceWorker) - applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + await applReadView.navigateToApplication(applicationFixtureId) await applReadView.assertNote(1, `Lähetetty viesti\n\n${replyContent}`) }) it('should open the reply to thread box and create an application note when the service worker sends a second message', async () => { await openStaffPage(mockedTime, serviceWorker) - let applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - let applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -260,11 +235,7 @@ describe('Service Worker Messaging', () => { await citizenMessagesPage.replyToFirstThread('This is a reply') await openStaffPage(mockedTime.addHours(2), serviceWorker) - applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + await applReadView.navigateToApplication(applicationFixtureId) const messagesPage = await applReadView.openMessagesPage() await messagesPage.assertReplyContentIsEmpty() const replyContent = 'Service worker reply' @@ -272,11 +243,7 @@ describe('Service Worker Messaging', () => { await messagesPage.sendReplyButton.click() await openStaffPage(mockedTime.addHours(2), serviceWorker) - applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + await applReadView.navigateToApplication(applicationFixtureId) await applReadView.assertNote(2, `Lähetetty viesti\n\n${replyContent}`) }) @@ -289,11 +256,8 @@ describe('Service Worker Messaging', () => { it('should show the simple message editor for service workers', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -302,11 +266,8 @@ describe('Service Worker Messaging', () => { it('should not be possible for service workers to delete or edit notes created from messages', async () => { await openStaffPage(mockedTime, serviceWorker) - const applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - const applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -322,11 +283,8 @@ describe('Service Worker Messaging', () => { it('should show the correct thread even when an employee with both messaging and service worker roles click the thread link on the application', async () => { await openStaffPage(mockedTime, serviceWorker) - let applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - let applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + const applReadView = new ApplicationReadView(staffPage) + await applReadView.navigateToApplication(applicationFixtureId) const messageEditor = ( await applReadView.openMessagesPage() ).getMessageEditor() @@ -337,11 +295,7 @@ describe('Service Worker Messaging', () => { await runPendingAsyncJobs(mockedTime.addMinutes(1)) await openStaffPage(mockedTime, messagingAndServiceWorker) - applicationsPage = new ApplicationsPage(staffPage) - await new EmployeeNav(staffPage).applicationsTab.click() - applReadView = await applicationsPage - .applicationRow(applicationFixtureId) - .openApplication() + await applReadView.navigateToApplication(applicationFixtureId) await applReadView.assertNote(0, `Lähetetty viesti\n\n${content}`) const messagesPageWithThread = await applReadView.clickMessageThreadLinkInNote(0)