From dea0ceab5729e0210c75726bb6661f8bd1be3e11 Mon Sep 17 00:00:00 2001 From: Mirna Silva Date: Mon, 21 Oct 2019 15:30:50 -0300 Subject: [PATCH] test: Adding Percy Snapshot on VTK, PDF and Microscopy tests (#1059) * Adding Percy Snapshot on VTK, PDF and Microscopy tests * Small improvement to always click on first search result * Wait for search result * Added timouts all over the code to avoid intermitted failures in CI * Increasing Default Timeout and other configs * Cleaning up the code * try force enabling gpu * Try custom executor with newer version of chrome * Fix based on review comments * Increased minimum thumbnails expected on VTK test * Fix config validation * Make sure we're using the chrome browser --- .circleci/config.yml | 15 ++- platform/viewer/cypress.json | 4 + .../common/OHIFCornerstoneToolbar.spec.js | 46 ++++++++-- .../common/OHIFStandaloneViewer.spec.js | 8 +- .../common/OHIFStudyViewer.spec.js | 6 +- .../integration/pwa/OHIFExtensionHTML.spec.js | 3 +- .../pwa/OHIFExtensionMicroscopy.spec.js | 27 ++++++ .../integration/pwa/OHIFExtensionPDF.spec.js | 5 +- .../integration/pwa/OHIFExtensionVTK.spec.js | 11 ++- platform/viewer/cypress/plugins/index.js | 6 ++ platform/viewer/cypress/support/aliases.js | 3 +- platform/viewer/cypress/support/commands.js | 92 +++++++++++++------ 12 files changed, 172 insertions(+), 54 deletions(-) create mode 100644 platform/viewer/cypress/integration/pwa/OHIFExtensionMicroscopy.spec.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 6eeaba736..51c986e61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,7 +13,7 @@ version: 2.1 ## orbs: codecov: codecov/codecov@1.0.5 - cypress: cypress-io/cypress@1.10.0 + cypress: cypress-io/cypress@1.11.0 defaults: &defaults docker: @@ -288,10 +288,13 @@ workflows: # E2E: PWA - cypress/run: name: 'E2E: PWA' + executor: cypress/browsers-chrome76 + browser: chrome pre-steps: - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global add wait-on' # Use yarn latest yarn: true + record: false store_artifacts: false working_directory: platform/viewer build: npx cross-env QUICK_BUILD=true yarn run build @@ -307,10 +310,13 @@ workflows: # E2E: script-tag - cypress/run: name: 'E2E: Script Tag' + executor: cypress/browsers-chrome76 + browser: chrome pre-steps: - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global add wait-on' # Use yarn latest yarn: true + record: false store_artifacts: false working_directory: platform/viewer build: npx cross-env QUICK_BUILD=true yarn run build:package @@ -335,11 +341,13 @@ workflows: # E2E: PWA + Persist - cypress/run: name: 'E2E: PWA' + executor: cypress/browsers-chrome76 + browser: chrome pre-steps: - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global add wait-on' # Use yarn latest yarn: true - record: true + record: false store_artifacts: true working_directory: platform/viewer build: npx cross-env QUICK_BUILD=true yarn run build @@ -358,10 +366,13 @@ workflows: # E2E: script-tag - cypress/run: name: 'E2E: Script Tag' + executor: cypress/browsers-chrome76 + browser: chrome pre-steps: - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global add wait-on' # Use yarn latest yarn: true + record: false store_artifacts: false working_directory: platform/viewer build: npx cross-env QUICK_BUILD=true yarn run build:package diff --git a/platform/viewer/cypress.json b/platform/viewer/cypress.json index 9e798681d..e448d0154 100644 --- a/platform/viewer/cypress.json +++ b/platform/viewer/cypress.json @@ -2,5 +2,9 @@ "baseUrl": "http://localhost:3000", "video": false, "chromeWebSecurity": false, + "waitForAnimations": true, + "defaultCommandTimeout": 10000, + "requestTimeout": 10000, + "responseTimeout": 10000, "projectId": "4oe38f" } diff --git a/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js b/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js index 75611a141..b6ae467eb 100644 --- a/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js +++ b/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js @@ -2,7 +2,7 @@ describe('OHIF Cornerstone Toolbar', () => { before(() => { cy.openStudy('MISTER^MR'); cy.waitDicomImage(); - cy.expectMinimumThumbnails(1); + cy.expectMinimumThumbnails(3); }); beforeEach(() => { @@ -202,6 +202,9 @@ describe('OHIF Cornerstone Toolbar', () => { }); it('checks if CINE tool will prompt a modal with working controls', () => { + cy.server(); + cy.route('GET', '/**/studies/**/').as('studies'); + //Click on button cy.get('@cineBtn').click(); //Vefiry if cine control overlay is being displayed @@ -216,26 +219,49 @@ describe('OHIF Cornerstone Toolbar', () => { .click(); let expectedText = 'Img: 1 1/26'; - cy.get('@viewportInfoBottomLeft').should('not.have.text', expectedText); + cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should( + 'not.have.text', + expectedText + ); //Test SKIP TO FIRST IMAGE button - cy.get('[title="Skip to first Image"]').click(); - cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + cy.get('[title="Skip to first Image"]') + .click() + .wait(1000); + cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should( + 'contain.text', + expectedText + ); //Test NEXT IMAGE button - cy.get('[title="Next Image"]').click(); + cy.get('[title="Next Image"]') + .click() + .wait(1000); expectedText = 'Img: 2 2/26'; - cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should( + 'contain.text', + expectedText + ); //Test SKIP TO LAST IMAGE button - cy.get('[title="Skip to last Image"]').click(); + cy.get('[title="Skip to last Image"]') + .click() + .wait(2000); expectedText = 'Img: 27 26/26'; - cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should( + 'contain.text', + expectedText + ); //Test PREVIOUS IMAGE button - cy.get('[title="Previous Image"]').click(); + cy.get('[title="Previous Image"]') + .click() + .wait(1000); expectedText = 'Img: 26 25/26'; - cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should( + 'contain.text', + expectedText + ); //Click on Cine button cy.get('@cineBtn').click(); diff --git a/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js b/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js index cb60af9b2..b79a4598c 100644 --- a/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js +++ b/platform/viewer/cypress/integration/common/OHIFStandaloneViewer.spec.js @@ -13,7 +13,11 @@ describe('OHIFStandaloneViewer', () => { }); it('first 2 rows has values', () => { - cy.get('#studyListData > :nth-child(1) > .patientId').should('be.visible'); - cy.get('#studyListData > :nth-child(2) > .patientId').should('be.visible'); + cy.get('#studyListData > :nth-child(1) > .patientId', { + timeout: 15000, + }).should('be.visible'); + cy.get('#studyListData > :nth-child(2) > .patientId', { + timeout: 15000, + }).should('be.visible'); }); }); diff --git a/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js b/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js index 9b735adbd..a308f5966 100644 --- a/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js +++ b/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js @@ -2,7 +2,7 @@ describe('OHIF Study Viewer Page', () => { before(() => { cy.openStudy('MISTER^MR'); cy.waitDicomImage(); - cy.expectMinimumThumbnails(1); + cy.expectMinimumThumbnails(6); }); beforeEach(() => { @@ -14,13 +14,13 @@ describe('OHIF Study Viewer Page', () => { cy.screenshot(); cy.percySnapshot(); - cy.get('.ThumbnailEntryContainer') + cy.get('[data-cy="thumbnail-list"]') .its('length') .should('be.gt', 1); }); it('drags and drop a series thumbnail into viewport', () => { - cy.get('.ThumbnailEntryContainer:nth-child(2)') //element to be dragged + cy.get('[data-cy="thumbnail-list"]:nth-child(2)') //element to be dragged .drag('.cornerstone-canvas'); //dropzone element const expectedText = diff --git a/platform/viewer/cypress/integration/pwa/OHIFExtensionHTML.spec.js b/platform/viewer/cypress/integration/pwa/OHIFExtensionHTML.spec.js index 7866efb6f..08757cec9 100644 --- a/platform/viewer/cypress/integration/pwa/OHIFExtensionHTML.spec.js +++ b/platform/viewer/cypress/integration/pwa/OHIFExtensionHTML.spec.js @@ -1,7 +1,7 @@ describe('OHIF HTML Extension', () => { before(() => { cy.openStudy('Dummy'); - cy.expectMinimumThumbnails(1); + cy.expectMinimumThumbnails(5); }); it('checks if series thumbnails are being displayed', () => { @@ -14,6 +14,7 @@ describe('OHIF HTML Extension', () => { it('drags and drop a SR thumbnail into viewport', () => { cy.get('[data-cy="thumbnail-list"]') .contains('SR') + .first() .drag('.viewport-drop-target'); cy.get(':nth-child(2) > h1').should( diff --git a/platform/viewer/cypress/integration/pwa/OHIFExtensionMicroscopy.spec.js b/platform/viewer/cypress/integration/pwa/OHIFExtensionMicroscopy.spec.js new file mode 100644 index 000000000..a8059018a --- /dev/null +++ b/platform/viewer/cypress/integration/pwa/OHIFExtensionMicroscopy.spec.js @@ -0,0 +1,27 @@ +describe('OHIF Microscopy Extension', () => { + before(() => { + cy.openStudyModality('SM'); + cy.expectMinimumThumbnails(6); + }); + + it('checks if series thumbnails are being displayed', () => { + cy.get('[data-cy="thumbnail-list"]') + .contains('SM') + .its('length') + .should('to.be.at.least', 1); + }); + + it('drags and drop a SM thumbnail into viewport', () => { + cy.get('[data-cy="thumbnail-list"]') + .contains('SM') + .drag('.viewport-drop-target'); + + cy.get('.DicomMicroscopyViewer') + .its('length') + .should('be.eq', 1); + + cy.wait(3000); //Waiting for image to render before taking the snapshot + cy.screenshot(); + cy.percySnapshot(); + }); +}); diff --git a/platform/viewer/cypress/integration/pwa/OHIFExtensionPDF.spec.js b/platform/viewer/cypress/integration/pwa/OHIFExtensionPDF.spec.js index 8e840ea1e..7b8c1b33a 100644 --- a/platform/viewer/cypress/integration/pwa/OHIFExtensionPDF.spec.js +++ b/platform/viewer/cypress/integration/pwa/OHIFExtensionPDF.spec.js @@ -1,7 +1,7 @@ describe('OHIF PDF Extension', () => { before(() => { cy.openStudy('Dummy'); - cy.expectMinimumThumbnails(1); + cy.expectMinimumThumbnails(6); }); it('checks if series thumbnails are being displayed', () => { @@ -19,5 +19,8 @@ describe('OHIF PDF Extension', () => { cy.get('.DicomPDFViewport') .its('length') .should('be.eq', 1); + + cy.screenshot(); + cy.percySnapshot(); }); }); diff --git a/platform/viewer/cypress/integration/pwa/OHIFExtensionVTK.spec.js b/platform/viewer/cypress/integration/pwa/OHIFExtensionVTK.spec.js index 802c62e05..2f2fc362f 100644 --- a/platform/viewer/cypress/integration/pwa/OHIFExtensionVTK.spec.js +++ b/platform/viewer/cypress/integration/pwa/OHIFExtensionVTK.spec.js @@ -2,7 +2,7 @@ describe('OHIF VTK Extension', () => { before(() => { cy.openStudy('Juno'); cy.waitDicomImage(); - cy.expectMinimumThumbnails(1); + cy.expectMinimumThumbnails(7); }); beforeEach(() => { @@ -11,7 +11,7 @@ describe('OHIF VTK Extension', () => { // has data from a drag-n-drop // Drag and drop first thumbnail into first viewport cy.get('[data-cy="thumbnail-list"]:nth-child(3)').drag( - '.cornerstone-canvas' + '.viewport-drop-target' ); cy.get('.PluginSwitch > .toolbar-button') @@ -22,12 +22,15 @@ describe('OHIF VTK Extension', () => { btn.click(); } }); - + //wait VTK toolbar and images to be loaded + cy.wait(3000); cy.initVTKToolsAliases(); - cy.wait(1000); }); it('checks if VTK buttons are displayed on the toolbar', () => { + cy.screenshot(); + cy.percySnapshot(); + cy.get('@crosshairsBtn') .should('be.visible') .contains('Crosshairs'); diff --git a/platform/viewer/cypress/plugins/index.js b/platform/viewer/cypress/plugins/index.js index 2d37daee2..57f5e34d8 100644 --- a/platform/viewer/cypress/plugins/index.js +++ b/platform/viewer/cypress/plugins/index.js @@ -23,6 +23,12 @@ module.exports = (on, config) => { // whatever you return here becomes the new args return args; } + + if (browser.name === 'chromium') { + const newArgs = args.filter(arg => arg !== '--disable-gpu'); + newArgs.push('--ignore-gpu-blacklist'); + return newArgs; + } }); on('task', percyHealthCheck); diff --git a/platform/viewer/cypress/support/aliases.js b/platform/viewer/cypress/support/aliases.js index d040dc09c..c32aa728d 100644 --- a/platform/viewer/cypress/support/aliases.js +++ b/platform/viewer/cypress/support/aliases.js @@ -35,7 +35,8 @@ export function initCommonElementsAliases() { //Creating aliases for Routes export function initRouteAliases() { cy.server(); - cy.route('GET', '/dcm4chee-arc/**/series').as('getStudySeries'); + cy.route('GET', '/**/series/**').as('getStudySeries'); + cy.route('GET', '/**/studies/**').as('getStudies'); } //Creating aliases for VTK tools buttons diff --git a/platform/viewer/cypress/support/commands.js b/platform/viewer/cypress/support/commands.js index 95140ab21..5981b9cf4 100644 --- a/platform/viewer/cypress/support/commands.js +++ b/platform/viewer/cypress/support/commands.js @@ -41,17 +41,45 @@ import { Cypress.Commands.add('openStudy', patientName => { cy.initRouteAliases(); cy.visit('/'); - cy.get('#patientName').type(patientName); + cy.wrap(null).then(() => { + return new Cypress.Promise((resolve, reject) => { + cy.get('#patientName').type(patientName); + setTimeout(() => { + cy.get('#studyListData') + .contains(patientName) + .first() + .click(); + resolve(); + }, 2000); + }); + }); +}); - cy.get('.studylistStudy > .patientName', { timeout: 5000 }) - .contains(patientName) +/** + * Command to search for a modality and open the study. + * + * @param {string} modality - Modality type that we would like to search for + */ +Cypress.Commands.add('openStudyModality', modality => { + cy.initRouteAliases(); + cy.visit('/'); + cy.get('#modalities') + .type(modality) + .wait(2000); + + cy.get('#studyListData') + .contains(modality) + .first() .click(); +}); - // cy.get('.studylistStudy > .patientName') - // .as('patientResult') - // .should({ timeout: 3000 }, () => { - // cy.contains(patientName).click(); - // }); +/** + * Command to wait and check if a new page was loaded + * + * @param {string} url - part of the expected url. Default value is /viewer/ + */ +Cypress.Commands.add('isPageLoaded', (url = '/viewer/') => { + return cy.location('pathname', { timeout: 60000 }).should('include', url); }); /** @@ -119,31 +147,35 @@ Cypress.Commands.add('expectMinimumThumbnails', (seriesToWait = 1) => { //Command to wait DICOM image to load into the viewport Cypress.Commands.add('waitDicomImage', (timeout = 20000) => { - cy.window() - .its('cornerstone') - .then({ timeout }, $cornerstone => { - return new Cypress.Promise(resolve => { - const onEvent = renderedEvt => { - const element = renderedEvt.detail.element; + const loaded = cy.isPageLoaded(); - element.removeEventListener('cornerstoneimagerendered', onEvent); - $cornerstone.events.removeEventListener( - 'cornerstoneimagerendered', - onEvent + if (loaded) { + cy.window() + .its('cornerstone') + .then({ timeout }, $cornerstone => { + return new Cypress.Promise(resolve => { + const onEvent = renderedEvt => { + const element = renderedEvt.detail.element; + + element.removeEventListener('cornerstoneimagerendered', onEvent); + $cornerstone.events.removeEventListener( + 'cornerstoneimagerendered', + onEvent + ); + resolve(); + }; + const onEnabled = enabledEvt => { + const element = enabledEvt.detail.element; + + element.addEventListener('cornerstoneimagerendered', onEvent); + }; + $cornerstone.events.addEventListener( + 'cornerstoneelementenabled', + onEnabled ); - resolve(); - }; - const onEnabled = enabledEvt => { - const element = enabledEvt.detail.element; - - element.addEventListener('cornerstoneimagerendered', onEvent); - }; - $cornerstone.events.addEventListener( - 'cornerstoneelementenabled', - onEnabled - ); + }); }); - }); + } }); //Command to reset and clear all the changes made to the viewport