« get me outta code hell

index.js « data-tests - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/data-tests/index.js
blob: 3901db07bbf93665cb57d3beedd3764325370e94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import * as path from 'node:path';
import {fileURLToPath} from 'node:url';

import chokidar from 'chokidar';

import {colors, logError, logInfo, logWarn, parseOptions} from '#cli';
import {bindFind, getAllFindSpecs} from '#find';
import {isMain} from '#node-utils';
import {getContextAssignments} from '#repl';
import {bindOpts, showAggregate} from '#sugar';
import {quickLoadAllFromYAML} from '#yaml';

async function main() {
  const miscOptions = await parseOptions(process.argv.slice(2), {
    'data-path': {
      type: 'value',
    },
  });

  const dataPath = miscOptions['data-path'] || process.env.HSMUSIC_DATA;

  if (!dataPath) {
    logError`Expected --data-path option or HSMUSIC_DATA to be set`;
    return;
  }

  console.log(`HSMusic automated data tests`);
  console.log(`${colors.bright(colors.yellow(`:star:`))} Now featuring quick-reloading! ${colors.bright(colors.cyan(`:earth:`))}`);

  // Watch adjacent files in data-tests directory
  const metaPath = fileURLToPath(import.meta.url);
  const metaDirname = path.dirname(metaPath);
  const watcher = chokidar.watch(metaDirname);

  const wikiData = await quickLoadAllFromYAML(dataPath, {
    bindFind,
    getAllFindSpecs,

    showAggregate: bindOpts(showAggregate, {
      showTraces: false,
    }),
  });

  const context = await getContextAssignments({
    wikiData,
  });

  let resolveNext;

  const queue = [];

  watcher.on('all', (event, path) => {
    if (!['add', 'change'].includes(event)) return;
    if (path === metaPath) return;
    if (resolveNext) {
      resolveNext(path);
    } else if (!queue.includes(path)) {
      queue.push(path);
    }
  });

  logInfo`Awaiting file changes.`;

  /* eslint-disable-next-line no-constant-condition */
  while (true) {
    const testPath = (queue.length
      ? queue.shift()
      : await new Promise(resolve => {
          resolveNext = resolve;
        }));

    resolveNext = null;

    const shortPath = path.basename(testPath);

    logInfo`Path updated: ${shortPath} - running this test!`;

    let imp;
    try {
      imp = await import(`${testPath}?${Date.now()}`)
    } catch (error) {
      logWarn`Failed to import ${shortPath} - ${error.constructor.name} details below:`;
      console.error(error);
      continue;
    }

    const {default: testFn} = imp;

    if (!testFn) {
      logWarn`No default export for ${shortPath}`;
      logWarn`Skipping this test for now!`;
      continue;
    }

    if (typeof testFn !== 'function') {
      logWarn`Default export for ${shortPath} is ${typeof testFn}, not function`;
      logWarn`Skipping this test for now!`;
      continue;
    }

    try {
      await testFn(context);
    } catch (error) {
      showAggregate(error, {
        pathToFileURL: f => path.relative(metaDirname, fileURLToPath(f)),
      });
    }
  }
}

if (isMain(import.meta.url)) {
  main().catch((error) => {
    if (error instanceof AggregateError) {
      showAggregate(error);
    } else {
      console.error(error);
    }
  });
}