Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: detect UI regressions #264

Merged
merged 5 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/docs-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: 🛠 Docs UI regressions

on:
push:
branches: [main]
paths:
- '.github/workflows/docs-e2e.yml'
- 'docs/**'
pull_request:
branches: [main]
paths:
- '.github/workflows/docs-e2e.yml'
- 'docs/**'

jobs:
take-screenshots:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
defaults:
run:
working-directory: ./docs
steps:
- name: Check out repository code
uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Install Playwright browsers
run: yarn playwright install --with-deps chromium

- name: Build the website
run: yarn docusaurus build

- name: Take screenshots with Playwright
run: yarn playwright test

- name: Upload screenshots to Argos
run: yarn argos upload ./screenshots
23 changes: 23 additions & 0 deletions docs/__tests__/screenshot.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Iframes can load lazily */
iframe,
/* Avatars can be flaky due to using external sources: GitHub/Unavatar */
.avatar__photo,
/* Gifs load lazily and are animated */
img[src$='.gif'],
/* Algolia keyboard shortcuts appear with a little delay */
.DocSearch-Button-Keys > kbd,
/* The live playground preview can often display dates/counters */
[class*='playgroundPreview'] {
visibility: hidden;
}

/* Different docs last-update dates can alter layout */
.theme-last-updated,
/* Mermaid diagrams are rendered client-side and produce layout shifts */
.docusaurus-mermaid-container {
display: none;
}
/* Lottie files are animated */
.lottie {
display: none;
}
41 changes: 41 additions & 0 deletions docs/__tests__/screenshot.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as fs from 'fs';
import {test} from '@playwright/test';
import {argosScreenshot} from '@argos-ci/playwright';
import {extractSitemapPathnames, pathnameToArgosName} from './utils';

// Constants
const siteUrl = 'http://localhost:3000';
const sitemapPath = './build/sitemap.xml';
const stylesheetPath = './__tests__/screenshot.css';
const stylesheet = fs.readFileSync(stylesheetPath).toString();

// Wait for hydration, requires Docusaurus v2.4.3+
// Docusaurus adds a <html data-has-hydrated="true"> once hydrated
// See https://github.com/facebook/docusaurus/pull/9256
function waitForDocusaurusHydration() {
return document.documentElement.dataset.hasHydrated === 'true';
}

function screenshotPathname(pathname: string) {
test(`pathname ${pathname}`, async ({page}) => {
const url = siteUrl + pathname;
await page.goto(url);
// Wait for hydration, requires Docusaurus v2.4.3+
// Docusaurus adds a <html data-has-hydrated="true"> once hydrated
// See https://github.com/facebook/docusaurus/pull/9256
// await page.waitForFunction(waitForDocusaurusHydration);
await page.addStyleTag({content: stylesheet});
await argosScreenshot(page, pathnameToArgosName(pathname));
});
}

function isNotVersionedDocsPathname(pathname: string): boolean {
return !/^\/[^/]+\/docs\/((\d+\.\d+\.\d+)|(next))\//.test(pathname);
}

test.describe('Docusaurus site screenshots', () => {
const pathnames = extractSitemapPathnames(sitemapPath)
.filter(isNotVersionedDocsPathname);
console.log('Pathnames to screenshot:', pathnames);
pathnames.forEach(screenshotPathname);
});
19 changes: 19 additions & 0 deletions docs/__tests__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as cheerio from 'cheerio';
import * as fs from 'fs';

// Extract a list of pathnames, given a fs path to a sitemap.xml file
// Docusaurus generates a build/sitemap.xml file for you!
export function extractSitemapPathnames(sitemapPath: string): string[] {
const sitemap = fs.readFileSync(sitemapPath).toString();
const $ = cheerio.load(sitemap, {xmlMode: true});
const urls: string[] = [];
$('loc').each(function handleLoc() {
urls.push($(this).text());
});
return urls.map((url) => new URL(url).pathname);
}

// Converts a pathname to a decent screenshot name
export function pathnameToArgosName(pathname: string): string {
return pathname.replace(/^\/|\/$/g, '') || 'index';
}
2 changes: 1 addition & 1 deletion docs/blog/2022-06-22-welcome/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Lottie from 'lottie-react';
import lottie from '../../src/components/HomepageFeatures/transform.lottie.json';

<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 20 }}>
<Lottie animationData={lottie} style={{ width: 400, height: 400 }} loop />
<Lottie className="lottie" animationData={lottie} style={{ width: 400, height: 400 }} loop />
</div>

<!--truncate-->
Expand Down
2 changes: 1 addition & 1 deletion docs/blog/2023-04-10-interactive-keyboard/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Lottie from 'lottie-react';
import lottie from '../../src/components/HomepageFeatures/interactive.lottie.json';

<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 20 }}>
<Lottie animationData={lottie} style={{ width: 400, height: 400 }} loop />
<Lottie className="lottie" animationData={lottie} style={{ width: 400, height: 400 }} loop />
</div>

<!--truncate-->
Expand Down
2 changes: 1 addition & 1 deletion docs/blog/2023-08-25-enhanced-metadata/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Lottie from 'lottie-react';
import lottie from '../../src/components/HomepageFeatures/text-inputs.lottie.json';

<div style={{ display: 'flex', justifyContent: 'center', marginBottom: 20 }}>
<Lottie animationData={lottie} style={{ width: 400, height: 400 }} loop />
<Lottie className="lottie" animationData={lottie} style={{ width: 400, height: 400 }} loop />
</div>

**Say goodbye to guesswork and hello to precision!** React Native Keyboard Controller `1.6.0` introduces a trio of new fields in the event metadata that will revolutionize the way you manage keyboard interactions in your React Native applications 😎
Expand Down
4 changes: 4 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@argos-ci/cli": "^1.0.0",
"@argos-ci/playwright": "^1.0.1",
"@docusaurus/module-type-aliases": "2.4.0",
"@playwright/test": "^1.39.0",
"@tsconfig/docusaurus": "^1.0.5",
"cheerio": "^1.0.0-rc.12",
"markdownlint-cli2": "^0.7.1",
"typescript": "^4.7.4"
},
Expand Down
19 changes: 19 additions & 0 deletions docs/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {devices} from '@playwright/test';
import type {PlaywrightTestConfig} from '@playwright/test';

const config: PlaywrightTestConfig = {
webServer: {
port: 3000,
command: 'yarn docusaurus serve',
},
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
},
},
],
};

export default config;
4 changes: 2 additions & 2 deletions docs/src/components/ComparisonTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export default function ComparisonTable({ leftLottie, leftText, rightLottie, rig
<tbody>
<tr style={withoutBorders}>
<td style={withoutBorders}>
<Lottie animationData={leftLottie} style={lottieView} loop />
<Lottie className="lottie" animationData={leftLottie} style={lottieView} loop />
</td>
<td style={withoutBorders}>
<Lottie animationData={rightLottie} style={lottieView} loop />
<Lottie className="lottie" animationData={rightLottie} style={lottieView} loop />
</td>
</tr>
<tr style={labels}>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/components/HomepageFeatures/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function Feature({ title, lottie, description }: FeatureItem) {
return (
<div className={clsx('col col--3')}>
<div className="text--center">
<Lottie animationData={lottie} style={lottieStyle} loop />
<Lottie className="lottie" animationData={lottie} style={lottieStyle} loop />
</div>
<div className="text--center padding-horiz--md">
<h3>{title}</h3>
Expand Down
Loading