53 lines
2.8 KiB
JavaScript
53 lines
2.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const frontendRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
const outputDirectory = path.join(frontendRoot, 'dist');
|
|
const htmlFiles = readdirSync(frontendRoot).filter((fileName) => fileName.endsWith('.html'));
|
|
|
|
assert.ok(existsSync(path.join(outputDirectory, 'index.html')), 'dist/index.html is missing');
|
|
assert.ok(existsSync(path.join(outputDirectory, 'favicon.ico')), 'dist/favicon.ico is missing');
|
|
assert.strictEqual(existsSync(path.join(outputDirectory, 'downloads')), false, 'runtime installers must stay outside dist');
|
|
|
|
for (const fileName of htmlFiles) {
|
|
const sourceHtml = readFileSync(path.join(frontendRoot, fileName), 'utf8');
|
|
const builtHtmlPath = path.join(outputDirectory, fileName);
|
|
assert.strictEqual(/\?v=\d+/.test(sourceHtml), false, `${fileName} still uses a manual cache version`);
|
|
assert.ok(existsSync(builtHtmlPath), `${fileName} was not emitted`);
|
|
|
|
const builtHtml = readFileSync(builtHtmlPath, 'utf8');
|
|
const assetUrls = [...builtHtml.matchAll(/(?:src|href)="(\/(?:assets|libs)\/[^"?#]+)"/g)]
|
|
.map((match) => match[1]);
|
|
for (const assetUrl of assetUrls) {
|
|
const assetPath = path.join(outputDirectory, ...assetUrl.split('/').filter(Boolean));
|
|
assert.ok(existsSync(assetPath), `${fileName} references missing asset ${assetUrl}`);
|
|
}
|
|
}
|
|
|
|
for (const fileName of ['app.html', 'share.html']) {
|
|
const html = readFileSync(path.join(outputDirectory, fileName), 'utf8');
|
|
assert.ok(/\/assets\/[^"']+\.js/.test(html), `${fileName} is not using a bundled module`);
|
|
assert.strictEqual(/vue\.global(?:\.prod)?\.js|axios\.min\.js/.test(html), false, `${fileName} still loads global Vue/Axios`);
|
|
}
|
|
|
|
const builtAppHtml = readFileSync(path.join(outputDirectory, 'app.html'), 'utf8');
|
|
const runtimeWorkspaceMatch = builtAppHtml.match(
|
|
/<link rel="stylesheet" href="\/(workspace-[a-f0-9]{12}\.css)" data-workspace-runtime>/
|
|
);
|
|
assert.ok(runtimeWorkspaceMatch, 'app.html is missing the hashed runtime workspace stylesheet');
|
|
|
|
const runtimeWorkspacePath = path.join(outputDirectory, runtimeWorkspaceMatch[1]);
|
|
assert.ok(existsSync(runtimeWorkspacePath), 'runtime workspace stylesheet is missing');
|
|
assert.ok(
|
|
builtAppHtml.indexOf(runtimeWorkspaceMatch[0]) > builtAppHtml.lastIndexOf('</style>'),
|
|
'runtime workspace stylesheet must load after every legacy inline style'
|
|
);
|
|
|
|
const runtimeWorkspaceCss = readFileSync(runtimeWorkspacePath, 'utf8');
|
|
assert.ok(runtimeWorkspaceCss.includes('.mobile-file-create-trigger'), 'runtime workspace stylesheet is incomplete');
|
|
assert.ok(runtimeWorkspaceCss.includes('@media (max-width: 900px)'), 'runtime workspace mobile breakpoint is missing');
|
|
|
|
console.log(`Verified ${htmlFiles.length} HTML entries and their emitted assets.`);
|