Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf8b6dbb

Browse files
jaggederestclaude
andcommitted
test: add Logger factory and verify backward compatibility
- Add createMockOutputChannelWithLogger factory function for consistent test setup- Verify Logger class implements the Logger interface required by error.ts- Add tests confirming writeToCoderOutputChannel backward compatibility- Update existing tests to use the new factory function- Prepare for systematic replacement of writeToCoderOutputChannel calls🤖 Generated with [Claude Code](https://claude.ai/code)Co-Authored-By: Claude <noreply@anthropic.com>
1 parent6c947fe commitf8b6dbb

File tree

4 files changed

+175
-25
lines changed

4 files changed

+175
-25
lines changed

‎src/error.test.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
X509_ERR_CODE,
1010
getErrorDetail,
1111
}from"./error";
12+
import{createMockOutputChannelWithLogger}from"./test-helpers";
1213

1314
// Before each test we make a request to sanity check that we really get the
1415
// error we are expecting, then we run it through CertificateError.
@@ -58,6 +59,7 @@ vi.mock("coder/site/src/api/errors", () => ({
5859
}),
5960
}));
6061

62+
// Use a mock logger that throws on error messages to ensure tests fail if unexpected logs occur
6163
constlogger={
6264
writeToCoderOutputChannel(message:string){
6365
thrownewError(message);
@@ -387,6 +389,101 @@ describe("CertificateError.maybeWrap error handling", () => {
387389
});
388390
});
389391

