cli
cli copied to clipboard
Custom matcher for ui logger
User story
As a developer I want to have a good signal to noise ration and want to write my tests with as less boilerplate as possible. Therefor I need a custom matcher for the UI logger.
Bad example:
// ui().logger.error('Something went wrong');
expect(ui().logger.getRenderer().getLogs()).toStrictEqual([
{
stream: 'stderr',
message: '[ red(error) ] Something went wrong'
}
])
Suggested matcher:
-
expect(ui()).toHaveLogged('...')
-
expect(ui()).toHaveLoggedNth(1, '...')
-
expect(ui()).not.toHaveLogged())
Conversation: https://github.com/code-pushup/cli/pull/487#discussion_r1517516666
Good example:
// ui().logger.error('Something went wrong');
expect(ui()).toHaveLoggedLevelNth(1, 'error');
expect(ui()).toHaveLoggedMessageNth(1, 'Something went wrong');
Acceptance criteria
I want to be able to use the custom matcher in the following libs:
- [ ] vitest
- jest (optional)
Internal logic:
- [ ] it handles removes ASCII color
expect(msg.replace(/\u001B\[\d+m/g, '')).toBe("[ blue(info) ] This is is blue in terminal")
- custom matcher
toMatchPlainCharacter
instead ofremoveColorCodes
(optional) I want to be able to have different matcher present: - [ ]
toHaveLoggedLevel('...')
- [ ]
toHaveLoggedLevelNth(1, '...')
- [ ]
toHaveLoggedMessage('...')
- [ ]
toHaveLoggedMessageNth(1, '...')
Implementation details
import { expect } from 'vitest';
import {cliui} from "@poppinss/cliui";
declare module 'vitest' {
export interface Assert {
toHaveLoggedMessage(expected: string): void;
toHaveLoggedMessageNth(nth: number, expected: string): void;
}
}
export type CliUi = ReturnType<typeof cliui>;
// Implementation of toHaveLogged
expect.extend({
toHaveLoggedMessage(received: CliUi, expected: string) {
const logs = received.logger.getRenderer().getLogs();
const pass = logs.some(log => log.message === expected);
return {
pass,
message: () => pass
? `expected not to have logged: ${expected}`
: `expected to have logged: ${expected}`,
};
},
toHaveLoggedMessageNth(received: CliUi, nth: number, expected: string) {
const logs = received.logger.getRenderer().getLogs();
const pass = (logs[nth - 1]?.message === expected) ?? false;
return {
pass,
message: () => pass
? `expected not to have logged at position ${nth}: ${expected}`
: `expected to have logged at position ${nth}: ${expected}`,
};
},
});
Usage in global-setup.ts
import './testing/test-utils/src/lib/matcher/ui-logger';