-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlogger.spec.ts
131 lines (118 loc) · 4.4 KB
/
logger.spec.ts
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
120
121
122
123
124
125
126
127
128
129
130
131
import { expect } from 'chai';
import { declareInjectToken, InjectConfig, Logger, TypeInjector } from './index';
/**
* Logger and its replacement.
*
* This small interface is used to send log messages from the Injector.
* The implementation can get replaced like every other injected value.
* You might replace it to:
* - get a more verbose logging
* - connect it to a central logging system instead of using console
* - to prevent all (even error) log outputs
*/
describe('logger', () => {
describe('default implementation', () => {
const calls = spyOnConsole();
const givenErrorMessage = 'test error message';
/**
* In its default configuration, the logger will only log errors to the console (stderr)
*/
it('should log errors to console', () => {
const injector = new TypeInjector();
const logger = injector.get(Logger);
logger.error(givenErrorMessage);
expect(calls.console.error[0][0]).to.equal(givenErrorMessage);
});
it('will not log warnings nor info', () => {
const injector = new TypeInjector();
const logger = injector.get(Logger);
logger.warn?.(givenErrorMessage);
logger.info?.(givenErrorMessage);
expect(calls.console.warn.length).to.equal(0);
expect(calls.console.log.length).to.equal(0);
});
});
describe('custom implementation', () => {
it('should be configurable to log info to any target', () => {
const infoMsgs = [] as string[];
class VerboseLogger extends Logger {
info = (message: string, ..._details: any[]) => infoMsgs.push(message);
}
const injectToken = { baseUrl: declareInjectToken('base url') };
const injector = TypeInjector.construct()
.provideImplementation(Logger, VerboseLogger)
.provideFactory(injectToken.baseUrl, { deps: [], create: () => 'https://base.url/' })
.build()
;
injector.get(injectToken.baseUrl);
// console.log(JSON.stringify(infoMsgs));
expect(infoMsgs[0]).to.equal('finished creation of Logger');
expect(infoMsgs[1]).to.match(/^top level injector starts creation of \n -> TypeInjectorToken: base url/);
expect(infoMsgs[2]).to.equal('finished creation of TypeInjectorToken: base url');
});
});
/**
* Injector tries to use a provided Logger to log error messages.
* Unfortunately it might cause a dependency error to inject the
* Logger to log the error... ∞-Loop.
* So it won't log info messages or warnings before the logger
* is created successfully. Errors that occur during the instantiation of the logger will get
* logged to console (stderr)
*/
it('should show cyclic errors during the creation of Logger (at least on console)', () => {
class HttpService {
static injectConfig: InjectConfig = { deps: [HttpService] };
constructor( public self: HttpService ) {}
}
class BuggyLogger extends Logger {
static injectConfig: InjectConfig = { deps: [HttpService] };
constructor( public httpService: HttpService ) { super(); }
}
class BusinessService {
static injectConfig: InjectConfig = { deps: [Logger] };
constructor( public logger: Logger ) {}
}
const injector = TypeInjector.construct()
.provideImplementation(Logger, BuggyLogger)
.build()
;
const origError = console.error;
let msg: string | false = false;
console.error = (error) => msg = String(error);
try {
injector.get(BusinessService);
expect.fail('no error thrown');
} catch (e) {
expect((e as { message: string }).message).to.include('dependency cycle detected');
expect(msg).to.include('dependency cycle detected');
} finally {
console.error = origError;
}
});
});
function spyOnConsole() {
const calls = {
console: {
log: [] as Parameters<(typeof console)['log']>[],
warn: [] as Parameters<(typeof console)['warn']>[],
error: [] as Parameters<(typeof console)['error']>[],
}
};
const orig = {
console: {
log: console.log,
warn: console.warn,
error: console.error,
}
};
beforeEach(() => {
calls.console = { log: [], warn: [], error: [] };
console.log = (...args) => calls.console.log.push(args);
console.warn = (...args) => calls.console.warn.push(args);
console.error = (...args) => calls.console.error.push(args);
});
afterEach(() => {
Object.assign(console, orig.console);
});
return calls;
}