392+
describe("CertificateError with real Logger",()=>{
393+
it("should be backward compatible with existing mock logger",()=>{
394+
// Verify our Logger class implements the Logger interface used by error.ts
395+
const{ mockOutputChannel,logger:realLogger}=
396+
createMockOutputChannelWithLogger();
397+
398+
// Verify the Logger has the required writeToCoderOutputChannel method
399+
expect(typeofrealLogger.writeToCoderOutputChannel).toBe("function");
400+
401+
// Verify it works like the mock logger
402+
realLogger.writeToCoderOutputChannel("Test message");
403+
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
404+
expect.stringMatching(/\[.*\]\[INFO\]Testmessage/),
405+
);
406+
});
407+
408+
it("should work with our Logger implementation",async()=>{
409+
// Create a real Logger instance with mock output channel
410+
const{ mockOutputChannel,logger:realLogger}=
411+
createMockOutputChannelWithLogger();
412+
413+
// Mock CertificateError.determineVerifyErrorCause to throw an error
414+
constoriginalDetermine=CertificateError.determineVerifyErrorCause;
415+
CertificateError.determineVerifyErrorCause=vi
416+
.fn()
417+
.mockRejectedValue(newError("Failed to parse certificate"));
418+
419+
constaxiosError={
420+
isAxiosError:true,
421+
code:X509_ERR_CODE.UNABLE_TO_VERIFY_LEAF_SIGNATURE,
422+
message:"unable to verify leaf signature",
423+
};
424+
425+
// Test that maybeWrap works with our real Logger
426+
constresult=awaitCertificateError.maybeWrap(
427+
axiosError,
428+
"https://test.com",
429+
realLogger,
430+
);
431+
432+
// Should return original error when determineVerifyErrorCause fails
433+
expect(result).toBe(axiosError);
434+
435+
// Verify the message was logged through our Logger
436+
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
437+
expect.stringMatching(
438+
/\[.*\]\[INFO\]Failedtoparsecertificatefromhttps:\/\/test.com/,
439+
),
440+
);
441+
442+
// Verify the log was stored in the Logger
443+
constlogs=realLogger.getLogs();
444+
expect(logs).toHaveLength(1);
445+
expect(logs[0].level).toBe("INFO");
446+
expect(logs[0].message).toContain(
447+
"Failed to parse certificate from https://test.com",
448+
);
449+
450+
// Restore original method
451+
CertificateError.determineVerifyErrorCause=originalDetermine;
452+
});
453+
454+
it("should log successful certificate wrapping with real Logger",async()=>{
455+
const{logger:realLogger}=createMockOutputChannelWithLogger();
456+
constaddress=awaitstartServer("chain");
457+
458+
constrequest=axios.get(address);
459+
awaitexpect(request).rejects.toHaveProperty(
460+
"code",
461+
X509_ERR_CODE.SELF_SIGNED_CERT_IN_CHAIN,
462+
);
463+
464+
try{
465+
awaitrequest;
466+
}catch(error){
467+
// Clear any existing logs
468+
realLogger.clear();
469+
470+
constwrapped=awaitCertificateError.maybeWrap(
471+
error,
472+
address,
473+
realLogger,
474+
);
475+
expect(wrappedinstanceofCertificateError).toBeTruthy();
476+
expect((wrappedasCertificateError).x509Err).toBe(
477+
X509_ERR.UNTRUSTED_CHAIN,
478+
);
479+
480+
// Since the certificate error was successfully wrapped, no error should be logged
481+
constlogs=realLogger.getLogs();
482+
expect(logs).toHaveLength(0);
483+
}
484+
});
485+
});
486+
390487
describe("CertificateError instance methods",()=>{
391488
it("should update configuration and show message when allowInsecure is called",async()=>{
392489
constvscode=awaitimport("vscode");

‎src/logger.test.ts

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import{describe,it,expect,beforeEach,vi}from"vitest";
22
import{Logger,LoggerService}from"./logger";
3+
import{createMockOutputChannelWithLogger}from"./test-helpers";
34

45
describe("Logger",()=>{
56
letlogger:Logger;
7+
letmockOutputChannel:{
8+
appendLine:ReturnType<typeofvi.fn>;
9+
};
610

711
beforeEach(()=>{
8-
logger=newLogger();
12+
mockOutputChannel={
13+
appendLine:vi.fn(),
14+
};
15+
logger=newLogger(mockOutputChannel);
916
});
1017

1118
it("should log error messages",()=>{
@@ -80,27 +87,52 @@ describe("Logger", () => {
8087

8188
describe("Logger with OutputChannel",()=>{
8289
it("should write logs to output channel when provided",()=>{
83-
constmockOutputChannel={
84-
appendLine:vi.fn(),
85-
};
86-
87-
constlogger=newLogger(mockOutputChannel);
90+
const{ mockOutputChannel, logger}=createMockOutputChannelWithLogger();
8891
logger.info("Test message");
8992

9093
expect(mockOutputChannel.appendLine).toHaveBeenCalledOnce();
9194
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
9295
expect.stringContaining("[INFO] Test message"),
9396
);
9497
});
98+
99+
it("should implement writeToCoderOutputChannel for backward compatibility",()=>{
100+
const{ mockOutputChannel, logger}=createMockOutputChannelWithLogger();
101+
102+
logger.writeToCoderOutputChannel("Test message");
103+
104+
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
105+
expect.stringMatching(/\[.*\]\[INFO\]Testmessage/),
106+
);
107+
});
108+
109+
it("should log writeToCoderOutputChannel messages as INFO level",()=>{
110+
constlogger=newLogger();
111+
112+
logger.writeToCoderOutputChannel("Backward compatible message");
113+
114+
constlogs=logger.getLogs();
115+
expect(logs).toHaveLength(1);
116+
expect(logs[0].level).toBe("INFO");
117+
expect(logs[0].message).toBe("Backward compatible message");
118+
});
119+
120+
it("should handle error-like messages appropriately",()=>{
121+
const{ mockOutputChannel, logger}=createMockOutputChannelWithLogger();
122+
123+
logger.writeToCoderOutputChannel("Error: Something went wrong");
124+
125+
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
126+
expect.stringMatching(/\[.*\]\[INFO\]Error:Somethingwentwrong/),
127+
);
128+
});
95129
});
96130

97131
describe("Logger with log level filtering",()=>{
98132
it("should filter debug logs when verbose is false",()=>{
99-
constmockOutputChannel={
100-
appendLine:vi.fn(),
101-
};
102-
103-
constlogger=newLogger(mockOutputChannel,{verbose:false});
133+
const{ mockOutputChannel, logger}=createMockOutputChannelWithLogger({
134+
verbose:false,
135+
});
104136
logger.debug("Debug message");
105137
logger.info("Info message");
106138
logger.warn("Warn message");
@@ -113,13 +145,10 @@ describe("Logger with log level filtering", () => {
113145
});
114146

115147
it("should include debug logs when verbose is true",()=>{
116-
constmockOutputChannel={
117-
appendLine:vi.fn(),
118-
};
119-
120-
constlogger=newLogger(mockOutputChannel,{verbose:true});
121-
logger.debug("Debug message");
122-
logger.info("Info message");
148+
const{ mockOutputChannel,logger:verboseLogger}=
149+
createMockOutputChannelWithLogger({verbose:true});
150+
verboseLogger.debug("Debug message");
151+
verboseLogger.info("Info message");
123152

124153
expect(mockOutputChannel.appendLine).toHaveBeenCalledTimes(2);
125154
expect(mockOutputChannel.appendLine).toHaveBeenCalledWith(
@@ -128,11 +157,7 @@ describe("Logger with log level filtering", () => {
128157
});
129158

130159
it("should include data in output when provided",()=>{
131-
constmockOutputChannel={
132-
appendLine:vi.fn(),
133-
};
134-
135-
constlogger=newLogger(mockOutputChannel);
160+
const{ mockOutputChannel, logger}=createMockOutputChannelWithLogger();
136161
constdata={userId:123,action:"login"};
137162
logger.info("User action",data);
138163

‎src/logger.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ export class Logger {
9898
this.outputChannel.appendLine(message);
9999
}
100100
}
101+
102+
/**
103+
* Backward compatibility method for existing code using writeToCoderOutputChannel
104+
* Logs messages at INFO level
105+
*/
106+
writeToCoderOutputChannel(message:string):void{
107+
this.info(message);
108+
}
101109
}
102110

103111
exportinterfaceWorkspaceConfiguration{

‎src/test-helpers.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
}from"coder/site/src/api/typesGenerated";
55
import{vi}from"vitest";
66
importtype*asvscodefrom"vscode";
7+
import{Logger}from"./logger";
78
importtype{Storage}from"./storage";
89

910
/**
@@ -164,6 +165,25 @@ export function createMockConfiguration(
164165
};
165166
}
166167

168+
/**
169+
* Create a mock output channel and Logger instance for testing
170+
* Returns both the mock output channel and a real Logger instance
171+
*/
172+
exportfunctioncreateMockOutputChannelWithLogger(options?:{
173+
verbose?:boolean;
174+
}):{
175+
mockOutputChannel:{
176+
appendLine:ReturnType<typeofvi.fn>;
177+
};
178+
logger:Logger;
179+
}{
180+
constmockOutputChannel={
181+
appendLine:vi.fn(),
182+
};
183+
constlogger=newLogger(mockOutputChannel,options);
184+
return{ mockOutputChannel, logger};
185+
}
186+
167187
/**
168188
* Create a partial mock Storage with only the methods needed
169189
*/
@@ -172,10 +192,10 @@ export function createMockStorage(
172192
getHeaders:ReturnType<typeofvi.fn>;
173193
writeToCoderOutputChannel:ReturnType<typeofvi.fn>;
174194
}>={},
175-
):Partial<Storage>{
195+
):Storage{
176196
return{
177197
getHeaders:overrides.getHeaders??vi.fn().mockResolvedValue({}),
178198
writeToCoderOutputChannel:overrides.writeToCoderOutputChannel??vi.fn(),
179199
...overrides,
180-
};
200+
}asunknownasStorage;
181201
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp