Skip to content

Commit 9ab350e

Browse files
committed
test(integrations): Add unit tests for caputureconsole
1 parent 4eadcaf commit 9ab350e

File tree

1 file changed

+289
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)