Skip to content

Commit

Permalink
setup e2e-website tests
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp committed Dec 27, 2021
1 parent 1a65adb commit df7910a
Show file tree
Hide file tree
Showing 8 changed files with 700 additions and 6 deletions.
31 changes: 31 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ parameters:
description: The dist-tag of react to be used
type: string
default: stable
e2e-base-url:
description: The base url for running end-to-end test
type: string
default: ''

defaults: &defaults
parameters:
react-dist-tag:
description: The dist-tag of react to be used
type: string
default: << pipeline.parameters.react-dist-tag >>
e2e-base-url:
description: The base url for running end-to-end test
type: string
default: << pipeline.parameters.e2e-base-url >>
environment:
# Keep in sync with "Save playwright cache"
PLAYWRIGHT_BROWSERS_PATH: /tmp/pw-browsers
Expand Down Expand Up @@ -202,6 +210,21 @@ jobs:
- run:
name: Run e2e tests
command: yarn test:e2e
test_e2e_website:
<<: *defaults
docker:
- image: mcr.microsoft.com/playwright@sha256:f08e263c95e83334104e6e2fee047ad92062a03af6ae94c0f8686ba2b3014823
environment:
NODE_ENV: development # Needed if playwright is in `devDependencies`
steps:
- checkout
- install_js:
browsers: true
- run:
name: yarn test:e2e-website
command: yarn test:e2e-website
environment:
PLAYWRIGHT_TEST_BASE_URL: << parameters.e2e-base-url >>
test_regressions:
<<: *defaults
docker:
Expand Down Expand Up @@ -241,3 +264,11 @@ workflows:
- test_regressions:
requires:
- checkout
e2e-website:
when:
equal: [e2e-website, << pipeline.parameters.workflow >>]
jobs:
- checkout
- test_e2e_website:
requires:
- checkout
43 changes: 43 additions & 0 deletions netlify/functions/deploy-succeeded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const fetch = require('node-fetch');

