From 8f1a5c93929465daa89dca8cebd972475b6181d3 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 10 Mar 2023 10:39:42 +0000 Subject: [PATCH] DEV: Fail core JS test runs if deprecations are triggered (#20614) It's important to keep our core log output as clean as possible to avoid 'crying wolf', and so that any deprecations triggered by plugin/theme tests are indeed caused by that theme/plugin, and not core. This commit will make the core test suite fail if any deprecations are triggered. If a new deprecation is introduced (e.g. as part of a dependency update) and we need more time to resolve it it can be silenced via ember-deprecation-workflow. This does not affect plugin/theme test runs. --- .../discourse-common/addon/lib/deprecated.js | 10 +++- .../discourse/config/environment.js | 13 +++-- .../tests/helpers/raise-on-deprecation.js | 49 +++++++++++++++++++ .../discourse/tests/setup-tests.js | 9 ++++ .../tests/unit/lib/deprecated-test.js | 9 ++++ 5 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 app/assets/javascripts/discourse/tests/helpers/raise-on-deprecation.js diff --git a/app/assets/javascripts/discourse-common/addon/lib/deprecated.js b/app/assets/javascripts/discourse-common/addon/lib/deprecated.js index 4752732e3c0..0dc0fea9640 100644 --- a/app/assets/javascripts/discourse-common/addon/lib/deprecated.js +++ b/app/assets/javascripts/discourse-common/addon/lib/deprecated.js @@ -1,5 +1,7 @@ const handlers = []; const disabledDeprecations = new Set(); +const emberCliDeprecationWorkflows = + window.deprecationWorkflow?.config?.workflow; /** * Display a deprecation warning with the provided message. The warning will be prefixed with the theme/plugin name @@ -47,7 +49,13 @@ export default function deprecated(msg, options = {}) { throw msg; } - console.warn(...[consolePrefix, msg].filter(Boolean)); //eslint-disable-line no-console + const matchedWorkflow = emberCliDeprecationWorkflows?.find( + (w) => w.matchId === id + ); + + if (matchedWorkflow?.handler !== "silence") { + console.warn(...[consolePrefix, msg].filter(Boolean)); //eslint-disable-line no-console + } } /** diff --git a/app/assets/javascripts/discourse/config/environment.js b/app/assets/javascripts/discourse/config/environment.js index b8dc3564e1c..efc8c76ccec 100644 --- a/app/assets/javascripts/discourse/config/environment.js +++ b/app/assets/javascripts/discourse/config/environment.js @@ -16,8 +16,6 @@ module.exports = function (environment) { // Prevent Ember Data from overriding Date.parse. Date: false, }, - // This is easier to toggle than the flag in ember-cli-deprecation-workflow. - RAISE_ON_DEPRECATION: false, }, exportApplicationGlobal: true, @@ -27,13 +25,20 @@ module.exports = function (environment) { }, }; + if (process.env.EMBER_RAISE_ON_DEPRECATION === "1") { + ENV.EmberENV.RAISE_ON_DEPRECATION = true; + } else if (process.env.EMBER_RAISE_ON_DEPRECATION === "0") { + ENV.EmberENV.RAISE_ON_DEPRECATION = false; + } else { + // Default (normally false; true in core qunit runs) + } + if (environment === "development") { // ENV.APP.LOG_RESOLVER = true; // ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; // ENV.APP.LOG_VIEW_LOOKUPS = true; - ENV.EmberENV.RAISE_ON_DEPRECATION = false; } if (environment === "test") { @@ -46,8 +51,6 @@ module.exports = function (environment) { ENV.APP.rootElement = "#ember-testing"; ENV.APP.autoboot = false; - - ENV.EmberENV.RAISE_ON_DEPRECATION = false; } if (environment === "production") { diff --git a/app/assets/javascripts/discourse/tests/helpers/raise-on-deprecation.js b/app/assets/javascripts/discourse/tests/helpers/raise-on-deprecation.js new file mode 100644 index 00000000000..6c6c0ebb6b2 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/helpers/raise-on-deprecation.js @@ -0,0 +1,49 @@ +import { registerDeprecationHandler } from "@ember/debug"; +import { registerDeprecationHandler as registerDiscourseDeprecationHandler } from "discourse-common/lib/deprecated"; +import QUnit from "qunit"; + +let disabled = false; + +export function configureRaiseOnDeprecation() { + const workflows = window.deprecationWorkflow?.config?.workflow; + if (!workflows) { + return; + } + + if (window.EmberENV.RAISE_ON_DEPRECATION !== undefined) { + return; + } + + registerDeprecationHandler((message, options, next) => { + if (disabled || workflows.find((w) => w.matchId === options.id)) { + return next(message, options); + } + raiseDeprecationError(message, options); + }); + + registerDiscourseDeprecationHandler((message, options) => { + if (disabled || workflows.find((w) => w.matchId === options?.id)) { + return; + } + raiseDeprecationError(message, options); + }); +} + +function raiseDeprecationError(message, options) { + message = `DEPRECATION IN CORE TEST: ${message} (deprecation id: ${options.id})\n\nCore test runs must be deprecation-free. Use ember-deprecation-workflow to silence unresolved deprecations.`; + if (QUnit.config.current) { + QUnit.assert.pushResult({ + result: false, + message, + }); + } + throw new Error(message); +} + +export function disableRaiseOnDeprecation() { + disabled = true; +} + +export function enableRaiseOnDeprecation() { + disabled = false; +} diff --git a/app/assets/javascripts/discourse/tests/setup-tests.js b/app/assets/javascripts/discourse/tests/setup-tests.js index 570f1f00e26..9125bed3585 100644 --- a/app/assets/javascripts/discourse/tests/setup-tests.js +++ b/app/assets/javascripts/discourse/tests/setup-tests.js @@ -39,6 +39,7 @@ import { addModuleExcludeMatcher } from "ember-cli-test-loader/test-support/inde import SiteSettingService from "discourse/services/site-settings"; import jQuery from "jquery"; import { setupDeprecationCounter } from "discourse/tests/helpers/deprecation-counter"; +import { configureRaiseOnDeprecation } from "discourse/tests/helpers/raise-on-deprecation"; const Plugin = $.fn.modal; const Modal = Plugin.Constructor; @@ -386,6 +387,14 @@ export default function setupTests(config) { setupToolbar(); reportMemoryUsageAfterTests(); patchFailedAssertion(); + + const hasPluginJs = Array.from( + document.querySelector("#dynamic-test-js").content.childNodes + ).some((script) => script.dataset?.discoursePlugin); + + if (skipPlugins || !hasPluginJs) { + configureRaiseOnDeprecation(); + } } function getUrlParameter(name) { diff --git a/app/assets/javascripts/discourse/tests/unit/lib/deprecated-test.js b/app/assets/javascripts/discourse/tests/unit/lib/deprecated-test.js index a6dd4aece1f..1b53cbb2ac4 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/deprecated-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/deprecated-test.js @@ -3,12 +3,17 @@ import { withSilencedDeprecations, withSilencedDeprecationsAsync, } from "discourse-common/lib/deprecated"; +import { + disableRaiseOnDeprecation, + enableRaiseOnDeprecation, +} from "discourse/tests/helpers/raise-on-deprecation"; import DeprecationCounter from "discourse/tests/helpers/deprecation-counter"; import { module, test } from "qunit"; import Sinon from "sinon"; module("Unit | Utility | deprecated", function (hooks) { hooks.beforeEach(function () { + disableRaiseOnDeprecation(); this.warnStub = Sinon.stub(console, "warn"); this.counterStub = Sinon.stub( DeprecationCounter.prototype, @@ -16,6 +21,10 @@ module("Unit | Utility | deprecated", function (hooks) { ); }); + hooks.afterEach(() => { + enableRaiseOnDeprecation(); + }); + test("works with just a message", function (assert) { deprecated("My message"); assert.strictEqual(