Skip to content

Commit f8bd679

Browse files
test: fix CI failures after async writeProfile merge
- await writeProfile in config and doctor unit tests - pass noColor=false in ticker TTY tests (CI sets NO_COLOR=1) Closes #77
1 parent 18ecebf commit f8bd679

3 files changed

Lines changed: 32 additions & 59 deletions

File tree

src/commands/doctor.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ beforeEach(() => {
6464

6565
describe('runDoctor — healthy environment', () => {
6666
it('returns an all-passing report and does not throw', async () => {
67-
writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
67+
await writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
6868
const { capture, deps } = makeCapture();
6969
const report = await runDoctor(
7070
{ profile: 'default', output: 'text', debug: false },
@@ -79,7 +79,7 @@ describe('runDoctor — healthy environment', () => {
7979
});
8080

8181
it('never prints the API key anywhere in the report', async () => {
82-
writeProfile('default', { apiKey: 'sk-super-secret-value' }, { path: credentialsPath });
82+
await writeProfile('default', { apiKey: 'sk-super-secret-value' }, { path: credentialsPath });
8383
const { capture, deps } = makeCapture();
8484
await runDoctor(
8585
{ profile: 'default', output: 'text', debug: false },
@@ -90,7 +90,7 @@ describe('runDoctor — healthy environment', () => {
9090
});
9191

9292
it('emits a machine-readable report under --output json without leaking the API key', async () => {
93-
writeProfile('default', { apiKey: 'sk-json-secret-value' }, { path: credentialsPath });
93+
await writeProfile('default', { apiKey: 'sk-json-secret-value' }, { path: credentialsPath });
9494
const { capture, deps } = makeCapture();
9595
await runDoctor(
9696
{ profile: 'default', output: 'json', debug: false },
@@ -124,7 +124,7 @@ describe('runDoctor — failing checks exit non-zero', () => {
124124
});
125125

126126
it('invalid endpoint URL fails the API endpoint check', async () => {
127-
writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
127+
await writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
128128
const { capture, deps } = makeCapture();
129129
const rejection = await runDoctor(
130130
{ profile: 'default', output: 'text', debug: false, endpointUrl: 'not-a-url' },
@@ -137,7 +137,7 @@ describe('runDoctor — failing checks exit non-zero', () => {
137137
});
138138

139139
it('rejected API key surfaces as a Connectivity failure', async () => {
140-
writeProfile('default', { apiKey: 'sk-bad' }, { path: credentialsPath });
140+
await writeProfile('default', { apiKey: 'sk-bad' }, { path: credentialsPath });
141141
const { capture, deps } = makeCapture();
142142
const authError = {
143143
error: { code: 'AUTH_INVALID', message: 'Bad key.', requestId: 'req_x', details: {} },
@@ -153,7 +153,7 @@ describe('runDoctor — failing checks exit non-zero', () => {
153153
});
154154

155155
it('a non-auth /me error is reported as a Connectivity failure with its code', async () => {
156-
writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
156+
await writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
157157
const { capture, deps } = makeCapture();
158158
const notFound = {
159159
error: { code: 'NOT_FOUND', message: 'nope', requestId: 'req_y', details: {} },
@@ -167,7 +167,7 @@ describe('runDoctor — failing checks exit non-zero', () => {
167167
});
168168

169169
it('an outdated Node runtime fails the Node.js check', async () => {
170-
writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
170+
await writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
171171
const { capture, deps } = makeCapture();
172172
const rejection = await runDoctor(
173173
{ profile: 'default', output: 'text', debug: false },
@@ -182,7 +182,7 @@ describe('runDoctor — failing checks exit non-zero', () => {
182182

183183
describe('runDoctor — warnings do not fail', () => {
184184
it('missing verify skill is a warning, not a failure', async () => {
185-
writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
185+
await writeProfile('default', { apiKey: 'sk-abc' }, { path: credentialsPath });
186186
const { capture, deps } = makeCapture();
187187
const report = await runDoctor(
188188
{ profile: 'default', output: 'text', debug: false },

src/lib/config.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ describe('loadConfig', () => {
8686
expect(config.apiKey).toBe('sk-dev');
8787
});
8888

89-
it('treats empty / whitespace TESTSPRITE_API_URL as unset (falls through to profile)', () => {
90-
writeProfile(
89+
it('treats empty / whitespace TESTSPRITE_API_URL as unset (falls through to profile)', async () => {
90+
await writeProfile(
9191
'default',
9292
{ apiKey: 'sk-file', apiUrl: 'https://api.example.com:8443' },
9393
{ path: credentialsPath },
@@ -99,8 +99,8 @@ describe('loadConfig', () => {
9999
expect(config.apiUrl).toBe('https://api.example.com:8443');
100100
});
101101

102-
it('treats empty / whitespace TESTSPRITE_API_KEY as unset (falls through to profile)', () => {
103-
writeProfile('default', { apiKey: 'sk-file' }, { path: credentialsPath });
102+
it('treats empty / whitespace TESTSPRITE_API_KEY as unset (falls through to profile)', async () => {
103+
await writeProfile('default', { apiKey: 'sk-file' }, { path: credentialsPath });
104104
const config = loadConfig({
105105
env: { TESTSPRITE_API_KEY: '' },
106106
credentialsPath,

src/lib/ticker.spec.ts

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@
33
*/
44

55
import { describe, expect, it, vi } from 'vitest';
6-
import { createTicker, isNoColor } from './ticker.js';
6+
import { createTicker, isNoColor, type Ticker } from './ticker.js';
7+
8+
/** TTY tests that expect ANSI in-place updates. CI sets NO_COLOR=1, so opt out explicitly. */
9+
function createTtyTicker(
10+
stderrWrite: (line: string) => void = () => {},
11+
stderrRaw?: (text: string) => void,
12+
): Ticker {
13+
return createTicker(stderrWrite, true, stderrRaw, false);
14+
}
715

816
describe('createTicker — non-TTY (CI mode)', () => {
917
it('update is a no-op (no writes)', () => {
@@ -58,11 +66,7 @@ function stripTickerTimestamp(raw: string): string {
5866
describe('createTicker — TTY mode', () => {
5967
it('update writes ANSI clear-line + carriage-return + content via rawWrite', () => {
6068
const raw: string[] = [];
61-
const ticker = createTicker(
62-
() => {},
63-
true, // isTTY = true
64-
text => raw.push(text),
65-
);
69+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
6670
ticker.update('Run run_abc — running (3/8 steps elapsed=12s)');
6771
expect(raw).toHaveLength(1);
6872
expect(stripTickerTimestamp(raw[0]!)).toBe(
@@ -72,11 +76,7 @@ describe('createTicker — TTY mode', () => {
7276

7377
it('update rewrites the line on each call (in-place update)', () => {
7478
const raw: string[] = [];
75-
const ticker = createTicker(
76-
() => {},
77-
true,
78-
text => raw.push(text),
79-
);
79+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
8080
ticker.update('first tick');
8181
ticker.update('second tick');
8282
ticker.update('third tick');
@@ -88,11 +88,7 @@ describe('createTicker — TTY mode', () => {
8888

8989
it('finalize with a final line emits the line then a newline', () => {
9090
const raw: string[] = [];
91-
const ticker = createTicker(
92-
() => {},
93-
true,
94-
text => raw.push(text),
95-
);
91+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
9692
ticker.update('working');
9793
ticker.finalize('done — passed');
9894
// Expect: clear+carriage-return+line, then \n
@@ -103,11 +99,7 @@ describe('createTicker — TTY mode', () => {
10399

104100
it('finalize without args emits just a newline when something was written', () => {
105101
const raw: string[] = [];
106-
const ticker = createTicker(
107-
() => {},
108-
true,
109-
text => raw.push(text),
110-
);
102+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
111103
ticker.update('progress');
112104
ticker.finalize();
113105
// Last call should be '\n' to flush the line
@@ -116,11 +108,7 @@ describe('createTicker — TTY mode', () => {
116108

117109
it('finalize without args emits nothing when nothing was written', () => {
118110
const raw: string[] = [];
119-
const ticker = createTicker(
120-
() => {},
121-
true,
122-
text => raw.push(text),
123-
);
111+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
124112
// No update calls
125113
ticker.finalize();
126114
// Nothing should have been written (lastLength is 0)
@@ -129,11 +117,7 @@ describe('createTicker — TTY mode', () => {
129117

130118
it('finalize without args but with prior update — emits newline only', () => {
131119
const raw: string[] = [];
132-
const ticker = createTicker(
133-
() => {},
134-
true,
135-
text => raw.push(text),
136-
);
120+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
137121
ticker.update('x');
138122
const lengthAfterUpdate = raw.length;
139123
ticker.finalize();
@@ -144,11 +128,7 @@ describe('createTicker — TTY mode', () => {
144128

145129
it('multiple finalize calls only move to fresh line once (idempotent-ish)', () => {
146130
const raw: string[] = [];
147-
const ticker = createTicker(
148-
() => {},
149-
true,
150-
text => raw.push(text),
151-
);
131+
const ticker = createTtyTicker(() => {}, text => raw.push(text));
152132
ticker.update('something');
153133
ticker.finalize();
154134
const lenAfterFirst = raw.length;
@@ -178,11 +158,7 @@ describe('createTicker — stderrWrite dependency injection', () => {
178158
it('does not call stderrWrite during update on TTY (rawWrite used instead)', () => {
179159
const stderrLines: string[] = [];
180160
const raw: string[] = [];
181-
const ticker = createTicker(
182-
line => stderrLines.push(line),
183-
true,
184-
text => raw.push(text),
185-
);
161+
const ticker = createTtyTicker(line => stderrLines.push(line), text => raw.push(text));
186162
ticker.update('progress');
187163
// stderrWrite should not be called (rawWrite handles TTY in-place updates)
188164
expect(stderrLines).toHaveLength(0);
@@ -192,11 +168,7 @@ describe('createTicker — stderrWrite dependency injection', () => {
192168
it('stderrWrite is referenced in finalize (no unused-var warning)', () => {
193169
// This is purely a compilation concern but we verify no throws.
194170
const stderrLines: string[] = [];
195-
const ticker = createTicker(
196-
line => stderrLines.push(line),
197-
true,
198-
() => {},
199-
);
171+
const ticker = createTtyTicker(line => stderrLines.push(line), () => {});
200172
expect(() => ticker.finalize('line')).not.toThrow();
201173
});
202174
});
@@ -209,7 +181,8 @@ describe('createTicker — spy on process.stderr', () => {
209181
const ticker = createTicker(
210182
() => {},
211183
true, // force TTY
212-
// No stderrRaw — should default to process.stderr.write
184+
undefined, // stderrRaw — should default to process.stderr.write
185+
false, // CI sets NO_COLOR=1; this test asserts ANSI rawWrite path
213186
);
214187
ticker.update('test line');
215188
// The ticker prepends an ISO timestamp; verify the call happened and

0 commit comments

Comments
 (0)