diff --git a/test/karma.tests.js b/test/karma.tests.js index 554e82aa9ea4cb..afd1e998df5f31 100644 --- a/test/karma.tests.js +++ b/test/karma.tests.js @@ -1,4 +1,32 @@ +/* eslint-env mocha */ import './utils/init'; +import { createMochaHooks } from './utils/mochaHooks'; + +const mochaHooks = createMochaHooks(window.Mocha); + +before(function beforeAllHook() { + mochaHooks.beforeAll.forEach((mochaHook) => { + mochaHook.call(this); + }); +}); + +after(function afterAllHook() { + mochaHooks.afterAll.forEach((mochaHook) => { + mochaHook.call(this); + }); +}); + +beforeEach(function beforeEachHook() { + mochaHooks.beforeEach.forEach((mochaHook) => { + mochaHook.call(this); + }); +}); + +afterEach(function afterEachHook() { + mochaHooks.afterEach.forEach((mochaHook) => { + mochaHook.call(this); + }); +}); const integrationContext = require.context( '../packages/material-ui/test/integration', diff --git a/test/utils/mochaHooks.js b/test/utils/mochaHooks.js new file mode 100644 index 00000000000000..590c8dad6d789a --- /dev/null +++ b/test/utils/mochaHooks.js @@ -0,0 +1,80 @@ +const formatUtil = require('format-util'); + +function createUnexpectedConsoleMessagesHooks(Mocha, methodName, expectedMatcher) { + const mochaHooks = { + beforeAll: [], + afterAll: [], + beforeEach: [], + afterEach: [], + }; + const unexpectedCalls = []; + const stackTraceFilter = Mocha.utils.stackTraceFilter(); + + function logUnexpectedConsoleCalls(format, ...args) { + const message = formatUtil(format, ...args); + // Safe stack so that test dev can track where the unexpected console message was created. + const { stack } = new Error(); + + unexpectedCalls.push([ + // first line includes the (empty) error message + // i.e. Remove the `Error:` line + // second line is this frame + stackTraceFilter(stack.split('\n').slice(2).join('\n')), + message, + ]); + } + + mochaHooks.beforeAll.push(function registerConsoleStub() { + // eslint-disable-next-line no-console + console[methodName] = logUnexpectedConsoleCalls; + }); + + mochaHooks.afterEach.push(function flushUnexpectedCalls() { + const hadUnexpectedCalls = unexpectedCalls.length > 0; + const formattedCalls = unexpectedCalls.map(([stack, message]) => `${message}\n${stack}`); + unexpectedCalls.length = 0; + + // eslint-disable-next-line no-console + if (console[methodName] !== logUnexpectedConsoleCalls) { + throw new Error(`Did not tear down spy or stub of console.${methodName} in your test.`); + } + if (hadUnexpectedCalls) { + // In karma `file` is `null`. + // We still have the stacktrace though + const location = this.currentTest.file ?? '(unknown file)'; + const testPath = `"${this.currentTest.parent + .titlePath() + .concat(this.currentTest.title) + .join('" -> "')}"`; + const message = + `Expected test not to call console.${methodName}()\n\n` + + 'If the warning is expected, test for it explicitly by ' + + `using the ${expectedMatcher}() matcher.`; + + const error = new Error( + `${location}: ${message}\n\n${formattedCalls.join('\n\n')}\n\n` + + `in ${testPath} (${location})`, + ); + // The stack of `flushUnexpectedCalls` is irrelevant. + // It includes no clue where the test was triggered + error.stack = ''; + throw error; + } + }); + + return mochaHooks; +} + +function createMochaHooks(Mocha) { + const warnHooks = createUnexpectedConsoleMessagesHooks(Mocha, 'warn', 'toWarnDev'); + const errorHooks = createUnexpectedConsoleMessagesHooks(Mocha, 'error', 'toErrorDev'); + + return { + beforeAll: [...warnHooks.beforeAll, ...errorHooks.beforeAll], + afterAll: [...warnHooks.afterAll, ...errorHooks.afterAll], + beforeEach: [...warnHooks.beforeEach, ...errorHooks.beforeEach], + afterEach: [...warnHooks.afterEach, ...errorHooks.afterEach], + }; +} + +module.exports = { createMochaHooks }; diff --git a/test/utils/setupJSDOM.js b/test/utils/setupJSDOM.js index 3dec8168b0f094..e15c50fec52a25 100644 --- a/test/utils/setupJSDOM.js +++ b/test/utils/setupJSDOM.js @@ -1,7 +1,7 @@ -const formatUtil = require('format-util'); -const Mocha = require('mocha'); const testingLibrary = require('@testing-library/dom'); +const Mocha = require('mocha'); const createDOM = require('./createDOM'); +const { createMochaHooks } = require('./mochaHooks'); // Enable missing act warnings: https://github.com/facebook/react/blob/v16.13.1/packages/react-reconciler/src/ReactFiberHooks.js#L965 // TODO: Revisit once https://github.com/facebook/react/issues/15439 is resolved. @@ -15,68 +15,6 @@ testingLibrary.configure({ computedStyleSupportsPseudoElements: false, }); -const mochaHooks = { - beforeAll: [], - beforeEach: [], - afterEach: [], -}; - -function throwOnUnexpectedConsoleMessages(methodName, expectedMatcher) { - const unexpectedCalls = []; - const stackTraceFilter = Mocha.utils.stackTraceFilter(); - - function logUnexpectedConsoleCalls(format, ...args) { - const message = formatUtil(format, ...args); - // Safe stack so that test dev can track where the unexpected console message was created. - const { stack } = new Error(); - - unexpectedCalls.push([ - // first line includes the (empty) error message - // i.e. Remove the `Error:` line - // second line is this frame - stackTraceFilter(stack.split('\n').slice(2).join('\n')), - message, - ]); - } - - mochaHooks.beforeAll.push(function registerConsoleStub() { - // eslint-disable-next-line no-console - console[methodName] = logUnexpectedConsoleCalls; - }); - - mochaHooks.afterEach.push(function flushUnexpectedCalls() { - const hadUnexpectedCalls = unexpectedCalls.length > 0; - const formattedCalls = unexpectedCalls.map(([stack, message]) => `${message}\n${stack}`); - unexpectedCalls.length = 0; - - // eslint-disable-next-line no-console - if (console[methodName] !== logUnexpectedConsoleCalls) { - throw new Error(`Did not tear down spy or stub of console.${methodName} in your test.`); - } - if (hadUnexpectedCalls) { - const location = this.currentTest.file; - const testPath = `"${this.currentTest.parent - .titlePath() - .concat(this.currentTest.title) - .join('" -> "')}"`; - const message = - `Expected test not to call console.${methodName}()\n\n` + - 'If the warning is expected, test for it explicitly by ' + - `using the ${expectedMatcher}() matcher.`; - - const error = new Error( - `${location}: ${message}\n\n${formattedCalls.join('\n\n')}\n\n` + - `in ${testPath} (${location})`, - ); - // The stack of `flushUnexpectedCalls` is irrelevant. - // It includes no clue where the test was triggered - error.stack = ''; - throw error; - } - }); -} - -throwOnUnexpectedConsoleMessages('warn', 'toWarnDev'); -throwOnUnexpectedConsoleMessages('error', 'toErrorDev'); +const mochaHooks = createMochaHooks(Mocha); module.exports = { mochaHooks };