sxy-test-runner 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/cli/index.js +33 -0
  2. package/dist/cli/init.js +170 -0
  3. package/dist/cli/init.unitTest.js +0 -0
  4. package/dist/cli/lib/addBasePath.js +15 -0
  5. package/dist/cli/lib/addBasePath.unitTest.js +31 -0
  6. package/dist/cli/lib/addExports.js +12 -0
  7. package/dist/cli/lib/addExports.unitTest.js +29 -0
  8. package/dist/cli/lib/applyConfigDefaults.js +41 -0
  9. package/dist/cli/lib/applyConfigDefaults.unitTest.js +25 -0
  10. package/dist/cli/lib/buildDependencyTree.js +32 -0
  11. package/dist/cli/lib/buildDependencyTree.unitTest.js +15 -0
  12. package/dist/cli/lib/buildDependencyTrees.js +34 -0
  13. package/dist/cli/lib/buildDependencyTrees.unitTest.js +17 -0
  14. package/dist/cli/lib/defaultConfig.js +22 -0
  15. package/dist/cli/lib/defaultConfig.test.js +7 -0
  16. package/dist/cli/lib/doUserSetup.js +30 -0
  17. package/dist/cli/lib/doUserSetup.unitTest.js +39 -0
  18. package/dist/cli/lib/doUserTeardown.js +30 -0
  19. package/dist/cli/lib/doUserTeardown.unitTest.js +39 -0
  20. package/dist/cli/lib/findTestFiles.js +24 -0
  21. package/dist/cli/lib/findTestFiles.unitTest.js +22 -0
  22. package/dist/cli/lib/getAllowedFlags.js +11 -0
  23. package/dist/cli/lib/getAllowedFlags.unitTest.js +20 -0
  24. package/dist/cli/lib/globArgCombine.js +1 -0
  25. package/dist/cli/lib/globArgCombine.unitTest.js +18 -0
  26. package/dist/cli/lib/injectProperties.js +11 -0
  27. package/dist/cli/lib/injectProperties.unitTest.js +75 -0
  28. package/dist/cli/lib/load.js +3 -0
  29. package/dist/cli/lib/load.unitTest.js +7 -0
  30. package/dist/cli/lib/loadConfig.js +21 -0
  31. package/dist/cli/lib/loadConfig.unitTest.js +15 -0
  32. package/dist/cli/lib/loadTestFile.js +75 -0
  33. package/dist/cli/lib/loadTestFile.unitTest.js +45 -0
  34. package/dist/cli/lib/loadTestFileStatic.js +40 -0
  35. package/dist/cli/lib/loadTestFileStatic.unitTest.js +29 -0
  36. package/dist/cli/lib/parseCommandLineArguments.js +57 -0
  37. package/dist/cli/lib/parseCommandLineArguments.unitTest.js +21 -0
  38. package/dist/cli/lib/parseDescribe.js +88 -0
  39. package/dist/cli/lib/parseDescribe.unitTest.js +17 -0
  40. package/dist/cli/lib/parseItsFromDescribe.js +115 -0
  41. package/dist/cli/lib/processWatchEvent.js +0 -0
  42. package/dist/cli/lib/processWatchEvent.unitTest.js +7 -0
  43. package/dist/cli/lib/reservedExportKeys.js +1 -0
  44. package/dist/cli/lib/reservedExportKeys.unitTest.js +7 -0
  45. package/dist/cli/lib/runDescribe.js +29 -0
  46. package/dist/cli/lib/runDescribe.old copy.js +115 -0
  47. package/dist/cli/lib/runDescribe.old.js +115 -0
  48. package/dist/cli/lib/runDescribe.old.unitTest.js +440 -0
  49. package/dist/cli/lib/runDescribe.unitTest.js +287 -0
  50. package/dist/cli/lib/runDescribeParseIts.js +87 -0
  51. package/dist/cli/lib/runDescribeParseIts.unitTest.js +0 -0
  52. package/dist/cli/lib/runDescribeRun.js +59 -0
  53. package/dist/cli/lib/runDescribeRun.unitTest.js +293 -0
  54. package/dist/cli/lib/runDescribeRunIts.js +56 -0
  55. package/dist/cli/lib/runDescribeRunIts.unitTest.js +0 -0
  56. package/dist/cli/lib/runIt.js +79 -0
  57. package/dist/cli/lib/runIt.unitTest.js +294 -0
  58. package/dist/cli/lib/runTasks.js +42 -0
  59. package/dist/cli/lib/runTasks.unitTest.js +30 -0
  60. package/dist/cli/lib/runTest-old.js +159 -0
  61. package/dist/cli/lib/runTest-old.unitTest.js +183 -0
  62. package/dist/cli/lib/runTest.js +71 -0
  63. package/dist/cli/lib/runTest.unitTest.js +269 -0
  64. package/dist/cli/lib/runTests.js +137 -0
  65. package/dist/cli/lib/runTests.unitTest.js +59 -0
  66. package/dist/cli/lib/showTestLoadingError.js +22 -0
  67. package/dist/cli/lib/showTestLoadingError.unitTest.js +25 -0
  68. package/dist/cli/lib/showTestResult.js +87 -0
  69. package/dist/cli/lib/showTestResult.unitTest.js +180 -0
  70. package/dist/cli/lib/timeProfier.js +7 -0
  71. package/dist/cli/lib/validateConfig.js +29 -0
  72. package/dist/cli/lib/validateConfig.unitTest.js +22 -0
  73. package/dist/cli/lib/watchFiles.js +1 -0
  74. package/dist/cli/lib/watchFiles.unitTest.js +48 -0
  75. package/dist/cli/lib/watchFilesAndRunTests.js +2 -0
  76. package/dist/cli/lib/watchFilesAndRunTests.unitTest.js +129 -0
  77. package/dist/cli/lib/watchFilesAndRunTestsChokidar.js +142 -0
  78. package/dist/cli/lib/watchFilesAndRunTestsChokidar.unitTest.js +133 -0
  79. package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.js +162 -0
  80. package/dist/cli/lib/watchFilesAndRunTestsNodeWatch.unitTest.js +131 -0
  81. package/dist/cli/lib/watchFilesChokidar.js +56 -0
  82. package/dist/cli/lib/watchFilesChokidar.unitTest.js +85 -0
  83. package/dist/cli/lib/watchFilesNodeWatch.js +42 -0
  84. package/dist/cli/lib/watchFilesNodeWatch.unitTest.js +48 -0
  85. package/dist/cli/once.js +47 -0
  86. package/dist/cli/once.unitTest.js +39 -0
  87. package/dist/cli/watch.js +100 -0
  88. package/dist/cli/watch.unitTest.js +117 -0
  89. package/dist/config.js +7 -0
  90. package/dist/describe-old.js +257 -0
  91. package/dist/describe-old.unitTest.js +21 -0
  92. package/dist/describe.js +24 -0
  93. package/dist/describe.unitTest.js +27 -0
  94. package/dist/exported.eslintrc.js +7 -0
  95. package/dist/index.js +1 -0
  96. package/dist/indexNumberToLetters.js +13 -0
  97. package/dist/load.js +3 -0
  98. package/dist/output.js +17 -0
  99. package/dist/testing/example.test.js +26 -0
  100. package/dist/testing/example2.test.js +19 -0
  101. package/dist/testing/example3.test.js +16 -0
  102. package/dist/testing/importTimeTarget.js +9 -0
  103. package/dist/testing/importTimeTarget2.js +11 -0
  104. package/dist/testing/importTimeTest.js +8 -0
  105. package/dist/testsState.js +4 -0
  106. package/dist/timeProfiling.js +9 -0
  107. package/package.json +68 -0
