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
This commit is contained in:
Mirna Silva 2019-10-21 15:30:50 -03:00 committed by Danny Brown
parent a6c1e6c717
commit dea0ceab57
12 changed files with 172 additions and 54 deletions

View File

@ -13,7 +13,7 @@ version: 2.1
## ##
orbs: orbs:
codecov: codecov/codecov@1.0.5 codecov: codecov/codecov@1.0.5
cypress: cypress-io/cypress@1.10.0 cypress: cypress-io/cypress@1.11.0
defaults: &defaults defaults: &defaults
docker: docker:
@ -288,10 +288,13 @@ workflows:
# E2E: PWA # E2E: PWA
- cypress/run: - cypress/run:
name: 'E2E: PWA' name: 'E2E: PWA'
executor: cypress/browsers-chrome76
browser: chrome
pre-steps: pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest add wait-on' # Use yarn latest
yarn: true yarn: true
record: false
store_artifacts: false store_artifacts: false
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build build: npx cross-env QUICK_BUILD=true yarn run build
@ -307,10 +310,13 @@ workflows:
# E2E: script-tag # E2E: script-tag
- cypress/run: - cypress/run:
name: 'E2E: Script Tag' name: 'E2E: Script Tag'
executor: cypress/browsers-chrome76
browser: chrome
pre-steps: pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest add wait-on' # Use yarn latest
yarn: true yarn: true
record: false
store_artifacts: false store_artifacts: false
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build:package build: npx cross-env QUICK_BUILD=true yarn run build:package
@ -335,11 +341,13 @@ workflows:
# E2E: PWA + Persist # E2E: PWA + Persist
- cypress/run: - cypress/run:
name: 'E2E: PWA' name: 'E2E: PWA'
executor: cypress/browsers-chrome76
browser: chrome
pre-steps: pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest add wait-on' # Use yarn latest
yarn: true yarn: true
record: true record: false
store_artifacts: true store_artifacts: true
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build build: npx cross-env QUICK_BUILD=true yarn run build
@ -358,10 +366,13 @@ workflows:
# E2E: script-tag # E2E: script-tag
- cypress/run: - cypress/run:
name: 'E2E: Script Tag' name: 'E2E: Script Tag'
executor: cypress/browsers-chrome76
browser: chrome
pre-steps: pre-steps:
- run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global - run: 'rm -rf ~/.yarn && npm i -g yarn && yarn -v && yarn global
add wait-on' # Use yarn latest add wait-on' # Use yarn latest
yarn: true yarn: true
record: false
store_artifacts: false store_artifacts: false
working_directory: platform/viewer working_directory: platform/viewer
build: npx cross-env QUICK_BUILD=true yarn run build:package build: npx cross-env QUICK_BUILD=true yarn run build:package

View File

@ -2,5 +2,9 @@
"baseUrl": "http://localhost:3000", "baseUrl": "http://localhost:3000",
"video": false, "video": false,
"chromeWebSecurity": false, "chromeWebSecurity": false,
"waitForAnimations": true,
"defaultCommandTimeout": 10000,
"requestTimeout": 10000,
"responseTimeout": 10000,
"projectId": "4oe38f" "projectId": "4oe38f"
} }

View File

