Skip to content

Commit 617ad2e

Browse files
test(docs): add script to test docs for warnings/errors (#6763)
* add script to test docs for warnings/errors * get links before testing * update yarn.lock * update script to get latest browser binaries first * support running with webkit and firefox * exit process at the end --------- Co-authored-by: Robert Snow <[email protected]>
1 parent 1dcc870 commit 617ad2e

File tree

3 files changed

+215
-12
lines changed

3 files changed

+215
-12
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"test": "cross-env STRICT_MODE=1 yarn jest",
3232
"test-loose": "cross-env VIRT_ON=1 yarn jest",
3333
"test-storybook": "test-storybook --url http://localhost:9003 --browsers chromium --no-cache",
34+
"test:docs": "yarn playwright install && node scripts/testDocs.js",
3435
"build": "make build",
3536
"test:ssr": "cross-env STRICT_MODE=1 yarn jest --config jest.ssr.config.js",
3637
"ci-test": "cross-env STRICT_MODE=1 yarn jest --maxWorkers=2 && cross-env STRICT_MODE=1 yarn test:ssr --runInBand",
@@ -172,6 +173,7 @@
172173
"parcel": "2.0.0-dev.1599",
173174
"parcel-resolver-storybook": "https://gitpkg.vercel.app/mischnic/storybook-parcel/packages/parcel-resolver-storybook?master",
174175
"patch-package": "^6.2.0",
176+
"playwright": "^1.45.3",
175177
"plop": "^2.4.0",
176178
"postcss": "^8.4.24",
177179
"postcss-custom-properties": "^13.2.0",

scripts/testDocs.js

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
const {chromium, firefox, webkit} = require('playwright');
2+
const {exec} = require('child_process');
3+
const http = require('http');
4+
const path = require('path');
5+
const glob = require('glob-promise');
6+
7+
function parseArgs() {
8+
const args = process.argv.slice(2);
9+
const browser = args[0] || 'chromium';
10+
if (!['chromium', 'firefox', 'webkit'].includes(browser)) {
11+
console.error('Invalid browser specified. Must be "chromium", "firefox", or "webkit". Using "chromium" as default.');
12+
return 'chromium';
13+
}
14+
return browser;
15+
}
16+
17+
async function startServer() {
18+
return new Promise((resolve, reject) => {
19+
console.log('Starting documentation server...');
20+
const child = exec('yarn start:docs', {
21+
env: {...process.env, DOCS_ENV: 'dev'}
22+
});
23+
child.stdout.on('data', (data) => {
24+
console.log(`Server output: ${data}`);
25+
if (data.includes('Server running at')) {
26+
console.log('Documentation server is running');
27+
resolve({process: child, baseUrl: data.split(' ')[3].trim()});
28+
}
29+
});
30+
child.stderr.on('data', (data) => {
31+
console.error(`Server error: ${data}`);
32+
});
33+
});
34+
}
35+
36+
function waitForServer(url, timeout = 30000, interval = 1000) {
37+
return new Promise((resolve, reject) => {
38+
const startTime = Date.now();
39+
const checkServer = () => {
40+
http.get(url, (res) => {
41+
if (res.statusCode === 200) {
42+
resolve();
43+
} else {
44+
retryOrFail();
45+
}
46+
}).on('error', retryOrFail);
47+
};
48+
49+
const retryOrFail = () => {
50+
if (Date.now() - startTime < timeout) {
51+
setTimeout(checkServer, interval);
52+
} else {
53+
reject(new Error('Server did not start in time'));
54+
}
55+
};
56+
57+
checkServer();
58+
});
59+
}
60+
61+
async function getPageLinks() {
62+
const packagePaths = [
63+
'packages/@react-{spectrum,aria,stately}/*/docs/*.mdx',
64+
'packages/react-aria-components/docs/**/*.mdx',
65+
'packages/@internationalized/*/docs/*.mdx'
66+
];
67+
68+
const rootPages = 'packages/dev/docs/pages/**/*.mdx';
69+
70+
let links = [];
71+
72+
for (const pattern of packagePaths) {
73+
const files = await glob(pattern);
74+
for (const file of files) {
75+
const parts = file.split(path.sep);
76+
const packageName = parts[1].replace('@', '');
77+
const componentName = path.basename(file, '.mdx');
78+
links.push(`/${packageName}/${componentName}.html`);
79+
}
80+
}
81+
82+
const rootFiles = await glob(rootPages);
83+
for (const file of rootFiles) {
84+
const relativePath = path.relative('packages/dev/docs/pages', file);
85+
const urlPath = path.join('/', path.dirname(relativePath), path.basename(relativePath, '.mdx'));
86+
links.push(`${urlPath}.html`);
87+
}
88+
89+
return links;
90+
}
91+
92+
async function testDocs() {
93+
let server;
94+
let browser;
95+
let messages = [];
96+
let currentPage = '';
97+
98+
const browserType = parseArgs();
99+
console.log(`Using ${browserType} browser for testing`);
100+
101+
try {
102+
server = await startServer();
103+
await waitForServer(server.baseUrl);
104+
105+
const pageLinks = await getPageLinks().then((links) => links.map((link) => `${server.baseUrl}${link}`));
106+
console.log(`Found ${pageLinks.length} pages to test`);
107+
108+
switch (browserType) {
109+
case 'firefox':
110+
browser = await firefox.launch();
111+
break;
112+
case 'webkit':
113+
browser = await webkit.launch();
114+
break;
115+
default:
116+
browser = await chromium.launch();
117+
}
118+
119+
const context = await browser.newContext();
120+
121+
context.on('console', (msg) => {
122+
const msgUrl = msg.location().url;
123+
if (msgUrl.startsWith(server.baseUrl) && (msg.type() === 'error' || msg.type() === 'warning')) {
124+
console.log(`${msg.type().toUpperCase()} on ${currentPage}: ${msg.text()}`);
125+
messages.push({type: msg.type(), path: currentPage, text: msg.text()});
126+
}
127+
});
128+
129+
for (let i = 0; i < pageLinks.length; i++) {
130+
const url = pageLinks[i];
131+
currentPage = new URL(url).pathname;
132+
console.log(`Testing page (${i + 1}/${pageLinks.length}): ${currentPage}`);
133+
134+
const page = await context.newPage();
135+
136+
try {
137+
const response = await page.goto(url, {
138+
waitUntil: 'networkidle',
139+
timeout: 10000
140+
});
141+
142+
if (!response.ok()) {
143+
console.error(
144+
`Failed to load ${currentPage}: ${response.status()} ${response.statusText()}`
145+
);
146+
}
147+
148+
await page.waitForTimeout(1000);
149+
} catch (error) {
150+
console.error(`Error on ${currentPage}:`, error.message);
151+
} finally {
152+
await page.close();
153+
}
154+
}
155+
156+
console.log('All pages tested successfully');
157+
console.log(`Total pages visited: ${pageLinks.length}`);
158+
console.log(`Total errors: ${messages.filter((msg) => msg.type === 'error').length}`);
159+
console.log(`Total warnings: ${messages.filter((msg) => msg.type === 'warning').length}`);
160+
messages.forEach((msg) => {
161+
console.log(`${msg.type.toUpperCase()} on ${msg.path}: ${msg.text}`);
162+
});
163+
} catch (error) {
164+
console.error('An error occurred during testing:', error);
165+
} finally {
166+
if (browser) {
167+
await browser.close();
168+
}
169+
if (server && server.process) {
170+
server.process.kill();
171+
}
172+
process.exit(0);
173+
}
174+
}
175+
176+
testDocs();

yarn.lock

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18591,6 +18591,16 @@ __metadata:
1859118591
languageName: node
1859218592
linkType: hard
1859318593

18594+
"fsevents@npm:2.3.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2":
18595+
version: 2.3.2
18596+
resolution: "fsevents@npm:2.3.2"
18597+
dependencies:
18598+
node-gyp: "npm:latest"
18599+
checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b
18600+
conditions: os=darwin
18601+
languageName: node
18602+
linkType: hard
18603+
1859418604
"fsevents@npm:^1.2.7":
1859518605
version: 1.2.12
1859618606
resolution: "fsevents@npm:1.2.12"
@@ -18604,12 +18614,11 @@ __metadata:
1860418614
languageName: node
1860518615
linkType: hard
1860618616

18607-
"fsevents@npm:^2.3.2, fsevents@npm:~2.3.2":
18617+
"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin<compat/fsevents>, fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin<compat/fsevents>, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin<compat/fsevents>":
1860818618
version: 2.3.2
18609-
resolution: "fsevents@npm:2.3.2"
18619+
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin<compat/fsevents>::version=2.3.2&hash=df0bf1"
1861018620
dependencies:
1861118621
node-gyp: "npm:latest"
18612-
checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b
1861318622
conditions: os=darwin
1861418623
languageName: node
1861518624
linkType: hard
@@ -18626,15 +18635,6 @@ __metadata:
1862618635
languageName: node
1862718636
linkType: hard
1862818637

18629-
"fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin<compat/fsevents>, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin<compat/fsevents>":
18630-
version: 2.3.2
18631-
resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin<compat/fsevents>::version=2.3.2&hash=df0bf1"
18632-
dependencies:
18633-
node-gyp: "npm:latest"
18634-
conditions: os=darwin
18635-
languageName: node
18636-
linkType: hard
18637-
1863818638
"full-icu@npm:^1.3.0":
1863918639
version: 1.3.0
1864018640
resolution: "full-icu@npm:1.3.0"
@@ -27614,6 +27614,15 @@ __metadata:
2761427614
languageName: node
2761527615
linkType: hard
2761627616

27617+
"playwright-core@npm:1.45.3":
27618+
version: 1.45.3
27619+
resolution: "playwright-core@npm:1.45.3"
27620+
bin:
27621+
playwright-core: cli.js
27622+
checksum: 10c0/39cc5920b27c42300e13a0646ca723578085d85940fc1f03e858fa348b5ac06f2eadf34cf15a0c0f4443e63ae188097d3ddbeb4389e7bbf5ae3438d8f6ed23e1
27623+
languageName: node
27624+
linkType: hard
27625+
2761727626
"playwright@npm:^1.14.0":
2761827627
version: 1.36.1
2761927628
resolution: "playwright@npm:1.36.1"
@@ -27625,6 +27634,21 @@ __metadata:
2762527634
languageName: node
2762627635
linkType: hard
2762727636

27637+
"playwright@npm:^1.45.3":
27638+
version: 1.45.3
27639+
resolution: "playwright@npm:1.45.3"
27640+
dependencies:
27641+
fsevents: "npm:2.3.2"
27642+
playwright-core: "npm:1.45.3"
27643+
dependenciesMeta:
27644+
fsevents:
27645+
optional: true
27646+
bin:
27647+
playwright: cli.js
27648+
checksum: 10c0/3516ca49deb589171ac6525c0367f2ff948514d791d197f3cc0a135154c2df08a4d7cd11a810e187f35ae9ca490b37ca3a92fb3eb51560f03aefcaca0613efdb
27649+
languageName: node
27650+
linkType: hard
27651+
2762827652
"plop@npm:^2.4.0":
2762927653
version: 2.4.0
2763027654
resolution: "plop@npm:2.4.0"
@@ -29041,6 +29065,7 @@ __metadata:
2904129065
parcel: "npm:2.0.0-dev.1599"
2904229066
parcel-resolver-storybook: "https://gitpkg.vercel.app/mischnic/storybook-parcel/packages/parcel-resolver-storybook?master"
2904329067
patch-package: "npm:^6.2.0"
29068+
playwright: "npm:^1.45.3"
2904429069
plop: "npm:^2.4.0"
2904529070
postcss: "npm:^8.4.24"
2904629071
postcss-custom-properties: "npm:^13.2.0"

0 commit comments

Comments
 (0)