Skip to content

Commit fa8e6bc

Browse files
committed
compare-screenshots: support worktree paths as arguments
When a path to a git-scm.com worktree is given instead of a URL, the script now automatically builds the site with Hugo and starts a local server to serve it. The server is torn down immediately after taking the screenshot. Due to indentation changes, this commit is best viewed with `-w`. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 405a437 commit fa8e6bc

1 file changed

Lines changed: 73 additions & 12 deletions

File tree

script/compare-screenshots.js

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,64 @@ const usage = `Generate before/after screenshots for two URLs using Playwright.
66
Usage:
77
node script/compare-screenshots.js [options] <before-url> <after-url>
88
9+
Arguments can be URLs or paths to git-scm.com worktrees. When a worktree
10+
path is given, Hugo is run to build the site and a local server is started.
11+
912
Options:
1013
--dark Emulate dark mode (prefers-color-scheme: dark)
1114
--light Emulate light mode (default)
1215
--clip=<WxH+X+Y> Clip screenshots to specified region (e.g., --clip=1280x720+0+0)
1316
1417
Examples:
1518
node script/compare-screenshots.js https://git-scm.com http://localhost:5000
19+
node script/compare-screenshots.js https://git-scm.com /path/to/worktree
1620
node script/compare-screenshots.js --dark https://git-scm.com http://localhost:5000
1721
node script/compare-screenshots.js --clip=1280x720+0+0 https://git-scm.com http://localhost:5000`;
1822

1923
const { chromium } = require('@playwright/test');
24+
const { spawn, execSync } = require('child_process');
25+
const fs = require('fs');
26+
const path = require('path');
27+
28+
function isWorktree(arg) {
29+
if (arg.startsWith('http://') || arg.startsWith('https://')) return false;
30+
try {
31+
return fs.statSync(path.join(arg, 'hugo.yml')).isFile();
32+
} catch {
33+
return false;
34+
}
35+
}
36+
37+
async function startServer(worktreePath, port) {
38+
// Build Hugo site
39+
console.error(`Building Hugo site in ${worktreePath}...`);
40+
execSync('hugo', { cwd: worktreePath, stdio: 'inherit' });
41+
42+
// Start serve-public.js
43+
const serverScript = path.join(worktreePath, 'script', 'serve-public.js');
44+
const server = spawn('node', [serverScript], {
45+
cwd: worktreePath,
46+
env: { ...process.env, PORT: String(port) },
47+
stdio: ['ignore', 'pipe', 'inherit'],
48+
});
49+
50+
// Wait for server to be ready
51+
await new Promise((resolve, reject) => {
52+
const timeout = setTimeout(() => reject(new Error('Server startup timeout')), 30000);
53+
server.stdout.on('data', (data) => {
54+
if (data.toString().includes('Now listening')) {
55+
clearTimeout(timeout);
56+
resolve();
57+
}
58+
});
59+
server.on('error', (err) => {
60+
clearTimeout(timeout);
61+
reject(err);
62+
});
63+
});
64+
65+
return server;
66+
}
2067

2168
async function main() {
2269
const args = process.argv.slice(2);
@@ -77,18 +124,32 @@ async function main() {
77124
console.error('Using dark mode (prefers-color-scheme: dark)');
78125
}
79126

80-
async function takeScreenshot(url, outputPath) {
81-
console.error(`Navigating to: ${url}`);
82-
await page.goto(url, { waitUntil: 'networkidle' });
83-
await page.screenshot({ path: outputPath, clip, fullPage: !clip });
84-
const pageDims = await page.evaluate(() => ({
85-
width: document.documentElement.scrollWidth,
86-
height: document.documentElement.scrollHeight,
87-
}));
88-
const info = clip
89-
? `${clip.width}x${clip.height}+${clip.x}+${clip.y} of ${pageDims.width}x${pageDims.height}`
90-
: `${pageDims.width}x${pageDims.height}`;
91-
console.error(`Saved: ${outputPath} (${info})`);
127+
async function takeScreenshot(urlOrWorktree, outputPath) {
128+
let server;
129+
let url = urlOrWorktree;
130+
131+
if (isWorktree(urlOrWorktree)) {
132+
server = await startServer(urlOrWorktree, 5000);
133+
url = 'http://localhost:5000/';
134+
}
135+
136+
try {
137+
console.error(`Navigating to: ${url}`);
138+
await page.goto(url, { waitUntil: 'networkidle' });
139+
await page.screenshot({ path: outputPath, clip, fullPage: !clip });
140+
const pageDims = await page.evaluate(() => ({
141+
width: document.documentElement.scrollWidth,
142+
height: document.documentElement.scrollHeight,
143+
}));
144+
const info = clip
145+
? `${clip.width}x${clip.height}+${clip.x}+${clip.y} of ${pageDims.width}x${pageDims.height}`
146+
: `${pageDims.width}x${pageDims.height}`;
147+
console.error(`Saved: ${outputPath} (${info})`);
148+
} finally {
149+
if (server) {
150+
server.kill();
151+
}
152+
}
92153
}
93154

94155
await takeScreenshot(beforeUrl, '.before.png');

0 commit comments

Comments
 (0)