@ -2,7 +2,7 @@ describe('OHIF Cornerstone Toolbar', () => {
before(() => { before(() => {
cy.openStudy('MISTER^MR'); cy.openStudy('MISTER^MR');
cy.waitDicomImage(); cy.waitDicomImage();
cy.expectMinimumThumbnails(1); cy.expectMinimumThumbnails(3);
}); });
beforeEach(() => { beforeEach(() => {
@ -202,6 +202,9 @@ describe('OHIF Cornerstone Toolbar', () => {
}); });
it('checks if CINE tool will prompt a modal with working controls', () => { it('checks if CINE tool will prompt a modal with working controls', () => {
cy.server();
cy.route('GET', '/**/studies/**/').as('studies');
//Click on button //Click on button
cy.get('@cineBtn').click(); cy.get('@cineBtn').click();
//Vefiry if cine control overlay is being displayed //Vefiry if cine control overlay is being displayed
@ -216,26 +219,49 @@ describe('OHIF Cornerstone Toolbar', () => {
.click(); .click();
let expectedText = 'Img: 1 1/26'; 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 //Test SKIP TO FIRST IMAGE button
cy.get('[title="Skip to first Image"]').click(); cy.get('[title="Skip to first Image"]')
cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); .click()
.wait(1000);
cy.get('@viewportInfoBottomLeft', { timeout: 15000 }).should(
'contain.text',
expectedText
);
//Test NEXT IMAGE button //Test NEXT IMAGE button
cy.get('[title="Next Image"]').click(); cy.get('[title="Next Image"]')
.click()
.wait(1000);
expectedText = 'Img: 2 2/26'; 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 //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'; 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 //Test PREVIOUS IMAGE button
cy.get('[title="Previous Image"]').click(); cy.get('[title="Previous Image"]')
.click()
.wait(1000);
expectedText = 'Img: 26 25/26'; 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 //Click on Cine button
cy.get('@cineBtn').click(); cy.get('@cineBtn').click();

View File

@ -13,7 +13,11 @@ describe('OHIFStandaloneViewer', () => {
}); });
it('first 2 rows has values', () => { it('first 2 rows has values', () => {
cy.get('#studyListData > :nth-child(1) > .patientId').should('be.visible'); cy.get('#studyListData > :nth-child(1) > .patientId', {
cy.get('#studyListData > :nth-child(2) > .patientId').should('be.visible'); timeout: 15000,
}).should('be.visible');
cy.get('#studyListData > :nth-child(2) > .patientId', {
timeout: 15000,
}).should('be.visible');
}); });
}); });

View File

@ -2,7 +2,7 @@ describe('OHIF Study Viewer Page', () => {
before(() => { before(() => {
cy.openStudy('MISTER^MR'); cy.openStudy('MISTER^MR');
cy.waitDicomImage(); cy.waitDicomImage();
cy.expectMinimumThumbnails(1); cy.expectMinimumThumbnails(6);
}); });
beforeEach(() => { beforeEach(() => {
@ -14,13 +14,13 @@ describe('OHIF Study Viewer Page', () => {
cy.screenshot(); cy.screenshot();
cy.percySnapshot(); cy.percySnapshot();
cy.get('.ThumbnailEntryContainer') cy.get('[data-cy="thumbnail-list"]')
.its('length') .its('length')
.should('be.gt', 1); .should('be.gt', 1);
}); });
it('drags and drop a series thumbnail into viewport', () => { 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 .drag('.cornerstone-canvas'); //dropzone element
const expectedText = const expectedText =

View File

@ -1,7 +1,7 @@
describe('OHIF HTML Extension', () => { describe('OHIF HTML Extension', () => {
before(() => { before(() => {
cy.openStudy('Dummy'); cy.openStudy('Dummy');
cy.expectMinimumThumbnails(1); cy.expectMinimumThumbnails(5);
}); });
it('checks if series thumbnails are being displayed', () => { 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', () => { it('drags and drop a SR thumbnail into viewport', () => {
cy.get('[data-cy="thumbnail-list"]') cy.get('[data-cy="thumbnail-list"]')
.contains('SR') .contains('SR')
.first()
.drag('.viewport-drop-target'); .drag('.viewport-drop-target');
cy.get(':nth-child(2) > h1').should( cy.get(':nth-child(2) > h1').should(

View File

@ -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();
});
});

View File

@ -1,7 +1,7 @@
describe('OHIF PDF Extension', () => { describe('OHIF PDF Extension', () => {
before(() => { before(() => {
cy.openStudy('Dummy'); cy.openStudy('Dummy');
cy.expectMinimumThumbnails(1); cy.expectMinimumThumbnails(6);
}); });
it('checks if series thumbnails are being displayed', () => { it('checks if series thumbnails are being displayed', () => {
@ -19,5 +19,8 @@ describe('OHIF PDF Extension', () => {
cy.get('.DicomPDFViewport') cy.get('.DicomPDFViewport')
.its('length') .its('length')
.should('be.eq', 1); .should('be.eq', 1);
cy.screenshot();
cy.percySnapshot();
}); });
}); });

View File

@ -2,7 +2,7 @@ describe('OHIF VTK Extension', () => {
before(() => { before(() => {
cy.openStudy('Juno'); cy.openStudy('Juno');
cy.waitDicomImage(); cy.waitDicomImage();
cy.expectMinimumThumbnails(1); cy.expectMinimumThumbnails(7);
}); });
beforeEach(() => { beforeEach(() => {
@ -11,7 +11,7 @@ describe('OHIF VTK Extension', () => {
// has data from a drag-n-drop // has data from a drag-n-drop
// Drag and drop first thumbnail into first viewport // Drag and drop first thumbnail into first viewport
cy.get('[data-cy="thumbnail-list"]:nth-child(3)').drag( cy.get('[data-cy="thumbnail-list"]:nth-child(3)').drag(
'.cornerstone-canvas' '.viewport-drop-target'
); );
cy.get('.PluginSwitch > .toolbar-button') cy.get('.PluginSwitch > .toolbar-button')
@ -22,12 +22,15 @@ describe('OHIF VTK Extension', () => {
btn.click(); btn.click();
} }
}); });
//wait VTK toolbar and images to be loaded
cy.wait(3000);
cy.initVTKToolsAliases(); cy.initVTKToolsAliases();
cy.wait(1000);
}); });
it('checks if VTK buttons are displayed on the toolbar', () => { it('checks if VTK buttons are displayed on the toolbar', () => {
cy.screenshot();
cy.percySnapshot();
cy.get('@crosshairsBtn') cy.get('@crosshairsBtn')
.should('be.visible') .should('be.visible')
.contains('Crosshairs'); .contains('Crosshairs');

View File

@ -23,6 +23,12 @@ module.exports = (on, config) => {
// whatever you return here becomes the new args // whatever you return here becomes the new args
return 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); on('task', percyHealthCheck);

View File

@ -35,7 +35,8 @@ export function initCommonElementsAliases() {
//Creating aliases for Routes //Creating aliases for Routes
export function initRouteAliases() { export function initRouteAliases() {
cy.server(); 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 //Creating aliases for VTK tools buttons

View File

@ -41,17 +41,45 @@ import {
Cypress.Commands.add('openStudy', patientName => { Cypress.Commands.add('openStudy', patientName => {
cy.initRouteAliases(); cy.initRouteAliases();
cy.visit('/'); 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(); .click();
});
// cy.get('.studylistStudy > .patientName') /**
// .as('patientResult') * Command to wait and check if a new page was loaded
// .should({ timeout: 3000 }, () => { *
// cy.contains(patientName).click(); * @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 //Command to wait DICOM image to load into the viewport
Cypress.Commands.add('waitDicomImage', (timeout = 20000) => { Cypress.Commands.add('waitDicomImage', (timeout = 20000) => {
cy.window() const loaded = cy.isPageLoaded();
.its('cornerstone')
.then({ timeout }, $cornerstone => {
return new Cypress.Promise(resolve => {
const onEvent = renderedEvt => {
const element = renderedEvt.detail.element;
element.removeEventListener('cornerstoneimagerendered', onEvent); if (loaded) {
$cornerstone.events.removeEventListener( cy.window()
'cornerstoneimagerendered', .its('cornerstone')
onEvent .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 //Command to reset and clear all the changes made to the viewport