Skip to content

Commit ee0d41f

Browse files
author
Luca Forstner
committed
test(integrations): Add unit tests for caputureconsole
1 parent 4eadcaf commit ee0d41f

File tree

1 file changed

+288
-0
lines changed

1 file changed

+288
-0
lines changed
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
import { Event, Integration } from '@sentry/types';
2+
import { CaptureConsole } from '../src/captureconsole';
3+
4+
const mockScope = {
5+
setLevel: jest.fn(),
6+
setExtra: jest.fn(),
7+
addEventProcessor: jest.fn(),
8+
};
9+
10+
const mockHub = {
11+
withScope: jest.fn(callback => {
12+
callback(mockScope);
13+
}),
14+
captureMessage: jest.fn(),
15+
captureException: jest.fn(),
16+
};
17+
18+
const getMockHubWithIntegration = (integration: Integration) => ({
19+
...mockHub,
20+
getIntegration: jest.fn(() => integration),
21+
});
22+
23+
// We're using this to un-monkey patch the console after each test.
24+
const originalConsole = Object.assign({}, global.console);
25+
26+
describe('CaptureConsole setup', () => {
27+
afterEach(() => {
28+
jest.clearAllMocks();
29+
30+
// Un-monkey-patch the console functions
31+
Object.assign(global.console, originalConsole);
32+
});
33+
34+
it('should respect user-provided console levels', () => {
35+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'warn'] });
36+
captureConsoleIntegration.setupOnce(
37+
() => undefined,
38+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
39+
);
40+
41+
expect(global.console.error).toBe(originalConsole.error); // not monkey patched
42+
expect(global.console.log).not.toBe(originalConsole.log); // monkey patched
43+
expect(global.console.warn).not.toBe(originalConsole.warn); // monkey patched
44+
});
45+
46+
it('should fall back to default console levels if none are provided', () => {
47+
const captureConsoleIntegration = new CaptureConsole();
48+
captureConsoleIntegration.setupOnce(
49+
() => undefined,
50+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
51+
);
52+
53+
// expect a set of defined console levels to have been monkey patched
54+
expect(global.console.debug).not.toBe(originalConsole.debug);
55+
expect(global.console.info).not.toBe(originalConsole.info);
56+
expect(global.console.warn).not.toBe(originalConsole.warn);
57+
expect(global.console.error).not.toBe(originalConsole.error);
58+
expect(global.console.log).not.toBe(originalConsole.log);
59+
expect(global.console.assert).not.toBe(originalConsole.assert);
60+
61+
// any other fields should not have been patched
62+
expect(global.console.trace).toBe(originalConsole.trace);
63+
expect(global.console.table).toBe(originalConsole.table);
64+
});
65+
66+
it('setup should fail gracefully when console is not available', () => {
67+
const consoleRef = global.console;
68+
// remove console
69+
delete global.console;
70+
71+
expect(() => {
72+
const captureConsoleIntegration = new CaptureConsole();
73+
captureConsoleIntegration.setupOnce(
74+
() => undefined,
75+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
76+
);
77+
}).not.toThrow();
78+
79+
// reinstate initial console
80+
global.console = consoleRef;
81+
});
82+
83+
it('should set a level in the scope when console function is called', () => {
84+
const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] });
85+
captureConsoleIntegration.setupOnce(
86+
() => undefined,
87+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
88+
);
89+
90+
// call a wrapped function
91+
global.console.error('some logging message');
92+
93+
expect(mockScope.setLevel).toHaveBeenCalledTimes(1);
94+
expect(mockScope.setLevel).toHaveBeenCalledWith('error');
95+
});
96+
97+
it('should send arguments as extra data on failed assertion', () => {
98+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] });
99+
captureConsoleIntegration.setupOnce(
100+
() => undefined,
101+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
102+
);
103+
104+
// call a wrapped function
105+
global.console.log('some arg 1', 'some arg 2');
106+
global.console.log();
107+
108+
expect(mockScope.setExtra).toHaveBeenCalledTimes(2);
109+
expect(mockScope.setExtra).toHaveBeenCalledWith('arguments', ['some arg 1', 'some arg 2']);
110+
expect(mockScope.setExtra).toHaveBeenCalledWith('arguments', []);
111+
});
112+
113+
it('should add an event processor that sets the `logger` field of events', () => {
114+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] });
115+
captureConsoleIntegration.setupOnce(
116+
() => undefined,
117+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
118+
);
119+
120+
// call a wrapped function
121+
global.console.log('some message');
122+
123+
expect(mockScope.addEventProcessor).toHaveBeenCalledTimes(1);
124+
125+
const addedEventProcessor = mockScope.addEventProcessor.mock.calls[0][0];
126+
const someEvent: Event = {};
127+
addedEventProcessor(someEvent);
128+
129+
expect(someEvent.logger).toBe('console');
130+
});
131+
132+
it('should capture message on a failed assertion', () => {
133+
const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] });
134+
captureConsoleIntegration.setupOnce(
135+
() => undefined,
136+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
137+
);
138+
139+
global.console.assert(1 + 1 === 3);
140+
141+
expect(mockScope.setExtra).toHaveBeenLastCalledWith('arguments', []);
142+
expect(mockHub.captureMessage).toHaveBeenCalledWith('Assertion failed: console.assert');
143+
});
144+
145+
it('should capture correct message on a failed assertion with message', () => {
146+
const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] });
147+
captureConsoleIntegration.setupOnce(
148+
() => undefined,
149+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
150+
);
151+
152+
global.console.assert(1 + 1 === 3, 'expression is false');
153+
154+
expect(mockScope.setExtra).toHaveBeenLastCalledWith('arguments', ['expression is false']);
155+
expect(mockHub.captureMessage).toHaveBeenCalledWith('Assertion failed: expression is false');
156+
});
157+
158+
it('should not capture message on a successful assertion', () => {
159+
const captureConsoleIntegration = new CaptureConsole({ levels: ['assert'] });
160+
captureConsoleIntegration.setupOnce(
161+
() => undefined,
162+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
163+
);
164+
165+
global.console.assert(1 + 1 === 2);
166+
});
167+
168+
it('should capture exception when console logs an error object with level set to "error"', () => {
169+
const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] });
170+
captureConsoleIntegration.setupOnce(
171+
() => undefined,
172+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
173+
);
174+
175+
const someError = new Error('some error');
176+
global.console.error(someError);
177+
178+
expect(mockHub.captureException).toHaveBeenCalledWith(someError);
179+
});
180+
181+
it('should capture message when console logs a non-error object with level set to "error"', () => {
182+
const captureConsoleIntegration = new CaptureConsole({ levels: ['error'] });
183+
captureConsoleIntegration.setupOnce(
184+
() => undefined,
185+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
186+
);
187+
188+
global.console.error('some non-error message');
189+
190+
expect(mockHub.captureMessage).toHaveBeenCalledWith('some non-error message');
191+
expect(mockHub.captureException).not.toHaveBeenCalled();
192+
});
193+
194+
it('should capture a message for non-error log levels', () => {
195+
const captureConsoleIntegration = new CaptureConsole({ levels: ['info'] });
196+
captureConsoleIntegration.setupOnce(
197+
() => undefined,
198+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
199+
);
200+
201+
global.console.info('some message');
202+
203+
expect(mockHub.captureMessage).toHaveBeenCalledWith('some message');
204+
});
205+
206+
it('should call the original console function when console members are called', () => {
207+
// Mock console log to test if it was called
208+
const originalConsoleLog = global.console.log;
209+
const mockConsoleLog = jest.fn();
210+
global.console.log = mockConsoleLog;
211+
212+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] });
213+
captureConsoleIntegration.setupOnce(
214+
() => undefined,
215+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
216+
);
217+
218+
global.console.log('some message 1', 'some message 2');
219+
220+
expect(mockConsoleLog).toHaveBeenCalledWith('some message 1', 'some message 2');
221+
222+
// Reset console log
223+
global.console.log = originalConsoleLog;
224+
});
225+
226+
it('should not wrap any levels that are not members of console', () => {
227+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'someNonExistingLevel', 'error'] });
228+
captureConsoleIntegration.setupOnce(
229+
() => undefined,
230+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
231+
);
232+
233+
// The provided level should not be created
234+
expect(global.console['someNonExistingLevel']).toBeUndefined();
235+
236+
// Ohter levels should be wrapped as expected
237+
expect(global.console.log).not.toBe(originalConsole.log);
238+
expect(global.console.error).not.toBe(originalConsole.error);
239+
});
240+
241+
it('should not wrap any levels that are not members of console', () => {
242+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'someNonExistingLevel', 'error'] });
243+
captureConsoleIntegration.setupOnce(
244+
() => undefined,
245+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
246+
);
247+
248+
// The provided level should not be created
249+
expect(global.console['someNonExistingLevel']).toBeUndefined();
250+
251+
// Ohter levels should be wrapped as expected
252+
expect(global.console.log).not.toBe(originalConsole.log);
253+
expect(global.console.error).not.toBe(originalConsole.error);
254+
});
255+
256+
it('should wrap the console when the client does not have a registered captureconsole integration, but not capture any messages', () => {
257+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log', 'error'] });
258+
captureConsoleIntegration.setupOnce(
259+
() => undefined,
260+
() => getMockHubWithIntegration(null) as any, // simulate not having the integration registered
261+
);
262+
263+
// Console should be wrapped
264+
expect(global.console.log).not.toBe(originalConsole.log);
265+
expect(global.console.error).not.toBe(originalConsole.error);
266+
267+
// Should not capture messages
268+
global.console.log('some message');
269+
expect(mockHub.captureMessage).not.toHaveBeenCalledWith();
270+
});
271+
272+
it("should not crash when the original console methods don't exist at time of invocation", () => {
273+
const originalConsoleLog = global.console.log;
274+
global.console.log = undefined; // don't `delete` here, otherwise `fill` won't wrap the function
275+
276+
const captureConsoleIntegration = new CaptureConsole({ levels: ['log'] });
277+
captureConsoleIntegration.setupOnce(
278+
() => undefined,
279+
() => getMockHubWithIntegration(captureConsoleIntegration) as any,
280+
);
281+
282+
expect(() => {
283+
global.console.log('some message');
284+
}).not.toThrow();
285+
286+
global.console.log = originalConsoleLog;
287+
});
288+
});

0 commit comments

Comments
 (0)