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

Implemented CI Workflow for visual regression testing using Argos and Playwright. #100

Merged
merged 4 commits into from
Oct 30, 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
34 changes: 34 additions & 0 deletions .github/workflows/argos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Argos CI Screenshots

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
take-screenshots:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4

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

- 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
18 changes: 18 additions & 0 deletions argos/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { devices } from '@playwright/test';

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

export default config;
27 changes: 27 additions & 0 deletions argos/screenshot.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
We need to hide some elements in Argos/Playwright screenshots
Those elements are source of flakiness due to nondeterministic rendering
They don't consistently render exactly the same across CI runs
*/

/******* DOCUSAURUS GLOBAL / THEME *******/

/* 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;
}
33 changes: 33 additions & 0 deletions argos/screenshot.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as fs from 'fs';
import { test } from '@playwright/test';
import { argosScreenshot } from '@argos-ci/playwright';
import { extractSitemapPathnames, pathnameToArgosName } from './utils';

// Constants
const siteUrl = 'https://uptane.github.io/';
const sitemapPath = './build/sitemap.xml';
const stylesheetPath = './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) {
test(`pathname ${pathname}`, async ({ page }) => {
const url = siteUrl + pathname;
await page.goto(url);
await page.waitForFunction(waitForDocusaurusHydration);
await page.addStyleTag({ content: stylesheet });
await argosScreenshot(page, pathnameToArgosName(pathname));
});
}

test.describe('Docusaurus site screenshots', () => {
const pathnames = extractSitemapPathnames(sitemapPath);
console.log('Pathnames to screenshot:', pathnames);
pathnames.forEach(screenshotPathname);
});
19 changes: 19 additions & 0 deletions argos/utils.js
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) {
const sitemap = fs.readFileSync(sitemapPath).toString();
const $ = cheerio.load(sitemap, { xmlMode: true });
const urls = [];
$('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) {
return pathname.replace(/^\/|\/$/g, '') || 'index';
}
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@
"react-lazyload": "^3.2.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^2.4.3"
"@argos-ci/cli": "^1.0.0",
"@argos-ci/playwright": "^1.0.1",
"@docusaurus/module-type-aliases": "^2.4.3",
"@playwright/test": "^1.39.0",
"cheerio": "^1.0.0-rc.12"
},
"browserslist": {
"production": [
Expand Down
Loading