run.js 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const path = require('path');
  4. const RED = '\x1b[31m';
  5. const GREEN = '\x1b[32m';
  6. const YELLOW = '\x1b[33m';
  7. const RESET = '\x1b[0m';
  8. const tests = [];
  9. function describe(name, fn) {
  10. const suite = { name, tests: [] };
  11. const t = (testName, testFn) => {
  12. suite.tests.push({ name: testName, fn: testFn });
  13. };
  14. fn(t);
  15. tests.push(suite);
  16. }
  17. global.describe = describe;
  18. const ROOT = __dirname;
  19. function loadAll(dir) {
  20. if (!fs.existsSync(dir)) return;
  21. for (const f of fs.readdirSync(dir)) {
  22. if (f === 'helpers' || f.startsWith('.')) continue;
  23. const p = path.join(dir, f);
  24. const stat = fs.statSync(p);
  25. if (stat.isDirectory()) loadAll(p);
  26. else if (f.endsWith('.test.js')) require(p);
  27. }
  28. }
  29. const args = process.argv.slice(2);
  30. const target = args[0];
  31. if (target) {
  32. const targetDir = path.join(ROOT, target);
  33. if (!fs.existsSync(targetDir)) {
  34. console.error(`${RED}Test directory not found: ${target}${RESET}`);
  35. process.exit(2);
  36. }
  37. loadAll(targetDir);
  38. } else {
  39. loadAll(ROOT);
  40. }
  41. (async () => {
  42. let total = 0, passed = 0, failed = 0;
  43. const failures = [];
  44. const startTime = Date.now();
  45. for (const suite of tests) {
  46. console.log(`\n${YELLOW}■ ${suite.name}${RESET}`);
  47. for (const t of suite.tests) {
  48. total++;
  49. try {
  50. await Promise.resolve(t.fn());
  51. passed++;
  52. console.log(` ${GREEN}✓${RESET} ${t.name}`);
  53. } catch (e) {
  54. failed++;
  55. console.log(` ${RED}✗ ${t.name}${RESET}`);
  56. console.log(` ${RED}${e.message}${RESET}`);
  57. if (process.env.STACK) console.log(e.stack);
  58. failures.push({ suite: suite.name, test: t.name, err: e });
  59. }
  60. }
  61. }
  62. const ms = Date.now() - startTime;
  63. console.log(`\n${total === passed ? GREEN : RED}${passed}/${total} passed${failed ? ` (${failed} failed)` : ''} in ${ms}ms${RESET}\n`);
  64. if (failed && !process.env.STACK) console.log(`Run with STACK=1 to see stack traces`);
  65. process.exit(failed ? 1 : 0);
  66. })();