build: Check test files

This commit is contained in:
Csaba Tuncsik 2023-06-16 10:32:10 +02:00
parent 1fe6459569
commit 645236753e
3 changed files with 98 additions and 2 deletions

70
.github/scripts/check-tests.mjs vendored Normal file
View file

@ -0,0 +1,70 @@
import fs from 'fs';
import path from 'path';
import util from 'util';
import { exec } from 'child_process';
import { glob } from "glob";
import parser from '@babel/parser';
import traverse from '@babel/traverse';
const readFileAsync = util.promisify(fs.readFile);
const execAsync = util.promisify(exec);
const filterAsync = async (asyncPredicate, arr) => {
const filterResults = await Promise.all(arr.map(async item => ({
item,
shouldKeep: await asyncPredicate(item)
})));
return filterResults.filter(({shouldKeep}) => shouldKeep).map(({item}) => item);
}
// Function to check if a file has a function declaration, function expression, object method or class
const hasFunctionOrClass = async filePath => {
const code = await readFileAsync(filePath);
const ast = parser.parse(code, {sourceType: 'module', plugins: ['typescript']});
let hasFunctionOrClass = false;
traverse(ast, {
enter(path) {
if (
path.isFunctionDeclaration() ||
path.isFunctionExpression() ||
path.isObjectMethod() ||
path.isClassDeclaration()
) {
hasFunctionOrClass = true;
path.stop(); // stop traversing as soon as we found a function or class
}
},
});
return hasFunctionOrClass;
}
const program = async () => {
// Run a git command to get a list of all files in the commit
const changedFilesCommand = "git diff --name-only --diff-filter=d origin/master...HEAD";
const changedFiles = await execAsync(changedFilesCommand).then(({stdout}) => stdout.toString().trim().split('\n'));
// Get all .spec.ts and .test.ts files from the packages
const specAndTestTsFiles = await glob('../../packages/*/**/__test__/*.{spec,test}.ts');
const specAndTestTsFilesNames = specAndTestTsFiles.map(file => path.parse(file).name.replace(/\.(test|spec)/, ''));
// Filter out the .ts and .vue files from the changed files, .ts files with any kind of function declaration or class
const changedVueFiles = changedFiles.filter(file => file.endsWith('.vue'));
const changedTsFilesWithFunction = await filterAsync(async file => file.endsWith('.ts') && await hasFunctionOrClass(file), changedFiles);
// For each .ts or .vue file, check if there's a corresponding .test.ts or .spec.ts file in the repository
changedVueFiles.concat(changedTsFilesWithFunction).forEach(async file => {
const fileName = path.parse(file).name;
if (!specAndTestTsFilesNames.includes(fileName)) {
console.error(`No corresponding test file for: ${file}`);
process.exit(1);
}
});
};
program();

View file

@ -1,6 +1,9 @@
{
"dependencies": {
"semver": "^7.3.8",
"conventional-changelog-cli": "^2.2.2"
"@babel/parser": "^7.22.5",
"@babel/traverse": "^7.22.5",
"conventional-changelog-cli": "^2.2.2",
"glob": "^10.2.7",
"semver": "^7.3.8"
}
}

23
.github/workflows/check-tests.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Check Test Files
on:
pull_request:
branches:
- master
jobs:
check-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Use Node.js
- uses: actions/setup-node@v3
with:
node-version: 18.x
- run: npm install --prefix=.github/scripts --no-package-lock
- name: Check for test files
run: node .github/actions/check-tests.mjs