Skip to content

Commit 8bb8934

Browse files
committed
test: improve assertions and remove test duplication
1 parent 04458d6 commit 8bb8934

12 files changed

+389
-156
lines changed

tests/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ await describe('tasuku', ({ runTestSuite }) => {
1313
runTestSuite(import('./specs/renderer-ansi.spec.js'));
1414
runTestSuite(import('./specs/renderer-spinner.spec.js'));
1515
runTestSuite(import('./specs/renderer-ci-mode.spec.js'));
16+
runTestSuite(import('./specs/renderer-colors.spec.js'));
1617
runTestSuite(import('./specs/renderer-cleanup.spec.js'));
1718
runTestSuite(import('./specs/renderer-console.spec.js'));
1819
});

tests/specs/renderer-ansi.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { stripVTControlCharacters } from 'node:util';
22
import { testSuite, expect } from 'manten';
33
import { createFixture } from 'fs-fixture';
44
import { node } from '../utils/node.js';
5-
6-
// Needs to be in project directory to resolve #tasuku via import maps
7-
const tempDir = new URL('../..', import.meta.url);
5+
import { tempDir } from '../utils/temp-dir.js';
86

97
export default testSuite(({ describe }) => {
108
describe('ANSI codes', ({ test }) => {

tests/specs/renderer-ci-mode.spec.ts

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { stripVTControlCharacters } from 'node:util';
22
import { testSuite, expect } from 'manten';
33
import { createFixture } from 'fs-fixture';
44
import { node } from '../utils/node.js';
5-
6-
// Needs to be in project directory to resolve #tasuku via import maps
7-
const tempDir = new URL('../..', import.meta.url);
5+
import { tempDir } from '../utils/temp-dir.js';
86

97
export default testSuite(({ describe }) => {
108
describe('CI mode', ({ test }) => {
@@ -21,10 +19,7 @@ export default testSuite(({ describe }) => {
2119
}, { tempDir });
2220

2321
const result = await node(fixture.getPath('test.mjs'), {
24-
env: {
25-
...process.env,
26-
CI: 'true',
27-
},
22+
CI: 'true',
2823
});
2924

3025
const hasMoveCursor = result.output.includes('\u001B[1A');
@@ -34,31 +29,29 @@ export default testSuite(({ describe }) => {
3429
expect(hasClearLine).toBe(false);
3530
});
3631

37-
// FIXME: This test reveals a bug in the current renderer where GITHUB_ACTIONS
38-
// env var is not respected. The renderer should disable ANSI clearing when
39-
// GITHUB_ACTIONS=true, but it currently doesn't. This will be fixed in the
40-
// renderer refactor.
41-
// test('GITHUB_ACTIONS=true disables ANSI clearing', async () => {
42-
// await using fixture = await createFixture({
43-
// 'test.mjs': `
44-
// import task from '#tasuku';
32+
test('GITHUB_ACTIONS=true does not disable ANSI clearing', async () => {
33+
await using fixture = await createFixture({
34+
'test.mjs': `
35+
import task from '#tasuku';
36+
import { setTimeout } from 'node:timers/promises';
4537
46-
// await task('Task', async () => {
47-
// await setTimeout(100);
48-
// });
49-
// `,
50-
// });
38+
await task('Task', async () => {
39+
await setTimeout(100);
40+
});
41+
`,
42+
}, { tempDir });
5143

52-
// const result = await node(fixture.getPath('test.mjs'), {
53-
// env: { ...process.env, GITHUB_ACTIONS: 'true' },
54-
// });
44+
const result = await node(fixture.getPath('test.mjs'), {
45+
GITHUB_ACTIONS: 'true',
46+
});
5547

56-
// const hasMoveCursor = result.output.includes('\u001B[1A');
57-
// const hasClearLine = result.output.includes('\u001B[2K');
48+
// Master only respects CI env var, not GITHUB_ACTIONS
49+
const hasMoveCursor = result.output.includes('\u001B[1A');
50+
const hasClearLine = result.output.includes('\u001B[2K');
5851

59-
// expect(hasMoveCursor).toBe(false);
60-
// expect(hasClearLine).toBe(false);
61-
// });
52+
expect(hasMoveCursor).toBe(true);
53+
expect(hasClearLine).toBe(true);
54+
});
6255

6356
test('CI mode still shows final task states', async () => {
6457
await using fixture = await createFixture({
@@ -73,10 +66,7 @@ export default testSuite(({ describe }) => {
7366
}, { tempDir });
7467

7568
const result = await node(fixture.getPath('test.mjs'), {
76-
env: {
77-
...process.env,
78-
CI: 'true',
79-
},
69+
CI: 'true',
8070
});
8171
const textOutput = stripVTControlCharacters(result.output);
8272

tests/specs/renderer-cleanup.spec.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { stripVTControlCharacters } from 'node:util';
22
import { testSuite, expect } from 'manten';
33
import { createFixture } from 'fs-fixture';
44
import { node } from '../utils/node.js';
5-
6-
// Needs to be in project directory to resolve #tasuku via import maps
7-
const tempDir = new URL('../..', import.meta.url);
5+
import { tempDir } from '../utils/temp-dir.js';
86

97
export default testSuite(({ describe }) => {
108
describe('cleanup', ({ test }) => {
@@ -217,5 +215,46 @@ export default testSuite(({ describe }) => {
217215
// Console should work normally after renderer destroyed
218216
expect(textOutput.includes('After all cleared')).toBe(true);
219217
});
218+
219+
test('tasks cleared with console output interspersed', async () => {
220+
await using fixture = await createFixture({
221+
'test.mjs': `
222+
import task from '#tasuku';
223+
import { setTimeout } from 'node:timers/promises';
224+
225+
let counter = 0;
226+
console.log(counter++);
227+
228+
const interval = setInterval(() => {
229+
console.log(counter++);
230+
}, 100);
231+
232+
const taskApi = await task('Some task', async ({ task }) => {
233+
await setTimeout(500);
234+
await task('Nested task', async () => {
235+
await setTimeout(500);
236+
});
237+
});
238+
239+
clearInterval(interval);
240+
taskApi.clear();
241+
242+
// No console output after clear - program exits
243+
// Without fix: tasks remain visible at end of output
244+
`,
245+
}, { tempDir });
246+
247+
const result = await node(fixture.getPath('test.mjs'));
248+
249+
// Check that ANSI clear codes are present
250+
const hasMoveCursor = result.output.includes('\u001B[1A');
251+
const hasClearLine = result.output.includes('\u001B[2K');
252+
expect(hasMoveCursor).toBe(true);
253+
expect(hasClearLine).toBe(true);
254+
255+
// Console output should have happened during execution
256+
const textOutput = stripVTControlCharacters(result.output);
257+
expect(textOutput.includes('0')).toBe(true);
258+
});
220259
});
221260
});
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import { stripVTControlCharacters } from 'node:util';
2+
import { testSuite, expect } from 'manten';
3+
import { createFixture } from 'fs-fixture';
4+
import { node } from '../utils/node.js';
5+
import { tempDir } from '../utils/temp-dir.js';
6+
7+
export default testSuite(({ describe }) => {
8+
describe('color environment variables', ({ test }) => {
9+
test('NO_COLOR disables colors', async () => {
10+
await using fixture = await createFixture({
11+
'test.mjs': `
12+
import task from '#tasuku';
13+
import { setTimeout } from 'node:timers/promises';
14+
15+
await task('Success task', async () => {
16+
await setTimeout(50);
17+
});
18+
`,
19+
}, { tempDir });
20+
21+
const result = await node(fixture.getPath('test.mjs'), {
22+
NO_COLOR: '1',
23+
});
24+
25+
const textOutput = stripVTControlCharacters(result.output);
26+
27+
// Should contain the checkmark but without color codes
28+
expect(textOutput.includes('✔')).toBe(true);
29+
30+
// Should NOT contain color codes (green for checkmark)
31+
expect(result.output.includes('\u001B[32m')).toBe(false);
32+
});
33+
34+
test('NODE_DISABLE_COLORS disables colors', async () => {
35+
await using fixture = await createFixture({
36+
'test.mjs': `
37+
import task from '#tasuku';
38+
import { setTimeout } from 'node:timers/promises';
39+
40+
await task('Success task', async () => {
41+
await setTimeout(50);
42+
});
43+
`,
44+
}, { tempDir });
45+
46+
const result = await node(fixture.getPath('test.mjs'), {
47+
NODE_DISABLE_COLORS: '1',
48+
});
49+
50+
const textOutput = stripVTControlCharacters(result.output);
51+
52+
// Should contain the checkmark but without color codes
53+
expect(textOutput.includes('✔')).toBe(true);
54+
55+
// Should NOT contain color codes (green for checkmark)
56+
expect(result.output.includes('\u001B[32m')).toBe(false);
57+
});
58+
59+
test('FORCE_COLOR=0 disables colors', async () => {
60+
await using fixture = await createFixture({
61+
'test.mjs': `
62+
import task from '#tasuku';
63+
import { setTimeout } from 'node:timers/promises';
64+
65+
await task('Success task', async () => {
66+
await setTimeout(50);
67+
});
68+
`,
69+
}, { tempDir });
70+
71+
const result = await node(fixture.getPath('test.mjs'), {
72+
FORCE_COLOR: '0',
73+
});
74+
75+
const textOutput = stripVTControlCharacters(result.output);
76+
77+
// Should contain the checkmark but without color codes
78+
expect(textOutput.includes('✔')).toBe(true);
79+
80+
// Should NOT contain color codes (green for checkmark)
81+
expect(result.output.includes('\u001B[32m')).toBe(false);
82+
});
83+
84+
test('FORCE_COLOR=1 enables colors', async () => {
85+
await using fixture = await createFixture({
86+
'test.mjs': `
87+
import task from '#tasuku';
88+
import { setTimeout } from 'node:timers/promises';
89+
90+
await task('Success task', async () => {
91+
await setTimeout(50);
92+
});
93+
`,
94+
}, { tempDir });
95+
96+
const result = await node(fixture.getPath('test.mjs'), {
97+
FORCE_COLOR: '1',
98+
});
99+
100+
const textOutput = stripVTControlCharacters(result.output);
101+
102+
// Should contain the checkmark
103+
expect(textOutput.includes('✔')).toBe(true);
104+
105+
// Should contain color codes (green for checkmark: \u001B[32m)
106+
expect(result.output.includes('\u001B[32m')).toBe(true);
107+
});
108+
109+
test('colors work with error state', async () => {
110+
await using fixture = await createFixture({
111+
'test.mjs': `
112+
import task from '#tasuku';
113+
import { setTimeout } from 'node:timers/promises';
114+
115+
await task('Error task', async ({ setError }) => {
116+
await setTimeout(50);
117+
setError('Something failed');
118+
});
119+
`,
120+
}, { tempDir });
121+
122+
const result = await node(fixture.getPath('test.mjs'), {
123+
FORCE_COLOR: '1',
124+
});
125+
126+
const textOutput = stripVTControlCharacters(result.output);
127+
128+
// Should contain the error icon
129+
expect(textOutput.includes('✖')).toBe(true);
130+
});
131+
132+
test('NO_COLOR removes all colors including warning', async () => {
133+
await using fixture = await createFixture({
134+
'test.mjs': `
135+
import task from '#tasuku';
136+
import { setTimeout } from 'node:timers/promises';
137+
138+
await task('Warning task', async ({ setWarning }) => {
139+
await setTimeout(50);
140+
setWarning('A warning');
141+
});
142+
`,
143+
}, { tempDir });
144+
145+
const result = await node(fixture.getPath('test.mjs'), {
146+
NO_COLOR: '1',
147+
});
148+
149+
const textOutput = stripVTControlCharacters(result.output);
150+
151+
// Should contain the warning icon
152+
expect(textOutput.includes('⚠')).toBe(true);
153+
154+
// Should NOT contain yellow color code (\u001B[33m)
155+
expect(result.output.includes('\u001B[33m')).toBe(false);
156+
});
157+
158+
test('colors work with nested tasks', async () => {
159+
await using fixture = await createFixture({
160+
'test.mjs': `
161+
import task from '#tasuku';
162+
import { setTimeout } from 'node:timers/promises';
163+
164+
await task('Parent task', async ({ task }) => {
165+
await setTimeout(50);
166+
await task('Child task', async () => {
167+
await setTimeout(50);
168+
});
169+
});
170+
`,
171+
}, { tempDir });
172+
173+
const result = await node(fixture.getPath('test.mjs'), {
174+
FORCE_COLOR: '1',
175+
});
176+
177+
const textOutput = stripVTControlCharacters(result.output);
178+
179+
// Should contain both pointer and checkmark
180+
expect(textOutput.includes('❯')).toBe(true);
181+
expect(textOutput.includes('✔')).toBe(true);
182+
183+
// Should contain yellow color for pointer (\u001B[33m)
184+
expect(result.output.includes('\u001B[33m')).toBe(true);
185+
186+
// Should contain green color for checkmark (\u001B[32m)
187+
expect(result.output.includes('\u001B[32m')).toBe(true);
188+
});
189+
190+
test('NO_COLOR with nested tasks removes all colors', async () => {
191+
await using fixture = await createFixture({
192+
'test.mjs': `
193+
import task from '#tasuku';
194+
import { setTimeout } from 'node:timers/promises';
195+
196+
await task('Parent task', async ({ task }) => {
197+
await setTimeout(50);
198+
await task('Child task', async () => {
199+
await setTimeout(50);
200+
});
201+
});
202+
`,
203+
}, { tempDir });
204+
205+
const result = await node(fixture.getPath('test.mjs'), {
206+
NO_COLOR: '1',
207+
});
208+
209+
const textOutput = stripVTControlCharacters(result.output);
210+
211+
// Should contain both pointer and checkmark (text only)
212+
expect(textOutput.includes('❯')).toBe(true);
213+
expect(textOutput.includes('✔')).toBe(true);
214+
215+
// Should NOT contain any color codes
216+
expect(result.output.includes('\u001B[32m')).toBe(false); // green
217+
expect(result.output.includes('\u001B[33m')).toBe(false); // yellow
218+
expect(result.output.includes('\u001B[31m')).toBe(false); // red
219+
expect(result.output.includes('\u001B[36m')).toBe(false); // cyan
220+
});
221+
});
222+
});

tests/specs/renderer-console.spec.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import { stripVTControlCharacters } from 'node:util';
22
import { testSuite, expect } from 'manten';
33
import { createFixture } from 'fs-fixture';
44
import { node } from '../utils/node.js';
5-
6-
// Needs to be in project directory to resolve #tasuku via import maps
7-
const tempDir = new URL('../..', import.meta.url);
5+
import { tempDir } from '../utils/temp-dir.js';
86

97
export default testSuite(({ describe }) => {
108
describe('console interception', ({ test }) => {

0 commit comments

Comments
 (0)