Build and publish Eldorado documentation / build (pull_request) Successful in 33s
154 lines
9.5 KiB
JavaScript
154 lines
9.5 KiB
JavaScript
import {test} from 'node:test';
|
||
import {createHash} from 'node:crypto';
|
||
import assert from 'node:assert/strict';
|
||
import {readFileSync, existsSync, mkdtempSync, mkdirSync, writeFileSync, symlinkSync, unlinkSync, rmSync, readdirSync} from 'node:fs';
|
||
import {tmpdir} from 'node:os';
|
||
import {join, resolve} from 'node:path';
|
||
import {spawnSync} from 'node:child_process';
|
||
const read = p => readFileSync(p, 'utf8');
|
||
test('real build removes stale diagrams, keeps receipts private and rejects collisions', () => {
|
||
const root = mkdtempSync(join(tmpdir(), 'eldorado-diagrams-'));
|
||
try {
|
||
mkdirSync(join(root,'diagrams'));
|
||
symlinkSync(resolve('vendor'),join(root,'vendor'),'dir');
|
||
const spec = JSON.parse(read('diagrams/organization-structure.architecture.json'));
|
||
const writeSpec = name => {
|
||
spec.meta.output = `static/diagrams/${name}/index.html`;
|
||
writeFileSync(join(root,`diagrams/${name}.architecture.json`),JSON.stringify(spec));
|
||
};
|
||
const build = () => spawnSync(process.execPath,[resolve('scripts/build-diagrams.mjs')],{cwd:root,encoding:'utf8'});
|
||
writeSpec('old');
|
||
let result = build(); assert.equal(result.status,0,result.stderr);
|
||
assert(existsSync(join(root,'static/diagrams/old/index.html')));
|
||
assert(!existsSync(join(root,'static/diagrams/old.json')));
|
||
assert(!readdirSync(join(root,'static/diagrams'),{recursive:true}).some(p=>p.endsWith('.delivery.json')));
|
||
unlinkSync(join(root,'diagrams/old.architecture.json'));
|
||
writeSpec('new');
|
||
result=build(); assert.equal(result.status,0,result.stderr);
|
||
assert(!existsSync(join(root,'static/diagrams/old')));
|
||
assert(!existsSync(join(root,'static/diagrams/old.json')));
|
||
writeFileSync(join(root,'diagrams/new.workflow.json'),JSON.stringify(spec));
|
||
result=build(); assert.notEqual(result.status,0);
|
||
assert(result.stderr.includes('Duplicate diagram output'));
|
||
} finally {rmSync(root,{recursive:true,force:true});}
|
||
});
|
||
test('vendored source matches the reviewed upstream snapshot', () => {
|
||
const checksums = JSON.parse(read('vendor/archify-checksums.json'));
|
||
for (const [path, hash] of Object.entries(checksums)) {
|
||
assert.equal(createHash('sha256').update(readFileSync(`vendor/archify/${path}`)).digest('hex'), hash, path);
|
||
}
|
||
});
|
||
test('three independent section menus and Structure first', () => {
|
||
const config = read('docusaurus.config.ts');
|
||
for (const section of ['Organization', 'Strategy', 'Contribution']) assert(config.includes(`label: '${section}'`));
|
||
assert(!config.includes("label: 'Documentation'"));
|
||
assert(!config.includes("label: 'Maintainer guide'"));
|
||
assert(read('sidebars/organization.ts').includes("organizationSidebar: ['structure', 'collaboration', 'sdlc']"));
|
||
for (const section of ['organization','strategy','contribution']) assert(config.includes(`id: '${section}'`));
|
||
});
|
||
test('Archify is pinned, licensed and rebuilt, not a remote embed', () => {
|
||
const provenance = JSON.parse(read('vendor/archify-provenance.json'));
|
||
assert.equal(provenance.commit, 'd5a1333d7447c866a765adac7d4d062f2f02e4d2');
|
||
assert(read('vendor/archify/LICENSE').includes('MIT License'));
|
||
const scripts = JSON.parse(read('package.json')).scripts;
|
||
assert(scripts.build.startsWith('pnpm diagrams:build'));
|
||
const wrapper = read('src/components/ArchifyDiagram/index.tsx');
|
||
assert(wrapper.includes('sandbox="allow-scripts allow-downloads"'));
|
||
assert(!wrapper.includes('allow-same-origin'));
|
||
assert(wrapper.includes('useBaseUrl'));
|
||
assert(wrapper.includes('showModal()') && wrapper.includes('onClose='));
|
||
assert(!wrapper.includes('target="_blank"'));
|
||
assert(wrapper.includes('Close full-screen diagram'));
|
||
assert(!wrapper.includes('JSON source') && !wrapper.includes('download>'));
|
||
assert(!wrapper.includes('Open full viewer'));
|
||
assert(wrapper.includes('aria-label={`Expand ${title}`}'));
|
||
assert(wrapper.includes('aria-hidden="true"'));
|
||
assert(read('src/css/custom.css').includes('justify-content: flex-end'));
|
||
});
|
||
test('full-screen close is cross-only with an accessible name and square touch target', () => {
|
||
const wrapper = read('src/components/ArchifyDiagram/index.tsx');
|
||
const button = wrapper.match(/<button[^>]*aria-label="Close full-screen diagram"[^>]*>(.*?)<\/button>/s);
|
||
assert(button, 'close button retains its accessible name');
|
||
assert.equal(button[1], '<span aria-hidden="true">×</span>');
|
||
assert(button[0].includes('autoFocus') && button[0].includes('onClick={close}'));
|
||
const styles = read('src/css/custom.css').match(/\.archify-modal-toolbar button \{([^}]+)\}/)[1];
|
||
assert(styles.includes('width: 44px') && styles.includes('height: 44px'));
|
||
assert(styles.includes('padding: 0') && styles.includes('flex-shrink: 0'));
|
||
});
|
||
test('Product owns two teams and Technology owns five separate teams', () => {
|
||
const spec = JSON.parse(read('diagrams/organization-structure.architecture.json'));
|
||
const page = read('docs/organization/structure.mdx');
|
||
assert(!/shared-delivery|squad-/i.test(JSON.stringify(spec)));
|
||
assert(!/shared squads|share a delivery structure|cross-functional teams/i.test(page));
|
||
for (const [dept, count, heading, next] of [['product',2,'Product','Technology'],['technology',5,'Technology','Operations']]) {
|
||
const teams = spec.components.filter(n => n.id.startsWith(`${dept}-team-`));
|
||
assert.equal(teams.length, count);
|
||
const section = page.split(`### ${heading}\n`)[1].split(`### ${next}\n`)[0];
|
||
const rows = section.split('\n').filter(l => l.startsWith('| ')).slice(2);
|
||
assert.equal(rows.length, count);
|
||
for (const team of teams) {
|
||
const parents = spec.connections.filter(e => e.to === team.id);
|
||
assert.deepEqual(parents.map(e => e.from), [dept]);
|
||
assert(rows.some(row => row.startsWith(`| ${team.label} |`)));
|
||
}
|
||
}
|
||
});
|
||
test('departments share one row and each has delivery teams below it', () => {
|
||
const spec = JSON.parse(read('diagrams/organization-structure.architecture.json'));
|
||
const page = read('docs/organization/structure.mdx');
|
||
const departments = ['product', 'technology', 'operations', 'marketing', 'finance', 'people'];
|
||
const nodes = new Map(spec.components.map(n => [n.id, n]));
|
||
assert.equal(new Set(departments.map(id => nodes.get(id).pos[1])).size, 1);
|
||
for (const [i, id] of departments.entries()) {
|
||
const department = nodes.get(id);
|
||
const teams = spec.connections.filter(e => e.from === id).map(e => nodes.get(e.to));
|
||
assert.equal(teams.length, i === 0 ? 2 : i === 1 ? 5 : 1);
|
||
for (const team of teams) {
|
||
assert(team.pos[1] > department.pos[1] + department.size[1]);
|
||
assert(team.size[0] < department.size[0]);
|
||
assert.equal(team.pos[0] + team.size[0], department.pos[0] + department.size[0]);
|
||
const edge = spec.connections.find(e => e.from === id && e.to === team.id);
|
||
assert.equal(edge.toSide, 'left');
|
||
assert.equal(edge.fromSide, 'bottom');
|
||
assert.equal(spec.connections.find(e => e.from === 'management' && e.to === id).toSide, 'top');
|
||
assert.deepEqual(spec.connections.filter(e => e.to === team.id).map(e => e.from), [id]);
|
||
assert(page.includes(team.label));
|
||
}
|
||
}
|
||
for (const [i, a] of spec.components.entries()) for (const b of spec.components.slice(i + 1)) {
|
||
assert(!(a.pos[0] < b.pos[0] + b.size[0] && a.pos[0] + a.size[0] > b.pos[0] && a.pos[1] < b.pos[1] + b.size[1] && a.pos[1] + a.size[1] > b.pos[1]), `${a.id} overlaps ${b.id}`);
|
||
}
|
||
});
|
||
test('organization content is split into linked focused pages', () => {
|
||
const structure = read('docs/organization/structure.mdx');
|
||
const collaboration = read('docs/organization/collaboration.mdx');
|
||
const sdlc = read('docs/organization/sdlc.mdx');
|
||
assert(!structure.includes('## How the departments work together'));
|
||
assert(!structure.includes('## Leadership and delivery structure'));
|
||
assert(!structure.includes('name="organization-reporting"'));
|
||
assert(collaboration.includes('## How the departments work together'));
|
||
for (const outcome of ['Better buyer experience', 'Stronger seller experience', 'Safe and trustworthy trading', 'Sustainable growth', 'AI-powered execution']) assert(collaboration.includes(outcome));
|
||
assert(sdlc.includes('title: SDLC — Software Delivery Life Cycle'));
|
||
assert(sdlc.includes('name="organization-reporting"'));
|
||
for (const role of ['Head of Engineering', 'AI Architect', 'Operational Quality', 'Brand Team Lead']) assert(sdlc.includes(role));
|
||
for (const [name, page] of [['structure',structure],['collaboration',collaboration],['sdlc',sdlc]]) {
|
||
for (const other of ['structure','collaboration','sdlc'].filter(n => n !== name)) assert(page.includes(`./${other}.mdx`));
|
||
}
|
||
});
|
||
test('organization page presents an operating model, not research notes', () => {
|
||
const page = read('docs/organization/structure.mdx');
|
||
assert(page.includes('operating model') && page.includes('## Departments and teams'));
|
||
const prohibited = /assum|job.advert|vacanc|publicly evidenced|research snapshot|## Sources|\[\d+\]|\b[EJA]:\s/i;
|
||
assert(!prohibited.test(page));
|
||
assert(page.includes('Vladas Jurkevičius') && page.includes('Lukas Deksnys'));
|
||
assert(existsSync('research/organization/reconstruction-snapshot.mdx'));
|
||
assert(JSON.parse(read('research/organization/sources.json')).sources.every(s => s.quotes?.length));
|
||
for (const name of ['organization-structure', 'organization-reporting']) {
|
||
const spec = JSON.parse(read(`diagrams/${name}.architecture.json`));
|
||
assert(!prohibited.test(JSON.stringify(spec)));
|
||
const ids = new Set(spec.components.map(n => n.id));
|
||
assert.equal(ids.size, spec.components.length);
|
||
for (const edge of spec.connections) assert(ids.has(edge.from) && ids.has(edge.to));
|
||
}
|
||
});
|