blob: 2ac4f50a7fdc880e2d9dc23453d0410bd99375bb [file] [log] [blame] [edit]
// Node can look at the filesystem, but JS in the browser can't.
// This crawls the file tree under src/suites/${suite} to generate a (non-hierarchical) static
// listing file that can then be used in the browser to load the modules containing the tests.
import * as fs from 'fs';
import * as path from 'path';
import { SpecFile } from '../framework/file_loader.js';
import { validQueryPart } from '../framework/query/validQueryPart.js';
import { TestSuiteListingEntry, TestSuiteListing } from '../framework/test_suite_listing.js';
import { assert, unreachable } from '../framework/util/util.js';
const fg = require('fast-glob');
const specFileSuffix = '.spec.ts';
export async function crawl(suite: string): Promise<TestSuiteListingEntry[]> {
const suiteDir = 'src/' + suite;
if (!fs.existsSync(suiteDir)) {
console.error(`Could not find ${suiteDir}`);
process.exit(1);
}
const glob = `${suiteDir}/**/{README.txt,*${specFileSuffix}}`;
const filesToEnumerate: string[] = await fg(glob, { onlyFiles: true });
filesToEnumerate.sort();
const entries: TestSuiteListingEntry[] = [];
for (const file of filesToEnumerate) {
const f = file.substring((suiteDir + '/').length); // Suite-relative file path
if (f.endsWith(specFileSuffix)) {
const filepathWithoutExtension = f.substring(0, f.length - specFileSuffix.length);
const filename = `../../../${suiteDir}/${filepathWithoutExtension}.spec.js`;
const mod = (await import(filename)) as SpecFile;
assert(mod.description !== undefined, 'Test spec file missing description: ' + filename);
assert(mod.g !== undefined, 'Test spec file missing TestGroup definition: ' + filename);
mod.g.validate();
const path = filepathWithoutExtension.split('/');
for (const p of path) {
assert(validQueryPart.test(p), `Invalid directory name ${p}; must match ${validQueryPart}`);
}
entries.push({ file: path, description: mod.description.trim() });
} else if (path.basename(file) === 'README.txt') {
const filepathWithoutExtension = f.substring(0, f.length - '/README.txt'.length);
const readme = fs.readFileSync(file, 'utf8').trim();
const path = filepathWithoutExtension ? filepathWithoutExtension.split('/') : [];
entries.push({ file: path, readme });
} else {
unreachable(`glob ${glob} matched an unrecognized filename ${file}`);
}
}
return entries;
}
export function makeListing(filename: string): Promise<TestSuiteListing> {
const suite = path.basename(path.dirname(filename));
return crawl(suite);
}