diff --git a/playwright-e2e/dsm/component/kitType/enums/kitType-enum.ts b/playwright-e2e/dsm/component/kitType/enums/kitType-enum.ts index c130e9da9e..85b5ad4af3 100644 --- a/playwright-e2e/dsm/component/kitType/enums/kitType-enum.ts +++ b/playwright-e2e/dsm/component/kitType/enums/kitType-enum.ts @@ -2,5 +2,7 @@ export enum KitTypeEnum { SALIVA = 'SALIVA', BLOOD = 'BLOOD', STOOL = 'STOOL', - BLOOD_AND_RNA = 'BLOOD & RNA' + BLOOD_AND_RNA = 'BLOOD & RNA', + FFPE_SECTION = 'FFPE-SECTION', + FFPE_SCROLL = 'FFPE-SCROLL' } diff --git a/playwright-e2e/dsm/component/kitType/kitType.ts b/playwright-e2e/dsm/component/kitType/kitType.ts index b4b790155d..57d70e1d18 100644 --- a/playwright-e2e/dsm/component/kitType/kitType.ts +++ b/playwright-e2e/dsm/component/kitType/kitType.ts @@ -14,7 +14,7 @@ export class KitType { } /* XPaths */ - private kitTypeCheckbox(kitType: KitTypeEnum): string { + public kitTypeCheckbox(kitType: KitTypeEnum): string { return `//mat-checkbox[.//label/span[text()[normalize-space()='${kitType}']]]`; } } diff --git a/playwright-e2e/dsm/pages/kit-page-base.ts b/playwright-e2e/dsm/pages/kit-page-base.ts new file mode 100644 index 0000000000..e6dd9fa13a --- /dev/null +++ b/playwright-e2e/dsm/pages/kit-page-base.ts @@ -0,0 +1,44 @@ +import { Page, expect } from '@playwright/test'; +import DsmPageBase from './dsm-page-base'; +import { KitsTable } from 'dsm/component/tables/kits-table'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import Checkbox from 'dss/component/checkbox'; +import { waitForNoSpinner } from 'utils/test-utils'; + +export default abstract class KitPageBase extends DsmPageBase { + protected abstract defaultKitTypes: KitTypeEnum[]; + private readonly kitsQueueTable = new KitsTable(this.page); + + constructor(readonly page: Page) { + super(page); + } + + public get kitsTable(): KitsTable { + return this.kitsQueueTable; + } + + public async waitForReady(kitTypes?: KitTypeEnum[]): Promise { + const knownKitTypes = kitTypes ?? this.defaultKitTypes; + await Promise.all([ + this.page.waitForLoadState(), + expect(this.page.locator('h1')).toHaveText('Kit Queue') + ]); + await expect(async () => expect(await this.page.locator('mat-checkbox[id]').count()).toBeGreaterThanOrEqual(1)).toPass({ timeout: 60000 }); + await this.assertDisplayedKitTypes(knownKitTypes); + await waitForNoSpinner(this.page); + } + + public async assertDisplayedKitTypes(kitTypes: KitTypeEnum[]): Promise { + for (const kitType of kitTypes) { + await expect(this.getKitCheckbox(kitType).toLocator()).toBeVisible(); + } + } + + public getKitCheckbox(buttonLabel: KitTypeEnum): Checkbox { + return new Checkbox(this.page, { label: buttonLabel }); + } + + public async selectKitType(buttonLabel: KitTypeEnum): Promise { + await this.getKitCheckbox(buttonLabel).check(); + } +} diff --git a/playwright-e2e/dsm/pages/kit-queue-page.ts b/playwright-e2e/dsm/pages/kit-queue-page.ts new file mode 100644 index 0000000000..5eee7933c9 --- /dev/null +++ b/playwright-e2e/dsm/pages/kit-queue-page.ts @@ -0,0 +1,33 @@ +import { Page, expect } from '@playwright/test'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import { KitType } from 'dsm/component/kitType/kitType'; +import Checkbox from 'dss/component/checkbox'; +import { waitForNoSpinner } from 'utils/test-utils'; +import KitPageBase from './kit-page-base'; + +export default class KitQueuePage extends KitPageBase { + private readonly defaultKitTypes = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; + + private readonly kitType = new KitType(this.page); + + constructor(page: Page) { + super(page); + } + + public async waitForReady(kitTypes?: KitTypeEnum[]): Promise { + const knownKitTypes = kitTypes ?? this.defaultKitTypes; + await Promise.all([ + this.page.waitForLoadState(), + expect(this.page.locator('h1')).toHaveText('Kit Queue') + ]); + await expect(async () => expect(await this.page.locator('mat-checkbox[id]').count()).toBeGreaterThanOrEqual(1)).toPass({ timeout: 60000 }); + await this.assertDisplayedKitTypes(knownKitTypes); + await waitForNoSpinner(this.page); + } + + public async assertDisplayedKitTypes(kitTypes: KitTypeEnum[]): Promise { + for (const kitType of kitTypes) { + await expect(this.kitType.displayedKitType(kitType)).toBeVisible() + } + } +} diff --git a/playwright-e2e/dsm/pages/kitUpload-page/kitUpload-page.ts b/playwright-e2e/dsm/pages/kitUpload-page/kitUpload-page.ts index 11e4040163..ec6f2e611c 100644 --- a/playwright-e2e/dsm/pages/kitUpload-page/kitUpload-page.ts +++ b/playwright-e2e/dsm/pages/kitUpload-page/kitUpload-page.ts @@ -24,7 +24,7 @@ export default class KitUploadPage { this.page.waitForLoadState(), this.assertPageTitle() ]); - await expect(this.skipAddressValidationCheckbox).toBeVisible(); + await expect(this.skipAddressValidationCheckbox).toBeVisible({timeout: 60 * 1000}); await waitForNoSpinner(this.page); await this.assertDisplayedKitTypes(knownKitTypes); } @@ -119,9 +119,7 @@ export default class KitUploadPage { } public async assertInstructionSnapshot() { - expect(await this.page.locator(this.uploadInstructionsXPath).screenshot(), - "Kit Upload page - Kit upload instructions screenshot doesn't match the provided one") - .toMatchSnapshot('upload_instructions.png'); + await expect(this.page.locator(this.uploadInstructionsXPath)).toHaveScreenshot('upload_instructions.png'); } public async assertDisplayedKitTypes(kitTypes: KitTypeEnum[]): Promise { @@ -133,7 +131,7 @@ export default class KitUploadPage { } public async assertBrowseBtn(): Promise { - await expect(this.page.locator('//label[text()[normalize-space()=\'Browse...\']][@class=\'label-button\']'), + await expect(this.browseBtn, 'Kit Upload page - Browse button is not visible') .toBeVisible(); } @@ -152,6 +150,10 @@ export default class KitUploadPage { return this.page.locator('//mat-checkbox[.//*[@class="mat-checkbox-label" and text()="Skip address validation on upload"]]'); } + public get browseBtn(): Locator { + return this.page.locator('//label[text()[normalize-space()=\'Browse...\']][@class=\'label-button\']'); + } + /* XPaths */ private get uploadInstructionsXPath(): string { return "//div[./b[text()[normalize-space()='Upload instructions:']]]" diff --git a/playwright-e2e/dsm/pages/kitsInfo-pages/kitsWithoutLabel-page.ts b/playwright-e2e/dsm/pages/kitsInfo-pages/kitsWithoutLabel-page.ts index f6fcd7e221..45ab95e970 100644 --- a/playwright-e2e/dsm/pages/kitsInfo-pages/kitsWithoutLabel-page.ts +++ b/playwright-e2e/dsm/pages/kitsInfo-pages/kitsWithoutLabel-page.ts @@ -15,6 +15,8 @@ export default class KitsWithoutLabelPage { KitsColumnsEnum.DDP_REALM, KitsColumnsEnum.TYPE, '']; // the last item is empty string because the deactivate buttons columns doesn't have one + private readonly expectedKitTypes = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; + private readonly kitType = new KitType(this.page); private readonly kitsTable = new KitsTable(this.page); @@ -24,6 +26,10 @@ export default class KitsWithoutLabelPage { return this.kitsTable; } + public get kitTypeCheckbox(): KitType { + return this.kitType; + } + public async goToPage(page: number): Promise { await this.kitsTable.goToPage(page); } @@ -32,11 +38,23 @@ export default class KitsWithoutLabelPage { await this.kitsTable.rowsPerPage(rows); } - public async waitForReady(): Promise { - await this.assertPageTitle(); - await waitForNoSpinner(this.page); + public async waitForReady(kitTypes?: KitTypeEnum[]): Promise { + const knownKitTypes = kitTypes ?? this.expectedKitTypes; //Use the param kit types if provided, if they are not, then use the general expected kit types + await Promise.all([ + this.page.waitForLoadState(), + this.assertPageTitle() + ]); await expect(async () => expect(await this.page.locator('mat-checkbox[id]').count()).toBeGreaterThanOrEqual(1)) .toPass({ timeout: 60000 }); + await this.assertDisplayedKitTypes(knownKitTypes); + } + + public async assertDisplayedKitTypes(kitTypes: KitTypeEnum[]): Promise { + await waitForNoSpinner(this.page); + for (const kitType of kitTypes) { + await expect(this.kitType.displayedKitType(kitType), + 'Kit without Labels page - Displayed kit types checkboxes are wrong').toBeVisible() + } } public async selectKitType(kitType: KitTypeEnum): Promise { @@ -126,11 +144,11 @@ export default class KitsWithoutLabelPage { + "//div[@class='app-modal-footer']/button[text()[normalize-space()='Deactivate']]"; } - private get reloadKitListBtnXPath(): string { + public get reloadKitListBtnXPath(): string { return '//button[normalize-space()="Reload Kit List"]'; } - private get createLabelsBtnXPath(): string { + public get createLabelsBtnXPath(): string { return '//button[normalize-space()="Create Labels"]'; } } diff --git a/playwright-e2e/dss/component/table.ts b/playwright-e2e/dss/component/table.ts index 002028230b..84643602ed 100644 --- a/playwright-e2e/dss/component/table.ts +++ b/playwright-e2e/dss/component/table.ts @@ -356,7 +356,7 @@ export default class Table { } public rowCountButton(rowCount = 10): Locator { - return this.footerLocator().locator(`xpath=//button[contains(., "${rowCount}")]`); + return this.footerLocator().locator(`xpath=//button[contains(., "${rowCount}")] | //a[contains(., "${rowCount}")]`); } private parseForNumber(text: string): number | null { diff --git a/playwright-e2e/tests/dsm/kitUploadFlow/kit-initial-scan-page-validation.spec.ts b/playwright-e2e/tests/dsm/kitUploadFlow/kit-initial-scan-page-validation.spec.ts index b4920a69e1..2a0f6e7ddc 100644 --- a/playwright-e2e/tests/dsm/kitUploadFlow/kit-initial-scan-page-validation.spec.ts +++ b/playwright-e2e/tests/dsm/kitUploadFlow/kit-initial-scan-page-validation.spec.ts @@ -82,6 +82,3 @@ test.describe.serial('Initial Scan page', () => { }); } }) - -// kit-d9b76c66-6 -// PAHV44 diff --git a/playwright-e2e/tests/dsm/kitUploadFlow/kit-queue-ui.spec.ts b/playwright-e2e/tests/dsm/kitUploadFlow/kit-queue-ui.spec.ts new file mode 100644 index 0000000000..20aedae4a0 --- /dev/null +++ b/playwright-e2e/tests/dsm/kitUploadFlow/kit-queue-ui.spec.ts @@ -0,0 +1,62 @@ +import {expect} from '@playwright/test'; +import {test} from 'fixtures/dsm-fixture'; +import {WelcomePage} from 'dsm/pages/welcome-page'; +import {Navigation} from 'dsm/component/navigation/navigation'; +import {StudyEnum} from 'dsm/component/navigation/enums/selectStudyNav-enum'; +import {SamplesNavEnum} from 'dsm/component/navigation/enums/samplesNav-enum'; +import {KitsColumnsEnum} from 'dsm/pages/kitsInfo-pages/enums/kitsColumns-enum'; +import {defaultKitTypes, studyShortName} from 'utils/test-utils'; +import KitQueuePage from 'dsm/pages/kit-queue-page'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; + +test.describe('Kits without Labels UI', () => { + let welcomePage: WelcomePage; + let navigation: Navigation; + + const studies = [StudyEnum.OSTEO2, StudyEnum.PANCAN, StudyEnum.RGP]; + + test.beforeEach(({page, request}) => { + welcomePage = new WelcomePage(page); + navigation = new Navigation(page, request); + }); + + for (const study of studies) { + test(`Page verifications @dsm @${study} @kit`, async ({page}) => { + const expectedKitSelection = defaultKitTypes(study); + const { realm: expectedRealm } = studyShortName(study); + await welcomePage.selectStudy(study); + + const kitQueuePage = await navigation.selectFromSamples(SamplesNavEnum.QUEUE); + await kitQueuePage.waitForReady(expectedKitSelection); + + expect(await kitQueuePage.getKitCheckbox(KitTypeEnum.SALIVA).isChecked()).toBeFalsy(); + expect(await kitQueuePage.getKitCheckbox(KitTypeEnum.BLOOD).isChecked()).toBeFalsy(); + + const kitsTable = kitQueuePage.kitsTable; + + for (const kitType of expectedKitSelection) { + await kitQueuePage.selectKitType(kitType); + await expect(page.locator(kitsWithoutLabelPage.reloadKitListBtnXPath)).toBeEnabled(); + const rows = await kitsTable.getRowsCount(); + if (rows > 0) { + await expect(page.locator(kitsWithoutLabelPage.createLabelsBtnXPath)).toBeDisabled(); + await kitsTable.rowCountButton(50).isVisible() && await kitsTable.changeRowCount(50); + } else { + await expect(page.locator('h4')).toHaveText('There are no kit requests'); + expect(await kitsTable.exists()).toBeFalsy(); + } + for (let i = 0; i < rows; i++) { + const typeValue = (await kitsTable.getRowText(i, KitsColumnsEnum.TYPE)).trim(); + // Kits in different types are not mixed. Kits should be uploaded for the right type. + expect.soft(typeValue).toStrictEqual(kitType); + const shortId = (await kitsTable.getRowText(i, KitsColumnsEnum.SHORT_ID)).trim(); + expect(shortId?.length).toBeTruthy(); + const realm = (await kitsTable.getRowText(i, KitsColumnsEnum.DDP_REALM)).trim(); + expect(realm).toStrictEqual(expectedRealm); + } + } + + expect(test.info().errors).toHaveLength(0); + }) + } +}) diff --git a/playwright-e2e/tests/dsm/kitUploadFlow/kit-upload-ui.spec.ts b/playwright-e2e/tests/dsm/kitUploadFlow/kit-upload-ui.spec.ts new file mode 100644 index 0000000000..85a4f38eaa --- /dev/null +++ b/playwright-e2e/tests/dsm/kitUploadFlow/kit-upload-ui.spec.ts @@ -0,0 +1,40 @@ +import {expect} from '@playwright/test'; +import {test} from 'fixtures/dsm-fixture'; +import {WelcomePage} from 'dsm/pages/welcome-page'; +import {Navigation} from 'dsm/component/navigation/navigation'; +import {StudyEnum} from 'dsm/component/navigation/enums/selectStudyNav-enum'; +import {SamplesNavEnum} from 'dsm/component/navigation/enums/samplesNav-enum'; +import KitUploadPage from 'dsm/pages/kitUpload-page/kitUpload-page'; +import {defaultKitTypes} from 'utils/test-utils'; + +test.describe('Kits Upload UI', () => { + let welcomePage: WelcomePage; + let navigation: Navigation; + + const studies = [StudyEnum.OSTEO2, StudyEnum.PANCAN, StudyEnum.RGP]; + + test.beforeEach(({page, request}) => { + welcomePage = new WelcomePage(page); + navigation = new Navigation(page, request); + }); + + for (const study of studies) { + test(`Page verifications @dsm @${study} @kit`, async ({page}) => { + const expectedKitSelection = defaultKitTypes(study); + await welcomePage.selectStudy(study); + + const kitUploadPage = await navigation.selectFromSamples(SamplesNavEnum.KIT_UPLOAD); + await kitUploadPage.waitForReady(expectedKitSelection); + + for (const kitType of expectedKitSelection) { + await expect.soft(kitUploadPage.browseBtn).toBeHidden(); + await kitUploadPage.selectKitType(kitType); + await expect.soft(kitUploadPage.browseBtn).toBeVisible(); + await expect.soft(page.locator('app-filepicker .FilePicker--Text')).toHaveText('No File selected'); + await kitUploadPage.selectKitType(kitType); // un-check + } + + expect(test.info().errors).toHaveLength(0); + }) + } +}) diff --git a/playwright-e2e/tests/dsm/kitUploadFlow/kit-without-labels-ui.spec.ts b/playwright-e2e/tests/dsm/kitUploadFlow/kit-without-labels-ui.spec.ts new file mode 100644 index 0000000000..6f2d8fc669 --- /dev/null +++ b/playwright-e2e/tests/dsm/kitUploadFlow/kit-without-labels-ui.spec.ts @@ -0,0 +1,55 @@ +import {expect} from '@playwright/test'; +import {test} from 'fixtures/dsm-fixture'; +import {WelcomePage} from 'dsm/pages/welcome-page'; +import {Navigation} from 'dsm/component/navigation/navigation'; +import {StudyEnum} from 'dsm/component/navigation/enums/selectStudyNav-enum'; +import {SamplesNavEnum} from 'dsm/component/navigation/enums/samplesNav-enum'; +import KitsWithoutLabelPage from 'dsm/pages/kitsInfo-pages/kitsWithoutLabel-page'; +import {KitsColumnsEnum} from 'dsm/pages/kitsInfo-pages/enums/kitsColumns-enum'; +import {defaultKitTypes, studyShortName} from 'utils/test-utils'; + +test.describe('Kits without Labels UI', () => { + let welcomePage: WelcomePage; + let navigation: Navigation; + + const studies = [StudyEnum.OSTEO2, StudyEnum.PANCAN, StudyEnum.RGP]; + + test.beforeEach(({page, request}) => { + welcomePage = new WelcomePage(page); + navigation = new Navigation(page, request); + }); + + for (const study of studies) { + test(`Page verifications @dsm @${study} @kit`, async ({page}) => { + const expectedKitSelection = defaultKitTypes(study); + const { realm: expectedRealm } = studyShortName(study); + await welcomePage.selectStudy(study); + + const kitsWithoutLabelPage = await navigation.selectFromSamples(SamplesNavEnum.KITS_WITHOUT_LABELS); + await kitsWithoutLabelPage.waitForReady(expectedKitSelection); + const kitsTable = kitsWithoutLabelPage.kitsWithoutLabelTable; + + for (const kitType of expectedKitSelection) { + await kitsWithoutLabelPage.selectKitType(kitType); + await expect(page.locator(kitsWithoutLabelPage.reloadKitListBtnXPath)).toBeEnabled(); + const rows = await kitsTable.getRowsCount(); + if (rows > 0) { + await expect(page.locator(kitsWithoutLabelPage.createLabelsBtnXPath)).toBeDisabled(); + await kitsTable.rowCountButton(50).isVisible() && await kitsTable.changeRowCount(50); + } else { + await expect(page.locator('h4')).toHaveText('There are no kit requests'); + expect(await kitsTable.exists()).toBeFalsy(); + } + for (let i = 0; i < rows; i++) { + const typeValue = (await kitsTable.getRowText(i, KitsColumnsEnum.TYPE)).trim(); + // Kits in different types are not mixed. Kits should be uploaded for the right type. + expect(typeValue).toStrictEqual(kitType); + const shortId = (await kitsTable.getRowText(i, KitsColumnsEnum.SHORT_ID)).trim(); + expect(shortId?.length).toBeTruthy(); + const realm = (await kitsTable.getRowText(i, KitsColumnsEnum.DDP_REALM)).trim(); + expect(realm).toStrictEqual(expectedRealm); + } + } + }) + } +}) diff --git a/playwright-e2e/tests/dsm/kitUploadFlow/blood-and-rna-kit-upload-flow.spec.ts b/playwright-e2e/tests/dsm/kitUploadFlow/rgp-blood-and-rna-kit-upload-flow.spec.ts similarity index 99% rename from playwright-e2e/tests/dsm/kitUploadFlow/blood-and-rna-kit-upload-flow.spec.ts rename to playwright-e2e/tests/dsm/kitUploadFlow/rgp-blood-and-rna-kit-upload-flow.spec.ts index df7eceadca..a58bbb0a56 100644 --- a/playwright-e2e/tests/dsm/kitUploadFlow/blood-and-rna-kit-upload-flow.spec.ts +++ b/playwright-e2e/tests/dsm/kitUploadFlow/rgp-blood-and-rna-kit-upload-flow.spec.ts @@ -88,7 +88,6 @@ test.describe.skip('Blood & RNA Kit Upload', () => { //Upload a Blood & RNA kit const kitUploadPage = await navigation.selectFromSamples(SamplesNavEnum.KIT_UPLOAD); await kitUploadPage.waitForReady(expectedKitTypes); - await kitUploadPage.assertPageTitle(); await kitUploadPage.selectKitType(kitType); await kitUploadPage.assertBrowseBtn(); await kitUploadPage.assertUploadKitsBtn(); diff --git a/playwright-e2e/utils/test-utils.ts b/playwright-e2e/utils/test-utils.ts index 0850418108..bbdcafee4d 100644 --- a/playwright-e2e/utils/test-utils.ts +++ b/playwright-e2e/utils/test-utils.ts @@ -5,6 +5,7 @@ import Checkbox from 'dss/component/checkbox'; import Select from 'dss/component/select'; import axios from 'axios'; import { logError } from './log-utils'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; export interface WaitForResponse { uri: string; @@ -262,6 +263,11 @@ export function studyShortName(study: StudyEnum): { shortName: string | null; re realm = 'cmi-esc'; collaboratorPrefix = 'GECProject'; break; + case StudyEnum.RGP: + shortName = 'rgp'; + realm = 'RGP'; + collaboratorPrefix = 'NULL'; + break; default: throw new Error(`Study ${study} is undefined.`); } @@ -295,3 +301,16 @@ export async function toHaveScreenshot(page: Page, locator: Locator | string, na const loc = typeof locator === 'string' ? page.locator(locator) : locator; await expect.soft(loc).toHaveScreenshot(name); } + +export function defaultKitTypes(study: StudyEnum): KitTypeEnum[] { + let types = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; + switch (study) { + case StudyEnum.PANCAN: + types = types.concat([KitTypeEnum.STOOL]); + break; + case StudyEnum.RGP: + types = [KitTypeEnum.BLOOD, KitTypeEnum.BLOOD_AND_RNA]; + break; + } + return types; +}