/**
* @param {object} event
* @param {string} event.body - https://jsoneditoronline.org/#left=cloud.fb1a4fa30a4f475fa6887071c682e2c1
*/
exports.handler = async (event) => {
const { payload } = JSON.parse(event.body);
const repo = payload.review_url.match(/github\.com\/(.*)\/pull\/(.*)/);
if (!repo) {
throw new Error(`No repo found at review_url: ${payload.review_url}`);
}

// eslint-disable-next-line no-console
console.info(`repo:`, repo[1]);
// eslint-disable-next-line no-console
console.info(`PR:`, repo[2]);
// eslint-disable-next-line no-console
console.info(`url:`, payload.deploy_ssl_url);

// for more details > https://circleci.com/docs/2.0/api-developers-guide/#
await fetch(`https://circleci.com/api/v2/project/gh/${repo[1]}/pipeline`, {
method: 'POST',
headers: {
'Content-type': 'application/json',
// token from https://app.netlify.com/sites/material-ui/settings/deploys#environment-variables
'Circle-Token': process.env.CIRCLE_CI_TOKEN,
},
body: JSON.stringify({
// For PR, /head is needed. https://support.circleci.com/hc/en-us/articles/360049841151
branch: `pull/${repo[2]}/head`,
parameters: {
// the parameters defined in .circleci/config.yml
workflow: 'e2e-website', // name of the workflow
'e2e-base-url': payload.deploy_ssl_url, // deploy preview url
},
}),
});
return {
statusCode: 200,
body: {},
};
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
"test:e2e:dev": "concurrently \"yarn test:e2e:build --watch\" \"yarn test:e2e:server\"",
"test:e2e:run": "mocha --config test/e2e/.mocharc.js 'test/e2e/**/*.test.{js,ts,tsx}'",
"test:e2e:server": "serve test/e2e -p 5001",
"test:e2e-website": "playwright test test/e2e-website --config test/e2e-website/playwright.config.ts",
"test:e2e-website:dev": "PLAYWRIGHT_TEST_BASE_URL=http://localhost:3001 playwright test test/e2e-website --config test/e2e-website/playwright.config.ts",
"test:regressions": "cross-env NODE_ENV=production yarn test:regressions:build && concurrently --success first --kill-others \"yarn test:regressions:run\" \"yarn test:regressions:server\"",
"test:regressions:build": "webpack --config test/regressions/webpack.config.js",
"test:regressions:dev": "concurrently \"yarn test:regressions:build --watch\" \"yarn test:regressions:server\"",
Expand Down Expand Up @@ -71,6 +73,7 @@
"@mui/material": "^5.2.5",
"@mui/styles": "^5.2.3",
"@mui/utils": "^5.2.3",
"@playwright/test": "1.17.1",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-node-resolve": "^13.1.1",
"@rollup/plugin-replace": "^3.0.0",
Expand Down
12 changes: 12 additions & 0 deletions test/e2e-website/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Docs end-to-end testing

## Running locally

1. Run `yarn docs:dev` to start docs in development server.
2. Run `yarn test:e2e-website` in a separate terminal to run the test suites (`*.spec.ts`) inside `test/e2e-website` folder.

> use --headed to run tests in headed browsers, check out [Playwright CLI](https://playwright.dev/docs/intro#command-line) for more options
## CI

After netlify deploy the preview site, the `netlify/functions/deploy-succeeded.js` hook calls CircleCI API to run the `e2e-website` workflow against the deployed url.
137 changes: 137 additions & 0 deletions test/e2e-website/data-grid-current.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { test as base, expect, Page } from '@playwright/test';
import kebabCase from 'lodash/kebabCase';
import { TestFixture } from './playwright.config';

const test = base.extend<TestFixture>({});

test.describe.parallel('Material docs', () => {
test('should have correct link with hash in the TOC', async ({ page }) => {
await page.goto(`/components/data-grid/getting-started/`);

const anchors = page.locator('[aria-label="Page table of contents"] ul a');

const anchorTexts = await anchors.allTextContents();

await Promise.all(
anchorTexts.map((text, index) => {
return expect(anchors.nth(index)).toHaveAttribute(
'href',
// This is fine for now even though the hash implementation (in textToHash.js) is not the same as kebabCase
`/components/data-grid/getting-started/#${kebabCase(text.toLowerCase())}`,
);
}),
);
});

test.describe.parallel('Demo page', () => {
test('should have correct link for API section', async ({ page }) => {
await page.goto(`/components/data-grid/`);

const anchors = await page.locator('div > h2#heading-api ~ ul a');

const anchorTexts = await anchors.allTextContents();

await Promise.all(
anchorTexts.map((text, index) => {
return expect(anchors.nth(index)).toHaveAttribute(
'href',
`/api/data-grid/${kebabCase(text)}/`,
);
}),
);
});

test('should have correct link for sidebar anchor', async ({ page }) => {
await page.goto(`/components/data-grid/`);

const anchor = await page.locator('nav[aria-label="documentation"] ul a:text-is("Overview")');

await expect(anchor).toHaveAttribute('href', `/components/data-grid/`);
});
});

test.describe.parallel('API page', () => {
test('should have correct link for sidebar anchor', async ({ page }) => {
await page.goto(`/api/data-grid/data-grid/`);

const anchor = await page.locator('nav[aria-label="documentation"] ul a:text-is("DataGrid")');

await expect(anchor).toHaveAttribute('app-drawer-active', '');
await expect(anchor).toHaveAttribute('href', `/api/data-grid/data-grid/`);
});

test('all the links in the main content should have correct prefix', async ({ page }) => {
await page.goto(`/api/data-grid/data-grid/`);

const anchors = await page.locator('div#main-content a');

const handles = await anchors.elementHandles();

const links = await Promise.all(handles.map((elm) => elm.getAttribute('href')));

links.forEach((link) => {
expect(link?.startsWith('/x/data-grid')).toBeFalsy();
});
});
});

test.describe.parallel('Search', () => {
const retryToggleSearch = async (page: Page, count = 3) => {
try {
await page.keyboard.press('Meta+k');
await page.waitForSelector('input#docsearch-input', { timeout: 2000 });
} catch (error) {
if (count === 0) {
throw error;
}
await retryToggleSearch(page, count - 1);
}
};
test('should have correct link when searching component', async ({ page }) => {
await page.goto(`/components/data-grid/getting-started/`, { waitUntil: 'networkidle' });

await retryToggleSearch(page);

await page.type('input#docsearch-input', 'datagrid', { delay: 50 });

const anchor = await page.locator('.DocSearch-Hits a:has-text("Data Grid - Components")');

await expect(anchor.first()).toHaveAttribute(
'href',
`/components/data-grid/components/#main-content`,
);
});

test('should have correct link when searching API', async ({ page }) => {
await page.goto(`/components/data-grid/getting-started/`, { waitUntil: 'networkidle' });

await retryToggleSearch(page);

await page.type('input#docsearch-input', 'datagrid api', { delay: 50 });

const anchor = await page.locator('.DocSearch-Hits a:has-text("DataGrid API")');

await expect(anchor.first()).toHaveAttribute(
'href',
`/api/data-grid/data-grid/#main-content`,
);
});

test('should have correct link when searching pro API', async ({ page }) => {
await page.goto(`/components/data-grid/getting-started/`);

await page.waitForLoadState('networkidle'); // wait for docsearch

await retryToggleSearch(page);

await page.type('input#docsearch-input', 'datagridpro api', { delay: 50 });

const anchor = await page.locator('.DocSearch-Hits a:has-text("DataGridPro API")');

await expect(anchor.first()).toHaveAttribute(
'href',
`/api/data-grid/data-grid-pro/#main-content`,
);
});
});
});
Loading

0 comments on commit df7910a

Please sign in to comment.