@@ -0,0 +1,142 @@
1
+ import { createTimeProfiler } from 'sxy-dev-tools';
2
+ import { showTimeProfiling } from '../../config.js';
3
+ import chalk from 'chalk-extensions';
4
+ import minimatch from 'minimatch';
5
+ import slash from 'slash';
6
+ import watch from 'node-watch'; //import chokidar from 'chokidar'
7
+ //import nsfw from 'nsfw'
8
+
9
+ import fs from 'fs';
10
+ import { out, log, debug } from '../../output.js';
11
+ import { runTests } from './runTests.js';
12
+ import { buildDependencyTree } from './buildDependencyTree.js';
13
+ import { globArgCombine } from './globArgCombine.js';
14
+ import { load } from './load.js';
15
+ const {
16
+ timeProfileAsync
17
+ } = await createTimeProfiler(showTimeProfiling);
18
+ import { watchFilesChokidar } from './watchFilesChokidar.js';
19
+ export async function watchFilesAndRunTestsChokidar(config, testFiles, dependencyTrees, failingTests, customOut = undefined) {
20
+ const projectDir = await process.cwd();
21
+ await timeProfileAsync('start watching', async () => {
22
+ let changedFiles = [];
23
+ let timeout = null;
24
+
25
+ const testFilter = file => minimatch(file, globArgCombine(config.tests)) && (!config.testsIgnore || !minimatch(file, globArgCombine(config.testsIgnore))); // start watching
26
+
27
+
28
+ await watchFilesChokidar(config, watchEvent);
29
+
30
+ async function watchEvent(filename, event) {
31
+ await debug('chokidar watch event', filename, event); //filename = slash(filename)
32
+ // remove dep tree for any tests that are deleted, avoiding trying to run it later
33
+
34
+ if (event === 'remove' && filename in dependencyTrees) {
35
+ await testFiles.remove(filename);
36
+ delete dependencyTrees[filename];
37
+ } // info on the event found
38
+
39
+
40
+ await out(chalk.grey`change: ${filename} (${event})`); // add the file to changed files
41
+
42
+ await changedFiles.push([filename, event]); // wait 100ms after any change before processing, to avoid multiple execution?
43
+
44
+ if (timeout) {
45
+ await clearTimeout(timeout);
46
+ }
47
+
48
+ timeout = await setTimeout(async () => {
49
+ await timeProfileAsync('handle changed files', async () => {
50
+ await debug('changed files', changedFiles); //out('changed files', changedFiles)
51
+
52
+ try {
53
+ // build related test list
54
+ const tests = [];
55
+
56
+ for (const [file, event] of changedFiles) {
57
+ await debug('check', file);
58
+ await debug('1 tests', tests);
59
+
60
+ if (event !== 'remove') {
61
+ // only check to see if its a test if it exists (has not just been removed)
62
+ if (await testFilter(file)) {
63
+ // it is a test file itself, add to run list
64
+ await debug('its a test', file);
65
+ await tests.push(file);
66
+
67
+ if (!(file in dependencyTrees)) {
68
+ // if its a new test
69
+ await debug('try to add a new test', file), await addNewTest(file);
70
+ }
71
+ }
72
+ }
73
+
74
+ await debug('dtrees', dependencyTrees);
75
+ await debug('2 tests', tests);
76
+
77
+ for (const f of await Object.getOwnPropertyNames(dependencyTrees)) {
78
+ await debug('dep tree', f, dependencyTrees[f]);
79
+
80
+ if (await dependencyTrees[f].some(dep => {
81
+ debug('checking dep', dep, file);
82
+ return dep === file;
83
+ })) {
84
+ // a test depends on this file
85
+ await debug('its a dependency', file);
86
+ await debug('its a dependency', file);
87
+ await tests.push(f);
88
+ }
89
+ }
90
+ }
91
+
92
+ changedFiles = [];
93
+ await debug('tests', tests);
94
+ await debug('3 tests', tests);
95
+
96
+ if (tests.length) {
97
+ await timeProfileAsync('run tests related to changes', async () => {
98
+ await debug('tests', tests);
99
+
100
+ if (config.reRunFailingTests) {
101
+ for (const failingTest of failingTests) {
102
+ if (!(await fs.existsSync(failingTest))) {
103
+ //debug('remove failing test', failingTest)
104
+ await failingTests.remove(failingTest); //(failingTests)
105
+ }
106
+ }
107
+ }
108
+
109
+ await debug('tests', tests);
110
+ await debug('failingTests', failingTests);
111
+ await debug('reRunFailingTests', config.watch.reRunFailingTests);
112
+ const toTest = config.watch.reRunFailingTests ? await (await [...tests, ...failingTests].dedupeSlow()).reverse() // dedupe return new? // reverse in place
113
+ : await [...tests].reverse(); // reverse in place
114
+
115
+ const results = {
116
+ total: 0,
117
+ passed: 0
118
+ };
119
+ await debug('run tests on change');
120
+ await debug('toTest', toTest); // clear load cache to allow accesing the new tets
121
+
122
+ await load.cache.clear();
123
+ const testResults = await runTests(config, toTest, failingTests, customOut);
124
+ });
125
+ }
126
+ } catch (e) {
127
+ await log('watch handler error', e);
128
+ } finally {//
129
+ }
130
+ });
131
+ }, 33);
132
+ } // end of watch event
133
+
134
+
135
+ async function addNewTest(testFile) {
136
+ await debug('new test', testFile);
137
+ const dependencyTree = await buildDependencyTree(config, testFile);
138
+ dependencyTrees[testFile] = await (await dependencyTree.map(async file => await (await slash(file)).slice(projectDir.length + 1))).filter(async f => f !== testFile);
139
+ }
140
+ });
141
+ await out(chalk.brightblue`watching...`);
142
+ }
@@ -0,0 +1,133 @@
1
+ import { promises as fs, existsSync } from 'fs';
2
+ import figures from 'figures';
3
+ import { watchFilesAndRunTestsChokidar } from './watchFilesAndRunTestsChokidar.js';
4
+ import { applyConfigDefaults } from './applyConfigDefaults.js'; // watchFiles(config, testFiles, dependencyTrees, failingTests)
5
+
6
+ await mochaDescribe('watchFilesAndRunTestsChokidar() function', async function () {
7
+ const tempFolder = 'temp/watchFilesAndRunTestsChokidar';
8
+ const baseConfig = await applyConfigDefaults({
9
+ testsBase: tempFolder,
10
+ tests: '**/*.test.js',
11
+ watch: {
12
+ watchFilesBase: tempFolder,
13
+ watchFiles: '**/*.js'
14
+ }
15
+ });
16
+ await mochaIt('should run a test when a test file is changed', async function () {
17
+ //this.timeout(100000)
18
+ const config = await Object.copy(baseConfig); // ignore the file from the last test, causing load errors
19
+
20
+ config.testsIgnore = '**/c.test.js'; // create a custom out function to capture the output
21
+
22
+ let outBuffer = '';
23
+
24
+ const customOut = (...texts) => {
25
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
26
+ };
27
+
28
+ const testFileName = 'temp/watchFilesAndRunTestsChokidar/a.test.js';
29
+ const thing = 'Sample test 1';
30
+ const should = '1 should equal 1';
31
+ await watchFilesAndRunTestsChokidar(config, [], {}, [], customOut);
32
+ await outBuffer.should.equal('');
33
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
34
+ import { expect, should } from 'chai'
35
+ should()
36
+
37
+ describe('${thing}', ({it}) => {
38
+
39
+ it('${should}', () => {
40
+ expect(1).to.equal(1)
41
+ })
42
+
43
+ })`);
44
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000));
45
+ await outBuffer.should.include(testFileName);
46
+ await outBuffer.should.include(thing);
47
+ await outBuffer.should.include(should);
48
+ await outBuffer.should.include(figures.tick);
49
+ });
50
+ await mochaIt('should run a test when a new test file is changed', async function () {
51
+ //this.timeout(100000)
52
+ const config = await Object.copy(baseConfig); // ignore the file from the last test, causing load errors
53
+
54
+ config.testsIgnore = '**/c.test.js'; // create a custom out function to capture the output
55
+
56
+ let outBuffer = '';
57
+
58
+ const customOut = (...texts) => {
59
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
60
+ };
61
+
62
+ const testFileName = `${tempFolder}/b.test.js`;
63
+ const thing = 'Sample test 2';
64
+ const should = '2 should equal 2';
65
+
66
+ if (await existsSync(testFileName)) {
67
+ await fs.unlink(testFileName);
68
+ }
69
+
70
+ await (await existsSync(testFileName)).should.equal(false);
71
+ await watchFilesAndRunTestsChokidar(config, [], {}, [], customOut);
72
+ await outBuffer.should.equal('');
73
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
74
+ import { expect, should } from 'chai'
75
+ should()
76
+
77
+ describe('${thing}', ({it}) => {
78
+
79
+ it('${should}', () => {
80
+ expect(2).to.equal(2)
81
+ })
82
+
83
+ })`);
84
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000));
85
+ await outBuffer.should.include(testFileName);
86
+ await outBuffer.should.include(thing);
87
+ await outBuffer.should.include(should);
88
+ await outBuffer.should.include(figures.tick);
89
+ });
90
+ await mochaIt('removes a test from tests and dependencyTrees when it is deleted', async function () {
91
+ //this.timeout(100000)
92
+ const config = await Object.copy(baseConfig); // create a custom out function to capture the output
93
+
94
+ let outBuffer = '';
95
+
96
+ const customOut = (...texts) => {
97
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
98
+ };
99
+
100
+ const testFileName = `${tempFolder}/c.test.js`;
101
+ const thing = 'Sample test 3';
102
+ const should = '3 should equal 3';
103
+
104
+ if (!(await existsSync(testFileName))) {
105
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
106
+ import { expect, should } from 'chai'
107
+ should()
108
+
109
+ describe('${thing}', ({it}) => {
110
+
111
+ it('${should}', () => {
112
+ expect(3).to.equal(3)
113
+ })
114
+
115
+ })`);
116
+ }
117
+
118
+ (await existsSync(testFileName)).should.be.true;
119
+ const originalTests = [testFileName];
120
+ const originalDependencyTrees = {
121
+ [testFileName]: ['dep-1.js', 'dep-2.js']
122
+ };
123
+ const tests = await Object.copy(originalTests);
124
+ const dependencyTrees = await Object.copy(originalDependencyTrees);
125
+ await tests.should.include.members([testFileName]);
126
+ await dependencyTrees.should.include.keys([testFileName]);
127
+ await watchFilesAndRunTestsChokidar(config, tests, dependencyTrees, [], customOut);
128
+ await fs.unlink(testFileName);
129
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000));
130
+ await tests.should.not.include.members([testFileName]);
131
+ await dependencyTrees.should.not.include.keys([testFileName]);
132
+ });
133
+ });
@@ -0,0 +1,162 @@
1
+ import { createTimeProfiler } from 'sxy-dev-tools';
2
+ import { showTimeProfiling } from '../../config.js';
3
+ import chalk from 'chalk-extensions';
4
+ import minimatch from 'minimatch';
5
+ import slash from 'slash'; //import watch from 'node-watch'
6
+ //import chokidar from 'chokidar'
7
+ //import nsfw from 'nsfw'
8
+
9
+ import fs from 'fs';
10
+ import { out, log, debug } from '../../output.js';
11
+ import { runTests } from './runTests.js';
12
+ import { buildDependencyTree } from './buildDependencyTree.js';
13
+ import { globArgCombine } from './globArgCombine.js';
14
+ import { load } from './load.js';
15
+ const {
16
+ timeProfileAsync
17
+ } = await createTimeProfiler(showTimeProfiling);
18
+ import { addBasePath } from './addBasePath.js';
19
+ import { watchFilesNodeWatch } from './watchFilesNodeWatch.js';
20
+ export async function watchFilesAndRunTestsNodeWatch(config, testFiles, dependencyTrees, failingTests, customOut = undefined) {
21
+ const projectDir = await process.cwd();
22
+ let watcher;
23
+ await timeProfileAsync('init watching', async () => {
24
+ await debug('failingTests', failingTests);
25
+ const testsGlobs = await addBasePath(config.testsBase, config.tests);
26
+ const testsIgnoreGlobs = await addBasePath(config.testsBase, config.testsIgnore); // indentify a test file
27
+
28
+ const testFilter = //file => minimatch(file, globArgCombine(config.tests))
29
+ // && ! minimatch(file, globArgCombine(config.testsIgnore))
30
+ file => {
31
+ debug('test filter', file, globArgCombine(testsGlobs), globArgCombine(testsIgnoreGlobs), minimatch(file, globArgCombine(testsGlobs)), minimatch(file, globArgCombine(testsIgnoreGlobs)), minimatch(file, globArgCombine(testsGlobs)) && !minimatch(file, globArgCombine(testsIgnoreGlobs)));
32
+ return minimatch(file, globArgCombine(testsGlobs)) && !minimatch(file, globArgCombine(testsIgnoreGlobs));
33
+ }; //log('tests glob', globArgCombine(testsGlobs))
34
+ //log('testsIgnore glob', globArgCombine(testsIgnoreGlobs))
35
+
36
+
37
+ let changedFiles = [];
38
+ let timeout = null;
39
+
40
+ if (!config.watch.watchFilesBase) {
41
+ await out(`No config.watch.watchFilesBase provided, defaulting to '.'`);
42
+ config.watch.watchFilesBase = '.';
43
+ }
44
+
45
+ watcher = await watchFilesNodeWatch(config, watchEvent);
46
+
47
+ async function watchEvent(filename, event) {
48
+ await debug('handle watch event ', filename, event);
49
+ filename = await slash(filename); // remove dep tree for any tests that are deleted, avoiding trying to run it later
50
+
51
+ if (event === 'remove') {
52
+ await debug('removing test', filename);
53
+
54
+ if (filename in dependencyTrees) {
55
+ await testFiles.remove(filename);
56
+ delete dependencyTrees[filename];
57
+ }
58
+ } // info on the event found
59
+
60
+
61
+ await out(chalk.grey`change: ${filename} (${event})`); // add the file to changed files
62
+
63
+ await changedFiles.push([filename, event]); // wait 100ms after any change before processing, to avoid multiple execution?
64
+
65
+ if (timeout) {
66
+ await clearTimeout(timeout);
67
+ }
68
+
69
+ timeout = await setTimeout(async () => {
70
+ await timeProfileAsync('handle changed files', async () => {
71
+ await debug('changedFiles', changedFiles);
72
+
73
+ try {
74
+ // build related test list
75
+ const tests = [];
76
+
77
+ for (const [file, event] of changedFiles) {
78
+ await debug('check', file);
79
+ await debug('1 tests', tests);
80
+
81
+ if (event !== 'remove') {
82
+ // only check to see if its a test if it exists (has not just been removed)
83
+ if (await testFilter(file)) {
84
+ // it is a test file itself, add to run list
85
+ await debug('its a test', file);
86
+ await tests.push(file);
87
+
88
+ if (!(file in dependencyTrees)) {
89
+ // if its a new test
90
+ await debug('try to add a new test', file), await addNewTest(file);
91
+ }
92
+ }
93
+ }
94
+
95
+ await debug('dtrees', dependencyTrees);
96
+ await debug('2 tests', tests);
97
+
98
+ for (const f of await Object.getOwnPropertyNames(dependencyTrees)) {
99
+ await debug('dep tree', f, dependencyTrees[f]);
100
+
101
+ if (await dependencyTrees[f].some(dep => {
102
+ debug('checking dep', dep, file);
103
+ return dep === file;
104
+ })) {
105
+ // a test depends on this file
106
+ await debug('its a dependency', file);
107
+ await debug('its a dependency', file);
108
+ await tests.push(f);
109
+ }
110
+ }
111
+ }
112
+
113
+ changedFiles = [];
114
+ await debug('tests', tests);
115
+ await debug('3 tests', tests);
116
+
117
+ if (tests.length) {
118
+ await timeProfileAsync('run tests related to changes', async () => {
119
+ await debug('tests', tests);
120
+
121
+ if (config.reRunFailingTests) {
122
+ for (const failingTest of failingTests) {
123
+ if (!(await fs.existsSync(failingTest))) {
124
+ //debug('remove failing test', failingTest)
125
+ await failingTests.remove(failingTest); //(failingTests)
126
+ }
127
+ }
128
+ }
129
+
130
+ await debug('tests', tests);
131
+ await debug('failingTests', failingTests);
132
+ await debug('reRunFailingTests', config.watch.reRunFailingTests);
133
+ const toTest = config.watch.reRunFailingTests ? await (await [...tests, ...failingTests].dedupeSlow()).reverse() // dedupe return new? // reverse in place
134
+ : await [...tests].reverse(); // reverse in place
135
+
136
+ const results = {
137
+ total: 0,
138
+ passed: 0
139
+ };
140
+ await debug('run tests on change');
141
+ await debug('toTest', toTest); // clear load cache to allow accesing the new tets
142
+
143
+ await load.cache.clear();
144
+ const testResults = await runTests(config, toTest, failingTests, customOut);
145
+ });
146
+ }
147
+ } catch (e) {
148
+ await log('watch handler error', e);
149
+ } finally {//
150
+ }
151
+ });
152
+ }, 33);
153
+ }
154
+ });
155
+ await out(chalk.brightblue`watching...`); //return new Promise( () => {} ) // infinite promise to let us watch
156
+
157
+ async function addNewTest(testFile) {
158
+ await debug('new test', testFile);
159
+ const dependencyTree = await buildDependencyTree(config, testFile);
160
+ dependencyTrees[testFile] = await (await dependencyTree.map(async file => await (await slash(file)).slice(projectDir.length + 1))).filter(async f => f !== testFile);
161
+ }
162
+ }
@@ -0,0 +1,131 @@
1
+ import { promises as fs, existsSync } from 'fs';
2
+ import figures from 'figures';
3
+ import { watchFilesAndRunTestsNodeWatch } from './watchFilesAndRunTestsNodeWatch.js';
4
+ import { applyConfigDefaults } from './applyConfigDefaults.js'; // watchFiles(config, testFiles, dependencyTrees, failingTests)
5
+
6
+ await mochaDescribe('watchFilesAndRunTestsNodeWatch() function', async function () {
7
+ const tempFolder = 'temp/watchFilesAndRunTestsNodeWatch';
8
+ const baseConfig = await applyConfigDefaults({
9
+ testsBase: tempFolder,
10
+ tests: '**/*.test.js',
11
+ watch: {
12
+ watchFilesBase: tempFolder,
13
+ watchFiles: '**/*.js'
14
+ }
15
+ });
16
+ await mochaIt('should run a test when a test file is changed', async function () {
17
+ //this.timeout(100000)
18
+ const config = await Object.copy(baseConfig); // create a custom out function to capture the output
19
+
20
+ let outBuffer = '';
21
+
22
+ const customOut = (...texts) => {
23
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
24
+ };
25
+
26
+ watchFilesAndRunTestsNodeWatch(config, [], {}, [], customOut); //console.log('outBuffer', outBuffer)
27
+
28
+ await outBuffer.should.equal('');
29
+ const testFileName = `${tempFolder}/a.test.js`;
30
+ const thing = 'Sample test 1';
31
+ const should = '1 should equal 1';
32
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
33
+ import { expect, should } from 'chai'
34
+ should()
35
+
36
+ describe('${thing}', ({it}) => {
37
+
38
+ it('${should}', () => {
39
+ expect(1).to.equal(1)
40
+ })
41
+
42
+ })`);
43
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000));
44
+ await outBuffer.should.not.equal('');
45
+ await outBuffer.should.include(testFileName);
46
+ await outBuffer.should.include(thing);
47
+ await outBuffer.should.include(should);
48
+ await outBuffer.should.include(figures.tick);
49
+ });
50
+ await mochaIt('should run a test when a new test file is changed', async function () {
51
+ const config = await Object.copy(baseConfig); // create a custom out function to capture the output
52
+
53
+ let outBuffer = '';
54
+
55
+ const customOut = (...texts) => {
56
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
57
+ };
58
+
59
+ const testFileName = `${tempFolder}/b.test.js`;
60
+ const thing = 'Sample test 2';
61
+ const should = '2 should equal 2';
62
+
63
+ if (await existsSync(testFileName)) {
64
+ await fs.unlink(testFileName);
65
+ }
66
+
67
+ await (await existsSync(testFileName)).should.equal(false);
68
+ await watchFilesAndRunTestsNodeWatch(config, [], {}, [], customOut);
69
+ await outBuffer.should.equal('');
70
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
71
+ import { expect, should } from 'chai'
72
+ should()
73
+
74
+ describe('${thing}', ({it}) => {
75
+
76
+ it('${should}', () => {
77
+ expect(2).to.equal(2)
78
+ })
79
+
80
+ })`);
81
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000)); //console.log('out', outBuffer)
82
+
83
+ await outBuffer.should.include(testFileName);
84
+ await outBuffer.should.include(thing);
85
+ await outBuffer.should.include(should);
86
+ await outBuffer.should.include(figures.tick);
87
+ });
88
+ await mochaIt('removes a test from tests and dependencyTrees when it is deleted', async function () {
89
+ //this.timeout(100000)
90
+ const config = await Object.copy(baseConfig); // create a custom out function to capture the output
91
+
92
+ let outBuffer = '';
93
+
94
+ const customOut = (...texts) => {
95
+ outBuffer += texts.join(' ') + '\n'; // join and save to the buffer
96
+ };
97
+
98
+ const testFileName = `${tempFolder}/c.test.js`;
99
+ const thing = 'Sample test 3';
100
+ const should = '3 should equal 3';
101
+
102
+ if (!(await existsSync(testFileName))) {
103
+ await fs.writeFile(testFileName, `import { describe } from '../../dist/index.js'
104
+ import { expect, should } from 'chai'
105
+ should()
106
+
107
+ describe('${thing}', ({it}) => {
108
+
109
+ it('${should}', () => {
110
+ expect(3).to.equal(3)
111
+ })
112
+
113
+ })`);
114
+ }
115
+
116
+ (await existsSync(testFileName)).should.be.true;
117
+ const originalTests = [testFileName];
118
+ const originalDependencyTrees = {
119
+ [testFileName]: ['dep-1.js', 'dep-2.js']
120
+ };
121
+ const tests = await Object.copy(originalTests);
122
+ const dependencyTrees = await Object.copy(originalDependencyTrees);
123
+ await tests.should.include.members([testFileName]);
124
+ await dependencyTrees.should.include.keys([testFileName]);
125
+ await watchFilesAndRunTestsNodeWatch(config, tests, dependencyTrees, [], customOut);
126
+ await fs.unlink(testFileName);
127
+ await new Promise(async (resolve, reject) => await setTimeout(resolve, 1000));
128
+ await tests.should.not.include.members([testFileName]);
129
+ await dependencyTrees.should.not.include.keys([testFileName]);
130
+ });
131
+ });
@@ -0,0 +1,56 @@
1
+ import { createTimeProfiler } from 'sxy-dev-tools';
2
+ import { showTimeProfiling } from '../../config.js';
3
+ import chalk from 'chalk-extensions';
4
+ import minimatch from 'minimatch';
5
+ import slash from 'slash'; //import watch from 'node-watch'
6
+
7
+ import chokidar from 'chokidar'; //import nsfw from 'nsfw'
8
+
9
+ import fs, { watch } from 'fs';
10
+ import { out, log, debug } from '../../output.js';
11
+ import { globArgCombine } from './globArgCombine.js';
12
+ import { addBasePath } from './addBasePath.js';
13
+ const {
14
+ timeProfileAsync
15
+ } = await createTimeProfiler(showTimeProfiling);
16
+ export async function watchFilesChokidar(config, onEvent) {
17
+ return await timeProfileAsync('start watching', async () => {
18
+ //const testGlobs = addBaseToGlobs(config.testsBase, config.tests)
19
+ //const ignoreGlobs = addBaseToGlobs(config.testsBase, config.testsIgnore)
20
+ // indentify a test file
21
+ const testFilter = file => minimatch(file, globArgCombine(config.tests)) && (!config.testsIgnore || !minimatch(file, globArgCombine(config.testsIgnore))); // identify a file we should be watching and responding to
22
+
23
+
24
+ const watchFilter = file => (!config.watch.watchFiles || minimatch(file, globArgCombine(config.watch.watchFiles))) && (!config.watch.watchFilesIgnore || !minimatch(file, globArgCombine(config.watch.watchFilesIgnore)));
25
+
26
+ if (!config.watch.watchFilesBase) {
27
+ await out(`No config.watch.watchFilesBase provided, defaulting to '.'`);
28
+ config.watch.watchFilesBase = '.';
29
+ }
30
+
31
+ const ignoreGlob = config.watch.watchFilesIgnore ? await addBasePath(config.watch.watchFilesBase, config.watch.watchFilesIgnore) : null; //log(`watch: ${config.watch.watchFilesBase}`)
32
+ // log(`ignore: ${ignoreGlob}`)
33
+
34
+ const watcher = await chokidar.watch(config.watch.watchFilesBase, {
35
+ ignored: ignoreGlob,
36
+ ignoreInitial: true
37
+ });
38
+ await watcher.on('all', async (event, filename) => {
39
+ //log('[watch event]', path, event)
40
+ filename = await slash(filename);
41
+ await debug('[watch event]', filename, event);
42
+ await onEvent(filename, event === 'unlink' ? 'remove' : event);
43
+ });
44
+ return new Promise(async (resolve, reject) => {
45
+ await watcher.on('ready', async () => {
46
+ //log('chokidar watcher ready')
47
+ await debug('chokidar watcher ready');
48
+ await resolve(watcher);
49
+ });
50
+ }); // watch(config.watch.watchFilesBase, { recursive: true, filter: watchFilter }, function(event, filename) {
51
+ // filename = slash(filename)
52
+ // debug('watch event')
53
+ // onEvent(filename, event)
54
+ // })
55
+ }); //return new Promise( () => {} ) // infinite promise to let us watch
56
+ }