Skip to content

Commit 626de83

Browse files
authored
feat: Console output test util (#1370)
Console output test util resolves #1369
1 parent bcce269 commit 626de83

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

packages/utils/src/TestUtils.test.tsx

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { render, screen } from '@testing-library/react';
33
import userEvent from '@testing-library/user-event';
44

5-
import TestUtils from './TestUtils';
5+
import TestUtils, { ConsoleMethodName } from './TestUtils';
66
import createMockProxy from './MockProxy';
77

88
beforeEach(() => {
@@ -19,6 +19,42 @@ describe('asMock', () => {
1919
expect(someFunc('a,b,c')).toEqual(3);
2020
});
2121

22+
/* eslint-disable no-console */
23+
describe('disableConsoleOutput', () => {
24+
const arg0 = 'mock arg';
25+
const allMethodNames = Object.getOwnPropertyNames(console).filter(
26+
(name): name is ConsoleMethodName =>
27+
typeof console[name as keyof Console] === 'function'
28+
);
29+
30+
it('should disable all methods if given no method names', () => {
31+
TestUtils.disableConsoleOutput();
32+
33+
allMethodNames.forEach(methodName => {
34+
console[methodName]();
35+
36+
expect(console[methodName]).toHaveBeenCalled();
37+
});
38+
});
39+
40+
it.each([
41+
[['log']],
42+
[['warn']],
43+
[['error']],
44+
[['info']],
45+
[['debug']],
46+
[allMethodNames],
47+
] as const)('should mock console method implementations: %s', methodNames => {
48+
TestUtils.disableConsoleOutput(...methodNames);
49+
50+
methodNames.forEach(methodName => {
51+
console[methodName](arg0);
52+
expect(console[methodName]).toHaveBeenCalledWith(arg0);
53+
});
54+
});
55+
});
56+
/* eslint-enable no-console */
57+
2258
describe('findLastCall', () => {
2359
it('should return undefined if call not matched', () => {
2460
const fn = jest.fn<void, [string, number]>();

packages/utils/src/TestUtils.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ export interface ClickOptions {
3131
rightClick?: boolean;
3232
}
3333

34+
/**
35+
* Filters a type down to only method properties.
36+
*/
37+
export type PickMethods<T> = {
38+
[K in keyof T as T[K] extends (...args: unknown[]) => unknown
39+
? K
40+
: never]: T[K];
41+
};
42+
43+
export type ConsoleMethodName = keyof PickMethods<Console>;
44+
3445
class TestUtils {
3546
/**
3647
* Type assertion to "cast" a function to it's corresponding jest.Mock
@@ -52,6 +63,27 @@ class TestUtils {
5263
fn: (...args: TArgs) => TResult
5364
): jest.Mock<TResult, TArgs> => (fn as unknown) as jest.Mock<TResult, TArgs>;
5465

66+
/**
67+
* Selectively disable logging methods on `console` object. Uses spyOn so that
68+
* changes will be reverted after leaving the test scope that it is set in. If
69+
* no method names are given, all will be disabled.
70+
* @param methodNames The console methods to disable.
71+
*/
72+
static disableConsoleOutput = (...methodNames: ConsoleMethodName[]): void => {
73+
if (methodNames.length === 0) {
74+
// eslint-disable-next-line no-param-reassign
75+
methodNames = Object.getOwnPropertyNames(console).filter(
76+
(name): name is ConsoleMethodName =>
77+
// eslint-disable-next-line no-console
78+
typeof console[name as keyof Console] === 'function'
79+
);
80+
}
81+
82+
methodNames.forEach(methodName => {
83+
jest.spyOn(console, methodName).mockImplementation();
84+
});
85+
};
86+
5587
/**
5688
* Find the last mock function call matching a given predicate.
5789
* @param fn jest.Mock function

0 commit comments

Comments
 (0)