javascriptstringjestjsmatcherhtml-escape-characters

Jest Equality Matcher For Strings That Disregards Whitespace


Jest's toEqual matcher takes whitespace into account when checking for equality. When formatting the expected value in tests it is impossible to do so in a way that matches a string containing newlines, tabs etc.

Does Jest offer a way to disregard whitespace when matching?


Solution

  • As @Timo says, the only way of doing this appears to be with a custom matcher. Here is one that compresses all whitespace down to a single space for readability based on Jest's toEqual matcher. It will deal with tabs, newlines etc. It will give you pretty output like the included Jest matchers:

    //matchStringIgnoringWhiteSpace.js
    
    import { replace, map, equals } from 'ramda';
    import { matcherHint, printReceived, printExpected } from 'jest-matcher-utils';
    import diff from 'jest-diff';
    
    const replaceWhitespace = replace(/\s+/g, ` `);
    const compressWhitespace = map(replaceWhitespace);
    
    const name = `toEqualWithCompressedWhitespace`;
    
    export default function (received, expected) {
      const [
        receivedWithCompresssedWhitespace,
        expectedWithCompresssedWhitespace,
      ] = compressWhitespace([received, expected]);
      const pass = equals(
        receivedWithCompresssedWhitespace,
        expectedWithCompresssedWhitespace
      );
      const message = pass
        ? () =>
            `${matcherHint(`.not.${name}`)}\n\n` +
            `Uncompressed expected value:\n` +
            `  ${printExpected(expected)}\n` +
            `Expected value with compressed whitespace to not equal:\n` +
            `  ${printExpected(expectedWithCompresssedWhitespace)}\n` +
            `Uncompressed received value:\n` +
            `  ${printReceived(received)}\n` +
            `Received value with compressed whitespace:\n` +
            `  ${printReceived(receivedWithCompresssedWhitespace)}`
        : () => {
            const diffString = diff(
              expectedWithCompresssedWhitespace,
              receivedWithCompresssedWhitespace,
              {
                expand: this.expand,
              }
            );
            return (
              `${matcherHint(`.${name}`)}\n\n` +
              `Uncompressed expected value:\n` +
              `  ${printExpected(expected)}\n` +
              `Expected value with compressed whitespace to equal:\n` +
              `  ${printExpected(expectedWithCompresssedWhitespace)}\n` +
              `Uncompressed received value:\n` +
              `  ${printReceived(received)}\n` +
              `Received value with compressed whitespace:\n` +
              `  ${printReceived(receivedWithCompresssedWhitespace)}${
                diffString ? `\n\nDifference:\n\n${diffString}` : ``
              }`
            );
          };
      return {
        actual: received,
        expected,
        message,
        name,
        pass,
      };
    };
    

    To register the custom matcher you need to add it to your setupTests files. First register setupTests in your jest.config.js using the setupFilesAfterEnv field:

     setupFilesAfterEnv: `<rootDir>/path/to/setupTests.js`,
    

    And then register the custom matcher on the expect object.

    //setupTests.js
    
    import toMatchStringIgnoringWhitespace from "<rootDir>/path/to/matchStringIgnoringWhiteSpace";
    
    expect.extend({
        toMatchStringIgnoringWhitespace: toMatchStringIgnoringWhitespace
    }); 
    
    

    If you are using TypeScript you will also want to add the typings to the expect object following the instructions here.