index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import * as path from 'node:path';
  2. import {fileURLToPath} from 'node:url';
  3. import chokidar from 'chokidar';
  4. import {colors, logError, logInfo, logWarn, parseOptions} from '#cli';
  5. import {bindFind, getAllFindSpecs} from '#find';
  6. import {isMain} from '#node-utils';
  7. import {getContextAssignments} from '#repl';
  8. import {bindOpts, showAggregate} from '#sugar';
  9. import {quickLoadAllFromYAML} from '#yaml';
  10. async function main() {
  11. const miscOptions = await parseOptions(process.argv.slice(2), {
  12. 'data-path': {
  13. type: 'value',
  14. },
  15. });
  16. const dataPath = miscOptions['data-path'] || process.env.HSMUSIC_DATA;
  17. if (!dataPath) {
  18. logError`Expected --data-path option or HSMUSIC_DATA to be set`;
  19. return;
  20. }
  21. console.log(`HSMusic automated data tests`);
  22. console.log(`${colors.bright(colors.yellow(`:star:`))} Now featuring quick-reloading! ${colors.bright(colors.cyan(`:earth:`))}`);
  23. // Watch adjacent files in data-tests directory
  24. const metaPath = fileURLToPath(import.meta.url);
  25. const metaDirname = path.dirname(metaPath);
  26. const watcher = chokidar.watch(metaDirname);
  27. const wikiData = await quickLoadAllFromYAML(dataPath, {
  28. bindFind,
  29. getAllFindSpecs,
  30. showAggregate: bindOpts(showAggregate, {
  31. showTraces: false,
  32. }),
  33. });
  34. const context = await getContextAssignments({
  35. wikiData,
  36. });
  37. let resolveNext;
  38. const queue = [];
  39. watcher.on('all', (event, path) => {
  40. if (!['add', 'change'].includes(event)) return;
  41. if (path === metaPath) return;
  42. if (resolveNext) {
  43. resolveNext(path);
  44. } else if (!queue.includes(path)) {
  45. queue.push(path);
  46. }
  47. });
  48. logInfo`Awaiting file changes.`;
  49. /* eslint-disable-next-line no-constant-condition */
  50. while (true) {
  51. const testPath = (queue.length
  52. ? queue.shift()
  53. : await new Promise(resolve => {
  54. resolveNext = resolve;
  55. }));
  56. resolveNext = null;
  57. const shortPath = path.basename(testPath);
  58. logInfo`Path updated: ${shortPath} - running this test!`;
  59. let imp;
  60. try {
  61. imp = await import(`${testPath}?${Date.now()}`)
  62. } catch (error) {
  63. logWarn`Failed to import ${shortPath} - ${error.constructor.name} details below:`;
  64. console.error(error);
  65. continue;
  66. }
  67. const {default: testFn} = imp;
  68. if (!testFn) {
  69. logWarn`No default export for ${shortPath}`;
  70. logWarn`Skipping this test for now!`;
  71. continue;
  72. }
  73. if (typeof testFn !== 'function') {
  74. logWarn`Default export for ${shortPath} is ${typeof testFn}, not function`;
  75. logWarn`Skipping this test for now!`;
  76. continue;
  77. }
  78. try {
  79. await testFn(context);
  80. } catch (error) {
  81. showAggregate(error, {
  82. pathToFileURL: f => path.relative(metaDirname, fileURLToPath(f)),
  83. });
  84. }
  85. }
  86. }
  87. if (isMain(import.meta.url)) {
  88. main().catch((error) => {
  89. if (error instanceof AggregateError) {
  90. showAggregate(error);
  91. } else {
  92. console.error(error);
  93. }
  94. });
  95. }