From 3b1d7ecfb6ae97cb22032756075b7a27575fee3e Mon Sep 17 00:00:00 2001 From: sabertazimi Date: Thu, 12 May 2022 21:02:00 +0800 Subject: [PATCH] test(e2e): add testing for `Header` menu items issue #849 --- .vscode/settings.json | 1 + cypress/integration/header.spec.ts | 122 +++++++++++++++++++++++++++++ cypress/integration/home.spec.ts | 11 +-- cypress/integration/routes.spec.ts | 13 --- cypress/support/commands.ts | 27 +++++++ cypress/support/index.ts | 13 +++ 6 files changed, 166 insertions(+), 21 deletions(-) create mode 100644 cypress/integration/header.spec.ts delete mode 100644 cypress/integration/routes.spec.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 905afd8d2..0d88071c4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "chainable", "codecov", "codesandbox", + "combobox", "flexbugs", "gemoji", "instanceof", diff --git a/cypress/integration/header.spec.ts b/cypress/integration/header.spec.ts new file mode 100644 index 000000000..e84e440a2 --- /dev/null +++ b/cypress/integration/header.spec.ts @@ -0,0 +1,122 @@ +import type { Route } from '@config'; +import { routes, siteConfig } from '@config'; + +describe('Header', () => { + const menuItems = ['/', ...routes, 'SearchBar', 'ThemeSwitch', 'Ellipsis']; + const logoIndex = 0; + const linksStartIndex = logoIndex + 1; + const searchBarIndex = linksStartIndex + routes.length; + const themeSwitchIndex = searchBarIndex + 1; + + it('should display fully menu items on each route', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu') + .findByRole('menuitem') + .should('have.length', menuItems.length); + }); + }); + + it('should route to home page when logo clicked', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu').findByRole('menuitem').eq(logoIndex).click(); + + cy.validRoute('/', siteConfig.title); + }); + }); + + it('should route to pages when links clicked', () => { + cy.wrap(routes).each((route: Route, index) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(index + linksStartIndex) + .click(); + + cy.validRoute(routes[index].path, routes[index].name); + }); + }); + + it('should focus search bar when search bar clicked', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(searchBarIndex) + .click() + .should('have.class', 'ant-menu-item-selected'); + }); + }); + + it('should search posts when search bar worked', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(searchBarIndex) + .findByRole('combobox') + .type('Notes') + .should('have.value', 'Notes'); + }); + }); + + it('should clear input when search bar clear button clicked', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(searchBarIndex) + .findByRole('combobox') + .type('Notes') + .should('have.value', 'Notes'); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(searchBarIndex) + .findByLabel('close-circle') + .click(); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(searchBarIndex) + .findByRole('combobox') + .should('have.value', ''); + }); + }); + + it('should switch theme when theme switch button clicked', () => { + cy.wrap(routes).each((route: Route) => { + cy.visitRoute(route.path, route.name); + cy.clearLocalStorage(); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(themeSwitchIndex) + .findByLabel('Sun') + .click(); + + cy.window().then(window => { + expect(window.localStorage.getItem('dark-mode')).to.equal('true'); + expect(window.document.body.classList.contains('dark')).to.equal(true); + }); + + cy.getByRole('menu') + .findByRole('menuitem') + .eq(themeSwitchIndex) + .findByLabel('Moon') + .click(); + + cy.window().then(window => { + expect(window.localStorage.getItem('dark-mode')).to.equal('false'); + expect(window.document.body.classList.contains('dark')).to.equal(false); + }); + }); + }); +}); diff --git a/cypress/integration/home.spec.ts b/cypress/integration/home.spec.ts index f3764f62c..a69342dcd 100644 --- a/cypress/integration/home.spec.ts +++ b/cypress/integration/home.spec.ts @@ -1,16 +1,11 @@ import { routes, siteConfig } from '@config'; -describe('Home', () => { +describe('Home Page', () => { beforeEach(() => { - cy.visit('/'); + cy.visitRoute('/', siteConfig.title); }); - it('should contain home page route', () => { - cy.url().should('include', '/'); - cy.title().should('include', siteConfig.title); - }); - - it('should display home page title', () => { + it('should display page title', () => { cy.getByRole('main').should('be.visible'); }); diff --git a/cypress/integration/routes.spec.ts b/cypress/integration/routes.spec.ts deleted file mode 100644 index 0c91c611a..000000000 --- a/cypress/integration/routes.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Route } from '@config'; -import { routes } from '@config'; - -describe('Routes', () => { - it('should make all routes accessible', () => { - cy.wrap(routes).each((route: Route) => { - cy.visit(route.path); - - cy.url().should('include', route.path); - cy.title().should('include', route.name); - }); - }); -}); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 180698f8b..6761e89bb 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -26,6 +26,16 @@ Cypress.Commands.add( } ); +Cypress.Commands.add( + 'findByLabel', + { prevSubject: 'element' }, + (subject, label, options) => { + return cy + .wrap(subject, { log: false }) + .find(`[aria-label="${label}"]`, options); + } +); + Cypress.Commands.add('getByRole', (role, options) => { return cy.get(`[role="${role}"]`, options); }); @@ -33,3 +43,20 @@ Cypress.Commands.add('getByRole', (role, options) => { Cypress.Commands.add('getByTestId', (testId, options) => { return cy.get(`[data-testid="${testId}"]`, options); }); + +Cypress.Commands.add('getByLabel', (label, options) => { + return cy.get(`[aria-label="${label}"]`, options); +}); + +Cypress.Commands.add('validRoute', (path, title) => { + cy.url().should('include', path); + + if (title) { + cy.title().should('include', title); + } +}); + +Cypress.Commands.add('visitRoute', (path, title) => { + cy.visit(path); + cy.validRoute(path, title); +}); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index 4322c2a0d..505e8d305 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -15,6 +15,11 @@ declare global { options?: Parameters[1] ): Chainable>; + findByLabel( + label: Parameters[0], + options?: Parameters[1] + ): Chainable>; + getByRole( role: Parameters[0], options?: Parameters[1] @@ -24,6 +29,14 @@ declare global { testId: Parameters[0], options?: Parameters[1] ): Chainable>; + + getByLabel( + label: Parameters[0], + options?: Parameters[1] + ): Chainable>; + + validRoute(path: string, title?: string): void; + visitRoute(path: string, title?: string): void; } } }