Skip to content

Commit 1ad04e2

Browse files
authored
test: add some validation for JSON doc output
PR-URL: #61413 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Claudio Wunder <cwunder@gnome.org> Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
1 parent 44bd030 commit 1ad04e2

File tree

2 files changed

+163
-2
lines changed

2 files changed

+163
-2
lines changed

doc/api/environment_variables.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Environment Variables
22

3+
<!--introduced_in=v20.12.0-->
4+
35
Environment variables are variables associated to the environment the Node.js process runs in.
46

57
## CLI Environment Variables
@@ -20,8 +22,6 @@ Set of utilities for dealing with additional environment variables defined in `.
2022

2123
> Stability: 2 - Stable
2224
23-
<!--introduced_in=v20.12.0-->
24-
2525
### .env files
2626

2727
`.env` files (also known as dotenv files) are files that define environment variables,

test/doctool/test-doc-api-json.mjs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import * as common from '../common/index.mjs';
2+
3+
import assert from 'node:assert';
4+
import { existsSync } from 'node:fs';
5+
import fs from 'node:fs/promises';
6+
import path from 'node:path';
7+
8+
// This tests that `make doc` generates the JSON documentation properly.
9+
// Note that for this test to pass, `make doc` must be run first.
10+
11+
if (common.isWindows) {
12+
common.skip('`make doc` does not run on Windows');
13+
}
14+
15+
function validateModule(module) {
16+
assert.strictEqual(typeof module, 'object');
17+
assert.strictEqual(module.type, 'module');
18+
assert.ok(module.name);
19+
assert.ok(module.textRaw);
20+
}
21+
22+
function validateMisc(misc) {
23+
assert.strictEqual(typeof misc, 'object');
24+
assert.strictEqual(misc.type, 'misc');
25+
assert.ok(misc.name);
26+
assert.strictEqual(typeof misc.name, 'string');
27+
assert.ok(misc.textRaw);
28+
assert.strictEqual(typeof misc.textRaw, 'string');
29+
}
30+
31+
let numberOfDeprecatedSections = 0;
32+
let numberOfRemovedAPIs = 0;
33+
34+
const metaExpectedKeys = new Set([
35+
'added',
36+
'changes',
37+
'deprecated',
38+
'napiVersion',
39+
'removed',
40+
]);
41+
42+
function validateMeta(meta) {
43+
assert.partialDeepStrictEqual(metaExpectedKeys, new Set(Object.keys(meta)));
44+
assert.ok(!Object.hasOwn(meta, 'added') || Array.isArray(meta.added) || typeof meta.added === 'string');
45+
if (meta.deprecated) {
46+
numberOfDeprecatedSections++;
47+
assert.ok(Array.isArray(meta.deprecated) || typeof meta.deprecated === 'string');
48+
}
49+
if (meta.removed) {
50+
numberOfRemovedAPIs++;
51+
assert.ok(Array.isArray(meta.removed) || typeof meta.removed === 'string');
52+
}
53+
54+
assert.ok(!Object.hasOwn(meta, 'napiVersion') || Number(meta.napiVersion));
55+
assert.ok(Array.isArray(meta.changes));
56+
}
57+
58+
function findAllKeys(obj, allKeys = new Set()) {
59+
for (const [key, value] of Object.entries(obj)) {
60+
if (Number.isNaN(Number(key))) allKeys.add(key);
61+
if (typeof value === 'object') findAllKeys(value, allKeys);
62+
63+
if (key === 'miscs') {
64+
assert.ok(Array.isArray(value));
65+
assert.ok(value.length);
66+
value.forEach(validateMisc);
67+
} else if (key === 'modules') {
68+
assert.ok(Array.isArray(value));
69+
assert.ok(value.length);
70+
value.forEach(validateModule);
71+
} else if (key === 'meta') {
72+
validateMeta(value);
73+
}
74+
}
75+
return allKeys;
76+
}
77+
78+
const allExpectedKeys = new Set([
79+
'added',
80+
'changes',
81+
'classes',
82+
'classMethods',
83+
'commit',
84+
'ctors',
85+
'default',
86+
'deprecated',
87+
'desc',
88+
'description',
89+
'displayName',
90+
'events',
91+
'examples',
92+
'globals',
93+
'introduced_in',
94+
'meta',
95+
'methods',
96+
'miscs',
97+
'modules',
98+
'name',
99+
'napiVersion',
100+
'options',
101+
'params',
102+
'pr-url',
103+
'properties',
104+
'removed',
105+
'return',
106+
'shortDesc',
107+
'signatures',
108+
'source',
109+
'stability',
110+
'stabilityText',
111+
'textRaw',
112+
'type',
113+
'version',
114+
]);
115+
116+
for await (const dirent of await fs.opendir(new URL('../../out/doc/api/', import.meta.url))) {
117+
if (!dirent.name.endsWith('.md')) continue;
118+
119+
const jsonPath = path.join(dirent.parentPath, dirent.name.slice(0, -2) + 'json');
120+
const expectedSource = `doc/api/${dirent.name}`;
121+
if (dirent.name === 'quic.md') {
122+
assert.ok(!existsSync(jsonPath)); // QUIC documentation is not public yet
123+
continue;
124+
}
125+
126+
console.log('testing', jsonPath, 'based on', expectedSource);
127+
128+
const fileContent = await fs.readFile(jsonPath, 'utf8');
129+
// A proxy to check if the file is human readable is to count if it contains
130+
// at least 3 line return.
131+
assert.strictEqual(fileContent.split('\n', 3).length, 3);
132+
133+
const json = JSON.parse(fileContent);
134+
135+
assert.strictEqual(json.type, 'module');
136+
assert.strictEqual(json.source, expectedSource);
137+
if (dirent.name !== 'index.md') {
138+
assert.ok(json.introduced_in || Object.values(json).at(-1)?.[0].introduced_in);
139+
}
140+
assert.deepStrictEqual(Object.keys(json), ['type', 'source', ...({
141+
'addons.md': ['introduced_in', 'miscs'],
142+
'cli.md': ['introduced_in', 'miscs'],
143+
'debugger.md': ['introduced_in', 'stability', 'stabilityText', 'miscs'],
144+
'deprecations.md': ['introduced_in', 'miscs'],
145+
'documentation.md': ['introduced_in', 'miscs'],
146+
'errors.md': ['introduced_in', 'classes', 'miscs'],
147+
'esm.md': ['introduced_in', 'meta', 'stability', 'stabilityText', 'properties', 'miscs'],
148+
'globals.md': ['introduced_in', 'stability', 'stabilityText', 'classes', 'methods', 'miscs'],
149+
'index.md': [],
150+
'intl.md': ['introduced_in', 'miscs'],
151+
'n-api.md': ['introduced_in', 'stability', 'stabilityText', 'miscs'],
152+
'packages.md': ['introduced_in', 'meta', 'miscs'],
153+
'process.md': ['globals'],
154+
'report.md': ['introduced_in', 'stability', 'stabilityText', 'meta', 'miscs'],
155+
}[dirent.name] ?? ['modules'])]);
156+
157+
assert.partialDeepStrictEqual(allExpectedKeys, findAllKeys(json));
158+
}
159+
160+
assert.strictEqual(numberOfDeprecatedSections, 39); // Increase this number every time a new API is deprecated.
161+
assert.strictEqual(numberOfRemovedAPIs, 46); // Increase this number every time a section is marked as removed.

0 commit comments

Comments
 (0)