test(frontend): garde-fou sur le transport des bundles construits (#74 Q1)
Vérifie sur les artefacts réels que `dist` résout `tauri` et `dist-web` `http`, en lisant le marqueur `__IDEA_TRANSPORT__` des assets JS émis. La régression de #74 était invisible aux tests unitaires : elle vivait dans la conf de build et de packaging, pas dans le code testé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
78
frontend/scripts/assert-bundle-transport.mjs
Normal file
78
frontend/scripts/assert-bundle-transport.mjs
Normal file
@ -0,0 +1,78 @@
|
||||
import { readdir, readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
const EXPECTED_TRANSPORT_BY_DIR = new Map([
|
||||
["dist", "tauri"],
|
||||
["dist-web", "http"],
|
||||
]);
|
||||
|
||||
async function readJavaScriptAssets(buildDir) {
|
||||
const assetsDir = join(process.cwd(), buildDir, "assets");
|
||||
let entries;
|
||||
try {
|
||||
entries = await readdir(assetsDir, { withFileTypes: true });
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Cannot read ${assetsDir}. Run npm run build:bundle before this check. ${error.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
const files = entries
|
||||
.filter((entry) => entry.isFile() && entry.name.endsWith(".js"))
|
||||
.map((entry) => join(assetsDir, entry.name));
|
||||
|
||||
if (files.length === 0) {
|
||||
throw new Error(`No JavaScript assets found in ${assetsDir}.`);
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
files.map(async (file) => ({
|
||||
file,
|
||||
source: await readFile(file, "utf8"),
|
||||
})),
|
||||
);
|
||||
}
|
||||
|
||||
function transportMarkers(source) {
|
||||
return [...source.matchAll(/__IDEA_TRANSPORT__="([a-z]+)"/g)].map(
|
||||
(match) => match[1],
|
||||
);
|
||||
}
|
||||
|
||||
async function assertBundleTransport(buildDir, expectedTransport) {
|
||||
const assets = await readJavaScriptAssets(buildDir);
|
||||
const markers = assets.flatMap(({ file, source }) =>
|
||||
transportMarkers(source).map((transport) => ({ file, transport })),
|
||||
);
|
||||
|
||||
if (markers.length === 0) {
|
||||
throw new Error(
|
||||
`${buildDir} does not publish a __IDEA_TRANSPORT__ marker in its built JavaScript assets.`,
|
||||
);
|
||||
}
|
||||
|
||||
const unexpected = markers.filter(
|
||||
({ transport }) => transport !== expectedTransport,
|
||||
);
|
||||
if (unexpected.length > 0) {
|
||||
const details = unexpected
|
||||
.map(({ file, transport }) => `${file}: ${transport}`)
|
||||
.join("\n");
|
||||
throw new Error(
|
||||
`${buildDir} resolves the wrong transport; expected ${expectedTransport}.\n${details}`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${buildDir}: __IDEA_TRANSPORT__="${expectedTransport}" (${markers.length} marker${markers.length === 1 ? "" : "s"})`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
for (const [buildDir, expectedTransport] of EXPECTED_TRANSPORT_BY_DIR) {
|
||||
await assertBundleTransport(buildDir, expectedTransport);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user