diff --git a/packages/react/package.json b/packages/react/package.json index a686943fd18..3134cc96ad6 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -41,6 +41,7 @@ "test:e2e:test:no-percy": "start-server-and-test 'yarn test:e2e:run' 8080 'cypress run --config video=false --config-file tests/e2e/cypress.json'", "test:e2e-storybook:run": "http-server -c-1 storybook-static --silent -p 8082", "test:e2e-storybook:test": "start-server-and-test 'yarn test:e2e-storybook:run' 8082 'percy exec --config tests/e2e-storybook/.percy.json -- cypress run --config video=false --config-file tests/e2e-storybook/cypress.json'", + "test:e2e-storybook:dev": "cypress open --config-file ./tests/e2e-storybook/cypress-local.json", "test:e2e-storybook:test:no-percy": "start-server-and-test 'yarn test:e2e-storybook:run' 8082 'cypress run --config video=false --config-file tests/e2e-storybook/cypress.json'", "test:e2e-storybook:test:no-percy:with-video": "start-server-and-test 'yarn test:e2e-storybook:run' 8082 'cypress run --config-file tests/e2e-storybook/cypress.json'", "test:e2e-storybook:browserstack:canary": "browserstack-cypress run --cf tests/e2e-storybook/browserstack.json --ccf tests/e2e-storybook/cypress-canary.json --sync", diff --git a/packages/react/tests/e2e-storybook/cypress-local.json b/packages/react/tests/e2e-storybook/cypress-local.json new file mode 100644 index 00000000000..9a7adfd38e7 --- /dev/null +++ b/packages/react/tests/e2e-storybook/cypress-local.json @@ -0,0 +1,17 @@ +{ + "baseUrl": "http://localhost:9000", + "browser": "chrome", + "headless": true, + "fixturesFolder": "tests/e2e-storybook/cypress/fixtures", + "fileServerFolder": "storybook-static", + "screenshotsFolder": "tests/e2e-storybook/cypress/screenshots", + "videosFolder": "tests/e2e-storybook/cypress/videos", + "integrationFolder": "tests/e2e-storybook/cypress/integration", + "supportFile": "tests/e2e-storybook/cypress/support/index.js", + "pluginsFile": "tests/e2e-storybook/cypress/plugins/index.js", + "nodeVersion": "system", + "includeShadowDom": true, + "testFiles": "**/*.e2e.js", + "pageLoadTimeout": 40000, + "defaultCommandTimeout": 40000 +} diff --git a/packages/react/tests/e2e-storybook/cypress/integration/TableOfContents/TableOfContents.e2e.js b/packages/react/tests/e2e-storybook/cypress/integration/TableOfContents/TableOfContents.e2e.js index 66aa7bdddf6..e69cf3bfe4d 100644 --- a/packages/react/tests/e2e-storybook/cypress/integration/TableOfContents/TableOfContents.e2e.js +++ b/packages/react/tests/e2e-storybook/cypress/integration/TableOfContents/TableOfContents.e2e.js @@ -11,51 +11,357 @@ * @type {string} * @private */ -const _path = - '/iframe.html?id=components-table-of-contents--manually-define-menu-items'; +const _paths = { + manual_default: + 'iframe.html?id=components-table-of-contents--manually-define-menu-items', + dynamic_default: 'iframe.html?id=components-table-of-contents--dynamic-items', + heading_content: + 'iframe.html?id=components-table-of-contents--with-heading-content', +}; -/* eslint-disable cypress/no-unnecessary-waiting */ -describe('TableOfContents | manually defined', () => { - it('should load the g100 theme', () => { - cy.visit(`${_path}&theme=g100`); - cy.viewport(1280, 780); +/** + * Collection of all tests for dds-table-of-contents + * + * @property {function} all + * @property {function} desktop + * @property {function} mobile + * @private + */ +const _tests = { + /** + * Collection of tests for use across browser dimensions. + * + * @function screenshotThemes - Takes a screenshot of the given page in each theme. + */ + all: { + screenshotThemes: () => { + cy.carbonThemesScreenshot({ + capture: 'viewport', + }); + }, + }, + /** + * Collection of tests for use on desktop-sized viewports. + * + * @function checkRender - Asserts [linkID] === [sectionID] + * @function checkLinkFunctionality - Asserts each link scrolls page to proper position + * @function checkScrollSpy - Asserts each link updates onscroll properly + * @function checkStickyNav - Asserts navigation stays within viewport + */ + desktop: { + checkRender: () => { + const navItemsIds = []; + const sectionIds = []; + + cy.get('.bx--tableofcontents__desktop__item a') + .each(link => { + navItemsIds.push(link.attr('href').replace('#', '')); + }) + .get('a[name]') + .each(section => { + sectionIds.push(section.attr('name')); + }) + .then(() => { + expect(navItemsIds).to.deep.equal(sectionIds); + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [1280], + }); + }); + }, + checkLinkFunctionality: () => { + const maxScrollVal = document.body.clientHeight - window.innerHeight; - cy.get('[data-autoid="dds--tableofcontents"]'); - cy.wait(500); + cy.get('.bx--tableofcontents__desktop__item a').each((link, i) => { + cy.get(link) + .click() + .get(`a[name="${link.attr('href').replace('#', '')}"]`) + .then(section => { + const sectionScrolledTo = + section.offset().top === 0 || window.scrollY === maxScrollVal; + expect(sectionScrolledTo).to.be.true; + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [1280], + }); + } + }); + }); + }, + checkScrollSpy: () => { + cy.get('a[name]').each((section, i) => { + cy.scrollTo(0, section.offset().top) + .wait(1000) // Give the browser time to execute the event callback. + .get(`a[href="#${section.attr('name')}"]`) + .then(link => { + expect(link.attr('aria-current')).to.equal('location'); + expect(link.parent()).to.have.class( + 'bx--tableofcontents__desktop__item--active' + ); + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [1280], + }); + } + }); + }); + }, + checkStickyNav: () => { + cy.wrap(['top', 'center', 'bottom']).each(pos => { + cy.scrollTo(pos) + .get('.bx--tableofcontents__desktop') + .then(sidebar => { + expect(sidebar.offset().top).to.be.greaterThan(0); + if (pos === 'bottom') { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [1280], + }); + } + }); + }); + }, + }, + /** + * Collection of tests for use on mobile-sized viewports. + * + * @function checkRender - Asserts [optionID] === [sectionID] + * @function checkLinkFunctionality - Asserts each select option scrolls page to proper position + * @function checkScrollSpy - Asserts select nav updates onscroll properly + * @function checkStickyNav - Asserts navigation stays within viewport + */ + mobile: { + checkRender: () => { + const navItemsIds = []; + const sectionIds = []; - cy.screenshot(); + cy.get('.bx--tableofcontents__mobile__select__option:not([disabled])') + .each(option => { + navItemsIds.push(option.val()); + }) + .get('a[name]') + .each(section => { + sectionIds.push(section.attr('name')); + }) + .then(() => { + expect(navItemsIds).to.deep.equal(sectionIds); + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [320], + }); + }); + }, + checkLinkFunctionality: () => { + const maxScrollVal = document.body.clientHeight - window.innerHeight; - // Take a snapshot for visual diffing - cy.percySnapshot('TableOfContents | manually defined | g100 theme', { - widths: [1280], - }); + cy.get( + '.bx--tableofcontents__mobile__select__option:not([disabled])' + ).each((option, i) => { + cy.get(option) + .parent() + .select(option.val()) + .get(`a[name=${option.val()}]`) + .then(section => { + const sectionScrolledTo = + section.offset().top === 0 || window.scrollY === maxScrollVal; + expect(sectionScrolledTo).to.be.true; + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [320], + }); + } + }); + }); + }, + checkScrollSpy: () => { + cy.get('a[name]').each((section, i) => { + cy.scrollTo(0, section.offset().top) + .wait(1000) // Give the browser time to execute the event callback. + .get('.bx--tableofcontents__mobile__select') + .then(select => { + expect(select.val()).to.equal(section.attr('name')); + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [320], + }); + } + }); + }); + }, + checkStickyNav: () => { + cy.wrap(['top', 'center', 'bottom']).each(pos => { + cy.scrollTo(pos) + .get('.bx--tableofcontents__mobile') + .then(mobileNav => { + expect(mobileNav.offset().top).to.be.greaterThan(-1); + if (pos === 'bottom') { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // Take a snapshot for visual diffing + cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + widths: [320], + }); + } + }); + }); + }, + }, +}; + +describe('TableOfContents | manually defined (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.manual_default}`); }); - it('should load the g90 theme', () => { - cy.visit(`${_path}&theme=g90`); - cy.viewport(1280, 780); + it( + 'should load table of contents sidebar with links', + _tests.desktop.checkRender + ); + it( + 'should navigate content to selected section', + _tests.desktop.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.desktop.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); - cy.get('[data-autoid="dds--tableofcontents"]'); - cy.wait(500); +describe('TableOfContents | dynamically defined (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.dynamic_default}`); + }); + + it( + 'should load table of contents sidebar with links', + _tests.desktop.checkRender + ); + it( + 'should navigate content to selected section', + _tests.desktop.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.desktop.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); - cy.screenshot(); - // Take a snapshot for visual diffing - cy.percySnapshot('TableOfContents | manually defined | g90 theme', { - widths: [1280], - }); +describe('TableOfContents | with heading content (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.heading_content}`); }); - it('should load the g10 theme', () => { - cy.visit(`${_path}&theme=g10`); - cy.viewport(1280, 780); + it( + 'should load table of contents horizontal bar with links', + _tests.desktop.checkRender + ); + it( + 'should navigate content to selected section', + _tests.desktop.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.desktop.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); - cy.get('[data-autoid="dds--tableofcontents"]'); - cy.wait(500); +describe('TableOfContents | manually defined (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.manual_default}`); + }); - cy.screenshot(); - // Take a snapshot for visual diffing - cy.percySnapshot('TableOfContents | manually defined | g10 theme', { - widths: [1280], - }); + it( + 'should load table of contents sidebar with links', + _tests.mobile.checkRender + ); + it( + 'should navigate content to selected section', + _tests.mobile.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.mobile.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('TableOfContents | dynamically defined (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.dynamic_default}`); }); + + it( + 'should load table of contents sidebar with links', + _tests.mobile.checkRender + ); + it( + 'should navigate content to selected section', + _tests.mobile.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.mobile.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('TableOfContents | with heading content (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.heading_content}`); + }); + + it( + 'should load table of contents sidebar with links', + _tests.mobile.checkRender + ); + it( + 'should navigate content to selected section', + _tests.mobile.checkLinkFunctionality + ); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it( + 'should remain visible on page throughout scroll', + _tests.mobile.checkStickyNav + ); + it('should render correctly in all themes', _tests.all.screenshotThemes); }); diff --git a/packages/react/tests/e2e-storybook/cypress/support/commands.js b/packages/react/tests/e2e-storybook/cypress/support/commands.js index df4f1a44721..60baff55919 100644 --- a/packages/react/tests/e2e-storybook/cypress/support/commands.js +++ b/packages/react/tests/e2e-storybook/cypress/support/commands.js @@ -26,3 +26,20 @@ Cypress.Commands.add('mockMastheadFooterData', () => { fixture: 'typeahead.json', }); }); + +/** + * Cycle through carbon themes and take a screenshot + */ +Cypress.Commands.add('carbonThemesScreenshot', (screenshotOpts = {}) => { + const themes = ['white', 'g10', 'g90', 'g100']; + + cy.wrap(themes).each(theme => { + cy.get('html') + .then(doc => doc.attr('storybook-carbon-theme', theme)) + .screenshot( + `${Cypress.currentTest.titlePath[0]} [${theme.toUpperCase()}]`, + screenshotOpts + ) + .percySnapshot(`${Cypress.currentTest.titlePath[0]}`); + }); +}); diff --git a/packages/web-components/package.json b/packages/web-components/package.json index 11c12a22125..afa42a9d8e7 100644 --- a/packages/web-components/package.json +++ b/packages/web-components/package.json @@ -77,6 +77,7 @@ "test:e2e-storybook:browserstack:canary": "browserstack-cypress run --cf tests/e2e-storybook/browserstack.json --ccf tests/e2e-storybook/cypress-canary.json --sync", "test:e2e-storybook:browserstack:staging": "browserstack-cypress run --cf tests/e2e-storybook/browserstack.json --ccf tests/e2e-storybook/cypress-staging.json --sync", "test:e2e-storybook:run": "http-server -c-1 storybook-static --silent -p 8081", + "test:e2e-storybook:dev": "cypress open --config-file ./tests/e2e-storybook/cypress-local.json", "test:e2e-storybook:test": "start-server-and-test 'yarn test:e2e-storybook:run' 8081 'percy exec --config tests/e2e-storybook/.percy.json -- cypress run --config video=false --config-file tests/e2e-storybook/cypress.json'", "test:e2e-storybook:test:no-percy": "start-server-and-test 'yarn test:e2e-storybook:run' 8081 'cypress run --config video=false --config-file tests/e2e-storybook/cypress.json'", "test:e2e-storybook:test:no-percy:with-video": "start-server-and-test 'yarn test:e2e-storybook:run' 8081 'cypress run --config-file tests/e2e-storybook/cypress.json'", diff --git a/packages/web-components/tests/e2e-storybook/cypress-local.json b/packages/web-components/tests/e2e-storybook/cypress-local.json new file mode 100644 index 00000000000..9a7adfd38e7 --- /dev/null +++ b/packages/web-components/tests/e2e-storybook/cypress-local.json @@ -0,0 +1,17 @@ +{ + "baseUrl": "http://localhost:9000", + "browser": "chrome", + "headless": true, + "fixturesFolder": "tests/e2e-storybook/cypress/fixtures", + "fileServerFolder": "storybook-static", + "screenshotsFolder": "tests/e2e-storybook/cypress/screenshots", + "videosFolder": "tests/e2e-storybook/cypress/videos", + "integrationFolder": "tests/e2e-storybook/cypress/integration", + "supportFile": "tests/e2e-storybook/cypress/support/index.js", + "pluginsFile": "tests/e2e-storybook/cypress/plugins/index.js", + "nodeVersion": "system", + "includeShadowDom": true, + "testFiles": "**/*.e2e.js", + "pageLoadTimeout": 40000, + "defaultCommandTimeout": 40000 +} diff --git a/packages/web-components/tests/e2e-storybook/cypress/integration/table-of-contents/table-of-contents.e2e.js b/packages/web-components/tests/e2e-storybook/cypress/integration/table-of-contents/table-of-contents.e2e.js new file mode 100644 index 00000000000..69d3d1e4c60 --- /dev/null +++ b/packages/web-components/tests/e2e-storybook/cypress/integration/table-of-contents/table-of-contents.e2e.js @@ -0,0 +1,305 @@ +/** + * Copyright IBM Corp. 2021 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * Sets the correct path + * + * @type {string} + * @private + */ +const _paths = { + default: 'iframe.html?id=components-table-of-contents--default', + heading: 'iframe.html?id=components-table-of-contents--with-heading-content', + horizontal: 'iframe.html?id=components-table-of-contents--horizontal', +}; + +/** + * Collection of all tests for dds-table-of-contents + * + * @property {function} all + * @property {function} desktop + * @property {function} mobile + * @private + */ +const _tests = { + /** + * Collection of tests for use across browser dimensions. + * + * @function screenshotThemes - Takes a screenshot of the given page in each theme. + */ + all: { + screenshotThemes: () => { + cy.carbonThemesScreenshot({ + capture: 'viewport', + }); + }, + }, + /** + * Collection of tests for use on desktop-sized viewports. + * + * @function checkRender - Asserts [linkID] === [sectionID] + * @function checkLinkFunctionality - Asserts each link scrolls page to proper position + * @function checkScrollSpy - Asserts each link updates onscroll properly + * @function checkStickyNav - Asserts navigation stays within viewport + */ + desktop: { + checkRender: () => { + const navItemsIds = []; + const sectionIds = []; + + cy.get('.bx--tableofcontents__desktop-container .bx--tableofcontents__desktop__item a') + .each(link => { + navItemsIds.push(link.attr('data-target')); + }) + .get('a[name]') + .each(section => { + sectionIds.push(section.attr('name')); + }) + .then(() => { + expect(navItemsIds).to.deep.equal(sectionIds); + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [1280], + // }); + }); + }, + checkLinkFunctionality: () => { + const maxScrollVal = document.body.clientHeight - window.innerHeight; + + cy.get('.bx--tableofcontents__desktop-container .bx--tableofcontents__desktop__item a').each(link => { + cy.get(link) + .click() + .get(`a[name="${link.attr('data-target')}"]`) + .then((section, i) => { + const sectionScrolledTo = section.offset().top === 0 || window.scrollY === maxScrollVal; + expect(sectionScrolledTo).to.be.true; + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [1280], + // }); + } + }); + }); + }, + checkScrollSpy: () => { + cy.get('a[name]').each((section, i) => { + cy.scrollTo(0, section.offset().top) + .wait(1000) // Give the browser time to execute the event callback. + .get(`a[data-target="${section.attr('name')}"]`) + .then(link => { + expect(link.attr('aria-current')).to.equal('location'); + expect(link.parent()).to.have.class('bx--tableofcontents__desktop__item--active'); + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [1280], + // }); + } + }); + }); + }, + checkStickyNav: () => { + cy.wrap(['top', 'center', 'bottom']).each(pos => { + cy.scrollTo(pos) + .get('.bx--tableofcontents__desktop-container') + .then(sidebar => { + expect(sidebar.offset().top).to.be.greaterThan(0); + if (pos === 'bottom') { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [1280], + // }); + } + }); + }); + }, + }, + /** + * Collection of tests for use on mobile-sized viewports. + * + * @function checkRender - Asserts [optionID] === [sectionID] + * @function checkLinkFunctionality - Asserts each select option scrolls page to proper position + * @function checkScrollSpy - Asserts select nav updates onscroll properly + * @function checkStickyNav - Asserts navigation stays within viewport + */ + mobile: { + checkRender: () => { + const navItemsIds = []; + const sectionIds = []; + + cy.get('.bx--tableofcontents__mobile__select__option') + .each(option => { + navItemsIds.push(option.val()); + }) + .get('a[name]') + .each(section => { + sectionIds.push(section.attr('name')); + }) + .then(() => { + expect(navItemsIds).to.deep.equal(sectionIds); + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [320], + // }); + }); + }, + checkLinkFunctionality: () => { + const maxScrollVal = document.body.clientHeight - window.innerHeight; + + cy.get('.bx--tableofcontents__mobile__select__option').each((option, i) => { + cy.get(option) + .parent() + .select(option.val()) + .get(`a[name=${option.val()}]`) + .then(section => { + const sectionScrolledTo = section.offset().top === 0 || window.scrollY === maxScrollVal; + expect(sectionScrolledTo).to.be.true; + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [320], + // }); + } + }); + }); + }, + checkScrollSpy: () => { + cy.get('a[name]').each((section, i) => { + cy.scrollTo(0, section.offset().top) + .wait(1000) // Give the browser time to execute the event callback. + .get('.bx--tableofcontents__mobile__select') + .then(select => { + expect(select.val()).to.equal(section.attr('name')); + if (i === 1) { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [320], + // }); + } + }); + }); + }, + checkStickyNav: () => { + cy.wrap(['top', 'center', 'bottom']).each(pos => { + cy.scrollTo(pos) + .get('.bx--tableofcontents__mobile') + .then(mobileNav => { + expect(mobileNav.offset().top).to.be.greaterThan(0); + if (pos === 'bottom') { + cy.screenshot(`${Cypress.currentTest.titlePath[0]}`, { + capture: 'viewport', + }); + // TODO: Take a snapshot for visual diffing + // cy.percySnapshot(`${Cypress.currentTest.titlePath[0]}`, { + // widths: [320], + // }); + } + }); + }); + }, + }, +}; + +describe('dds-table-of-contents | default (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.default}`); + }); + + it('should load table of contents sidebar with links', _tests.desktop.checkRender); + it('should navigate content to selected section', _tests.desktop.checkLinkFunctionality); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.desktop.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('dds-table-of-contents | with heading content (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.heading}`); + }); + + it('should load table of contents sidebar with links', _tests.desktop.checkRender); + it('should navigate content to selected section', _tests.desktop.checkLinkFunctionality); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.desktop.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('dds-table-of-contents | horizontal (desktop)', () => { + beforeEach(() => { + cy.viewport(1280, 720); + cy.visit(`/${_paths.horizontal}`); + }); + + it('should load table of contents horizontal bar with links', _tests.desktop.checkRender); + it('should navigate content to selected section', _tests.desktop.checkLinkFunctionality); + it('should update current section on scroll', _tests.desktop.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.desktop.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('dds-table-of-contents | default (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.default}`); + }); + + it('should load table of contents sidebar with links', _tests.mobile.checkRender); + it('should navigate content to selected section', _tests.mobile.checkLinkFunctionality); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.mobile.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('dds-table-of-contents | with heading content (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.heading}`); + }); + + it('should load table of contents sidebar with links', _tests.mobile.checkRender); + it('should navigate content to selected section', _tests.mobile.checkLinkFunctionality); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.mobile.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); + +describe('dds-table-of-contents | horizontal (mobile)', () => { + beforeEach(() => { + cy.viewport(320, 720); + cy.visit(`/${_paths.horizontal}`); + }); + + it('should load table of contents sidebar with links', _tests.mobile.checkRender); + it('should navigate content to selected section', _tests.mobile.checkLinkFunctionality); + it('should update current section on scroll', _tests.mobile.checkScrollSpy); + it('should remain visible on page throughout scroll', _tests.mobile.checkStickyNav); + it('should render correctly in all themes', _tests.all.screenshotThemes); +}); diff --git a/packages/web-components/tests/e2e-storybook/cypress/support/commands.js b/packages/web-components/tests/e2e-storybook/cypress/support/commands.js index 83a9eb011c9..1c7475d1ac9 100644 --- a/packages/web-components/tests/e2e-storybook/cypress/support/commands.js +++ b/packages/web-components/tests/e2e-storybook/cypress/support/commands.js @@ -22,3 +22,18 @@ Cypress.Commands.add('mockMastheadFooterData', () => { fixture: 'typeahead.json', }); }); + +/** + * Cycle through carbon themes and take a screenshot + */ +Cypress.Commands.add('carbonThemesScreenshot', (screenshotOpts = {}) => { + const themes = ['white', 'g10', 'g90', 'g100']; + + cy.wrap(themes).each(theme => { + cy.get('html') + .then(doc => doc.attr('storybook-carbon-theme', theme)) + .screenshot(`${Cypress.currentTest.titlePath[0]} [${theme.toUpperCase()}]`, screenshotOpts); + // TODO: + //.percySnapshot(`${Cypress.currentTest.titlePath[0]}`); + }); +});