From 325f3c94bb9dc2798260ee3d590ecaa182618f9a Mon Sep 17 00:00:00 2001 From: Sampo Tawast Date: Fri, 29 Sep 2023 14:34:35 +0300 Subject: [PATCH] chore: deminimis tests --- .../newApplication/deminimis.testcafe.ts | 233 ++++++++++++++++++ .../browser-tests/page-model/WizardStep.ts | 28 ++- .../browser-tests/page-model/step1.ts | 65 +++++ .../browser-tests/utils/url.utils.ts | 7 + 4 files changed, 329 insertions(+), 4 deletions(-) create mode 100644 frontend/benefit/applicant/browser-tests/newApplication/deminimis.testcafe.ts diff --git a/frontend/benefit/applicant/browser-tests/newApplication/deminimis.testcafe.ts b/frontend/benefit/applicant/browser-tests/newApplication/deminimis.testcafe.ts new file mode 100644 index 0000000000..ca807a9479 --- /dev/null +++ b/frontend/benefit/applicant/browser-tests/newApplication/deminimis.testcafe.ts @@ -0,0 +1,233 @@ +import { HttpRequestHook } from '@frontend/shared/browser-tests/http-utils/http-request-hook'; +import requestLogger from '@frontend/shared/browser-tests/utils/request-logger'; +import { clearDataToPrintOnFailure } from '@frontend/shared/browser-tests/utils/testcafe.utils'; +import { Role, Selector } from 'testcafe'; + +import Login from '../page-model/login'; +import MainIngress from '../page-model/MainIngress'; +import Step1 from '../page-model/step1'; +import Step2 from '../page-model/step2'; +import TermsOfService from '../page-model/TermsOfService'; +import { getFrontendUrl } from '../utils/url.utils'; + +const getBackendDomain = (): string => + process.env.NEXT_PUBLIC_BACKEND_URL || 'https://localhost:8000'; + +const url = getFrontendUrl('/'); + +type DeMinimisRow = { + granter: string; + amount: string; + grantedAt: string; +}; + +const applicantRole = Role( + url, + async (t: TestController) => { + await t.click(Login.loginButton); + const termsAndConditions = new TermsOfService(); + await termsAndConditions.isLoaded(); + await termsAndConditions.clickContinueButton(); + }, + { + preserveUrl: true, + } +); + +enum SAVE_ACTIONS { + CONTINUE = 'continue', + SAVE_AND_EXIT = 'saveAndExit', +} + +let step1: Step1; +let step2: Step2; +const deminimisRowSelector = '[data-testid="deminimis-row"]'; + +const fillMandatoryFields = async () => { + const mainIngress = new MainIngress(); + await mainIngress.isLoaded(); + await mainIngress.clickCreateNewApplicationButton(); + + await step1.isLoaded(30_000); + + await step1.fillEmployerInfo('6051437344779954', false); + await step1.fillContactPerson( + 'Tester', + 'Example', + '050001234', + 'tester@example.com' + ); + await step1.selectNocoOperationNegotiations(); +}; + +const getRowCount = async () => Selector(deminimisRowSelector).count; + +const step1ToStep2 = async () => { + await step1.clickSubmit(); + await step2.isLoaded(); +}; + +const step2ToStep1 = async () => { + await step2.clickPrevious(); + await step1.isLoaded(); +}; +const saveStep1AndReturn = async () => { + await step1ToStep2(); + await step2ToStep1(); +}; + +const saveExitAndEdit = async (t: TestController) => { + await step1.clickSaveAndClose(); + const mainIngress = new MainIngress(); + await mainIngress.isLoaded(); + await t.click(Selector('[data-testid="application-edit-button"]')); + await step1.isLoaded(); +}; + +const fillRows = async ( + t: TestController, + rows: DeMinimisRow[], + action?: SAVE_ACTIONS +) => { + for (const row of rows) { + await step1.fillDeminimisAid(row.granter, row.amount, row.grantedAt); + } + if (action === SAVE_ACTIONS.CONTINUE) { + await saveStep1AndReturn(); + await t.scrollIntoView(Selector('button').withText('Jatka')); + await t.expect(await getRowCount()).eql(rows.length); + } + if (action === SAVE_ACTIONS.SAVE_AND_EXIT) { + await saveExitAndEdit(t); + await t.expect(await getRowCount()).eql(rows.length); + } +}; + +const removeRow = async (index: number) => { + await step1.clickDeminimisRemove(index); +}; + +const removeAllRows = async (rows: DeMinimisRow[]) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const _ of rows) { + await step1.clickDeminimisRemove(0); + } +}; + +const fillTooBigAmounts = async (t: TestController) => { + const rows = [ + { granter: 'One', amount: '2', grantedAt: '1.1.2023' }, + { granter: 'Two', amount: '199999', grantedAt: '2.2.2023' }, + ]; + await fillRows(t, rows); + + const deminimisMaxError = Selector( + '[data-testid="deminimis-maxed-notification"]' + ); + await t.expect(await deminimisMaxError.exists).ok(); + await step1.expectSubmitDisabled(); + + await removeAllRows(rows); + + await t.expect(await getRowCount()).eql(0); +}; + +const fillAndLeaveUnfinished = async (t: TestController) => { + await step1.fillDeminimisAid('One', '1', ''); + await step1.clickSubmit(); + const toastError = Selector('.Toastify__toast-body[role="alert"]').withText( + 'Puuttuvia de minimis-tuen tietoja' + ); + await t.expect(await toastError.exists).ok(); + await t.click(toastError.find('[title="Sulje ilmoitus"]')); +}; + +const clearRowsWithSelectNo = async ( + t: TestController, + action: SAVE_ACTIONS +) => { + await step1.selectNoDeMinimis(); + + if (action === SAVE_ACTIONS.CONTINUE) { + await saveStep1AndReturn(); + } + if (action === SAVE_ACTIONS.SAVE_AND_EXIT) { + await saveExitAndEdit(t); + } + + await step1.selectYesDeMinimis(); + await t.scrollIntoView(Selector('button').withText('Jatka')); + + await t.expect(await getRowCount()).eql(0); +}; + +fixture('Deminimis') + .page(url) + .requestHooks(requestLogger, new HttpRequestHook(url, getBackendDomain())) + .beforeEach(async (t: TestController) => { + clearDataToPrintOnFailure(t); + step1 = new Step1(); + step2 = new Step2(); + await t.useRole(applicantRole); + await fillMandatoryFields(); + await step1.selectYesDeMinimis(); + }) + .afterEach( + async () => + // eslint-disable-next-line no-console + console.log('#####################################') + // console.log(filterLoggedRequests(requestLogger)) + ); + +test('De Minimis aid form (errors)', async (t: TestController) => { + await fillAndLeaveUnfinished(t); + await fillTooBigAmounts(t); +}); + +test('De Minimis aid form (using continue)', async (t: TestController) => { + await fillRows( + t, + [{ granter: 'One', amount: '1', grantedAt: '1.1.2023' }], + SAVE_ACTIONS.CONTINUE + ); + + await clearRowsWithSelectNo(t, SAVE_ACTIONS.CONTINUE); + + await fillRows( + t, + [ + { granter: 'One', amount: '1', grantedAt: '1.1.2023' }, + { granter: 'Two', amount: '2', grantedAt: '2.2.2023' }, + { granter: 'Three', amount: '3', grantedAt: '3.3.2023' }, + ], + SAVE_ACTIONS.CONTINUE + ); + + await removeRow(1); + await saveStep1AndReturn(); + await t.expect(await getRowCount()).eql(2); +}); + +test('De Minimis aid form (save and exit)', async (t: TestController) => { + await fillRows( + t, + [{ granter: 'One', amount: '1', grantedAt: '1.1.2023' }], + SAVE_ACTIONS.SAVE_AND_EXIT + ); + + await clearRowsWithSelectNo(t, SAVE_ACTIONS.SAVE_AND_EXIT); + + await fillRows( + t, + [ + { granter: 'One', amount: '1', grantedAt: '1.1.2023' }, + { granter: 'Two', amount: '2', grantedAt: '2.2.2023' }, + { granter: 'Three', amount: '3', grantedAt: '3.3.2023' }, + ], + SAVE_ACTIONS.SAVE_AND_EXIT + ); + + await removeRow(1); + await saveExitAndEdit(t); + await t.expect(await getRowCount()).eql(2); +}); diff --git a/frontend/benefit/applicant/browser-tests/page-model/WizardStep.ts b/frontend/benefit/applicant/browser-tests/page-model/WizardStep.ts index 45cea56757..d972f30e17 100644 --- a/frontend/benefit/applicant/browser-tests/page-model/WizardStep.ts +++ b/frontend/benefit/applicant/browser-tests/page-model/WizardStep.ts @@ -14,6 +14,11 @@ class WizardStep extends ApplicantPageComponent { protected nextButton = this.component.findByRole('button', { name: this.translations.applications.actions.continue, }); + + protected previousButton = this.component.findByRole('button', { + name: this.translations.applications.actions.back, + }); + protected saveAndCloseButton = this.component.findByRole('button', { name: this.translations.applications.actions.saveAndContinueLater, }); @@ -28,16 +33,31 @@ class WizardStep extends ApplicantPageComponent { name: this.translations.applications.actions.deleteApplication, }); - public clickSubmit() { + public clickSubmit(): Promise { return t.click(this.nextButton); } - public clickSaveAndClose() { + + public expectSaveAndClose(): Promise { + return t.expect(this.nextButton).notOk(); + } + + public expectSubmitDisabled(): Promise { + return t.expect(this.nextButton.hasAttribute('disabled')).ok(); + } + + public clickPrevious(): Promise { + return t.click(this.previousButton); + } + + public clickSaveAndClose(): Promise { return t.click(this.saveAndCloseButton); } - public async clickDeleteApplication() { + + public async clickDeleteApplication(): Promise { return t.click(this.deleteButton); } - public confirmDeleteApplication() { + + public confirmDeleteApplication(): Promise { return t.click(this.dialogConfirmDeleteButton); } } diff --git a/frontend/benefit/applicant/browser-tests/page-model/step1.ts b/frontend/benefit/applicant/browser-tests/page-model/step1.ts index 40973194fc..01b4b10c95 100644 --- a/frontend/benefit/applicant/browser-tests/page-model/step1.ts +++ b/frontend/benefit/applicant/browser-tests/page-model/step1.ts @@ -1,3 +1,5 @@ +import { t } from 'testcafe'; + import WizardStep from './WizardStep'; class Step1 extends WizardStep { @@ -19,6 +21,27 @@ class Step1 extends WizardStep { ), }); + private deminimisAmount = this.component.findByRole('textbox', { + name: this.regexp( + this.translations.applications.sections.company.fields.deMinimisAidAmount + .label + ), + }); + + private deminimisGranter = this.component.findByRole('textbox', { + name: this.regexp( + this.translations.applications.sections.company.fields.deMinimisAidGranter + .label + ), + }); + + private deminimisGrantedAt = this.component.findByRole('textbox', { + name: this.regexp( + this.translations.applications.sections.company.fields + .deMinimisAidGrantedAt.label + ), + }); + private lastName = this.component.findByRole('textbox', { name: this.regexp( this.translations.applications.sections.company.fields @@ -64,6 +87,18 @@ class Step1 extends WizardStep { .no, }); + private deMinimisAidTrue = this.within( + this.component.getByRole('group', { + name: this.regexp( + this.translations.applications.sections.company.fields.deMinimisAid + .label + ), + }) + ).findByRole('radio', { + name: this.translations.applications.sections.company.fields.deMinimisAid + .yes, + }); + hasImmediateManagerCheckbox = this.component.findByRole('checkbox', { name: this.regexp( this.translations.applications.sections.employee.fields @@ -106,6 +141,32 @@ class Step1 extends WizardStep { return this.fillInput(this.email, email); } + public async fillDeminimisAid( + granter?: string, + amount?: string, + grantedAt?: string + ): Promise { + if (granter) await this.fillInput(this.deminimisGranter, granter); + if (amount) await this.fillInput(this.deminimisAmount, amount); + if (grantedAt) await this.fillInput(this.deminimisGrantedAt, grantedAt); + return this.clickDeminimisSave(); + } + + private deminimisSave = this.component.findByRole('button', { + name: this.translations.applications.sections.company.deMinimisAidsAdd, + }); + + private deminimisRemove = (index: number): SelectorPromise => + this.component.findByTestId(`deminimis-remove-${index}`); + + public clickDeminimisSave(): Promise { + return t.click(this.deminimisSave); + } + + public clickDeminimisRemove(index: number): Promise { + return t.click(this.deminimisRemove(index)); + } + public selectNoBusinessActivities(): Promise { return this.clickSelectRadioButton(this.businessActivitiesFalse); } @@ -114,6 +175,10 @@ class Step1 extends WizardStep { return this.clickSelectRadioButton(this.deMinimisAidFalse); } + public selectYesDeMinimis(): Promise { + return this.clickSelectRadioButton(this.deMinimisAidTrue); + } + public selectNocoOperationNegotiations(): Promise { return this.clickSelectRadioButton(this.coOperationNegotiationsFalse); } diff --git a/frontend/benefit/applicant/browser-tests/utils/url.utils.ts b/frontend/benefit/applicant/browser-tests/utils/url.utils.ts index 1f7c97994a..5cc686aab7 100644 --- a/frontend/benefit/applicant/browser-tests/utils/url.utils.ts +++ b/frontend/benefit/applicant/browser-tests/utils/url.utils.ts @@ -1,4 +1,11 @@ import { getUrl } from '@frontend/shared/browser-tests/utils/url.utils'; +import { ClientFunction } from 'testcafe'; export const getFrontendUrl = (path = ''): string => getUrl(process.env.APPLICANT_URL ?? 'https://localhost:3000', path); + +const goBack = ClientFunction(() => window.history.back()); + +export const clickBrowserBackButton = async (): Promise => { + await goBack(); +};