cli icon indicating copy to clipboard operation
cli copied to clipboard

Custom matcher for ui logger

Open BioPhoton opened this issue 11 months ago • 2 comments

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 of removeColorCodes (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';

BioPhoton avatar Mar 08 '24 22:03 BioPhoton