Skip to content

Instantly share code, notes, and snippets.

@zeusdeux
Last active May 24, 2023 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeusdeux/99e981c6f6a5d2457009a2c07ff534c1 to your computer and use it in GitHub Desktop.
Save zeusdeux/99e981c6f6a5d2457009a2c07ff534c1 to your computer and use it in GitHub Desktop.
Cleaner console for jest test runs + fail on certain console messages
/**
* Fail jest test run if certain messages are logged to console (e.g., `[vuex warn] unknown getter: ....`)
* Conditionally (on CI or not) add this file and the file below to `setupFilesAfterEnv` in jest config.
*
* Example config:
*
* import type { Config } from "@jest/types"
*
* const config: Config.InitialOptions = {
* ...
* setupFilesAfterEnv: [
* // fail on Vue and Vuex warnings on CI. Locally, provide full error messages
* // and don't fail for great DX in watch mode
* ...(process.env.CI
* ? [
* path.resolve(__dirname, "./fail-on-select-console-calls.ts"),
* path.resolve(__dirname, "./swallow-selected-jsdom-errors.ts"),
* ]
* : []),
* ]
* ...
* }
*
* export default config
*/
const CONSOLE_FAIL_TYPES = ["error", "warn"] as (keyof Pick<Console, "error" | "warn">)[];
const builtInConsole = {
log: console.log.bind(console),
warn: console.warn.bind(console),
error: console.error.bind(console),
};
function isFailureMessage(message: string): boolean {
const vuexWarning = /\[vuex\] unknown.+:/g;
const vueWarning = /\[Vue warn\]:/g;
const vueTestUtilsWarning = /deprecated on Vue Test Utils v1/g;
return (
vuexWarning.test(message) ||
vueWarning.test(message) ||
vueTestUtilsWarning.test(message)
);
}
// Fail tests that trigger calls to console.<method> matching some criteria
// so that you have clean unit testing logs
CONSOLE_FAIL_TYPES.forEach((type) => {
console[type] = (...args: any[]) => {
const [message] = args;
// Fail tests that log message which match some criteria
if (typeof message === "string" && isFailureMessage(message)) {
// show full error, warning, etc that caused the test failure
builtInConsole[type](...args);
throw new Error(message + `\nPlease run test locally for full error`);
}
};
});
// needed to enable the declare global augementation below
// which can only be done in es modules in TypeScript
export {};
declare global {
interface Window {
_virtualConsole: any;
}
}
/**
* This module swallows the following error from jsdom on CI:
*
* console.error
* Error: Not implemented: navigation (except hash changes)
*
* This error comes from jsdom which doesn't implement the full
* window.location object. Specifically, methods such as:
* - assign
* - reload
* etc
*
* To test window.location.assign/reload/etc calls, please
* mock them in your tests. Even upon mocking though, you'll
* see the "Not implemented" error locally hence the need for
* this error swallowing fix for cleaner logs on CI.
*/
// jsdom attaches a single listener to this event which prints to
// console. We will grab that, and if it exists, overwrite it
// with our own implementation that swallows the "Not implemented"
// error on CI.
const listeners = window._virtualConsole.listeners("jsdomError");
const originalListener = listeners && listeners[0];
if (originalListener) {
// remove default listener
window._virtualConsole.removeAllListeners("jsdomError");
// swallow errors stemming from usage of window.location.assign/reload, etc
// For the rest, call the original listener from jsdom
window._virtualConsole.addListener("jsdomError", (error: any) => {
if (
error.type === "not implemented" &&
error.message === "Not implemented: navigation (except hash changes)" &&
originalListener
) {
return;
}
originalListener(error);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment