From a36cb63926d2cf439e7e68f29be160cc4799eaa3 Mon Sep 17 00:00:00 2001 From: Mirna Silva Date: Thu, 10 Oct 2019 16:46:41 -0300 Subject: [PATCH] tests: Test cases implemented: Cornerstone tools Clear and Eraser; Measurement panel Relabel and Description (#1014) * Fix for test scripts that were failing in CI * Test cases for tools: Length and Angle * Test cases implemented: Scroll series, Levels, Pan, Reset, Zoom * Added test cases for tools: Cine, More, Layout, Invert, Rotate, FlipH, FlipV * Fixes made according to comments on PR review * Fixes for failing scenarios: Layout and Cine * Test cases implemented: Cornerstone tools Clear and Eraser; Measurement panel Relabel and Description * Fix for CI failure --- .../common/OHIFCornerstoneToolbar.spec.js | 808 ++++++++++-------- .../common/OHIFStudyViewer.spec.js | 89 +- platform/viewer/cypress/support/aliases.js | 34 + platform/viewer/cypress/support/commands.js | 63 +- 4 files changed, 590 insertions(+), 404 deletions(-) create mode 100644 platform/viewer/cypress/support/aliases.js diff --git a/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js b/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js index bdedf572e..d4a15720c 100644 --- a/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js +++ b/platform/viewer/cypress/integration/common/OHIFCornerstoneToolbar.spec.js @@ -1,407 +1,457 @@ describe('OHIF Cornerstone Toolbar', () => { - before(() => { - cy.openStudy("MISTER^MR"); - cy.waitDicomImage(); + cy.openStudy('MISTER^MR'); + cy.waitDicomImage(); + }); + + beforeEach(() => { + cy.initCornerstoneToolsAliases(); + cy.initCommonElementsAliases(); + //Following best practices, reset should be done before each test + cy.resetViewport(); + }); + + it('checks if all primary buttons are being displayed', () => { + cy.get('@stackScrollBtn') + .should('be.visible') + .contains('Stack Scroll'); + cy.get('@zoomBtn') + .should('be.visible') + .contains('Zoom'); + cy.get('@levelsBtn') + .should('be.visible') + .contains('Levels'); + cy.get('@panBtn') + .should('be.visible') + .contains('Pan'); + cy.get('@lengthBtn') + .should('be.visible') + .contains('Length'); + cy.get('@annotateBtn') + .should('be.visible') + .contains('Annotate'); + cy.get('@angleBtn') + .should('be.visible') + .contains('Angle'); + cy.get('@resetBtn') + .should('be.visible') + .contains('Reset'); + cy.get('@cineBtn') + .should('be.visible') + .contains('CINE'); + cy.get('@moreBtn') + .should('be.visible') + .contains('More'); + cy.get('@twodmprBtn') + .should('be.visible') + .contains('2D MPR'); + cy.get('@layoutBtn') + .should('be.visible') + .contains('Layout'); + }); + + it('checks if Stack Scroll tool will navigate across all series in the viewport', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@stackScrollBtn') + .click() + .then($stackScrollBtn => { + cy.wrap($stackScrollBtn).should('have.class', 'active'); + }); + + //drags the mouse inside the viewport to be able to interact with series + cy.get('@viewport') + .trigger('mousedown', 'top', { which: 1 }) + .trigger('mousemove', 'center', { which: 1 }) + .trigger('mouseup'); + + const expectedText = + 'Ser: 1Img: 14 14/26256 x 256Loc: 0.00 mm Thick: 5.00 mm'; + cy.get('@viewportInfoBottomLeft').should('have.text', expectedText); + }); + + it('checks if Zoom tool will zoom in/out an image in the viewport', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@zoomBtn') + .click() + .then($zoomBtn => { + cy.wrap($zoomBtn).should('have.class', 'active'); + }); + + //drags the mouse inside the viewport to be able to interact with series + cy.get('@viewport') + .trigger('mousedown', 'top', { which: 1 }) + .trigger('mousemove', 'center', { which: 1 }) + .trigger('mouseup'); + + const expectedText = 'Zoom: 884%W: 820 L: 410Lossless / Uncompressed'; + cy.get('@viewportInfoBottomRight').should('have.text', expectedText); + }); + + it('checks if Levels tool will change the contrast and brightness of an image in the viewport', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@levelsBtn') + .click() + .then($levelsBtn => { + cy.wrap($levelsBtn).should('have.class', 'active'); + }); + + //drags the mouse inside the viewport to be able to interact with series + cy.get('@viewport') + .trigger('mousedown', 'top', { which: 1 }) + .trigger('mousemove', 'center', { which: 1 }) + .trigger('mouseup') + .trigger('mousedown', 'center', { which: 1 }) + .trigger('mousemove', 'left', { which: 1 }) + .trigger('mouseup'); + + const expectedText = 'Zoom: 211%W: 544 L: 626Lossless / Uncompressed'; + cy.get('@viewportInfoBottomRight').should('have.text', expectedText); + }); + + it('checks if Pan tool will move the image inside the viewport', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@panBtn') + .click() + .then($panBtn => { + cy.wrap($panBtn).should('have.class', 'active'); + }); + + //Get image position from cornerstone and check if y axis was modified + let cornerstone; + let currentPan; + + cy.window() + .its('cornerstone') + .then(c => { + cornerstone = c; + currentPan = () => + cornerstone.getEnabledElements()[0].viewport.translation; + }); + + cy.get('@viewport') + .trigger('mousedown', 'center', { which: 1 }) + .trigger('mousemove', 'bottom', { which: 1 }) + .trigger('mouseup', 'bottom') + .then(() => { + expect(currentPan().y > 0).to.eq(true); + }); + }); + + it('checks if Length annotation can be added on viewport and on measurements panel', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@lengthBtn') + .click() + .then($lengthbtn => { + cy.wrap($lengthbtn).should('have.class', 'active'); + }); + + //Add annotation on the viewport + const firstClick = [150, 100]; + const secondClick = [130, 170]; + cy.addLine('.cornerstone-canvas', firstClick, secondClick); + + //Verify if measurement annotation was added into the measurements panel + cy.get('@measurementsBtn') + .click() + .then($measurementsBtn => { + cy.get('@measurementsPanel').should('be.visible'); + + cy.get('.measurementItem') + .its('length') + .should('be.eq', 1); + + cy.wrap($measurementsBtn).click(); + }); + }); + + it('checks if Angle annotation can be added on viewport and on measurements panel', () => { + //Click on button and vefiry if icon is active on toolbar + cy.get('@angleBtn') + .click() + .then($angleBtn => { + cy.wrap($angleBtn).should('have.class', 'active'); + }); + + //Add annotation on the viewport + const initPos = [180, 390]; + const midPos = [300, 410]; + const finalPos = [180, 450]; + cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos); + + //Verify if measurement annotation was added into the measurements panel + cy.get('@measurementsBtn') + .click() + .then($measurementsBtn => { + cy.get('@measurementsPanel').should('be.visible'); + + cy.get('.measurementItem') + .its('length') + .should('be.eq', 1); + + cy.wrap($measurementsBtn).click(); + }); + }); + + it('checks if Reset tool will reset all changes made on the image', () => { + //Make some changes by zooming in and rotating the image + cy.imageZoomIn(); + cy.imageContrast(); + + //Click on reset button + cy.get('@resetBtn').click(); + + const expectedText = 'Zoom: 211%W: 820 L: 410Lossless / Uncompressed'; + cy.get('@viewportInfoBottomRight').should('have.text', expectedText); + }); + + it('checks if CINE tool will prompt a modal with working controls', () => { + //Click on button + cy.get('@cineBtn').click(); + //Vefiry if cine control overlay is being displayed + cy.get('.cine-controls') + .as('cineControls') + .should('be.visible'); + + //Test PLAY button + cy.get('[title="Play / Stop"]') + .click() + .wait(100) + .click(); + + let expectedText = 'Img: 1 1/26'; + cy.get('@viewportInfoBottomLeft').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); + + //Test NEXT IMAGE button + cy.get('[title="Next Image"]').click(); + expectedText = 'Img: 2 2/26'; + cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + + //Test SKIP TO LAST IMAGE button + cy.get('[title="Skip to last Image"]').click(); + expectedText = 'Img: 27 26/26'; + cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + + //Test PREVIOUS IMAGE button + cy.get('[title="Previous Image"]').click(); + expectedText = 'Img: 26 25/26'; + cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); + + //Click on Cine button + cy.get('@cineBtn').click(); + //Vefiry if cine control overlay is hidden + cy.get('@cineControls').should('not.be.visible'); + }); + + it('checks if More button will prompt a modal with secondary tools', () => { + cy.get('@moreBtn').click(); + //Verify if overlay is displayed + cy.get('.tooltip-toolbar-overlay') + .as('toolbarOverlay') + .should('be.visible'); + + let iconName; + //Click on one of the secondary tools from the overlay + cy.get('.tooltip-inner > :nth-child(1)') + .click() + .then($magnifyBtn => { + cy.wrap($magnifyBtn) + .should('have.class', 'active') + .find('svg') + .then($icon => { + iconName = $icon.text(); + }); + }); + + //Check if More button is active and if it has same icon as the secondary tool selected + cy.get('@moreBtn') + .click() + .then($moreBtn => { + cy.wrap($moreBtn) + .should('have.class', 'active') + .contains(iconName); + }); + + //Verify if overlay is hidden + cy.get('@toolbarOverlay').should('not.be.visible'); + }); + + it('checks if Layout tool will multiply the number of viewports displayed', () => { + //Click on Layout button and verify if overlay is displayed + cy.get('@layoutBtn') + .click() + .then(() => { + cy.get('.layoutChooser') + .as('layoutChooser') + .should('be.visible') + .find('td') + .its('length') + .should('be.eq', 9); + }); + + //verify if layout has changed to 2 viewports + cy.get('tbody > :nth-child(1) > :nth-child(2)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 2); }); - beforeEach(() => { - //Creating aliases for Cornerstone tools buttons - cy.get('.toolbar-button:nth-child(2)').as('stackScrollBtn'); - cy.get('.toolbar-button:nth-child(3)').as('zoomBtn'); - cy.get('.toolbar-button:nth-child(4)').as('levelsBtn'); - cy.get('.toolbar-button:nth-child(5)').as('panBtn'); - cy.get('.toolbar-button:nth-child(6)').as('lengthBtn'); - cy.get('.toolbar-button:nth-child(7)').as('annotateBtn'); - cy.get('.toolbar-button:nth-child(8)').as('angleBtn'); - cy.get('.toolbar-button:nth-child(9)').as('resetBtn'); - cy.get('.toolbar-button:nth-child(10)').as('cineBtn'); - cy.get('.expandableToolMenu').as('moreBtn'); - cy.get('.PluginSwitch > .toolbar-button').as('twodmprBtn'); - cy.get('.btn-group > .toolbar-button').as('layoutBtn'); - cy.get('.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton').as('measurementsBtn'); - cy.get('.viewport-element').as('viewport'); - cy.get('section.sidepanel.from-right').as('measurementsPanel') - //Following best practices, reset should be done before each test - cy.resetViewport(); - }) - - - it('checks if all primary buttons are being displayed', () => { - cy.get('@stackScrollBtn').should('be.visible').contains('Stack Scroll'); - cy.get('@zoomBtn').should('be.visible').contains('Zoom'); - cy.get('@levelsBtn').should('be.visible').contains('Levels'); - cy.get('@panBtn').should('be.visible').contains('Pan'); - cy.get('@lengthBtn').should('be.visible').contains('Length'); - cy.get('@annotateBtn').should('be.visible').contains('Annotate'); - cy.get('@angleBtn').should('be.visible').contains('Angle'); - cy.get('@resetBtn').should('be.visible').contains('Reset'); - cy.get('@cineBtn').should('be.visible').contains('CINE'); - cy.get('@moreBtn').should('be.visible').contains('More'); - cy.get('@twodmprBtn').should('be.visible').contains('2D MPR'); - cy.get('@layoutBtn').should('be.visible').contains('Layout'); + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(2) > :nth-child(1)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 2); }); - - it('checks if Stack Scroll tool will navigate across all series in the viewport', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@stackScrollBtn') - .click() - .then(($stackScrollBtn) =>{ - cy.wrap($stackScrollBtn) - .should('have.class', 'active') - }) - - //drags the mouse inside the viewport to be able to interact with series - cy.get('@viewport') - .trigger('mousedown', 'top', { which: 1 }) - .trigger('mousemove', 'center', { which: 1 }) - .trigger('mouseup'); - - const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-left.overlay-element > div'; - const expectedText = 'Ser: 1Img: 14 14/26256 x 256Loc: 0.00 mm Thick: 5.00 mm'; - cy.get(overlaySeriesInformation) - .should('have.text', expectedText); + //verify if layout has changed to 3 viewports + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(1) > :nth-child(3)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wait(1000); + cy.wrap($viewport) + .its('length') + .should('be.eq', 3); }); - - it('checks if Zoom tool will zoom in/out an image in the viewport', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@zoomBtn') - .click() - .then(($zoomBtn) =>{ - cy.wrap($zoomBtn) - .should('have.class', 'active') - }) - - //drags the mouse inside the viewport to be able to interact with series - cy.get('@viewport') - .trigger('mousedown', 'top', { which: 1 }) - .trigger('mousemove', 'center', { which: 1 }) - .trigger('mouseup'); - - const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div'; - const expectedText = 'Zoom: 884%W: 820 L: 410Lossless / Uncompressed'; - cy.get(overlaySeriesInformation) - .should('have.text', expectedText); + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(3) > :nth-child(1)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 3); }); - - it('checks if Levels tool will change the contrast and brightness of an image in the viewport', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@levelsBtn') - .click() - .then(($levelsBtn) =>{ - cy.wrap($levelsBtn) - .should('have.class', 'active') - }) - - //drags the mouse inside the viewport to be able to interact with series - cy.get('@viewport') - .trigger('mousedown', 'top', { which: 1 }) - .trigger('mousemove', 'center', { which: 1 }) - .trigger('mouseup') - .trigger('mousedown', 'center', { which: 1 }) - .trigger('mousemove', 'left', { which: 1 }) - .trigger('mouseup'); - - const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div'; - const expectedText = 'Zoom: 211%W: 544 L: 626Lossless / Uncompressed'; - cy.get(overlaySeriesInformation) - .should('have.text', expectedText); - }); - - - it('checks if Pan tool will move the image inside the viewport', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@panBtn') - .click() - .then(($panBtn) =>{ - cy.wrap($panBtn) - .should('have.class', 'active') - }) - - //Get image position from cornerstone and check if y axis was modified - let cornerstone; - let currentPan; - - cy.window() - .its('cornerstone') - .then((c) => { - cornerstone = c; - currentPan = () => cornerstone.getEnabledElements()[0].viewport.translation; - }); - - cy.get('@viewport') - .trigger('mousedown', 'center', { which: 1 }) - .trigger('mousemove', 'bottom', { which: 1 }) - .trigger('mouseup', 'bottom') - .then(() => { - expect(currentPan().y > 0).to.eq(true); - }); + //verify if layout has changed to 4 viewports + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(2) > :nth-child(2)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 4); }); - - it('checks if Length annotation can be added on viewport and on measurements panel', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@lengthBtn') - .click() - .then(($lengthbtn) =>{ - cy.wrap($lengthbtn) - .should('have.class', 'active') - }) - - //Add annotation on the viewport - const firstClick = [150, 100]; - const secondClick = [130, 170]; - cy.addLine('.cornerstone-canvas', firstClick, secondClick) - - //Verify if measurement annotation was added into the measurements panel - cy.get('@measurementsBtn') - .click() - .then($measurementsBtn => { - cy.get('@measurementsPanel') - .should('be.visible'); - - cy.get('.measurementItem') - .its('length') - .should('be.eq', 1); - - cy.wrap($measurementsBtn) - .click(); - }) + //verify if layout has changed to 6 viewports + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(2) > :nth-child(3)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 6); }); - - it('checks if Angle annotation can be added on viewport and on measurements panel', () => { - //Click on button and vefiry if icon is active on toolbar - cy.get('@angleBtn') - .click() - .then(($angleBtn) =>{ - cy.wrap($angleBtn) - .should('have.class', 'active') - }) - - //Add annotation on the viewport - const initPos = [180, 390]; - const midPos = [300, 410]; - const finalPos = [180, 450]; - cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos); - - //Verify if measurement annotation was added into the measurements panel - cy.get('@measurementsBtn') - .click() - .then($measurementsBtn => { - cy.get('@measurementsPanel') - .should('be.visible'); - - cy.get('.measurementItem') - .its('length') - .should('be.eq', 2); - - cy.wrap($measurementsBtn) - .click(); - }) + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(3) > :nth-child(2)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 6); }); - - it('checks if Reset tool will reset all changes made on the image', () => { - //Make some changes by zooming in and rotating the image - cy.imageZoomIn(); - cy.imageContrast(); - - //Click on reset button - cy.get('@resetBtn').click() - - const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-right.overlay-element > div'; - const expectedText = 'Zoom: 211%W: 820 L: 410Lossless / Uncompressed'; - cy.get(overlaySeriesInformation) - .should('have.text', expectedText); - }); - - - it('checks if CINE tool will prompt a modal with working controls', () => { - //Click on button - cy.get('@cineBtn') - .click(); - //Vefiry if cine control overlay is being displayed - cy.get('.cine-controls').as('cineControls') - .should('be.visible'); - - //Test PLAY button - cy.get('[title="Play / Stop"]') - .click() - .wait(100) - .click(); - - const overlaySeriesInformation = 'div.ViewportOverlay > div.bottom-left.overlay-element > div'; - let expectedText = 'Img: 1 1/26'; - cy.get(overlaySeriesInformation) - .should('not.have.text', expectedText); - - //Test SKIP TO FIRST IMAGE button - cy.get('[title="Skip to first Image"]') - .click() - cy.get(overlaySeriesInformation) - .should('contain.text', expectedText); - - //Test NEXT IMAGE button - cy.get('[title="Next Image"]') //Title is wrong and was reported on bug #995: https://github.com/OHIF/Viewers/issues/995 - .click() - expectedText = 'Img: 2 2/26'; - cy.get(overlaySeriesInformation) - .should('contain.text', expectedText); - - //Test SKIP TO LAST IMAGE button - cy.get('[title="Skip to last Image"]') //Title is wrong and was reported on bug #995: https://github.com/OHIF/Viewers/issues/995 - .click() - expectedText = 'Img: 27 26/26'; - cy.get(overlaySeriesInformation) - .should('contain.text', expectedText); - - //Test PREVIOUS IMAGE button - cy.get('[title="Previous Image"]') - .click() - expectedText = 'Img: 26 25/26'; - cy.get(overlaySeriesInformation) - .should('contain.text', expectedText); - - //Click on Cine button - cy.get('@cineBtn') - .click(); - //Vefiry if cine control overlay is hidden - cy.get('@cineControls') - .should('not.be.visible'); - }); - - - it('checks if More button will prompt a modal with secondary tools', () => { - cy.get('@moreBtn') - .click(); - //Verify if overlay is displayed - cy.get('.tooltip-toolbar-overlay').as('toolbarOverlay') - .should('be.visible'); - - let iconName; - //Click on one of the secondary tools from the overlay - cy.get('.tooltip-inner > :nth-child(1)') - .click() - .then(($magnifyBtn) =>{ - cy.wrap($magnifyBtn) - .should('have.class', 'active') - .find('svg').then(($icon)=>{ - iconName = $icon.text(); - }) - }) - - //Check if More button is active and if it has same icon as the secondary tool selected - cy.get('@moreBtn') - .click() - .then(($moreBtn) =>{ - cy.wrap($moreBtn) - .should('have.class', 'active') - .contains(iconName); - }) - - //Verify if overlay is hidden - cy.get('@toolbarOverlay') - .should('not.be.visible'); + //verify if layout has changed to 9 viewports + cy.get('@layoutBtn').click(); + cy.get('tbody > :nth-child(3) > :nth-child(3)').click(); + cy.get('.viewport-container').then($viewport => { + cy.wrap($viewport) + .its('length') + .should('be.eq', 9); }); + //Commented this to avoid throwing an wrong exception at the end of "Layout button" test + //this commented section should be uncommented once issue #999 is fixed. (https://github.com/OHIF/Viewers/issues/999) - it('checks if Layout tool will multiply the number of viewports displayed', () => { - //Click on Layout button and verify if overlay is displayed - cy.get('@layoutBtn') - .click() - .then(() => { - cy.get('.layoutChooser').as('layoutChooser') - .should('be.visible') - .find('td') - .its('length') - .should('be.eq', 9); - }) - - //verify if layout has changed to 2 viewports - cy.get('tbody > :nth-child(1) > :nth-child(2)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 2); - }) - - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(2) > :nth-child(1)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 2); - }) + //verify if layout has changed to 1 viewport + // cy.get('@layoutBtn').click(); + // cy.get('tbody > :nth-child(1) > :nth-child(1)').click(); + // cy.get('.viewport-container').then(($viewport) =>{ + // cy.wrap($viewport) + // .its('length') + // .should('be.eq', 1); + // }) + cy.reload(); + cy.waitDicomImage(); + }); - //verify if layout has changed to 3 viewports - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(1) > :nth-child(3)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wait(1000); - cy.wrap($viewport) - .its('length') - .should('be.eq', 3); - }) - - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(3) > :nth-child(1)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 3); - }) + it('checks if Clear tool will delete all measurements added in the viewport', () => { + //Add measurements in the viewport + cy.get('@lengthBtn').click(); + const firstClick = [150, 100]; + const secondClick = [130, 170]; + cy.addLine('.cornerstone-canvas', firstClick, secondClick); - //verify if layout has changed to 4 viewports - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(2) > :nth-child(2)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 4); - }) + cy.get('@angleBtn').click(); + const initPos = [180, 390]; + const midPos = [300, 410]; + const finalPos = [180, 450]; + cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos); - //verify if layout has changed to 6 viewports - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(2) > :nth-child(3)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 6); - }) + //Verify if measurement annotation was added into the measurements panel + cy.get('@measurementsBtn').click(); + cy.get('.measurementItem') + .its('length') + .should('be.eq', 2); - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(3) > :nth-child(2)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 6); - }) + //Click on More button + cy.get('@moreBtn').click(); + //Verify if overlay is displayed + cy.get('.tooltip-toolbar-overlay') + .as('toolbarOverlay') + .should('be.visible'); + //Click on Clear button + cy.get('.tooltip-inner > :nth-child(10)').click(); - //verify if layout has changed to 9 viewports - cy.get('@layoutBtn').click(); - cy.get('tbody > :nth-child(3) > :nth-child(3)').click(); - cy.get('.viewport-container').then(($viewport) =>{ - cy.wrap($viewport) - .its('length') - .should('be.eq', 9); - }) + //Verify if measurements were removed from the measurements panel + cy.get('.measurementItem').should('not.exist'); - //Commented this to avoid throwing an wrong exception at the end of "Layout button" test - //this commented section should be uncommented once issue #999 is fixed. (https://github.com/OHIF/Viewers/issues/999) - - //verify if layout has changed to 1 viewport - // cy.get('@layoutBtn').click(); - // cy.get('tbody > :nth-child(1) > :nth-child(1)').click(); - // cy.get('.viewport-container').then(($viewport) =>{ - // cy.wrap($viewport) - // .its('length') - // .should('be.eq', 1); - // }) + //Close More button overlay + cy.get('@moreBtn').click(); + //Close the measurements panel + cy.get('@measurementsBtn').then($btn => { + $btn.click(); + cy.get('@measurementsPanel').should('not.be.enabled'); }); + }); - }); \ No newline at end of file + it('checks if Eraser tool will remove the measurements added in the viewport', () => { + //Add measurements in the viewport + cy.get('@lengthBtn').click(); + const firstClick = [150, 100]; + const secondClick = [130, 170]; + cy.addLine('.cornerstone-canvas', firstClick, secondClick); + + cy.get('@angleBtn').click(); + const initPos = [180, 390]; + const midPos = [300, 410]; + const finalPos = [180, 450]; + cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos); + + //Verify if measurement annotation was added into the measurements panel + cy.get('@measurementsBtn').click(); + cy.get('.measurementItem') + .its('length') + .should('be.eq', 2); + cy.get('@measurementsBtn').click(); + + //Click More button + cy.get('@moreBtn').click(); + //Click Eraser button + cy.get('.tooltip-inner > :nth-child(12)').click(); + + //Erase measurement #1 and Verify if it was removed from the measurements panel + const [x1, y1] = firstClick; + cy.get('@viewport').click(x1, y1, { force: true }); + cy.get('.measurementItem') + .its('length') + .should('be.eq', 1); + + //Erase measurement #2 and Verify if it was removed from the measurements panel + const [x2, y2] = initPos; + cy.get('@viewport').click(x2, y2, { force: true }); + cy.get('.measurementItem').should('not.exist'); + }); +}); diff --git a/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js b/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js index f5fc1c2ec..04a6fa122 100644 --- a/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js +++ b/platform/viewer/cypress/integration/common/OHIFStudyViewer.spec.js @@ -4,45 +4,90 @@ describe('OHIF Study Viewer Page', () => { cy.waitDicomImage(); }); + beforeEach(() => { + cy.initCommonElementsAliases(); + //Following best practices, reset should be done before each test + cy.resetViewport(); + }); + it('checks if series thumbnails are being displayed', () => { - cy.get('[data-cy="thumbnail-list"]') + cy.get('.ThumbnailEntryContainer') .its('length') .should('be.gt', 1); }); it('drags and drop a series thumbnail into viewport', () => { - cy.get('[data-cy="thumbnail-list"]:nth-child(2)') //element to be dragged + cy.get('.ThumbnailEntryContainer:nth-child(2)') //element to be dragged .drag('.cornerstone-canvas'); //dropzone element - const overlaySeriesInformation = - 'div.ViewportOverlay > div.bottom-left.overlay-element > div'; const expectedText = 'Ser: 2Img: 1 1/13512 x 512Loc: -17.60 mm Thick: 3.00 mm'; - - cy.get(overlaySeriesInformation).should('have.text', expectedText); + cy.get('@viewportInfoBottomLeft').should('contain.text', expectedText); }); it('checks if Series left panel can be hidden/displayed', () => { - const seriesButton = - '.pull-left > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton'; - const leftPanel = 'section.sidepanel.from-left'; + cy.get('@seriesBtn').click(); + cy.get('@seriesPanel').should('not.be.enabled'); - cy.get(seriesButton).click(); - cy.get(leftPanel).should('not.be.enabled'); - - cy.get(seriesButton).click(); - cy.get(leftPanel).should('be.visible'); + cy.get('@seriesBtn').click(); + cy.get('@seriesPanel').should('be.visible'); }); it('checks if Measurements right panel can be hidden/displayed', () => { - const measurementsButton = - '.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton'; - const rightPanel = 'section.sidepanel.from-right'; + cy.get('@measurementsBtn').click(); + cy.get('@measurementsPanel').should('be.visible'); - cy.get(measurementsButton).click(); - cy.get(rightPanel).should('be.visible'); - - cy.get(measurementsButton).click(); - cy.get(rightPanel).should('not.be.enabled'); + cy.get('@measurementsBtn').click(); + cy.get('@measurementsPanel').should('not.be.enabled'); }); + + it('checks if measurement item can be Relabeled under Measurements panel', () => { + cy.addLengthMeasurement(); //Adding measurement in the viewport + cy.get('@measurementsBtn').click(); + cy.get('.measurementItem').click(); + + // Click "Relabel" + cy.get('.btnAction') + .contains('Relabel') + .click(); + + // Search for "Bone" + cy.get('.searchInput').type('Bone'); + + // Select "Bone" Result + cy.get('.treeInputs > .wrapperLabel') + .contains('Bone') + .click(); + + // Confirm Selection + cy.get('.checkIconWrapper').click(); + + //Verify if 'Bone' label was added + cy.get('.measurementLocation').should('contain.text', 'Bone'); + }); + + //TO-DO: Test case will fail due to issue #1013: https://github.com/OHIF/Viewers/issues/1013 + + // it('checks if Description can be added to measurement item under Measurements panel', () => { + // cy.addLengthMeasurement(); //Adding measurement in the viewport + // cy.get('@measurementsBtn').click(); + // cy.get('.measurementItem').click(); + // + // // Click "Description" + // cy.get('.btnAction') + // .contains('Description') + // .click(); + // + // // Enter description text + // const descriptionText = 'Adding text for description test'; + // cy.get('#description') + // .type(descriptionText); + // + // // Confirm + // cy.get('.btn-confirm').click(); + // + // //Verify if descriptionText was added + // cy.get('.measurementLocation') + // .should('contain.text', descriptionText); + // }); }); diff --git a/platform/viewer/cypress/support/aliases.js b/platform/viewer/cypress/support/aliases.js new file mode 100644 index 000000000..b914c506c --- /dev/null +++ b/platform/viewer/cypress/support/aliases.js @@ -0,0 +1,34 @@ +//Creating aliases for Cornerstone tools buttons +export function initCornerstoneToolsAliases() { + cy.get('.ToolbarRow > :nth-child(2)').as('stackScrollBtn'); + cy.get('.ToolbarRow > :nth-child(3)').as('zoomBtn'); + cy.get('.ToolbarRow > :nth-child(4)').as('levelsBtn'); + cy.get('.ToolbarRow > :nth-child(5)').as('panBtn'); + cy.get('.ToolbarRow > :nth-child(6)').as('lengthBtn'); + cy.get('.ToolbarRow > :nth-child(7)').as('annotateBtn'); + cy.get('.ToolbarRow > :nth-child(8)').as('angleBtn'); + cy.get('.ToolbarRow > :nth-child(9)').as('resetBtn'); + cy.get('.ToolbarRow > :nth-child(10)').as('cineBtn'); + cy.get('.expandableToolMenu').as('moreBtn'); + cy.get('.PluginSwitch > .toolbar-button').as('twodmprBtn'); + cy.get('.btn-group > .toolbar-button').as('layoutBtn'); +} + +//Creating aliases for Common page elements +export function initCommonElementsAliases() { + cy.get( + '.pull-right > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton' + ).as('measurementsBtn'); + cy.get('.viewport-element').as('viewport'); + cy.get('section.sidepanel.from-right').as('measurementsPanel'); + cy.get( + '.pull-left > .RoundedButtonGroup > .roundedButtonWrapper > .roundedButton' + ).as('seriesBtn'); + cy.get('section.sidepanel.from-left').as('seriesPanel'); + cy.get('div.ViewportOverlay > div.bottom-left.overlay-element > div').as( + 'viewportInfoBottomLeft' + ); + cy.get('div.ViewportOverlay > div.bottom-right.overlay-element > div').as( + 'viewportInfoBottomRight' + ); +} diff --git a/platform/viewer/cypress/support/commands.js b/platform/viewer/cypress/support/commands.js index c9064aa28..9cfd2e6ee 100644 --- a/platform/viewer/cypress/support/commands.js +++ b/platform/viewer/cypress/support/commands.js @@ -1,6 +1,8 @@ import { DragSimulator } from '../helpers/DragSimulator.js'; -import { doesNotReject } from 'assert'; -import { disconnect } from 'cluster'; +import { + initCornerstoneToolsAliases, + initCommonElementsAliases, +} from './aliases.js'; // *********************************************** // This example commands.js shows you how to @@ -28,6 +30,11 @@ import { disconnect } from 'cluster'; // -- This is will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +/** + * Command to search for a patient name and open his/her study. + * + * @param {string} PatientName - Patient name that we would like to search for + */ Cypress.Commands.add('openStudy', patientName => { cy.visit('/'); cy.get('#patientName').type(patientName); @@ -39,6 +46,12 @@ Cypress.Commands.add('openStudy', patientName => { }); }); +/** + * Command to perform a drag and drop action. Before using this command, we must get the element that should be dragged first. + * Example of usage: cy.get(element-to-be-dragged).drag(dropzone-element) + * + * @param {*} element - Selector for element that we want to use as dropzone + */ Cypress.Commands.add('drag', { prevSubject: 'element' }, (...args) => DragSimulator.simulate(...args) ); @@ -119,12 +132,26 @@ Cypress.Commands.add('waitDicomImage', (timeout = 20000) => { }); }); -//Command to reset the viewport changes throught the cornerstone method +//Command to reset and clear all the changes made to the viewport Cypress.Commands.add('resetViewport', () => { + cy.initCornerstoneToolsAliases(); cy.get('@resetBtn').click(); + //Click on More button + cy.get('@moreBtn').click(); + //Verify if overlay is displayed + cy.get('body').then(body => { + if (body.find('.tooltip-toolbar-overlay').length == 0) { + cy.get('@moreBtn').click(); + } + }); + //Click on Clear button + cy.get('.tooltip-inner > :nth-child(10)') + .as('clearBtn') + .click(); }); Cypress.Commands.add('imageZoomIn', () => { + cy.initCornerstoneToolsAliases(); cy.get('@zoomBtn').click(); //drags the mouse inside the viewport to be able to interact with series @@ -135,6 +162,7 @@ Cypress.Commands.add('imageZoomIn', () => { }); Cypress.Commands.add('imageContrast', () => { + cy.initCornerstoneToolsAliases(); cy.get('@levelsBtn').click(); //drags the mouse inside the viewport to be able to interact with series @@ -143,3 +171,32 @@ Cypress.Commands.add('imageContrast', () => { .trigger('mousemove', 'top', { which: 1 }) .trigger('mouseup'); }); + +//Initialize aliases for Cornerstone tools buttons +Cypress.Commands.add('initCornerstoneToolsAliases', () => { + initCornerstoneToolsAliases(); +}); + +//Initialize aliases for Common page elements +Cypress.Commands.add('initCommonElementsAliases', () => { + initCommonElementsAliases(); +}); + +//Add measurements in the viewport +Cypress.Commands.add('addLengthMeasurement', () => { + cy.initCornerstoneToolsAliases(); + cy.get('@lengthBtn').click(); + const firstClick = [150, 100]; + const secondClick = [130, 170]; + cy.addLine('.cornerstone-canvas', firstClick, secondClick); +}); + +//Add measurements in the viewport +Cypress.Commands.add('addAngleMeasurement', () => { + cy.initCornerstoneToolsAliases(); + cy.get('@angleBtn').click(); + const initPos = [180, 390]; + const midPos = [300, 410]; + const finalPos = [180, 450]; + cy.addAngle('.cornerstone-canvas', initPos, midPos, finalPos); +});