UNPKG

fava

Version:

A wannabe tiny largely-drop-in replacement for ava that works in the browser too.

102 lines (101 loc) 4.13 kB
/* IMPORT */ import { execFileSync } from 'node:child_process'; import delay from 'promise-resolve-timeout'; import color from 'tiny-colors'; import readdir from 'tiny-readdir'; import Watcher from 'watcher'; import zeptomatch from 'zeptomatch'; import Env from './env.js'; import Utils from './utils.js'; /* MAIN */ const CLI = { /* API */ execute: async (globs, options) => { //TODO: Implement this better //TODO: Add support for executing different test files in parallel const filterGlobs = globs; const filter = (targetPath) => zeptomatch(filterGlobs, targetPath); const includeGlobs = ['**/test.{js,mjs}', '**/src/test.{js,mjs}', '**/source/test.{js,mjs}', '**/test-*.{js,mjs}', '**/*.spec.{js,mjs}', '**/*.test.{js,mjs}', '**/test/**/*.{js,mjs}', '**/tests/**/*.{js,mjs}', '**/__tests__/**/*.{js,mjs}']; const include = (targetPath) => zeptomatch(includeGlobs, targetPath); const ignoreGlobs = ['**/.git/**', '**/node_modules/**', '**/dist/**', '**/out/**', '**/_[!_]*', '**/fixtures.{js,mjs}', '**/__tests__/**/__helper__/**/*', '**/__tests__/**/__helpers__/**/*', '**/__tests__/**/__fixture__/**/*', '**/__tests__/**/__fixtures__/**/*', '**/test/**/helper/**/*', '**/test/**/helpers/**/*', '**/test/**/fixture/**/*', '**/test/**/fixtures/**/*', '**/tests/**/helper/**/*', '**/tests/**/helpers/**/*', '**/tests/**/fixture/**/*', '**/tests/**/fixtures/**/*']; const ignore = (targetPath) => zeptomatch(ignoreGlobs, targetPath); const spawn = (filePath) => { try { execFileSync(process.execPath, [filePath], { stdio: ['ignore', 'inherit', 'inherit'], env: { ...process.env, FAVA_CLI: '1', FAVA_FAIL_FAST: options.failFast ? '1' : '0', FAVA_MATCH: options.match?.length ? options.match.join(',') : '', FAVA_TIMEOUT: options.timeout ? String(options.timeout) : '0', FAVA_VERBOSE: options.verbose ? '1' : '0' } }); return true; } catch { return false; } }; const divider = (() => { let count = 0; return () => { if (count) { const width = Utils.getStdoutColumns(); const divider = color.dim('-'.repeat(width)); console.log(divider); } count += 1; }; })(); const execute = (filePath) => { divider(); const isSuccess = spawn(filePath); if ((Env.options.failFast || options.failFast) && !isSuccess && !options.watch) { process.exit(1); } }; const watch = () => { const watcherOptions = { native: true, recursive: true, ignoreInitial: false, debounce: 500, ignore }; new Watcher(process.cwd(), watcherOptions, (event, targetPath) => onChange(targetPath)); }; const input = () => { process.stdin.on('data', (data) => { if (data.toString().trim().toLowerCase() !== 'rs') return; find(); }); }; const find = async () => { const { files } = await readdir(process.cwd(), { ignore }); for (const file of files) { onChange(file); await delay(0); } }; const onChange = (targetPath) => { if (!include(targetPath)) return; if (globs.length && !filter(targetPath)) return; execute(targetPath); }; if (options.watch) { watch(); input(); await Utils.lang.hang(); } else { await find(); } } }; /* EXPORT */ export default CLI;