From e7dc74f3e73e53b6562d606a3d9bf65cb160c460 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Thu, 17 Aug 2023 14:50:35 -0400 Subject: [PATCH 01/14] samples received in progress --- .../filters/sections/customize-view.ts | 10 +++ .../dsm/pages/participant-list-page.ts | 45 ++++++++++++ ...t-saliva-kit-and-then-tumor-sample.spec.ts | 70 +++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts diff --git a/playwright-e2e/dsm/component/filters/sections/customize-view.ts b/playwright-e2e/dsm/component/filters/sections/customize-view.ts index 2985f43795..cc7dd87e3c 100644 --- a/playwright-e2e/dsm/component/filters/sections/customize-view.ts +++ b/playwright-e2e/dsm/component/filters/sections/customize-view.ts @@ -96,4 +96,14 @@ export class CustomizeView { private columnPathXPath(columnName: string): string { return `/ul/li/mat-checkbox[label[.//*[text()[normalize-space()='${columnName}']]]]`; } + + public async columnGroupIsDisplayed(columnGroupName: string): Promise { + //Note: Some studies have column groups that share the same name + const numberOfMatches = await this.page.locator(`//button[contains(@data-toggle, 'dropdown') and contains(., '${columnGroupName}')]`).count(); + if (numberOfMatches > 0) { + return true; + } else { + return false; + } + } } diff --git a/playwright-e2e/dsm/pages/participant-list-page.ts b/playwright-e2e/dsm/pages/participant-list-page.ts index 9cac0234bb..b4b27bfdb0 100644 --- a/playwright-e2e/dsm/pages/participant-list-page.ts +++ b/playwright-e2e/dsm/pages/participant-list-page.ts @@ -8,6 +8,7 @@ import Checkbox from 'dss/component/checkbox'; import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; import { Filters } from 'dsm/component/filters/filters'; import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; export default class ParticipantListPage { private readonly PAGE_TITLE: string = 'Participant List'; @@ -227,6 +228,50 @@ export default class ParticipantListPage { await waitForNoSpinner(this.page); } + /** + * Function to search for a participant that does not have a specific kit type + * @param kitType the kit type being searched for to make sure the participant has no history e.g. they have not had a saliva kit sent or received + * @returns the short id of the matched participant + */ + async findParticipantWithoutKitType(kitType: KitTypeEnum): Promise { + const participantListTable = this.participantListTable; + + //First filter for enrolled participants + const searchPanel = this.filters.searchPanel; + await searchPanel.open(); + await searchPanel.checkboxes('Status', { checkboxValues: ['Enrolled'] }); + await searchPanel.search(); + expect(await participantListTable.rowsCount).toBeGreaterThanOrEqual(1); + + //Make sure the following columns are selected - not all studies might have the following columns selected as part of their default filter: + //Participant Columns -> Short ID (usually selected in the default filter) + //Sample Columns -> Sample Type, Status + const customizeViewPanel = this.filters.customizeViewPanel; + await customizeViewPanel.open(); + + //Note: Not all studies have a Sample Columns group + expect(await customizeViewPanel.columnGroupIsDisplayed('Sample Columns'), 'ERROR: Sample Columns group is not displayed').toBe(true); + + await customizeViewPanel.deselectColumns('Participant Columns', ['Status']); //To reduce confusion when Sample Columns -> Status is added and filtered + await customizeViewPanel.selectColumns('Sample Columns', ['Sample Type', 'Status']); + + await searchPanel.open(); + await searchPanel.checkboxes('Sample Type', { checkboxValues: ['SALIVA'] }); + await searchPanel.radioButton('Status', { radioButtonValue: 'Waiting on GP' }); + await searchPanel.search(); + + const kitSampleTypeColumn = 'Sample Type'; + const kitSampleStatusColumn = 'Status'; + const participantListRows = await participantListTable.rowsCount; + + for (let count = 0; count < participantListRows; count++) { + const participantSampleStatus: string[] = (await participantListTable.getParticipantDataAt(count, kitSampleStatusColumn)).split('/n'); + console.log(`Participant Sample Status info: ${participantSampleStatus.length} \n`); + } + + return 'some promise string'; + } + async findParticipantForKitUpload(): Promise { const participantListTable = this.participantListTable; diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts new file mode 100644 index 0000000000..3a92954778 --- /dev/null +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -0,0 +1,70 @@ +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import { StudyEnum } from 'dsm/component/navigation/enums/selectStudyNav-enum'; +import { Navigation } from 'dsm/component/navigation/navigation'; +import HomePage from 'dsm/pages/home-page'; +import { WelcomePage } from 'dsm/pages/welcome-page'; +import { test } from 'fixtures/dsm-fixture'; +import {login} from 'authentication/auth-dsm'; +import Select from 'dss/component/select'; +import ParticipantListPage from 'dsm/pages/participant-list-page'; +import { StudyNavEnum } from 'dsm/component/navigation/enums/studyNav-enum'; +import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; + +test.describe('Samples Received Event - Recieved saliva kit first and then tumor sample', () => { + const studies = [StudyEnum.OSTEO2, StudyEnum.LMS]; + let welcomePage: WelcomePage; + let navigation: Navigation; + let homePage: HomePage; + + const kitType = KitTypeEnum.SALIVA; + const expectedKitTypes = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; + + test.beforeEach(async ({ page, request }) => { + navigation = new Navigation(page, request); + welcomePage = new WelcomePage(page); + homePage = new HomePage(page); + }); + + for (const study of studies) { + test(`${study} - Verify SAMPLES_RECEIVED occurs if the saliva kit is received before the tumor sample`, async ({ page }, testInfo) => { + const testResultDirectory = testInfo.outputDir; + + //Select the study + await new Select(page, { label: 'Select study' }).selectOption(`${study}`); + + //Find a participant who does not have any sent or received saliva or blood kits - who also has at least 1 physician's information in medical release + const participantListPage = await navigation.selectFromStudy(StudyNavEnum.PARTICIPANT_LIST); + await participantListPage.assertPageTitle(); + await participantListPage.waitForReady(); + + const shortID = await participantListPage.findParticipantWithoutKitType(KitTypeEnum.SALIVA); + + //Upload a saliva kit for the participant + + //Send out the saliva kit + + //Go to the participant's participant page + + //Go into their Onc History tab + + //Input a new row of onc history data, where at least the following is added: Date of PX + Accession Number; Afterwards change request status to 'Request' + + //Verify the Request checkbox appears + + //Verify that Download Request Documents button is interactable and can be used + + //Go into Onc History Detail a.k.a Tissue Information a.k.a Tissue Request page + + //Verify the onc history's Request Status is 'Sent' + + //Make sure the following details are added: + //Fax Sent, Tissue Received, Gender, Materials Received (note: only use USS or Scrolls), SM-IDs, Tumor Collaborator Sample ID, Date sent to GP + + //Receive the saliva kit + + //Receive the tumor sample + + //Verify the Germline Consent Addendum activity has been created for the participant + }); + } +}); From 459da15c30a1a261191630414876ac1d7c9b9c24 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 18 Aug 2023 15:44:35 -0400 Subject: [PATCH 02/14] wip --- .../filters/sections/search/search-enums.ts | 59 +++++++++++++++++++ .../filters/sections/search/search.ts | 18 +++++- .../dsm/pages/participant-list-page.ts | 16 +---- 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts index 541ac63087..875bc9d697 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts @@ -12,3 +12,62 @@ export enum CustomViewColumns { RESEARCH_CONSENT_FORM = 'Research Consent Form Columns', SAMPLE = 'Sample Columns', } + +/* Participant Column group related enums */ + +export enum ParticipantColumns { + CONSENT_BLOOD = 'Consent Blood', + CONSENT_TISSUE = 'Consent Tissue', + COUNTRY = 'Country', + DATE_OF_BIRTH = 'Date of Birth', + DATE_OF_MAJORITY = 'Date of Majority', + DDP = 'DDP', + DIAGNOSIS_MONTH = 'Diagnosis Month', + DIAGNOSIS_YEAR = 'Diagnosis Year', + DO_NOT_CONTACT = 'Do Not Contact', + EMAIL = 'Email', + FILE_UPLOAD_TIME = 'File Upload Time', + FIRST_NAME = 'First Name', + LAST_NAME = 'Last Name', + PARTICIPANT_ID = 'Participant ID', + PREFERRED_LANGUAGE = 'Preferred Language', + REGISTRATION_DATE = 'Registration Date', + SHORT_ID = 'Short ID', + STATUS = 'Status', + UPLOADED_FILE_NAME = 'Uploaded File Name', +} + +export enum EnrollmentStatus { + REGISTERED = 'Registered', + EXITED_BEFORE_ENROLLMENT = 'Exited before Enrollment', + EXITED_AFTER_ENROLLMENT = 'Exited after Enrollment', + ENROLLED = 'Enrolled', + LOST_TO_FOLLOWUP = 'Lost to Followup', + COMPLETED = 'Completed', +} + +/* Sample Column group related enums */ + +export enum SampleColumns { + COLLABORATOR_PARTICIPANT_ID = 'Collaborator Participant ID', + COLLECTION_DATE = 'Collection Date', + MF_CODE = 'MF code', + NORMAL_COLLABORATOR_SAMPLE_ID = 'Normal Collaborator Sample ID', + SAMPLE_DEACTIVATION = 'Sample Deactivation', + SAMPLE_NOTES = 'Sample Notes', + SAMPLE_RECEIVED = 'Sample Received', + SAMPLE_SENT = 'Sample Sent', + SAMPLE_TYPE = 'Sample Type', + SEQUENCING_RESTRICTION = 'Sequecung Restriction', + STATUS = 'Status', + TRACKING_IN = 'Tracking-in', + TRACKING_OUT = 'Tracking-out', +} + +export enum KitStatus { + WAITING_ON_GP = 'Waiting on GP', + GP_MANUAL_LABEL = 'GP manual Label', + DEACTIVATED = 'Deactivated', + SHIPPED = 'Shipped', + RECEIVED = 'Received', +} diff --git a/playwright-e2e/dsm/component/filters/sections/search/search.ts b/playwright-e2e/dsm/component/filters/sections/search/search.ts index 89cc9a7384..92c3daab10 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search.ts @@ -1,8 +1,9 @@ import { expect, Locator, Page } from '@playwright/test'; import DatePicker from 'dsm/component/date-picker'; import { CheckboxConfig, DateConfig, RadioButtonConfig, TextConfig } from 'dsm/component/filters/sections/search/search-types'; -import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums'; +import { AdditionalFilter, EnrollmentStatus, KitStatus, SampleColumns } from 'dsm/component/filters/sections/search/search-enums'; import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; export class Search { private readonly enUSDateRegExp = new RegExp(/\b(0[1-9]|1[012])([/])(0[1-9]|[12]\d|3[01])\2(\d{4})/); @@ -153,6 +154,21 @@ export class Search { return isDisabled || false; } + public async searchForParticipantsWithEnrollmentStatus(enrollmentStatuses: EnrollmentStatus[]): Promise { + await this.open(); + const amountOfStatusesToSelect = enrollmentStatuses.length; + for (let statusIndex = 0; statusIndex < amountOfStatusesToSelect; statusIndex++) { + + } + } + + public async searchForKitSampleStatus(kitTypes: KitTypeEnum[], kitStatus: KitStatus): Promise { + await this.open(); + await this.checkboxes(SampleColumns.SAMPLE_TYPE, { checkboxValues: kitTypes }); + await this.radioButton(SampleColumns.STATUS, { radioButtonValue: kitStatus }); + await this.search(); + } + /* Locators */ private checkboxLocator(columnName: string, checkboxName: string): Locator { diff --git a/playwright-e2e/dsm/pages/participant-list-page.ts b/playwright-e2e/dsm/pages/participant-list-page.ts index b4b27bfdb0..cecd120b77 100644 --- a/playwright-e2e/dsm/pages/participant-list-page.ts +++ b/playwright-e2e/dsm/pages/participant-list-page.ts @@ -9,6 +9,7 @@ import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; import { Filters } from 'dsm/component/filters/filters'; import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import { KitStatus } from 'dsm/component/filters/sections/search/search-enums'; export default class ParticipantListPage { private readonly PAGE_TITLE: string = 'Participant List'; @@ -255,20 +256,7 @@ export default class ParticipantListPage { await customizeViewPanel.deselectColumns('Participant Columns', ['Status']); //To reduce confusion when Sample Columns -> Status is added and filtered await customizeViewPanel.selectColumns('Sample Columns', ['Sample Type', 'Status']); - await searchPanel.open(); - await searchPanel.checkboxes('Sample Type', { checkboxValues: ['SALIVA'] }); - await searchPanel.radioButton('Status', { radioButtonValue: 'Waiting on GP' }); - await searchPanel.search(); - - const kitSampleTypeColumn = 'Sample Type'; - const kitSampleStatusColumn = 'Status'; - const participantListRows = await participantListTable.rowsCount; - - for (let count = 0; count < participantListRows; count++) { - const participantSampleStatus: string[] = (await participantListTable.getParticipantDataAt(count, kitSampleStatusColumn)).split('/n'); - console.log(`Participant Sample Status info: ${participantSampleStatus.length} \n`); - } - + await searchPanel.searchForKitSampleStatus([KitTypeEnum.SALIVA], KitStatus.WAITING_ON_GP); return 'some promise string'; } From fdfc36d2567ea0baef8f55f780079a37f467ac77 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Mon, 21 Aug 2023 15:17:04 -0400 Subject: [PATCH 03/14] WIP --- .../filters/sections/search/search.ts | 51 +++++++++++++++++-- .../tables/participant-list-table.ts | 31 +++++++++++ .../dsm/pages/participant-list-page.ts | 35 ++++++++----- ...t-saliva-kit-and-then-tumor-sample.spec.ts | 2 +- 4 files changed, 99 insertions(+), 20 deletions(-) diff --git a/playwright-e2e/dsm/component/filters/sections/search/search.ts b/playwright-e2e/dsm/component/filters/sections/search/search.ts index 92c3daab10..0c680fc420 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search.ts @@ -1,9 +1,10 @@ import { expect, Locator, Page } from '@playwright/test'; import DatePicker from 'dsm/component/date-picker'; import { CheckboxConfig, DateConfig, RadioButtonConfig, TextConfig } from 'dsm/component/filters/sections/search/search-types'; -import { AdditionalFilter, EnrollmentStatus, KitStatus, SampleColumns } from 'dsm/component/filters/sections/search/search-enums'; +import { AdditionalFilter, EnrollmentStatus, KitStatus, ParticipantColumns, SampleColumns } from 'dsm/component/filters/sections/search/search-enums'; import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; export class Search { private readonly enUSDateRegExp = new RegExp(/\b(0[1-9]|1[012])([/])(0[1-9]|[12]\d|3[01])\2(\d{4})/); @@ -156,10 +157,8 @@ export class Search { public async searchForParticipantsWithEnrollmentStatus(enrollmentStatuses: EnrollmentStatus[]): Promise { await this.open(); - const amountOfStatusesToSelect = enrollmentStatuses.length; - for (let statusIndex = 0; statusIndex < amountOfStatusesToSelect; statusIndex++) { - - } + await this.checkboxes(ParticipantColumns.STATUS, { checkboxValues: enrollmentStatuses }); + await this.search(); } public async searchForKitSampleStatus(kitTypes: KitTypeEnum[], kitStatus: KitStatus): Promise { @@ -169,6 +168,48 @@ export class Search { await this.search(); } + public async searchForParticipantWithUnsentSalivaKit(): Promise { + const [filterListReponse] = await Promise.all([ + this.page.waitForResponse(response => response.url().includes('/ui/filterList') && response.status() === 200), + this.searchForKitSampleStatus([KitTypeEnum.SALIVA], KitStatus.WAITING_ON_GP), + ]); + let responseBody = JSON.parse(await filterListReponse.text()); + const participantListTable = new ParticipantListTable(this.page); + const amountOfRowsDisplayed = await participantListTable.rowsCount; + console.log(`Amount of rows displayed: ${amountOfRowsDisplayed}`); + + //Check for a participant with a saliva kit that neither has scanDate or deactivatedDate + for (let index = 0; index < amountOfRowsDisplayed; index++) { + if (await participantListTable.onLastPage()) { + console.log('On last page'); + break; + } + console.log(`Participant ${index}'s information: ${responseBody.participants[index].esData.profile.hruid}`); + + if (this.isReadyToGoToTheNextPage(index, amountOfRowsDisplayed)) { + const [nextResponse] = await Promise.all([ + this.page.waitForResponse(response => response.url().includes('/ui/filterList') && response.status() === 200), + await participantListTable.nextPage(), + ]); + await participantListTable.waitForReady(); + responseBody = JSON.parse(await nextResponse.text()); + index = -1; + console.log('Should be on the next page now'); + } + } + return 'stuff'; + } + + /** + * Determines if it's time to go to the next page based on the current index used in a for-loop & whether the last row was looked at + * @param index Current index being used in a for-loop in a different method + * @param amountOfRowsDisplayed The amount of rows currently displayed in the DSM Participant List + * @returns if it's time to turn the page + */ + private isReadyToGoToTheNextPage(index: number, amountOfRowsDisplayed: number): boolean { + return (index > 0) && (index % (amountOfRowsDisplayed - 1) === 0); + } + /* Locators */ private checkboxLocator(columnName: string, checkboxName: string): Locator { diff --git a/playwright-e2e/dsm/component/tables/participant-list-table.ts b/playwright-e2e/dsm/component/tables/participant-list-table.ts index a21de08125..7486f88574 100644 --- a/playwright-e2e/dsm/component/tables/participant-list-table.ts +++ b/playwright-e2e/dsm/component/tables/participant-list-table.ts @@ -114,11 +114,42 @@ export class ParticipantListTable extends Table { return this.page.locator(`//table/tbody/tr`).nth(position); } + public async getLastPageNumber(): Promise { + const lastPageButton = this.lastPage; + const pageButtonContents = (await lastPageButton.innerText()).split(`You're on page`); + const pageNumber = pageButtonContents[1].trim(); + return parseInt(pageNumber); + } + + public async getCurrentPageNumber(): Promise { + const currentPageButton = this.currentPage; + const pageButtonContents = (await currentPageButton.innerText()).split(`You're on page`); + const pageNumber = pageButtonContents[1].trim(); + return parseInt(pageNumber); + } + + public async onLastPage(): Promise { + console.log(`Current Page #: ${await this.getCurrentPageNumber()}`); + console.log(`Last Page #: ${await this.getLastPageNumber()}`); + if (await this.getCurrentPageNumber() === await this.getLastPageNumber()) { + return true; + } + return false; + } + /* Locators */ public get rowsCount(): Promise { return this.getRowsCount(); } + public get lastPage(): Locator { + return this.page.locator(`//li[contains(@class, 'pagination-next')]/preceding-sibling::li[1]`); + } + + public get currentPage(): Locator { + return this.page.locator(`//li[contains(@class, 'current')]`); + } + /* XPaths */ private participantDataByXPath(columnName: string, columnValue: string, xColumnName: string): string { return ( diff --git a/playwright-e2e/dsm/pages/participant-list-page.ts b/playwright-e2e/dsm/pages/participant-list-page.ts index cecd120b77..9cd4bd40bd 100644 --- a/playwright-e2e/dsm/pages/participant-list-page.ts +++ b/playwright-e2e/dsm/pages/participant-list-page.ts @@ -9,7 +9,7 @@ import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; import { Filters } from 'dsm/component/filters/filters'; import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; -import { KitStatus } from 'dsm/component/filters/sections/search/search-enums'; +import { CustomViewColumns, EnrollmentStatus, KitStatus, ParticipantColumns } from 'dsm/component/filters/sections/search/search-enums'; export default class ParticipantListPage { private readonly PAGE_TITLE: string = 'Participant List'; @@ -230,33 +230,40 @@ export default class ParticipantListPage { } /** - * Function to search for a participant that does not have a specific kit type + * Function to search for a participant that has not had a specific kit type sent out * @param kitType the kit type being searched for to make sure the participant has no history e.g. they have not had a saliva kit sent or received * @returns the short id of the matched participant */ - async findParticipantWithoutKitType(kitType: KitTypeEnum): Promise { + async findParticipantWithoutSentKitType(kitType: KitTypeEnum): Promise { const participantListTable = this.participantListTable; - //First filter for enrolled participants const searchPanel = this.filters.searchPanel; - await searchPanel.open(); - await searchPanel.checkboxes('Status', { checkboxValues: ['Enrolled'] }); - await searchPanel.search(); + await searchPanel.searchForParticipantsWithEnrollmentStatus([EnrollmentStatus.ENROLLED]); expect(await participantListTable.rowsCount).toBeGreaterThanOrEqual(1); - //Make sure the following columns are selected - not all studies might have the following columns selected as part of their default filter: - //Participant Columns -> Short ID (usually selected in the default filter) - //Sample Columns -> Sample Type, Status const customizeViewPanel = this.filters.customizeViewPanel; await customizeViewPanel.open(); - - //Note: Not all studies have a Sample Columns group - expect(await customizeViewPanel.columnGroupIsDisplayed('Sample Columns'), 'ERROR: Sample Columns group is not displayed').toBe(true); + expect(await customizeViewPanel.columnGroupIsDisplayed(CustomViewColumns.SAMPLE), 'ERROR: Sample Columns group is not displayed').toBe(true); await customizeViewPanel.deselectColumns('Participant Columns', ['Status']); //To reduce confusion when Sample Columns -> Status is added and filtered await customizeViewPanel.selectColumns('Sample Columns', ['Sample Type', 'Status']); + await searchPanel.open(); + let validTestParticipantShortID: string; - await searchPanel.searchForKitSampleStatus([KitTypeEnum.SALIVA], KitStatus.WAITING_ON_GP); + switch (kitType) { + case KitTypeEnum.SALIVA: { + //Many study groups e.g. CMI have a saliva kit that gets automatically created and be found in Kits w/o Label; usually has Waiting on GP status + validTestParticipantShortID = await searchPanel.searchForParticipantWithUnsentSalivaKit(); + break; + } + case KitTypeEnum.BLOOD: { + //TODO Fill the case for blood kits; Note: blood kits are not usually automatically created + break; + } + default: { + break; + } + } return 'some promise string'; } diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index 3a92954778..cc8147a47f 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -37,7 +37,7 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor await participantListPage.assertPageTitle(); await participantListPage.waitForReady(); - const shortID = await participantListPage.findParticipantWithoutKitType(KitTypeEnum.SALIVA); + const shortID = await participantListPage.findParticipantWithoutSentKitType(KitTypeEnum.SALIVA); //Upload a saliva kit for the participant From 2222581f244b060c63b291b57fa9fcc59ce8d955 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Mon, 21 Aug 2023 15:37:40 -0400 Subject: [PATCH 04/14] tweak page number methods --- .../dsm/component/tables/participant-list-table.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/playwright-e2e/dsm/component/tables/participant-list-table.ts b/playwright-e2e/dsm/component/tables/participant-list-table.ts index 7486f88574..b47ad2504a 100644 --- a/playwright-e2e/dsm/component/tables/participant-list-table.ts +++ b/playwright-e2e/dsm/component/tables/participant-list-table.ts @@ -114,9 +114,13 @@ export class ParticipantListTable extends Table { return this.page.locator(`//table/tbody/tr`).nth(position); } + /** + * Returns the number of the last page of the participant list + * @returns The number of the last page button e.g. if there are 3 pages, this method returns: 3 + */ public async getLastPageNumber(): Promise { const lastPageButton = this.lastPage; - const pageButtonContents = (await lastPageButton.innerText()).split(`You're on page`); + const pageButtonContents = (await lastPageButton.innerText()).split('page'); const pageNumber = pageButtonContents[1].trim(); return parseInt(pageNumber); } @@ -129,8 +133,6 @@ export class ParticipantListTable extends Table { } public async onLastPage(): Promise { - console.log(`Current Page #: ${await this.getCurrentPageNumber()}`); - console.log(`Last Page #: ${await this.getLastPageNumber()}`); if (await this.getCurrentPageNumber() === await this.getLastPageNumber()) { return true; } From d23c698cba7e147c649cf502c33422ee35ace5ac Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Wed, 23 Aug 2023 11:50:46 -0400 Subject: [PATCH 05/14] valid test participants for saliva kit search found --- .../filters/sections/customize-view.ts | 2 +- .../filters/sections/search/search.ts | 22 +++++++++++++++++-- .../navigation/enums/accessibility-enum.ts | 4 ++++ .../tables/participant-list-table.ts | 7 +++--- .../dsm/pages/participant-list-page.ts | 8 +++---- ...t-saliva-kit-and-then-tumor-sample.spec.ts | 1 + 6 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 playwright-e2e/dsm/component/navigation/enums/accessibility-enum.ts diff --git a/playwright-e2e/dsm/component/filters/sections/customize-view.ts b/playwright-e2e/dsm/component/filters/sections/customize-view.ts index cc7dd87e3c..a190740f4c 100644 --- a/playwright-e2e/dsm/component/filters/sections/customize-view.ts +++ b/playwright-e2e/dsm/component/filters/sections/customize-view.ts @@ -97,7 +97,7 @@ export class CustomizeView { return `/ul/li/mat-checkbox[label[.//*[text()[normalize-space()='${columnName}']]]]`; } - public async columnGroupIsDisplayed(columnGroupName: string): Promise { + public async isColumnGroupDisplayed(columnGroupName: string): Promise { //Note: Some studies have column groups that share the same name const numberOfMatches = await this.page.locator(`//button[contains(@data-toggle, 'dropdown') and contains(., '${columnGroupName}')]`).count(); if (numberOfMatches > 0) { diff --git a/playwright-e2e/dsm/component/filters/sections/search/search.ts b/playwright-e2e/dsm/component/filters/sections/search/search.ts index 0c680fc420..ac12bbc50c 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search.ts @@ -174,9 +174,10 @@ export class Search { this.searchForKitSampleStatus([KitTypeEnum.SALIVA], KitStatus.WAITING_ON_GP), ]); let responseBody = JSON.parse(await filterListReponse.text()); + const participantListTable = new ParticipantListTable(this.page); const amountOfRowsDisplayed = await participantListTable.rowsCount; - console.log(`Amount of rows displayed: ${amountOfRowsDisplayed}`); + let validTestParticipantShortIDFound; //Check for a participant with a saliva kit that neither has scanDate or deactivatedDate for (let index = 0; index < amountOfRowsDisplayed; index++) { @@ -185,6 +186,23 @@ export class Search { break; } console.log(`Participant ${index}'s information: ${responseBody.participants[index].esData.profile.hruid}`); + const kitInformation = responseBody.participants[index].kits; + const amountOfKits = kitInformation.length; + console.log(`Participant kit amount: ${kitInformation.length}`); + for (let kitNumber = 0; kitNumber < amountOfKits; kitNumber++) { + console.log(`Participant kit info: ${kitInformation[kitNumber].kitTypeName}`); + if ((kitInformation[kitNumber].kitTypeName) === KitTypeEnum.SALIVA) { + if (kitInformation[kitNumber].scanDate === undefined && kitInformation[kitNumber].deactivatedDate === undefined) { + console.log(`ALERT: Valid participant found!`); + validTestParticipantShortIDFound = responseBody.participants[index].esData.profile.hruid; + break; + } + } + } + + if (validTestParticipantShortIDFound) { + break; + } if (this.isReadyToGoToTheNextPage(index, amountOfRowsDisplayed)) { const [nextResponse] = await Promise.all([ @@ -197,7 +215,7 @@ export class Search { console.log('Should be on the next page now'); } } - return 'stuff'; + return validTestParticipantShortIDFound; } /** diff --git a/playwright-e2e/dsm/component/navigation/enums/accessibility-enum.ts b/playwright-e2e/dsm/component/navigation/enums/accessibility-enum.ts new file mode 100644 index 0000000000..e0d44ced40 --- /dev/null +++ b/playwright-e2e/dsm/component/navigation/enums/accessibility-enum.ts @@ -0,0 +1,4 @@ +export enum ScreenReaderText { + CURRENT_PAGE = `You're on page`, + GENERAL_PAGE = `page`, +} diff --git a/playwright-e2e/dsm/component/tables/participant-list-table.ts b/playwright-e2e/dsm/component/tables/participant-list-table.ts index b47ad2504a..59721202c6 100644 --- a/playwright-e2e/dsm/component/tables/participant-list-table.ts +++ b/playwright-e2e/dsm/component/tables/participant-list-table.ts @@ -7,6 +7,7 @@ import { getDate, offsetDaysFromToday } from 'utils/date-utils'; import { waitForNoSpinner } from 'utils/test-utils'; import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums'; import ParticipantListPage from 'dsm/pages/participant-list-page'; +import { ScreenReaderText } from '../navigation/enums/accessibility-enum'; export class ParticipantListTable extends Table { private readonly _participantPage: ParticipantPage = new ParticipantPage(this.page); @@ -120,14 +121,14 @@ export class ParticipantListTable extends Table { */ public async getLastPageNumber(): Promise { const lastPageButton = this.lastPage; - const pageButtonContents = (await lastPageButton.innerText()).split('page'); - const pageNumber = pageButtonContents[1].trim(); + const pageButtonContents0Based = (await lastPageButton.innerText()).split(ScreenReaderText.GENERAL_PAGE); + const pageNumber = pageButtonContents0Based[1].trim(); return parseInt(pageNumber); } public async getCurrentPageNumber(): Promise { const currentPageButton = this.currentPage; - const pageButtonContents = (await currentPageButton.innerText()).split(`You're on page`); + const pageButtonContents = (await currentPageButton.innerText()).split(ScreenReaderText.CURRENT_PAGE); const pageNumber = pageButtonContents[1].trim(); return parseInt(pageNumber); } diff --git a/playwright-e2e/dsm/pages/participant-list-page.ts b/playwright-e2e/dsm/pages/participant-list-page.ts index 9cd4bd40bd..12447ae909 100644 --- a/playwright-e2e/dsm/pages/participant-list-page.ts +++ b/playwright-e2e/dsm/pages/participant-list-page.ts @@ -230,7 +230,7 @@ export default class ParticipantListPage { } /** - * Function to search for a participant that has not had a specific kit type sent out + * Searches for a participant that has not had a specific kit type sent out * @param kitType the kit type being searched for to make sure the participant has no history e.g. they have not had a saliva kit sent or received * @returns the short id of the matched participant */ @@ -243,12 +243,12 @@ export default class ParticipantListPage { const customizeViewPanel = this.filters.customizeViewPanel; await customizeViewPanel.open(); - expect(await customizeViewPanel.columnGroupIsDisplayed(CustomViewColumns.SAMPLE), 'ERROR: Sample Columns group is not displayed').toBe(true); + expect(await customizeViewPanel.isColumnGroupDisplayed(CustomViewColumns.SAMPLE), 'ERROR: Sample Columns group is not displayed').toBe(true); await customizeViewPanel.deselectColumns('Participant Columns', ['Status']); //To reduce confusion when Sample Columns -> Status is added and filtered await customizeViewPanel.selectColumns('Sample Columns', ['Sample Type', 'Status']); await searchPanel.open(); - let validTestParticipantShortID: string; + let validTestParticipantShortID = ''; switch (kitType) { case KitTypeEnum.SALIVA: { @@ -264,7 +264,7 @@ export default class ParticipantListPage { break; } } - return 'some promise string'; + return validTestParticipantShortID; } async findParticipantForKitUpload(): Promise { diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index cc8147a47f..9cca57f790 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -38,6 +38,7 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor await participantListPage.waitForReady(); const shortID = await participantListPage.findParticipantWithoutSentKitType(KitTypeEnum.SALIVA); + console.log(`Planned test participant: ${shortID}`); //Upload a saliva kit for the participant From 1e4fcd6a8cdfe277acf65823b569fa4d65656c47 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Wed, 23 Aug 2023 15:55:09 -0400 Subject: [PATCH 06/14] up until the onc history tab section --- .../filters/sections/search/search-enums.ts | 14 ++++ .../filters/sections/search/search.ts | 4 ++ .../participant-page/participant-page.ts | 37 ++++++++++ ...t-saliva-kit-and-then-tumor-sample.spec.ts | 68 +++++++++++++++++-- 4 files changed, 119 insertions(+), 4 deletions(-) diff --git a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts index 875bc9d697..26f5da1bd3 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts @@ -71,3 +71,17 @@ export enum KitStatus { SHIPPED = 'Shipped', RECEIVED = 'Received', } + +/* Contact Information Columns group enums */ + +export enum ContactInformation { + CITY = 'City', + COUNTRY = 'Country', + MAIL_TO_NAME = 'Mail To Name', + PHONE = 'Phone', + STATE = 'State', + STREET_ONE = 'Street 1', + STREET_TWO = 'Street 2', + VALID = 'Valid', + ZIP = 'Zip', +} diff --git a/playwright-e2e/dsm/component/filters/sections/search/search.ts b/playwright-e2e/dsm/component/filters/sections/search/search.ts index ac12bbc50c..807dca7680 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search.ts @@ -168,6 +168,10 @@ export class Search { await this.search(); } + /** + * Searches for the first instance of a participant that has no sent saliva kits + * @returns the short id of the found participant + */ public async searchForParticipantWithUnsentSalivaKit(): Promise { const [filterListReponse] = await Promise.all([ this.page.waitForResponse(response => response.url().includes('/ui/filterList') && response.status() === 200), diff --git a/playwright-e2e/dsm/pages/participant-page/participant-page.ts b/playwright-e2e/dsm/pages/participant-page/participant-page.ts index 38c8439203..36f68cee3b 100644 --- a/playwright-e2e/dsm/pages/participant-page/participant-page.ts +++ b/playwright-e2e/dsm/pages/participant-page/participant-page.ts @@ -3,6 +3,8 @@ import {waitForResponse} from 'utils/test-utils'; import {MainInfoEnum} from 'dsm/pages/participant-page/enums/main-info-enum'; import Tabs from 'dsm/component/tabs/tabs'; import {TabEnum} from 'dsm/component/tabs/enums/tab-enum'; +import { KitUploadInfo } from '../kitUpload-page/models/kitUpload-model'; +import ContactInformationTab from 'dsm/component/tabs/contactInformationTab'; export default class ParticipantPage { private readonly PAGE_TITLE: string = 'Participant Page'; @@ -89,6 +91,41 @@ export default class ParticipantPage { private readMainCheckboxValueFor(key: MainInfoEnum) { return this.page.locator(this.getMainCheckboxValueInfoXPath(key)).isChecked(); } + + /** + * Checks a participant's Contact Information tab in order to make a KitUploadInfo object + * @param shortID participant's short id + * @returns KitUploadInfo object that can be used for kit upload + */ + public async getContactInformation(shortID: string): Promise { + //Check to make sure only the intended participant's contact information is used + const pageShortID = await this.getShortId(); + expect(pageShortID, `ERROR - Wrong participant page: Currently on ${pageShortID}'s participant page, not ${shortID}'s`).toEqual(shortID); + + //Check for Contact Information tab since not all studies have it + const hasContactInformationTab = await this.isTabVisible(TabEnum.CONTACT_INFORMATION); + expect(hasContactInformationTab, `Participant ${shortID} does not have a Contact Information Tab`).toBe(true); + const kitUploadInfo = new KitUploadInfo( + shortID, + await this.getFirstName(), + await this.getLastName(), + ); + + //If participant's address is valid, use that - else just use the test address which is already set + if (hasContactInformationTab) { + const contactInformationTab = await this.clickTab(TabEnum.CONTACT_INFORMATION); + const hasValidAddress = JSON.parse(await contactInformationTab.getValid()); + if (hasValidAddress) { + kitUploadInfo.street1 = await contactInformationTab.getStreet1(); + kitUploadInfo.city = await contactInformationTab.getCity(); + kitUploadInfo.postalCode = await contactInformationTab.getZip(); + kitUploadInfo.state = await contactInformationTab.getState(); + kitUploadInfo.country = await contactInformationTab.getCountry(); + } + } + return kitUploadInfo; + } + /* ---- */ /* Locators */ diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index 9cca57f790..539f6c4fce 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -9,12 +9,22 @@ import Select from 'dss/component/select'; import ParticipantListPage from 'dsm/pages/participant-list-page'; import { StudyNavEnum } from 'dsm/component/navigation/enums/studyNav-enum'; import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; +import KitsWithoutLabelPage from 'dsm/pages/kitsInfo-pages/kitsWithoutLabel-page'; +import { SamplesNavEnum } from 'dsm/component/navigation/enums/samplesNav-enum'; +import { KitUploadInfo } from 'dsm/pages/kitUpload-page/models/kitUpload-model'; +import { expect } from '@playwright/test'; +import KitUploadPage from 'dsm/pages/kitUpload-page/kitUpload-page'; +import InitialScanPage from 'dsm/pages/scanner-pages/initialScan-page'; +import { KitsColumnsEnum } from 'dsm/pages/kitsInfo-pages/enums/kitsColumns-enum'; +import FinalScanPage from 'dsm/pages/scanner-pages/finalScan-page'; +import { TabEnum } from 'dsm/component/tabs/enums/tab-enum'; test.describe('Samples Received Event - Recieved saliva kit first and then tumor sample', () => { const studies = [StudyEnum.OSTEO2, StudyEnum.LMS]; let welcomePage: WelcomePage; let navigation: Navigation; let homePage: HomePage; + let kitUploadInfo: KitUploadInfo; const kitType = KitTypeEnum.SALIVA; const expectedKitTypes = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; @@ -37,17 +47,67 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor await participantListPage.assertPageTitle(); await participantListPage.waitForReady(); - const shortID = await participantListPage.findParticipantWithoutSentKitType(KitTypeEnum.SALIVA); - console.log(`Planned test participant: ${shortID}`); + const participantShortID = await participantListPage.findParticipantWithoutSentKitType(KitTypeEnum.SALIVA); + console.log(`Planned test participant: ${participantShortID}`); - //Upload a saliva kit for the participant + //Get the participant information that is needed to do a kit upload + await participantListPage.reloadWithDefaultFilter(); + await participantListPage.filterListByShortId(participantShortID); + + const participantListTable = new ParticipantListTable(page); + const amountOfParticipants = await participantListTable.rowsCount; + expect(amountOfParticipants).toBe(1); //Placement of the participant in the participant list after filtering + + const participantPage = await participantListTable.openParticipantPageAt(amountOfParticipants - 1); //Count starts from zero + kitUploadInfo = await participantPage.getContactInformation(participantShortID); - //Send out the saliva kit + //Deactivate existing saliva kit(s) + const kitsWithoutLabelPage = await navigation.selectFromSamples(SamplesNavEnum.KITS_WITHOUT_LABELS); + await kitsWithoutLabelPage.waitForLoad(); + await kitsWithoutLabelPage.assertPageTitle(); + await kitsWithoutLabelPage.selectKitType(kitType); + await kitsWithoutLabelPage.assertCreateLabelsBtn(); + await kitsWithoutLabelPage.assertReloadKitListBtn(); + await kitsWithoutLabelPage.assertTableHeader(); + await kitsWithoutLabelPage.deactivateAllKitsFor(participantShortID); + + //Upload a saliva kit for the participant + const kitUploadPage = await navigation.selectFromSamples(SamplesNavEnum.KIT_UPLOAD); + await kitUploadPage.waitForLoad(); + await kitUploadPage.assertPageTitle(); + await kitUploadPage.assertDisplayedKitTypes(expectedKitTypes); + await kitUploadPage.selectKitType(kitType); + await kitUploadPage.assertBrowseBtn(); + await kitUploadPage.assertUploadKitsBtn(); + await kitUploadPage.uploadFile(kitType, [kitUploadInfo], study, testResultDirectory); + + //Go to Kits w/o Label in order to get the Shipping ID a.k.a DSM Label + await navigation.selectFromSamples(SamplesNavEnum.KITS_WITHOUT_LABELS); + await kitsWithoutLabelPage.waitForLoad(); + await kitsWithoutLabelPage.selectKitType(kitType); + await kitsWithoutLabelPage.search(KitsColumnsEnum.SHORT_ID, participantShortID); + const shippingID = (await kitsWithoutLabelPage.getData(KitsColumnsEnum.SHIPPING_ID)).trim(); + + //Send out the saliva kit - Note: PE-CGS saliva kit flow is: Kit Upload -> Kits w/o Label -> Initial Scan -> Final Scan + const initialScanPage = await navigation.selectFromSamples(SamplesNavEnum.INITIAL_SCAN); + await initialScanPage.assertPageTitle(); + const kitLabel = `kit-${crypto.randomUUID().toString().substring(0, 10)}`; //Saliva PE-CGS kit labels must be 14 chars + await initialScanPage.fillScanPairs([kitLabel, participantShortID]); + await initialScanPage.save(); + + const finalScan = await navigation.selectFromSamples(SamplesNavEnum.FINAL_SCAN); + await finalScan.assertPageTitle(); + await finalScan.fillScanPairs([kitLabel, shippingID]); + await finalScan.save(); //Go to the participant's participant page + await navigation.selectFromStudy(StudyNavEnum.PARTICIPANT_LIST); + await participantListPage.filterListByShortId(participantShortID); + await participantListTable.openParticipantPageAt(0); //Go into their Onc History tab + //Input a new row of onc history data, where at least the following is added: Date of PX + Accession Number; Afterwards change request status to 'Request' //Verify the Request checkbox appears From 54bd4834da9daaa12d3fb143634f65d935a6fcad Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Wed, 23 Aug 2023 17:12:57 -0400 Subject: [PATCH 07/14] onc history automation in progress --- .../component/tabs/enums/oncHistory-enum.ts | 28 ++++++++++++++ .../dsm/component/tabs/enums/tab-enum.ts | 1 + .../tabs/model/oncHistoryDetailModel.ts | 38 +++++++++++++++++++ .../dsm/component/tabs/oncHistoryTab.ts | 0 4 files changed, 67 insertions(+) create mode 100644 playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts create mode 100644 playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts create mode 100644 playwright-e2e/dsm/component/tabs/oncHistoryTab.ts diff --git a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts new file mode 100644 index 0000000000..6f03853acb --- /dev/null +++ b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts @@ -0,0 +1,28 @@ +export enum OncHistoryRequestStatus { + NEEDS_REVIEW = 'Needs Review', + DONT_REQUEST = `Don't Request`, + ON_HOLD = 'On Hold', + REQUEST = 'Request', + SENT = 'Sent', + RECEIVED = 'Received', + RETURNED = 'Returned', + UNABLE_TO_OBTAIN = 'Unable To Obtain', +} + +export enum Decalcification { + NITRIC_ACID = `Nitric Acid (includes Perenyi's fluid)`, + HYDROCHLORIC_ACID = `Hydrochloric Acid (includes Von Ebner's solution)`, + FORMIC_ACID = `Formic Acid (includes Evans/Kajian, Kristensen/Gooding/Stewart)`, + ACID_NOS = 'Acid NOS', + EDTA = 'EDTA', + SAMPLE_NOT_DECALCIFIED = 'Sample not decalcified', + OTHER = 'Other', + UNKNOWN = 'Unknown', + IMMUNOCAL = 'Immunocal/Soft Decal', +} + +export enum GeneralAnswer { + YES = 'Yes', + NO = 'No', + UNKNOWN = 'Unknown', +} diff --git a/playwright-e2e/dsm/component/tabs/enums/tab-enum.ts b/playwright-e2e/dsm/component/tabs/enums/tab-enum.ts index 609b113c70..473cbe0925 100644 --- a/playwright-e2e/dsm/component/tabs/enums/tab-enum.ts +++ b/playwright-e2e/dsm/component/tabs/enums/tab-enum.ts @@ -4,4 +4,5 @@ export enum TabEnum { INVITAE = 'Invitae', SAMPLE_INFORMATION = 'Sample Information', SURVEY_DATA = 'Survey Data', + ONC_HISTORY = 'Onc History', } diff --git a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts new file mode 100644 index 0000000000..0e5530f749 --- /dev/null +++ b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts @@ -0,0 +1,38 @@ +import { Decalcification, GeneralAnswer, OncHistoryRequestStatus } from '../enums/oncHistory-enum' + +interface OncHistoryDetail { + requestOncHistoryDetail(): Promise, + accessTissueInformation(): Promise, + dateOfPX?: string | Date, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + accessionNumber?: string, + facility?: string, + phone?: string, + fax?: string, + destructionPolicy?: string | number + setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise, +} + +interface Osteo2OncHistoryDetail extends OncHistoryDetail{ + localControl?: GeneralAnswer, + decalcification?: Decalcification, + ffpe?: GeneralAnswer, + blocksWithTumor?: string, + tumorSize?: string, + blockToRequest?: string, + necrosis?: string, + viableTumor?: string, +} + +interface LMSOncHistoryDetail extends OncHistoryDetail{ + tumorSize?: string, + slidesToRequest?: string, + facilityWhereSampleWasReviewed?: string, + slidesTotal?: string, + blocksToRequest?: string, + treatmentEffect?: string, + viableTumor?: string, + necrosis?: string, +} diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts new file mode 100644 index 0000000000..e69de29bb2 From 1099cd123c6e01b8366618844625163cf7fb9421 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Mon, 28 Aug 2023 09:59:51 -0400 Subject: [PATCH 08/14] WIP might be deleting oncHistoryDetailRow.ts --- .../filters/sections/search/search-enums.ts | 2 +- .../tables/participant-list-table.ts | 9 +- .../component/tabs/enums/oncHistory-enum.ts | 28 +++ .../tabs/model/oncHistoryDetailModel.ts | 11 +- .../dsm/component/tabs/oncHistoryDetailRow.ts | 176 ++++++++++++++++++ .../dsm/component/tabs/oncHistoryTab.ts | 72 +++++++ 6 files changed, 290 insertions(+), 8 deletions(-) create mode 100644 playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts diff --git a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts index 26f5da1bd3..a409df0487 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search-enums.ts @@ -58,7 +58,7 @@ export enum SampleColumns { SAMPLE_RECEIVED = 'Sample Received', SAMPLE_SENT = 'Sample Sent', SAMPLE_TYPE = 'Sample Type', - SEQUENCING_RESTRICTION = 'Sequecung Restriction', + SEQUENCING_RESTRICTION = 'Sequencing Restriction', STATUS = 'Status', TRACKING_IN = 'Tracking-in', TRACKING_OUT = 'Tracking-out', diff --git a/playwright-e2e/dsm/component/tables/participant-list-table.ts b/playwright-e2e/dsm/component/tables/participant-list-table.ts index 59721202c6..0dc1c6793e 100644 --- a/playwright-e2e/dsm/component/tables/participant-list-table.ts +++ b/playwright-e2e/dsm/component/tables/participant-list-table.ts @@ -117,15 +117,20 @@ export class ParticipantListTable extends Table { /** * Returns the number of the last page of the participant list + * @type pagebuttonContents - 0 based- string array that splits "page" and {page number} * @returns The number of the last page button e.g. if there are 3 pages, this method returns: 3 */ public async getLastPageNumber(): Promise { const lastPageButton = this.lastPage; - const pageButtonContents0Based = (await lastPageButton.innerText()).split(ScreenReaderText.GENERAL_PAGE); - const pageNumber = pageButtonContents0Based[1].trim(); + const pageButtonContents = (await lastPageButton.innerText()).split(ScreenReaderText.GENERAL_PAGE); + const pageNumber = pageButtonContents[1].trim(); return parseInt(pageNumber); } + /** + * Return the current page number + * @returns @type pagebuttonContents - 0 based- string array that splits "You're on page" and {page number} + */ public async getCurrentPageNumber(): Promise { const currentPageButton = this.currentPage; const pageButtonContents = (await currentPageButton.innerText()).split(ScreenReaderText.CURRENT_PAGE); diff --git a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts index 6f03853acb..6a90adcd86 100644 --- a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts +++ b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts @@ -26,3 +26,31 @@ export enum GeneralAnswer { NO = 'No', UNKNOWN = 'Unknown', } + +/* Lists the placements of certain columns in the onc history. Note: Number assumes 0-based/counting from zero */ +export enum OncHistoryColumn { + DATE_OF_PX = 2, + TYPE_OF_PX = 3, + LOCATION_OF_PX = 4, + HISTOLOGY = 5, + ACCESSION_NUMBER = 6, + FACILITY = 7, + PHONE = 8, + FAX = 9, + DESTRUCTION_POLICY = 10, + OS2_SAMPLE_FROM_LOCAL_CONTROL = 11, + LMS_TUMOR_SIZE = 11, + OS2_DECALCIFICATION = 12, + LMS_SLIDES_TO_REQUEST = 12, + OS2_FFPE = 13, + LMS_FACILITY_WHERE_SAMPLE_REVIEWED = 13, + OS2_BLOCKS_WITH_TUMOR = 14, + LMS_SLIDES_TOTAL = 14, + OS2_TUMOR_SIZE = 15, + LMS_BLOCKS_TO_REQUEST = 15, + OS2_NECROSIS = 16, + LMS_TREATMENT_EFFECT = 16, + VIABLE_TUMOR = 17, + LMS_NECROSIS = 18, + REQUEST_STATUS = 21, +} diff --git a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts index 0e5530f749..6b24ae11a2 100644 --- a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts +++ b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts @@ -1,8 +1,9 @@ import { Decalcification, GeneralAnswer, OncHistoryRequestStatus } from '../enums/oncHistory-enum' -interface OncHistoryDetail { +export interface OncHistoryDetail { + _oncHistoryID?: number, requestOncHistoryDetail(): Promise, - accessTissueInformation(): Promise, + accessTissueRequestPage(): Promise, dateOfPX?: string | Date, typeOfPX?: string, locationOfPX?: string, @@ -11,11 +12,11 @@ interface OncHistoryDetail { facility?: string, phone?: string, fax?: string, - destructionPolicy?: string | number + destructionPolicy?: string | number, setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise, } -interface Osteo2OncHistoryDetail extends OncHistoryDetail{ +export interface Osteo2OncHistoryDetail extends OncHistoryDetail{ localControl?: GeneralAnswer, decalcification?: Decalcification, ffpe?: GeneralAnswer, @@ -26,7 +27,7 @@ interface Osteo2OncHistoryDetail extends OncHistoryDetail{ viableTumor?: string, } -interface LMSOncHistoryDetail extends OncHistoryDetail{ +export interface LMSOncHistoryDetail extends OncHistoryDetail{ tumorSize?: string, slidesToRequest?: string, facilityWhereSampleWasReviewed?: string, diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts new file mode 100644 index 0000000000..687da42503 --- /dev/null +++ b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts @@ -0,0 +1,176 @@ +import { OncHistoryDetail } from 'dsm/component/tabs/model/oncHistoryDetailModel'; +import { Locator, Page, expect } from '@playwright/test'; +import { OncHistoryColumn, OncHistoryRequestStatus } from './enums/oncHistory-enum'; + +export default class OncHistoryDetailRow { + private _oncHistoryID!: number; + private _dateOfPX!: string | Date; + private _typeOfPX!: string; + private _locationOfPx!: string; + private _histology!: string; + private _accessionNumber!: string; + private _facility!: string; + private _phone!: string; + private _fax!: string; + private _destructionPolicy!: string; + + constructor(protected readonly page: Page) { + this._oncHistoryID; + this._dateOfPX; + this._typeOfPX; + this._locationOfPx; + this._histology; + this._accessionNumber; + this._facility; + this._phone; + this._fax; + this._destructionPolicy; + } + + /* Getters and Setters */ + + public set oncHistoryID(id: number) { + this._oncHistoryID = id; + } + + public get oncHistoryID(): number { + return this._oncHistoryID; + } + + public set dateOfPX(diagnosisDate: string | Date) { + this._dateOfPX = diagnosisDate; + } + + public get dateOfPX(): string { + return this._dateOfPX as string; + } + + public set typeOfPX(diagnosisType: string) { + this._typeOfPX = diagnosisType; + } + + public get typeOfPX(): string { + return this._typeOfPX; + } + + public set locationOfPX(location: string) { + this._locationOfPx = location; + } + + public get locationOfPX(): string { + return this._locationOfPx; + } + + public set histology(histology: string) { + this._histology = histology; + } + + public get histology(): string { + return this._histology; + } + + public set accessionNumber(accessionNumber: string) { + this._accessionNumber = accessionNumber; + } + + public get accessionNumber(): string { + return this._accessionNumber; + } + + public set facility(facility: string) { + this._facility = facility; + } + + public get facility(): string { + return this._facility; + } + + public set phone(phoneNumber: string) { + this._phone = phoneNumber; + } + + public get phone(): string { + return this._phone; + } + + public set fax(faxNumber: string) { + this._fax = faxNumber; + } + + public get fax(): string { + return this._fax; + } + + public set destructionPolicy(amountOfYears: number | string) { + this._destructionPolicy = amountOfYears as string; + } + + public get destructionPolicy(): string { + return this._destructionPolicy; + } + + /* Basic onc history related functions */ + public async requestOncHistoryDetail(): Promise { + const checkbox = await this.getRequestOncHistoryDetailCheckbox(); + await checkbox.check(); + } + + public async accessTissueRequestPage(): Promise { + const button = await this.getTissueRequestPageButton(); + await button.click(); + } + + public async setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise { + const id = this.assertOncHistoryIDIsAssigned(); + const requestDropdown = this.page.locator(`//tr[@id='${id}']//td[${OncHistoryColumn.REQUEST_STATUS}]//mat-select`); + } + + + + /* Locators */ + + public getDownloadRequestDocumentsButton(): Locator { + return this.page.getByRole('button', { name: 'Download Request Documents' }); + } + + public async clickDownloadRequestDocuments(): Promise { + const documentsButton = this.getDownloadRequestDocumentsButton(); + await documentsButton.click(); + } + + public getDownloadPDFBundleButton(): Locator { + return this.page.getByRole('button', { name: 'Download PDF Bundle' }); + } + + public async clickDownloadPDFBundle(): Promise { + const bundleButton = this.getDownloadPDFBundleButton(); + await bundleButton.click(); + } + + /* Onc History specific helper methods */ + + private async getRequestOncHistoryDetailCheckbox(): Promise { + const id = this.assertOncHistoryIDIsAssigned(); + + //Checkbox only appears if the onc history status is set to Request + const requestStatus = await this.getOncHistoryRequestStatus(); + expect(requestStatus, `ERROR: Onc History id ${id}'s status is ${requestStatus}, not Request - Onc History request checkbox cannot be seen`). + toBe(OncHistoryRequestStatus.REQUEST); + + const checkbox = this.page.locator(`//tr[@id='${id}']//button[@tooltip='Tissue information']/preceding-sibling::mat-checkbox`); + return checkbox; + } + + private async getTissueRequestPageButton(): Promise { + const id = this.assertOncHistoryIDIsAssigned(); + const button = this.page.locator(`//tr[@id='${id}']//button[@tooltip='Tissue information']`); + return button; + } + + private assertOncHistoryIDIsAssigned(): number { + //First check to make sure that the onc history deatil has an assigned id + const id = this._oncHistoryID; + expect(id, 'ERROR: Onc History id is null').not.toBeNull(); + return id; + } +} diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts index e69de29bb2..e43eba9664 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts @@ -0,0 +1,72 @@ +import {Locator, Page} from '@playwright/test'; +import { LMSOncHistoryDetail, OncHistoryDetail, Osteo2OncHistoryDetail } from 'dsm/component/tabs/model/oncHistoryDetailModel'; +import { GeneralAnswer, Decalcification } from './enums/oncHistory-enum'; +import { StudyEnum } from '../navigation/enums/selectStudyNav-enum'; + +export default class OncHistoryTab { + constructor(private readonly page: Page) {} + + public get addOncHistory() { + const page = this.page; + + return new class implements OncHistoryDetail, Osteo2OncHistoryDetail, LMSOncHistoryDetail { + async createOncHistoryDetail(opts: { + study: StudyEnum, + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string, + localControl?: GeneralAnswer, + decalcification?: Decalcification, + ffpe?: GeneralAnswer, + blocksWithTumor?: string, + tumorSize?: string, + blocksToRequest?: string, + necrosis?: string, + viableTumor?: string, + slidesToRequest?: string, + facilityWhereSampleWasReviewed?: string, + slidesTotal?: string, + treatmentEffect?: string, + }): Promise { + switch (study) { + case StudyEnum.OSTEO2: + //Handle inputting onc history for OS2 - do a wait for a patch request and get the onc istory id after that + + break; + case StudyEnum.LMS: + //Handle inputting onc history for LMS - do a wait for a patch request and get the onc istory id after that + break; + default: + //Handle inputting onc history for all other CMI research studies - do a wait for a patch request and get the onc istory id after that + break; + } + } + } + } + + public async clickDownloadRequestDocuments(): Promise { + const documentsButton = this.getDownloadRequestDocumentsButton(); + await documentsButton.click(); + } + + public async clickDownloadPDFBundle(): Promise { + const bundleButton = this.getDownloadPDFBundleButton(); + await bundleButton.click(); + } + + /* Locators */ + + public getDownloadRequestDocumentsButton(): Locator { + return this.page.getByRole('button', { name: 'Download Request Documents' }); + } + + public getDownloadPDFBundleButton(): Locator { + return this.page.getByRole('button', { name: 'Download PDF Bundle' }); + } +} From 8d714c497e369bbb92b89b7632349302499327a6 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Mon, 28 Aug 2023 12:19:58 -0400 Subject: [PATCH 09/14] WIP --- .../dsm/component/tabs/oncHistoryTab.ts | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts index e43eba9664..b9841b0a27 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts @@ -11,7 +11,6 @@ export default class OncHistoryTab { return new class implements OncHistoryDetail, Osteo2OncHistoryDetail, LMSOncHistoryDetail { async createOncHistoryDetail(opts: { - study: StudyEnum, dateOfPX: string, accessionNumber: string, facility: string, @@ -20,32 +19,37 @@ export default class OncHistoryTab { typeOfPX?: string, locationOfPX?: string, histology?: string, - destructionPolicy?: string, - localControl?: GeneralAnswer, - decalcification?: Decalcification, - ffpe?: GeneralAnswer, - blocksWithTumor?: string, - tumorSize?: string, - blocksToRequest?: string, - necrosis?: string, - viableTumor?: string, - slidesToRequest?: string, - facilityWhereSampleWasReviewed?: string, - slidesTotal?: string, - treatmentEffect?: string, + destructionPolicy?: string }): Promise { - switch (study) { - case StudyEnum.OSTEO2: - //Handle inputting onc history for OS2 - do a wait for a patch request and get the onc istory id after that + const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; + } - break; - case StudyEnum.LMS: - //Handle inputting onc history for LMS - do a wait for a patch request and get the onc istory id after that - break; - default: - //Handle inputting onc history for all other CMI research studies - do a wait for a patch request and get the onc istory id after that - break; - } + async createOsteoOncHistoryDetail(opts: { + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string + }): Promise { + const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; + } + + async createLMSOncHistoryDetail(opts: { + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string + }): Promise { + const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; } } } From cb96b98b7700b8c1946bca02ebebaa375dcaf4dd Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 8 Sep 2023 15:35:43 -0400 Subject: [PATCH 10/14] onc history automation WIP --- .../component/tabs/enums/oncHistory-enum.ts | 4 +- .../tabs/model/oncHistoryDetailModel.ts | 16 +- .../dsm/component/tabs/oncHistoryDetailRow.ts | 478 ++++++++++++++++-- .../dsm/component/tabs/oncHistoryTab.ts | 136 +++-- ...t-saliva-kit-and-then-tumor-sample.spec.ts | 39 +- 5 files changed, 594 insertions(+), 79 deletions(-) diff --git a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts index 6a90adcd86..c7fea77019 100644 --- a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts +++ b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts @@ -19,12 +19,14 @@ export enum Decalcification { OTHER = 'Other', UNKNOWN = 'Unknown', IMMUNOCAL = 'Immunocal/Soft Decal', + BLANK = '', } export enum GeneralAnswer { YES = 'Yes', NO = 'No', UNKNOWN = 'Unknown', + BLANK = '', } /* Lists the placements of certain columns in the onc history. Note: Number assumes 0-based/counting from zero */ @@ -38,7 +40,7 @@ export enum OncHistoryColumn { PHONE = 8, FAX = 9, DESTRUCTION_POLICY = 10, - OS2_SAMPLE_FROM_LOCAL_CONTROL = 11, + OS2_LOCAL_CONTROL = 11, LMS_TUMOR_SIZE = 11, OS2_DECALCIFICATION = 12, LMS_SLIDES_TO_REQUEST = 12, diff --git a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts index 6b24ae11a2..c324ab0040 100644 --- a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts +++ b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts @@ -1,10 +1,10 @@ import { Decalcification, GeneralAnswer, OncHistoryRequestStatus } from '../enums/oncHistory-enum' export interface OncHistoryDetail { - _oncHistoryID?: number, + oncHistoryID?: number, requestOncHistoryDetail(): Promise, accessTissueRequestPage(): Promise, - dateOfPX?: string | Date, + dateOfPX?: string, typeOfPX?: string, locationOfPX?: string, histology?: string, @@ -13,10 +13,6 @@ export interface OncHistoryDetail { phone?: string, fax?: string, destructionPolicy?: string | number, - setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise, -} - -export interface Osteo2OncHistoryDetail extends OncHistoryDetail{ localControl?: GeneralAnswer, decalcification?: Decalcification, ffpe?: GeneralAnswer, @@ -25,15 +21,9 @@ export interface Osteo2OncHistoryDetail extends OncHistoryDetail{ blockToRequest?: string, necrosis?: string, viableTumor?: string, -} - -export interface LMSOncHistoryDetail extends OncHistoryDetail{ - tumorSize?: string, slidesToRequest?: string, facilityWhereSampleWasReviewed?: string, slidesTotal?: string, - blocksToRequest?: string, treatmentEffect?: string, - viableTumor?: string, - necrosis?: string, + setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise, } diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts index 687da42503..baebe41368 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts @@ -1,35 +1,59 @@ import { OncHistoryDetail } from 'dsm/component/tabs/model/oncHistoryDetailModel'; import { Locator, Page, expect } from '@playwright/test'; -import { OncHistoryColumn, OncHistoryRequestStatus } from './enums/oncHistory-enum'; +import { Decalcification, GeneralAnswer, OncHistoryColumn, OncHistoryRequestStatus } from './enums/oncHistory-enum'; +import { waitForResponse } from 'utils/test-utils'; +import { StudyEnum } from '../navigation/enums/selectStudyNav-enum'; -export default class OncHistoryDetailRow { +export default class OncHistoryDetailRow implements OncHistoryDetail { private _oncHistoryID!: number; - private _dateOfPX!: string | Date; + private _dateOfPX!: string; private _typeOfPX!: string; - private _locationOfPx!: string; + private _locationOfPX!: string; private _histology!: string; private _accessionNumber!: string; private _facility!: string; private _phone!: string; private _fax!: string; private _destructionPolicy!: string; + private _localControl!: GeneralAnswer; + private _decalcification!: Decalcification; + private _ffpe!: GeneralAnswer; + private _blocksWithTumor!: string; + private _tumorSize!: string; + private _necrosis!: string; + private _viableTumor!: string; + private _slidesToRequest!: string; + private _facilityWhereSampleWasReviewed!: string; + private _slidesTotal!: string; + private _blocksToRequest!: string; + private _treatmentEffect!: string; constructor(protected readonly page: Page) { this._oncHistoryID; this._dateOfPX; this._typeOfPX; - this._locationOfPx; + this._locationOfPX; this._histology; this._accessionNumber; this._facility; this._phone; this._fax; this._destructionPolicy; + this._localControl; + this._decalcification; + this._ffpe; + this._blocksWithTumor; + this._tumorSize; + this._necrosis; + this._viableTumor; + this._slidesToRequest; + this._facilityWhereSampleWasReviewed; + this._slidesTotal; } /* Getters and Setters */ - public set oncHistoryID(id: number) { + private set oncHistoryID(id: number) { this._oncHistoryID = id; } @@ -37,7 +61,12 @@ export default class OncHistoryDetailRow { return this._oncHistoryID; } - public set dateOfPX(diagnosisDate: string | Date) { + private async setOncHistoryDetailID(currentRow: Locator): Promise { + const oncHistoryDetailID = parseInt(await currentRow.getAttribute('id') as string); + this.oncHistoryID = oncHistoryDetailID; + } + + public set dateOfPX(diagnosisDate: string) { this._dateOfPX = diagnosisDate; } @@ -45,6 +74,13 @@ export default class OncHistoryDetailRow { return this._dateOfPX as string; } + public async fillDateOfPXField(currentRow: Locator, dateOfPX: string): Promise { + this._dateOfPX = dateOfPX; + const dateOfPXField = currentRow.locator(`//td[${OncHistoryColumn.DATE_OF_PX}]//mat-form-field//input`); + await dateOfPXField.fill(this._dateOfPX); + await dateOfPXField.blur(); + } + public set typeOfPX(diagnosisType: string) { this._typeOfPX = diagnosisType; } @@ -53,12 +89,24 @@ export default class OncHistoryDetailRow { return this._typeOfPX; } + public async fillTypeOfPXField(currentRow: Locator, typeOfPX: string): Promise { + this._typeOfPX = typeOfPX; + const typeOfPXField = currentRow.locator(`//td[${OncHistoryColumn.TYPE_OF_PX}]//mat-form-field//textarea`); + await typeOfPXField.fill(this._typeOfPX); + } + public set locationOfPX(location: string) { - this._locationOfPx = location; + this._locationOfPX = location; } public get locationOfPX(): string { - return this._locationOfPx; + return this._locationOfPX; + } + + public async fillLocationOfPXField(currentRow: Locator, locationOfPX: string): Promise { + this._locationOfPX = locationOfPX; + const locationOfPXField = currentRow.locator(`//td[${OncHistoryColumn.LOCATION_OF_PX}]//mat-form-field//input`); + await locationOfPXField.fill(this._locationOfPX); } public set histology(histology: string) { @@ -69,6 +117,12 @@ export default class OncHistoryDetailRow { return this._histology; } + public async fillHistologyField(currentRow: Locator, histology: string): Promise { + this._histology = histology; + const histologyField = currentRow.locator(`//td[${OncHistoryColumn.HISTOLOGY}]//mat-form-field//textarea`); + await histologyField.fill(this._histology); + } + public set accessionNumber(accessionNumber: string) { this._accessionNumber = accessionNumber; } @@ -77,6 +131,12 @@ export default class OncHistoryDetailRow { return this._accessionNumber; } + public async fillAccessionNumberField(currentRow: Locator, accessionNumber: string): Promise { + this._accessionNumber = accessionNumber; + const accessionNumberField = currentRow.locator(`//td[${OncHistoryColumn.ACCESSION_NUMBER}]//mat-form-field//input`); + await accessionNumberField.fill(this._accessionNumber); + } + public set facility(facility: string) { this._facility = facility; } @@ -85,6 +145,12 @@ export default class OncHistoryDetailRow { return this._facility; } + public async fillFacilityNameField(currentRow: Locator, facilityName: string): Promise { + this._facility = facilityName; + const facilityNameField = currentRow.locator(`//td[${OncHistoryColumn.FACILITY}]//mat-form-field//input`); + await facilityNameField.fill(this._facility); + } + public set phone(phoneNumber: string) { this._phone = phoneNumber; } @@ -93,6 +159,12 @@ export default class OncHistoryDetailRow { return this._phone; } + public async fillFacilityPhoneNumberField(currentRow: Locator, phone: string): Promise { + this._phone = phone; + const facilityPhoneNumberField = currentRow.locator(`//td[${OncHistoryColumn.PHONE}]//mat-form-field//input`); + await facilityPhoneNumberField.fill(this._phone); + } + public set fax(faxNumber: string) { this._fax = faxNumber; } @@ -101,6 +173,12 @@ export default class OncHistoryDetailRow { return this._fax; } + public async fillFacilityFaxNumberField(currentRow: Locator, fax: string): Promise { + this._fax = fax; + const facilityfaxNumberField = currentRow.locator(`//td[${OncHistoryColumn.FAX}]//mat-form-field//input`); + await facilityfaxNumberField.fill(this._fax); + } + public set destructionPolicy(amountOfYears: number | string) { this._destructionPolicy = amountOfYears as string; } @@ -109,7 +187,352 @@ export default class OncHistoryDetailRow { return this._destructionPolicy; } + public async fillDestructionPolicyField(currentRow: Locator, destructionPolicy: string): Promise { + this._destructionPolicy = destructionPolicy; + const destructionPolicyField = currentRow.locator(`//td[${OncHistoryColumn.DESTRUCTION_POLICY}]//mat-form-field//input`); + await destructionPolicyField.fill(this._destructionPolicy); + } + + public set localControl(answer: GeneralAnswer) { + this._localControl = answer; + } + + public get localControl(): GeneralAnswer { + return this._localControl; + } + + public async fillLocalControlDropdown(currentRow: Locator, sampleIsFromLocalControl: GeneralAnswer): Promise { + this._localControl = sampleIsFromLocalControl; + const localcontrolDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_LOCAL_CONTROL}]`); + const answer = this._localControl as string; + await localcontrolDropdown.filter({ hasText: answer }).click(); + } + + public set decalcification(answer: Decalcification) { + this._decalcification = answer; + } + + public get decalcification(): Decalcification { + return this._decalcification; + } + + public async fillDecalcificationDropdown(currentRow: Locator, decalcification: Decalcification): Promise { + this._decalcification = decalcification; + const decalcificationDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_DECALCIFICATION}]`); + const answer = this._decalcification as string; + await decalcificationDropdown.filter({ hasText: answer }).click(); + } + + public set ffpe(answer: GeneralAnswer) { + this._ffpe = answer; + } + + public get ffpe(): GeneralAnswer { + return this.ffpe; + } + + public async fillFFPEDropdown(currentRow: Locator, ffpe: GeneralAnswer): Promise { + this._ffpe = ffpe; + const ffpeDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_FFPE}]`); + const answer = this._ffpe as string; + await ffpeDropdown.filter({ hasText: answer }).click(); + } + + public set blocksWithTumor(answer: string) { + this._blocksWithTumor = answer; + } + + public get blocksWithTumor(): string { + return this._blocksWithTumor; + } + + public async fillBlocksWithTumorField(currentRow: Locator, tumorDescription: string): Promise { + this._blocksWithTumor = tumorDescription; + const blocksWithTumorField = currentRow.locator(`//td[${OncHistoryColumn.OS2_BLOCKS_WITH_TUMOR}]//mat-form-field//input`); + await blocksWithTumorField.fill(this._blocksWithTumor); + } + + public set tumorSize(sizeDescription: string) { + this._tumorSize = sizeDescription; + } + + public get tumorSize(): string { + return this._tumorSize; + } + + public async fillTumorSizeField(currentRow: Locator, studyName: StudyEnum, tumorDescription: string): Promise { + let tumorSizeField; + this._tumorSize = tumorDescription; + switch (studyName) { + case StudyEnum.OSTEO2: + tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.OS2_TUMOR_SIZE}]//mat-form-field//textarea`); + break; + case StudyEnum.LMS: + tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.LMS_TUMOR_SIZE}]//mat-form-field//textarea`); + break; + default: + //Throw error since only OS2 and LMS have a tumor size field + throw new Error(`Study name ${studyName} was used in fillTumorSizeField(). Only OS2 or LMS should be used!`); + } + await tumorSizeField.fill(this._tumorSize); + } + + public set blockToRequest(blockDescription: string) { + this._blocksToRequest = blockDescription; + } + + public get blockToRequest(): string { + return this._blocksToRequest; + } + + public async fillBlockToRequestField(currentRow: Locator, requestDescription: string): Promise { + this._blocksToRequest = requestDescription; + const blockToRequestField = currentRow.locator(`//td[${OncHistoryColumn.LMS_BLOCKS_TO_REQUEST}]//mat-form-field//input`); + await blockToRequestField.fill(this._blocksToRequest); + } + + public set necrosis(necrosisDescription: string) { + this._necrosis = necrosisDescription; + } + + public get necrosis(): string { + return this.necrosis; + } + + public async fillNecrosisField(currentRow: Locator, studyName: StudyEnum, necrosisDescription: string): Promise { + let necrosisField; + this._necrosis = necrosisDescription; + switch (studyName) { + case StudyEnum.OSTEO2: + necrosisField = currentRow.locator(`//td[${OncHistoryColumn.OS2_NECROSIS}]//mat-form-field//input`); + break; + case StudyEnum.LMS: + necrosisField = currentRow.locator(`//td[${OncHistoryColumn.LMS_NECROSIS}]//mat-form-field//input`); + break; + default: + //Throw error since only OS2 and LMS have a tumor size field + throw new Error(`Study name ${studyName} was used in fillNecrosisField(). Only OS2 or LMS should be used!`); + } + await necrosisField.fill(this._necrosis); + } + + public set viableTumor(tumorDescription: string) { + this._viableTumor = tumorDescription; + } + + public get viableTumor(): string { + return this._viableTumor; + } + + public async fillViableTumorField(currentRow: Locator, viableTumorDescription: string): Promise { + this._viableTumor = viableTumorDescription; + const viableTumorField = currentRow.locator(`//td[${OncHistoryColumn.VIABLE_TUMOR}]//mat-form-field//input`); + await viableTumorField.fill(this._viableTumor); + } + + public set slidesToRequest(requestDescription: string) { + this._slidesToRequest = requestDescription; + } + + public get slidesToRequest(): string { + return this._slidesToRequest; + } + + public async fillSlidesToRequestField(currentRow: Locator, slides: string): Promise { + this._slidesToRequest = slides; + const slidesToRequestField = currentRow.locator(`//td[${OncHistoryColumn.LMS_SLIDES_TO_REQUEST}]//mat-form-field//input`); + await slidesToRequestField.fill(this._slidesToRequest); + } + + public set facilityWhereSampleWasReviewed(facilityName: string) { + this._facilityWhereSampleWasReviewed = facilityName; + } + + public get facilityWhereSampleWasReceived(): string { + return this._facilityWhereSampleWasReviewed; + } + + public async fillFacilityWhereSampleWasReceivedField(currentRow: Locator, facility: string): Promise { + this._facilityWhereSampleWasReviewed = facility; + const facilityField = currentRow.locator(`//td[${OncHistoryColumn.LMS_FACILITY_WHERE_SAMPLE_REVIEWED}]//mat-form-field//input`); + await facilityField.fill(this._facilityWhereSampleWasReviewed); + } + + public set slidesTotal(slideDescription: string) { + this._slidesTotal = slideDescription; + } + + public get slidesTotal(): string { + return this._slidesTotal; + } + + public async fillSlidesTotalField(currentRow: Locator, slidesDescription: string): Promise { + this._slidesTotal = slidesDescription; + const slidesTotalField = currentRow.locator(`//td[${OncHistoryColumn.LMS_SLIDES_TOTAL}]//mat-form-field//input`); + await slidesTotalField.fill(this._slidesToRequest); + } + + public set treatmentEffect(effectOfTreatment: string) { + this._treatmentEffect = effectOfTreatment; + } + + public get treatmentEffect(): string { + return this._treatmentEffect; + } + + public async fillTreatmentEffectField(currentRow: Locator, treatmentEffect: string): Promise { + this._treatmentEffect = treatmentEffect; + const treatmentEffecrField = currentRow.locator(`//td[${OncHistoryColumn.LMS_TREATMENT_EFFECT}]//mat-form-field//input`); + await treatmentEffecrField.fill(this._treatmentEffect); + } + + public async inputOncHistory(opts: { + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string + }): Promise { + const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX = '', locationOfPX = '', histology = '', destructionPolicy = '' } = opts; + const row = await this.getNextAvailableRow(); + await this.fillDateOfPXField(row, dateOfPX); + await this.fillAccessionNumberField(row, accessionNumber); + await this.fillFacilityNameField(row, facility); + await this.fillFacilityPhoneNumberField(row, phone); + await this.fillFacilityFaxNumberField(row, fax); + await this.fillTypeOfPXField(row, typeOfPX); + await this.fillLocationOfPXField(row, locationOfPX); + await this.fillHistologyField(row, histology); + await this.fillDestructionPolicyField(row, destructionPolicy); + await this.setOncHistoryDetailID(row); //Ids are given to each row afer at least 1 input in any field in that row + } + + public async inputOncHistoryOsteo(opts: { + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string, + blocksWithTumor?: string, + tumorSize?: string, + localControl?: GeneralAnswer, + necrosis?: string, + viableTumor?: string, + ffpe?: GeneralAnswer, + decalcification?: Decalcification, + blocksToRequest?: string + }): Promise { + const row = await this.getNextAvailableRow(); + const { + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX = '', + locationOfPX = '', + histology = '', + destructionPolicy = '', + blocksWithTumor = '', + tumorSize = '', + localControl = GeneralAnswer.BLANK, + necrosis = '', + viableTumor = '', + ffpe = GeneralAnswer.BLANK, + decalcification = Decalcification.BLANK, + blocksToRequest = '' + } = opts; + await this.fillDateOfPXField(row, dateOfPX); + await this.fillAccessionNumberField(row, accessionNumber); + await this.fillFacilityNameField(row, facility); + await this.fillFacilityPhoneNumberField(row, phone); + await this.fillFacilityFaxNumberField(row, fax); + await this.fillTypeOfPXField(row, typeOfPX); + await this.fillLocationOfPXField(row, locationOfPX); + await this.fillHistologyField(row, histology); + await this.fillDestructionPolicyField(row, destructionPolicy); + await this.fillBlocksWithTumorField(row, blocksWithTumor); + await this.fillTumorSizeField(row, StudyEnum.OSTEO2, tumorSize); + await this.fillLocalControlDropdown(row, localControl); + await this.fillNecrosisField(row, StudyEnum.OSTEO2, necrosis); + await this.fillViableTumorField(row, viableTumor); + await this.fillFFPEDropdown(row, ffpe); + await this.fillDecalcificationDropdown(row, decalcification); + await this.fillBlockToRequestField(row, blocksToRequest); + await this.setOncHistoryDetailID(row); //Ids are given to each row afer at least 1 input in any field in that row + } + + public async inputOncHistoryLMS(opts: { + dateOfPX: string, + accessionNumber: string, + facility: string, + phone: string, + fax: string, + typeOfPX?: string, + locationOfPX?: string, + histology?: string, + destructionPolicy?: string, + tumorSize?: string, + slidesToRequest?: string, + facilityWhereSampleWasReviewed?: string, + slidesTotal?: string, + blocksToRequest?: string, + treatmentEffect?: string, + viableTumor?: string, + necrosis?: string + }): Promise { + const row = await this.getNextAvailableRow(); + const { + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX = '', + locationOfPX = '', + histology = '', + destructionPolicy = '', + tumorSize = '', + slidesToRequest = '', + facilityWhereSampleWasReviewed = '', + slidesTotal = '', + blocksToRequest = '', + treatmentEffect = '', + viableTumor = '', + necrosis = '' + } = opts; + await this.fillDateOfPXField(row, dateOfPX); + await this.fillAccessionNumberField(row, accessionNumber); + await this.fillFacilityNameField(row, facility); + await this.fillFacilityPhoneNumberField(row, phone); + await this.fillFacilityFaxNumberField(row, fax); + await this.fillTypeOfPXField(row, typeOfPX); + await this.fillLocationOfPXField(row, locationOfPX); + await this.fillHistologyField(row, histology); + await this.fillDestructionPolicyField(row, destructionPolicy); + await this.fillTumorSizeField(row, StudyEnum.LMS, tumorSize); + await this.fillSlidesToRequestField(row, slidesToRequest); + await this.fillFacilityWhereSampleWasReceivedField(row, facilityWhereSampleWasReviewed); + await this.fillSlidesTotalField(row, slidesTotal); + await this.fillBlockToRequestField(row, blocksToRequest); + await this.fillTreatmentEffectField(row, treatmentEffect); + await this.fillViableTumorField(row, viableTumor); + await this.fillNecrosisField(row, StudyEnum.LMS, necrosis); + await this.setOncHistoryDetailID(row); //Ids are given to each row afer at least 1 input in any field in that row + } + /* Basic onc history related functions */ + /** + * Clicks the checkbox that appears in an onc history row as soon as the row is set to Request status + */ public async requestOncHistoryDetail(): Promise { const checkbox = await this.getRequestOncHistoryDetailCheckbox(); await checkbox.check(); @@ -122,40 +545,35 @@ export default class OncHistoryDetailRow { public async setOncHistoryRequestStatus(status: OncHistoryRequestStatus): Promise { const id = this.assertOncHistoryIDIsAssigned(); - const requestDropdown = this.page.locator(`//tr[@id='${id}']//td[${OncHistoryColumn.REQUEST_STATUS}]//mat-select`); + const statusDropdownOptions = this.page.locator(`//tr[@id=${id}]//td[contains(@class, 'request-td')]//mat-select`); + await statusDropdownOptions.filter({ hasText: status }).click(); } - - - /* Locators */ - - public getDownloadRequestDocumentsButton(): Locator { - return this.page.getByRole('button', { name: 'Download Request Documents' }); - } - - public async clickDownloadRequestDocuments(): Promise { - const documentsButton = this.getDownloadRequestDocumentsButton(); - await documentsButton.click(); + public async getOncHistoryRequestStatus(): Promise { + const id = this.assertOncHistoryIDIsAssigned(); + const statusDropdownOptions = this.page.locator(`//tr[@id=${id}]//td[contains(@class, 'request-td')]//mat-select`); + const status = await statusDropdownOptions.innerText(); + return status; } - public getDownloadPDFBundleButton(): Locator { - return this.page.getByRole('button', { name: 'Download PDF Bundle' }); - } + /* Locators */ - public async clickDownloadPDFBundle(): Promise { - const bundleButton = this.getDownloadPDFBundleButton(); - await bundleButton.click(); - } /* Onc History specific helper methods */ + private async getNextAvailableRow(): Promise { + const availableRows = this.page.locator('//app-onc-history-detail//tbody//tr').all(); + const amountOfRows = (await availableRows).length; + const row = this.page.locator(`//app-onc-history-detail//tbody//tr[${amountOfRows}]`); //Gets the latest row that is likely empty & ready to go + return row; + } private async getRequestOncHistoryDetailCheckbox(): Promise { const id = this.assertOncHistoryIDIsAssigned(); //Checkbox only appears if the onc history status is set to Request const requestStatus = await this.getOncHistoryRequestStatus(); - expect(requestStatus, `ERROR: Onc History id ${id}'s status is ${requestStatus}, not Request - Onc History request checkbox cannot be seen`). - toBe(OncHistoryRequestStatus.REQUEST); + expect(requestStatus, `ERROR: Onc History id ${id}'s status is ${requestStatus}, not Request; Onc History request checkbox cannot be seen`). + toBe(OncHistoryRequestStatus.REQUEST as string); const checkbox = this.page.locator(`//tr[@id='${id}']//button[@tooltip='Tissue information']/preceding-sibling::mat-checkbox`); return checkbox; diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts index b9841b0a27..ada46251bc 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts @@ -1,6 +1,6 @@ import {Locator, Page} from '@playwright/test'; -import { LMSOncHistoryDetail, OncHistoryDetail, Osteo2OncHistoryDetail } from 'dsm/component/tabs/model/oncHistoryDetailModel'; -import { GeneralAnswer, Decalcification } from './enums/oncHistory-enum'; +import OncHistoryDetailRow from './oncHistoryDetailRow'; +import { Decalcification, GeneralAnswer } from './enums/oncHistory-enum'; import { StudyEnum } from '../navigation/enums/selectStudyNav-enum'; export default class OncHistoryTab { @@ -8,9 +8,11 @@ export default class OncHistoryTab { public get addOncHistory() { const page = this.page; + let oncHistoryDetails: OncHistoryDetailRow[]; - return new class implements OncHistoryDetail, Osteo2OncHistoryDetail, LMSOncHistoryDetail { + return new class { async createOncHistoryDetail(opts: { + study: StudyEnum, dateOfPX: string, accessionNumber: string, facility: string, @@ -19,37 +21,105 @@ export default class OncHistoryTab { typeOfPX?: string, locationOfPX?: string, histology?: string, - destructionPolicy?: string + destructionPolicy?: string, + localControl?: GeneralAnswer, + decalcification?: Decalcification, + ffpe?: GeneralAnswer, + blocksWithTumor?: string, + tumorSize?: string, + blocksToRequest?: string, + necrosis?: string, + viableTumor?: string, + slidesToRequest?: string, + facilityWhereSampleWasReviewed?: string, + slidesTotal?: string, + treatmentEffect?: string }): Promise { - const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; - } - - async createOsteoOncHistoryDetail(opts: { - dateOfPX: string, - accessionNumber: string, - facility: string, - phone: string, - fax: string, - typeOfPX?: string, - locationOfPX?: string, - histology?: string, - destructionPolicy?: string - }): Promise { - const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; - } - - async createLMSOncHistoryDetail(opts: { - dateOfPX: string, - accessionNumber: string, - facility: string, - phone: string, - fax: string, - typeOfPX?: string, - locationOfPX?: string, - histology?: string, - destructionPolicy?: string - }): Promise { - const { dateOfPX, accessionNumber, facility, phone, fax, typeOfPX, locationOfPX, histology, destructionPolicy } = opts; + const { + study, + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX = '', + locationOfPX = '', + histology = '', + destructionPolicy = '', + localControl = GeneralAnswer.BLANK, + decalcification = Decalcification.BLANK, + ffpe = GeneralAnswer.BLANK, + blocksWithTumor = '', + tumorSize = '', + blocksToRequest = '', + necrosis = '', + viableTumor = '', + slidesToRequest = '', + facilityWhereSampleWasReviewed = '', + slidesTotal = '', + treatmentEffect = '' + } = opts; + const row = new OncHistoryDetailRow(page); + switch (study) { + case StudyEnum.OSTEO2: + //Handle OS2 (CMI Clinical Study) + await row.inputOncHistoryOsteo({ + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX, + locationOfPX, + histology, + destructionPolicy, + blocksWithTumor, + tumorSize, + localControl, + necrosis, + viableTumor, + ffpe, + decalcification, + blocksToRequest + }); + break; + case StudyEnum.LMS: + //Handle LMS (CMI Clinical Study) + await row.inputOncHistoryLMS({ + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX, + locationOfPX, + histology, + destructionPolicy, + tumorSize, + slidesToRequest, + facilityWhereSampleWasReviewed, + slidesTotal, + blocksToRequest, + treatmentEffect, + viableTumor, + necrosis + }); + break; + default: + //Handle CMI Research studies + await row.inputOncHistory({ + dateOfPX, + accessionNumber, + facility, + phone, + fax, + typeOfPX, + locationOfPX, + histology, + destructionPolicy, + }); + break; + } } } } diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index 539f6c4fce..d553ab8823 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -18,6 +18,8 @@ import InitialScanPage from 'dsm/pages/scanner-pages/initialScan-page'; import { KitsColumnsEnum } from 'dsm/pages/kitsInfo-pages/enums/kitsColumns-enum'; import FinalScanPage from 'dsm/pages/scanner-pages/finalScan-page'; import { TabEnum } from 'dsm/component/tabs/enums/tab-enum'; +import OncHistoryTab from 'dsm/component/tabs/oncHistoryTab'; +import { Decalcification, GeneralAnswer } from 'dsm/component/tabs/enums/oncHistory-enum'; test.describe('Samples Received Event - Recieved saliva kit first and then tumor sample', () => { const studies = [StudyEnum.OSTEO2, StudyEnum.LMS]; @@ -36,7 +38,7 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor }); for (const study of studies) { - test(`${study} - Verify SAMPLES_RECEIVED occurs if the saliva kit is received before the tumor sample`, async ({ page }, testInfo) => { + test(`@${study} - Verify SAMPLES_RECEIVED occurs if the saliva kit is received before the tumor sample`, async ({ page }, testInfo) => { const testResultDirectory = testInfo.outputDir; //Select the study @@ -106,9 +108,42 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor await participantListTable.openParticipantPageAt(0); //Go into their Onc History tab - + await participantPage.clickTab(TabEnum.ONC_HISTORY); //Input a new row of onc history data, where at least the following is added: Date of PX + Accession Number; Afterwards change request status to 'Request' + const oncHistoryTab = new OncHistoryTab(page); + await oncHistoryTab.addOncHistory.createOncHistoryDetail({ + study, + dateOfPX: '09/08/2023', + accessionNumber: 'AccessionExampleNumber123', + facility: 'MGH', + phone: '123-456-7890', + fax: '111-222-3333', + }); + /*await oncHistoryTab.addOncHistory.createOncHistoryDetail({ + study, + dateOfPX: '09/08/2023', + accessionNumber: 'AccessionExampleNumber123', + facility: 'MGH', + phone: '123-456-7890', + fax: '111-222-3333', + typeOfPX: 'Type of PX Playwright Example', + locationOfPX: 'Unknown location', + histology: 'Histology example', + destructionPolicy: 'indefinitely', + localControl: GeneralAnswer.YES, + decalcification: Decalcification.NITRIC_ACID, + ffpe: GeneralAnswer.UNKNOWN, + blocksWithTumor: 'Blocks with Tumor Description', + tumorSize: 'Description of tumor size', + blocksToRequest: 'Description of blocks to request', + necrosis: 'Unknown necrosis percentage', + viableTumor: 'Unknown amount of viable tumor', + slidesToRequest: 'Description of slides to request', + facilityWhereSampleWasReviewed: 'Tufts', + slidesTotal: 'Description of total amount of slides', + treatmentEffect: 'Description of extensive treatment effect' + });*/ //Verify the Request checkbox appears From f0f851f28e5e4b2f61b5fb5349725c1e0fb12789 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 8 Sep 2023 16:16:45 -0400 Subject: [PATCH 11/14] botched prior merge conflict but should be fixed now input stuff into onc history fields --- .../filters/sections/search/search.ts | 77 ++++++++++++++++++- .../dsm/component/tabs/oncHistoryTab.ts | 2 +- ...t-saliva-kit-and-then-tumor-sample.spec.ts | 8 +- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/playwright-e2e/dsm/component/filters/sections/search/search.ts b/playwright-e2e/dsm/component/filters/sections/search/search.ts index 5b0b4a5c4a..d17ec0d440 100644 --- a/playwright-e2e/dsm/component/filters/sections/search/search.ts +++ b/playwright-e2e/dsm/component/filters/sections/search/search.ts @@ -1,9 +1,11 @@ import { expect, Locator, Page } from '@playwright/test'; import DatePicker from 'dsm/component/date-picker'; import { CheckboxConfig, DateConfig, RadioButtonConfig, TextConfig } from 'dsm/component/filters/sections/search/search-types'; -import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums'; +import { AdditionalFilter, EnrollmentStatus, KitStatus, ParticipantColumns, SampleColumns } from 'dsm/component/filters/sections/search/search-enums'; import { waitForNoSpinner, waitForResponse } from 'utils/test-utils'; import { logError } from 'utils/log-utils'; +import { KitTypeEnum } from 'dsm/component/kitType/enums/kitType-enum'; +import { ParticipantListTable } from 'dsm/component/tables/participant-list-table'; export class Search { private readonly enUSDateRegExp = new RegExp(/\b(0[1-9]|1[012])([/])(0[1-9]|[12]\d|3[01])\2(\d{4})/); @@ -155,6 +157,79 @@ export class Search { return isDisabled || false; } + public async searchForParticipantsWithEnrollmentStatus(enrollmentStatuses: EnrollmentStatus[]): Promise { + await this.open(); + await this.checkboxes(ParticipantColumns.STATUS, { checkboxValues: enrollmentStatuses }); + await this.search(); + } + + public async searchForKitSampleStatus(kitTypes: KitTypeEnum[], kitStatus: KitStatus): Promise { + await this.open(); + await this.checkboxes(SampleColumns.SAMPLE_TYPE, { checkboxValues: kitTypes }); + await this.radioButton(SampleColumns.STATUS, { radioButtonValue: kitStatus }); + await this.search(); + } + + public async searchForParticipantWithUnsentSalivaKit(): Promise { + const [filterListReponse] = await Promise.all([ + this.page.waitForResponse(response => response.url().includes('/ui/filterList') && response.status() === 200), + this.searchForKitSampleStatus([KitTypeEnum.SALIVA], KitStatus.WAITING_ON_GP), + ]); + let responseBody = JSON.parse(await filterListReponse.text()); + + const participantListTable = new ParticipantListTable(this.page); + const amountOfRowsDisplayed = await participantListTable.rowsCount; + let validTestParticipantShortIDFound; + + //Check for a participant with a saliva kit that neither has scanDate or deactivatedDate + for (let index = 0; index < amountOfRowsDisplayed; index++) { + if (await participantListTable.onLastPage()) { + console.log('On last page'); + break; + } + console.log(`Participant ${index}'s information: ${responseBody.participants[index].esData.profile.hruid}`); + const kitInformation = responseBody.participants[index].kits; + const amountOfKits = kitInformation.length; + console.log(`Participant kit amount: ${kitInformation.length}`); + for (let kitNumber = 0; kitNumber < amountOfKits; kitNumber++) { + console.log(`Participant kit info: ${kitInformation[kitNumber].kitTypeName}`); + if ((kitInformation[kitNumber].kitTypeName) === KitTypeEnum.SALIVA) { + if (kitInformation[kitNumber].scanDate === undefined && kitInformation[kitNumber].deactivatedDate === undefined) { + console.log(`ALERT: Valid participant found!`); + validTestParticipantShortIDFound = responseBody.participants[index].esData.profile.hruid; + break; + } + } + } + + if (validTestParticipantShortIDFound) { + break; + } + + if (this.isReadyToGoToTheNextPage(index, amountOfRowsDisplayed)) { + const [nextResponse] = await Promise.all([ + this.page.waitForResponse(response => response.url().includes('/ui/filterList') && response.status() === 200), + await participantListTable.nextPage(), + ]); + await participantListTable.waitForReady(); + responseBody = JSON.parse(await nextResponse.text()); + index = -1; + console.log('Should be on the next page now'); + } + } + return validTestParticipantShortIDFound; + } + + /** + * Determines if it's time to go to the next page based on the current index used in a for-loop & whether the last row was looked at + * @param index Current index being used in a for-loop in a different method + * @param amountOfRowsDisplayed The amount of rows currently displayed in the DSM Participant List + * @returns if it's time to turn the page + */ + private isReadyToGoToTheNextPage(index: number, amountOfRowsDisplayed: number): boolean { + return (index > 0) && (index % (amountOfRowsDisplayed - 1) === 0); + } + /* Locators */ private checkboxLocator(columnName: string, checkboxName: string): Locator { diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts index ada46251bc..c93fb86677 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryTab.ts @@ -1,7 +1,7 @@ import {Locator, Page} from '@playwright/test'; import OncHistoryDetailRow from './oncHistoryDetailRow'; import { Decalcification, GeneralAnswer } from './enums/oncHistory-enum'; -import { StudyEnum } from '../navigation/enums/selectStudyNav-enum'; +import { StudyEnum } from 'dsm/component/navigation/enums/selectStudyNav-enum'; export default class OncHistoryTab { constructor(private readonly page: Page) {} diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index d553ab8823..fc89e6075c 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -112,15 +112,15 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor //Input a new row of onc history data, where at least the following is added: Date of PX + Accession Number; Afterwards change request status to 'Request' const oncHistoryTab = new OncHistoryTab(page); - await oncHistoryTab.addOncHistory.createOncHistoryDetail({ + /*await oncHistoryTab.addOncHistory.createOncHistoryDetail({ study, dateOfPX: '09/08/2023', accessionNumber: 'AccessionExampleNumber123', facility: 'MGH', phone: '123-456-7890', fax: '111-222-3333', - }); - /*await oncHistoryTab.addOncHistory.createOncHistoryDetail({ + });*/ + await oncHistoryTab.addOncHistory.createOncHistoryDetail({ study, dateOfPX: '09/08/2023', accessionNumber: 'AccessionExampleNumber123', @@ -143,7 +143,7 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor facilityWhereSampleWasReviewed: 'Tufts', slidesTotal: 'Description of total amount of slides', treatmentEffect: 'Description of extensive treatment effect' - });*/ + }); //Verify the Request checkbox appears From 9c17f2839b1fb21b9e564ab01b69ac6ee130ef23 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 8 Sep 2023 16:42:51 -0400 Subject: [PATCH 12/14] tweaks to make sure dropdown options can be used for the most part inputting onc history info should work now though at least for OS2 in a DSM Test run but tweaks needed to handle and keep track of array of onc history detail rows --- .../dsm/component/tabs/enums/oncHistory-enum.ts | 10 +++++----- .../dsm/component/tabs/oncHistoryDetailRow.ts | 16 +++++++++------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts index c7fea77019..678f613949 100644 --- a/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts +++ b/playwright-e2e/dsm/component/tabs/enums/oncHistory-enum.ts @@ -42,16 +42,16 @@ export enum OncHistoryColumn { DESTRUCTION_POLICY = 10, OS2_LOCAL_CONTROL = 11, LMS_TUMOR_SIZE = 11, - OS2_DECALCIFICATION = 12, LMS_SLIDES_TO_REQUEST = 12, - OS2_FFPE = 13, + OS2_TUMOR_SIZE = 12, LMS_FACILITY_WHERE_SAMPLE_REVIEWED = 13, - OS2_BLOCKS_WITH_TUMOR = 14, + OS2_BLOCKS_WITH_TUMOR = 11, LMS_SLIDES_TOTAL = 14, - OS2_TUMOR_SIZE = 15, LMS_BLOCKS_TO_REQUEST = 15, - OS2_NECROSIS = 16, + OS2_NECROSIS = 14, LMS_TREATMENT_EFFECT = 16, + OS2_FFPE = 16, + OS2_DECALCIFICATION = 17, VIABLE_TUMOR = 17, LMS_NECROSIS = 18, REQUEST_STATUS = 21, diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts index baebe41368..0330ac76b0 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts @@ -1,8 +1,7 @@ import { OncHistoryDetail } from 'dsm/component/tabs/model/oncHistoryDetailModel'; import { Locator, Page, expect } from '@playwright/test'; import { Decalcification, GeneralAnswer, OncHistoryColumn, OncHistoryRequestStatus } from './enums/oncHistory-enum'; -import { waitForResponse } from 'utils/test-utils'; -import { StudyEnum } from '../navigation/enums/selectStudyNav-enum'; +import { StudyEnum } from 'dsm/component/navigation/enums/selectStudyNav-enum'; export default class OncHistoryDetailRow implements OncHistoryDetail { private _oncHistoryID!: number; @@ -203,7 +202,8 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { public async fillLocalControlDropdown(currentRow: Locator, sampleIsFromLocalControl: GeneralAnswer): Promise { this._localControl = sampleIsFromLocalControl; - const localcontrolDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_LOCAL_CONTROL}]`); + const localcontrolDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_LOCAL_CONTROL}]//mat-select`); + await localcontrolDropdown.click(); const answer = this._localControl as string; await localcontrolDropdown.filter({ hasText: answer }).click(); } @@ -218,7 +218,8 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { public async fillDecalcificationDropdown(currentRow: Locator, decalcification: Decalcification): Promise { this._decalcification = decalcification; - const decalcificationDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_DECALCIFICATION}]`); + const decalcificationDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_DECALCIFICATION}]//mat-select`); + await decalcificationDropdown.click(); const answer = this._decalcification as string; await decalcificationDropdown.filter({ hasText: answer }).click(); } @@ -233,7 +234,8 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { public async fillFFPEDropdown(currentRow: Locator, ffpe: GeneralAnswer): Promise { this._ffpe = ffpe; - const ffpeDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_FFPE}]`); + const ffpeDropdown = currentRow.locator(`//td[${OncHistoryColumn.OS2_FFPE}]//mat-select`); + await ffpeDropdown.click(); const answer = this._ffpe as string; await ffpeDropdown.filter({ hasText: answer }).click(); } @@ -265,10 +267,10 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { this._tumorSize = tumorDescription; switch (studyName) { case StudyEnum.OSTEO2: - tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.OS2_TUMOR_SIZE}]//mat-form-field//textarea`); + tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.OS2_TUMOR_SIZE}]//textarea`); break; case StudyEnum.LMS: - tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.LMS_TUMOR_SIZE}]//mat-form-field//textarea`); + tumorSizeField = currentRow.locator(`//td[${OncHistoryColumn.LMS_TUMOR_SIZE}]//textarea`); break; default: //Throw error since only OS2 and LMS have a tumor size field From c171b52ae0e4a510e240b199493bb14a8dae3e42 Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 8 Sep 2023 16:57:52 -0400 Subject: [PATCH 13/14] fix eslint stuff --- playwright-e2e/dsm/component/tables/participant-list-table.ts | 2 +- .../dsm/component/tabs/model/oncHistoryDetailModel.ts | 2 +- playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts | 2 +- playwright-e2e/dsm/pages/participant-page/participant-page.ts | 2 +- ...ples-received-first-saliva-kit-and-then-tumor-sample.spec.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playwright-e2e/dsm/component/tables/participant-list-table.ts b/playwright-e2e/dsm/component/tables/participant-list-table.ts index 5008e73d68..2abd2a07df 100644 --- a/playwright-e2e/dsm/component/tables/participant-list-table.ts +++ b/playwright-e2e/dsm/component/tables/participant-list-table.ts @@ -7,7 +7,7 @@ import { getDate, offsetDaysFromToday } from 'utils/date-utils'; import { waitForNoSpinner } from 'utils/test-utils'; import { AdditionalFilter } from 'dsm/component/filters/sections/search/search-enums'; import ParticipantListPage from 'dsm/pages/participant-list-page'; -import { ScreenReaderText } from '../navigation/enums/accessibility-enum'; +import { ScreenReaderText } from 'dsm/component/navigation/enums/accessibility-enum'; export class ParticipantListTable extends Table { private readonly _participantPage: ParticipantPage = new ParticipantPage(this.page); diff --git a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts index c324ab0040..3d42ced067 100644 --- a/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts +++ b/playwright-e2e/dsm/component/tabs/model/oncHistoryDetailModel.ts @@ -1,4 +1,4 @@ -import { Decalcification, GeneralAnswer, OncHistoryRequestStatus } from '../enums/oncHistory-enum' +import { Decalcification, GeneralAnswer, OncHistoryRequestStatus } from 'dsm/component/tabs/enums/oncHistory-enum' export interface OncHistoryDetail { oncHistoryID?: number, diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts index 0330ac76b0..1a2b412412 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts @@ -581,7 +581,7 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { return checkbox; } - private async getTissueRequestPageButton(): Promise { + private getTissueRequestPageButton(): Locator { const id = this.assertOncHistoryIDIsAssigned(); const button = this.page.locator(`//tr[@id='${id}']//button[@tooltip='Tissue information']`); return button; diff --git a/playwright-e2e/dsm/pages/participant-page/participant-page.ts b/playwright-e2e/dsm/pages/participant-page/participant-page.ts index a5395b5766..6da6c0a9cc 100644 --- a/playwright-e2e/dsm/pages/participant-page/participant-page.ts +++ b/playwright-e2e/dsm/pages/participant-page/participant-page.ts @@ -3,7 +3,7 @@ import {waitForResponse} from 'utils/test-utils'; import {MainInfoEnum} from 'dsm/pages/participant-page/enums/main-info-enum'; import Tabs from 'dsm/component/tabs/tabs'; import {TabEnum} from 'dsm/component/tabs/enums/tab-enum'; -import { KitUploadInfo } from '../kitUpload-page/models/kitUpload-model'; +import { KitUploadInfo } from 'dsm/pages/kitUpload-page/models/kitUpload-model'; import ContactInformationTab from 'dsm/component/tabs/contactInformationTab'; export default class ParticipantPage { diff --git a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts index fc89e6075c..dd9d0254fc 100644 --- a/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts +++ b/playwright-e2e/tests/dsm/samplesReceivedFlow/samples-received-first-saliva-kit-and-then-tumor-sample.spec.ts @@ -31,7 +31,7 @@ test.describe('Samples Received Event - Recieved saliva kit first and then tumor const kitType = KitTypeEnum.SALIVA; const expectedKitTypes = [KitTypeEnum.SALIVA, KitTypeEnum.BLOOD]; - test.beforeEach(async ({ page, request }) => { + test.beforeEach(({ page, request }) => { navigation = new Navigation(page, request); welcomePage = new WelcomePage(page); homePage = new HomePage(page); From 8018815bc44eba856d0708e3a2150c80c90683cd Mon Sep 17 00:00:00 2001 From: Kiara Westbrooks Date: Fri, 8 Sep 2023 17:00:04 -0400 Subject: [PATCH 14/14] es lint fix --- playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts index 1a2b412412..6f65379b00 100644 --- a/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts +++ b/playwright-e2e/dsm/component/tabs/oncHistoryDetailRow.ts @@ -541,7 +541,7 @@ export default class OncHistoryDetailRow implements OncHistoryDetail { } public async accessTissueRequestPage(): Promise { - const button = await this.getTissueRequestPageButton(); + const button = this.getTissueRequestPageButton(); await button.click(); }