Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
191 lines
6.8 KiB
JavaScript
191 lines
6.8 KiB
JavaScript
import * as url from 'url';
|
|
import * as path from 'path';
|
|
import * as fs from 'node:fs/promises';
|
|
import { chromium } from '@playwright/test';
|
|
|
|
const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));
|
|
|
|
async function main() {
|
|
const baseUrl = 'http://localhost:5001';
|
|
const screenshotDir = path.resolve(currentDirectory, './screenshots/chrome');
|
|
|
|
const browser = await chromium.launch({
|
|
args: ['--font-render-hinting=none'],
|
|
// otherwise the loaded google Roboto font isn't applied
|
|
headless: false,
|
|
});
|
|
// reuse viewport from `vrtest`
|
|
// https://github.com/nathanmarks/vrtest/blob/1185b852a6c1813cedf5d81f6d6843d9a241c1ce/src/server/runner.js#L44
|
|
const page = await browser.newPage({
|
|
viewport: { width: 1000, height: 700 },
|
|
reducedMotion: 'reduce',
|
|
});
|
|
|
|
// Block images since they slow down tests (need download).
|
|
// They're also most likely decorative for documentation demos
|
|
await page.route(/./, async (route, request) => {
|
|
const type = await request.resourceType();
|
|
if (type === 'image') {
|
|
route.abort();
|
|
} else {
|
|
route.continue();
|
|
}
|
|
});
|
|
|
|
// Wait for all requests to finish.
|
|
// This should load shared resources such as fonts.
|
|
await page.goto(`${baseUrl}#dev`, { waitUntil: 'networkidle0' });
|
|
// If we still get flaky fonts after awaiting this try `document.fonts.ready`
|
|
await page.waitForSelector('[data-webfontloader="active"]', { state: 'attached' });
|
|
|
|
// Simulate portrait mode for date pickers.
|
|
// See `useIsLandscape`.
|
|
await page.evaluate(() => {
|
|
Object.defineProperty(window.screen.orientation, 'angle', {
|
|
get() {
|
|
return 0;
|
|
},
|
|
});
|
|
});
|
|
|
|
let routes = await page.$$eval('#tests a', (links) => {
|
|
return links.map((link) => link.href);
|
|
});
|
|
routes = routes.map((route) => route.replace(baseUrl, ''));
|
|
|
|
/**
|
|
* @param {string} route
|
|
*/
|
|
async function renderFixture(route) {
|
|
await page.evaluate((_route) => {
|
|
// Use client-side routing which is much faster than full page navigation via page.goto().
|
|
window.muiFixture.navigate(`${_route}#no-dev`);
|
|
|
|
// Playwright hides scrollbar when capturing a screenshot on an element or with fullPage: true.
|
|
// When the body has a scrollbar, this causes a brief layout shift. Disable the body overflow
|
|
// altogether to prevent this
|
|
window.document.body.style.overflow = 'hidden';
|
|
}, route);
|
|
|
|
// Move cursor offscreen to not trigger unwanted hover effects.
|
|
await page.mouse.move(0, 0);
|
|
|
|
const testcase = await page.waitForSelector(
|
|
`[data-testid="testcase"][data-testpath="${route}"]:not([aria-busy="true"])`,
|
|
);
|
|
|
|
return testcase;
|
|
}
|
|
|
|
async function takeScreenshot({ testcase, route }) {
|
|
const screenshotPath = path.resolve(screenshotDir, `.${route}.png`);
|
|
await fs.mkdir(path.dirname(screenshotPath), { recursive: true });
|
|
|
|
const explicitScreenshotTarget = await page.$('[data-testid="screenshot-target"]');
|
|
const screenshotTarget = explicitScreenshotTarget || testcase;
|
|
|
|
await screenshotTarget.screenshot({
|
|
path: screenshotPath,
|
|
type: 'png',
|
|
animations: 'disabled',
|
|
});
|
|
}
|
|
|
|
// prepare screenshots
|
|
await fs.rm(screenshotDir, { recursive: true, force: true });
|
|
await fs.mkdir(screenshotDir, { recursive: true });
|
|
|
|
describe('visual regressions', () => {
|
|
beforeEach(async () => {
|
|
await page.evaluate(() => {
|
|
localStorage.clear();
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await browser.close();
|
|
});
|
|
|
|
routes.forEach((route) => {
|
|
it(`creates screenshots of ${route}`, async function test() {
|
|
// With the playwright inspector we might want to call `page.pause` which would lead to a timeout.
|
|
if (process.env.PWDEBUG) {
|
|
this?.timeout?.(0);
|
|
}
|
|
|
|
const testcase = await renderFixture(route);
|
|
await takeScreenshot({ testcase, route });
|
|
});
|
|
});
|
|
|
|
describe('Rating', () => {
|
|
it('should handle focus-visible correctly', async () => {
|
|
const testcase = await renderFixture('/regression-Rating/FocusVisibleRating');
|
|
await page.keyboard.press('Tab');
|
|
await takeScreenshot({ testcase, route: '/regression-Rating/FocusVisibleRating2' });
|
|
await page.keyboard.press('ArrowLeft');
|
|
await takeScreenshot({ testcase, route: '/regression-Rating/FocusVisibleRating3' });
|
|
});
|
|
|
|
it('should handle focus-visible with precise ratings correctly', async () => {
|
|
const testcase = await renderFixture('/regression-Rating/PreciseFocusVisibleRating');
|
|
await page.keyboard.press('Tab');
|
|
await takeScreenshot({ testcase, route: '/regression-Rating/PreciseFocusVisibleRating2' });
|
|
await page.keyboard.press('ArrowRight');
|
|
await takeScreenshot({ testcase, route: '/regression-Rating/PreciseFocusVisibleRating3' });
|
|
});
|
|
});
|
|
|
|
describe('Autocomplete', () => {
|
|
it('should not close immediately when textbox expands', async () => {
|
|
const testcase = await renderFixture(
|
|
'/regression-Autocomplete/TextboxExpandsOnListboxOpen',
|
|
);
|
|
await page.getByRole('combobox').click();
|
|
await page.waitForTimeout(10);
|
|
await takeScreenshot({
|
|
testcase,
|
|
route: '/regression-Autocomplete/TextboxExpandsOnListboxOpen2',
|
|
});
|
|
});
|
|
|
|
it('should style virtualized listbox correctly', async () => {
|
|
const testcase = await renderFixture('/regression-Autocomplete/Virtualize');
|
|
await page.getByRole('combobox').click();
|
|
await takeScreenshot({ testcase, route: '/regression-Autocomplete/Virtualize2' });
|
|
await page.hover('[role="option"]');
|
|
await takeScreenshot({ testcase, route: '/regression-Autocomplete/Virtualize3' });
|
|
await page.click('[role="option"]');
|
|
await takeScreenshot({ testcase, route: '/regression-Autocomplete/Virtualize4' });
|
|
});
|
|
});
|
|
|
|
describe('Textarea', () => {
|
|
it('should keep input caret position at the end when adding a newline', async () => {
|
|
await renderFixture('/regression-Textarea/TextareaAutosize');
|
|
await page.getByTestId('input').focus();
|
|
|
|
const textWithEndline = `abc def abc def abc def\n`;
|
|
await page.evaluate((text) => {
|
|
navigator.clipboard.writeText(text);
|
|
}, textWithEndline);
|
|
|
|
const pasteCommand = process.platform === 'darwin' ? 'Meta+V' : 'Control+V';
|
|
|
|
await page.keyboard.press(pasteCommand);
|
|
await page.keyboard.press(pasteCommand);
|
|
await page.keyboard.press(pasteCommand);
|
|
|
|
await page.evaluate(() => {
|
|
const textarea = document.querySelector('textarea');
|
|
if (textarea.selectionStart !== textarea.value.length) {
|
|
throw new Error('The caret is not at the end of the textarea');
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
await main();
|