|
| 1 | +import {readdirSync, readFileSync} from 'fs'; |
| 2 | +import {join, basename} from 'path'; |
| 3 | +import {sync as glob} from 'glob'; |
| 4 | +import chalk from 'chalk'; |
| 5 | +import * as ts from 'typescript'; |
| 6 | + |
| 7 | +const srcDirectory = join(__dirname, '../src'); |
| 8 | +const materialDirectories = readdirSync(join(srcDirectory, 'material')); |
| 9 | + |
| 10 | +// Goes through all the unit tests and flags the ones that don't exist in the MDC components. |
| 11 | +readdirSync(join(srcDirectory, 'material-experimental'), {withFileTypes: true}) |
| 12 | + .reduce((matches, entity) => { |
| 13 | + // Go through all the `material-experimental` directories and match them to ones in `material`. |
| 14 | + if (entity.isDirectory()) { |
| 15 | + const materialName = entity.name.replace(/^mdc-/, ''); |
| 16 | + |
| 17 | + if (materialDirectories.indexOf(materialName) > -1) { |
| 18 | + matches.set(materialName, entity.name); |
| 19 | + } |
| 20 | + } |
| 21 | + |
| 22 | + return matches; |
| 23 | + }, new Map<string, string>()) |
| 24 | + .forEach((mdcPackage, materialPackage) => { |
| 25 | + const mdcTestFiles = getUnitTestFiles(`material-experimental/${mdcPackage}`); |
| 26 | + |
| 27 | + // MDC entry points that don't have test files may not have been implemented yet. |
| 28 | + if (mdcTestFiles.length > 0) { |
| 29 | + // Filter out files that don't exist in the MDC package, allowing |
| 30 | + // us to ignore some files which may not need to be ported to MDC. |
| 31 | + const materialTestFiles = getUnitTestFiles(`material/${materialPackage}`).filter(path => { |
| 32 | + const fileName = basename(path); |
| 33 | + return mdcTestFiles.some(file => basename(file) === fileName); |
| 34 | + }); |
| 35 | + const materialTests = getTestNames(materialTestFiles); |
| 36 | + const mdcTests = getTestNames(mdcTestFiles); |
| 37 | + const missingTests = materialTests.filter(test => !mdcTests.includes(test)); |
| 38 | + |
| 39 | + if (missingTests.length > 0) { |
| 40 | + console.log(chalk.redBright(`\nMissing tests for ${mdcPackage}:`)); |
| 41 | + console.log(missingTests.join('\n')); |
| 42 | + } |
| 43 | + } |
| 44 | + }); |
| 45 | + |
| 46 | +/** |
| 47 | + * Gets all the names of all unit test files inside a |
| 48 | + * package name, excluding `testing` packages and e2e tests. |
| 49 | + */ |
| 50 | +function getUnitTestFiles(name: string): string[] { |
| 51 | + return glob('{,!(testing)/**/}!(*.e2e).spec.ts', { |
| 52 | + absolute: true, |
| 53 | + cwd: join(srcDirectory, name) |
| 54 | + }); |
| 55 | +} |
| 56 | + |
| 57 | +/** Gets the name of all unit tests within a set of files. */ |
| 58 | +function getTestNames(files: string[]): string[] { |
| 59 | + const testNames: string[] = []; |
| 60 | + |
| 61 | + files.forEach(file => { |
| 62 | + const content = readFileSync(file, 'utf-8'); |
| 63 | + const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.ES2015); |
| 64 | + |
| 65 | + sourceFile.forEachChild(function walk(node: ts.Node) { |
| 66 | + if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && |
| 67 | + node.expression.text === 'it') { |
| 68 | + // Note that this is a little naive since it'll take the literal text of the test |
| 69 | + // name expression which could include things like string concatenation. It's fine |
| 70 | + // for the limited use cases of the script. |
| 71 | + testNames.push(node.arguments[0].getText(sourceFile) |
| 72 | + // Replace the quotes around the test name. |
| 73 | + .replace(/^['`]|['`]$/g, '') |
| 74 | + // Strip newlines followed by indentation. |
| 75 | + .replace(/\n\s+/g, ' ') |
| 76 | + // Strip escape characters. |
| 77 | + .replace(/\\/g, '') |
| 78 | + // Collapse concatenated strings. |
| 79 | + .replace(/['`]\s+\+\s+['`]/g, '')); |
| 80 | + } else { |
| 81 | + node.forEachChild(walk); |
| 82 | + } |
| 83 | + }); |
| 84 | + }); |
| 85 | + |
| 86 | + return testNames; |
| 87 | +} |
0 commit comments