diff --git a/CHANGELOG.md b/CHANGELOG.md index f8ab752d3e..a6afd01346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,18 @@ This was added in pull requests: - [#2818: Add support for localisation via data-* attributes to Accordion component](https://github.com/alphagov/govuk-frontend/pull/2818) - [#2826: Add support for localisation via JavaScript configuration to Accordion component](https://github.com/alphagov/govuk-frontend/pull/2826) +#### Suppress deprecation warnings + +You can now suppress warnings from deprecations within GOV.UK Frontend by updating the `$govuk-suppressed-warnings` map in sass. Every deprecation warning will now include a warning "key" which you can use in the following code, placed at the root of your sass project: + +```scss +$govuk-suppressed-warnings: ( + deprecated-feature +); +``` + +This was added in [#2911 Add warning suppression functionality](https://github.com/alphagov/govuk-frontend/pull/2911) + ### Recommended changes #### Remove `aria-labelledby`, remove `id="error-summary-title"` from title and move `role="alert"` to child container on the error summary component diff --git a/docs/contributing/managing-change.md b/docs/contributing/managing-change.md index da16e7f4b8..7ffe5452ae 100644 --- a/docs/contributing/managing-change.md +++ b/docs/contributing/managing-change.md @@ -55,7 +55,7 @@ In the annotation description include: - the suggested alternative, if there is one - a link to the GitHub issue for its removal -If possible, update the mixin or function to output a warning (using `@warn`). +If possible, update the mixin or function to output a warning using the `_warning` mixin (see section below on allowing users to suppress warnings). For example: @@ -67,7 +67,7 @@ For example: /// @deprecated Use govuk-multiply(number, 2) instead. /// See https://github.com/alphagov/govuk-frontend/issues/1234 @function govuk-double($number) { - @warn "govuk-double($number) is deprecated. Use govuk-multiply($number, 2) instead."; + @include _warning("double", "govuk-double($number) is deprecated. Use govuk-multiply($number, 2) instead."); @return govuk-multiply($number, 2); } ``` @@ -86,7 +86,7 @@ If possible, update the mixin or function to maintain the existing functionality /// @param {Boolean} $rightAngle Deprecated. Use $angle: 90 instead. @mixin govuk-reticulate-splines($spline, $angle: 180, $rightAngle: false) { @if ($rightAngle != false) { - @warn "Passing $rightAngle to govuk-reticulate-splines is deprecated. Pass $angle: 90 instead."; + @include _warning("right-angle", "Passing $rightAngle to govuk-reticulate-splines is deprecated. Pass $angle: 90 instead."); $angle: 90; } @@ -123,7 +123,7 @@ For example: /// @alias the-new-name /// @deprecated Use the-new-name($foo) instead. @function the-old-name($foo) { - @warn "the-old-name is deprecated. Use the-new-name instead."; + @include _warning("the-old-name", "the-old-name is deprecated. Use the-new-name instead."); @return the-new-name($foo); } @@ -151,7 +151,7 @@ Add 'Deprecated.' to the description for the parameter. /// @param {String} $spilne Deprecated. Use $spline instead. @function govuk-reticulate-splines($spline, $spilne: false) { @if ($spilne != false) { - @warn "Passing $spilne to govuk-reticulate-splines is deprecated. Pass $spline instead."; + @include _warning("spilne", "Passing $spilne to govuk-reticulate-splines is deprecated. Pass $spline instead."); $spline: $spilne; } @@ -171,3 +171,11 @@ Keep the old name in the selector list, and mark it as deprecated. foo: bar; } ``` + +### The `_warning` mixin and allowing users to suppress warnings + +In the above examples we've used `@include _warning(...)` instead of the native sass `@warn` at-rule. We use this instead of `@warn` because it gives users the option to suppress deprecation warnings by interacting with the `$govuk-suppressed-warnings` map. + +You can read more about how `$govuk-suppressed-warnings` and `_warning` work by reading their respective sassdocs in `/src/govuk/settings/warnings.scss`. + +We make this option available for users because they can not always action deprecation warnings or upgrade their codebase beyond a specific version of GOV.UK Frontend. For example, a legacy codebase that does not have the resource to upgrade to the latest breaking change where a deprecated feature will be removed. This feature allows those users to continue to operate their codebase without having to repeatedly see non-actionable deprecation warnings in their testing. diff --git a/src/govuk/helpers/colour.test.js b/src/govuk/helpers/colour.test.js index da9a187423..e9cac646eb 100644 --- a/src/govuk/helpers/colour.test.js +++ b/src/govuk/helpers/colour.test.js @@ -72,6 +72,7 @@ describe('@function govuk-colour', () => { describe('when $govuk-use-legacy-palette is true', () => { beforeEach(() => { sassBootstrap = ` + @import "settings/warnings"; $govuk-use-legacy-palette: true; ${sassBootstrap} ` @@ -138,8 +139,9 @@ describe('@function govuk-colour', () => { // argument, which should be the deprecation notice return expect(mockWarnFunction.mock.calls[0][0].getValue()) .toEqual( - '$govuk-use-legacy-palette is deprecated. ' + - 'Only the modern colour palette will be supported from v5.0' + '$govuk-use-legacy-palette is deprecated. Only the modern colour ' + + 'palette will be supported from v5.0. To silence this warning, ' + + 'update $govuk-suppressed-warnings with key: "legacy-palette"' ) }) }) diff --git a/src/govuk/helpers/typography.test.js b/src/govuk/helpers/typography.test.js index dd40da3e85..9cee1c19ec 100644 --- a/src/govuk/helpers/typography.test.js +++ b/src/govuk/helpers/typography.test.js @@ -15,7 +15,7 @@ const sassConfig = { } } -const sassBootstrap = ` +let sassBootstrap = ` $govuk-breakpoints: ( desktop: 30em ); @@ -335,6 +335,13 @@ describe('@mixin govuk-typography-responsive', () => { }) describe('when $govuk-typography-use-rem is disabled', () => { + beforeEach(() => { + sassBootstrap = ` + @import "settings/warnings"; + ${sassBootstrap} + ` + }) + it('outputs CSS with suitable media queries', async () => { const sass = ` $govuk-typography-use-rem: false; @@ -411,8 +418,10 @@ describe('@mixin govuk-typography-responsive', () => { // deprecation notice return expect(mockWarnFunction.mock.calls.at(-1)[0].getValue()) .toEqual( - '$govuk-typography-use-rem is deprecated. ' + - 'From version 5.0, GOV.UK Frontend will not support disabling rem font sizes' + '$govuk-typography-use-rem is deprecated. From version 5.0, ' + + 'GOV.UK Frontend will not support disabling rem font sizes. To ' + + 'silence this warning, update $govuk-suppressed-warnings with ' + + 'key: "allow-not-using-rem"' ) }) }) @@ -609,9 +618,10 @@ describe('$govuk-font-family-tabular value is specified', () => { // deprecation notice return expect(mockWarnFunction.mock.calls.at(-1)[0].getValue()) .toEqual( - '$govuk-font-family-tabular is deprecated. ' + - 'From version 5.0, GOV.UK Frontend will not support using a separate ' + - 'font-face for tabular numbers' + '$govuk-font-family-tabular is deprecated. From version 5.0, ' + + 'GOV.UK Frontend will not support using a separate font-face for ' + + 'tabular numbers. To silence this warning, update ' + + '$govuk-suppressed-warnings with key: "tabular-font-face"' ) }) }) diff --git a/src/govuk/settings/_all.scss b/src/govuk/settings/_all.scss index 017169a601..a202073d72 100644 --- a/src/govuk/settings/_all.scss +++ b/src/govuk/settings/_all.scss @@ -3,6 +3,7 @@ @import "assets"; +@import "warnings"; @import "compatibility"; @import "global-styles"; @import "ie8"; diff --git a/src/govuk/settings/_colours-palette.scss b/src/govuk/settings/_colours-palette.scss index 233166deff..789cfd0936 100644 --- a/src/govuk/settings/_colours-palette.scss +++ b/src/govuk/settings/_colours-palette.scss @@ -34,8 +34,8 @@ $govuk-use-legacy-palette: if( $govuk-compatibility-govukfrontendtoolkit == false and $govuk-compatibility-govuktemplate == false and $govuk-compatibility-govukelements == false { - @warn "$govuk-use-legacy-palette is deprecated. " + - "Only the modern colour palette will be supported from v5.0"; + @include _warning(legacy-palette, "$govuk-use-legacy-palette is deprecated. " + + "Only the modern colour palette will be supported from v5.0."); } /// Modern colour palette diff --git a/src/govuk/settings/_typography-font.scss b/src/govuk/settings/_typography-font.scss index 63d66926a7..2dd0aa4ed4 100644 --- a/src/govuk/settings/_typography-font.scss +++ b/src/govuk/settings/_typography-font.scss @@ -32,9 +32,9 @@ $govuk-use-legacy-font: if( $govuk-compatibility-govukfrontendtoolkit == false and $govuk-compatibility-govuktemplate == false and $govuk-compatibility-govukelements == false { - @warn "$govuk-use-legacy-font is deprecated. " + - "From version 5.0, GOV.UK Frontend will only support the included version " + - "of GDS Transport"; + @include _warning(legacy-font, "$govuk-use-legacy-font is deprecated. " + + "From version 5.0, GOV.UK Frontend will only support the included version " + + "of GDS Transport."); } // ========================================================= @@ -68,9 +68,9 @@ $govuk-font-family-tabular: if( // Only show the deprecation warning if user is setting $govuk-font-family-tabular // manually instead of automatically via $govuk-use-legacy-font @if $govuk-font-family-tabular != false and $govuk-use-legacy-font == false { - @warn "$govuk-font-family-tabular is deprecated. " + - "From version 5.0, GOV.UK Frontend will not support using a separate " + - "font-face for tabular numbers"; + @include _warning(tabular-font-face, "$govuk-font-family-tabular is deprecated. " + + "From version 5.0, GOV.UK Frontend will not support using a separate " + + "font-face for tabular numbers."); } /// Font families to use for print media diff --git a/src/govuk/settings/_typography-responsive.scss b/src/govuk/settings/_typography-responsive.scss index ef5298a96a..5bd09423d3 100644 --- a/src/govuk/settings/_typography-responsive.scss +++ b/src/govuk/settings/_typography-responsive.scss @@ -32,8 +32,8 @@ $govuk-typography-use-rem: if( $govuk-compatibility-govukfrontendtoolkit == false and $govuk-compatibility-govuktemplate == false and $govuk-compatibility-govukelements == false { - @warn "$govuk-typography-use-rem is deprecated. " + - "From version 5.0, GOV.UK Frontend will not support disabling rem font sizes"; + @include _warning(allow-not-using-rem, "$govuk-typography-use-rem is deprecated. " + + "From version 5.0, GOV.UK Frontend will not support disabling rem font sizes."); } /// Root font size diff --git a/src/govuk/settings/_warnings.scss b/src/govuk/settings/_warnings.scss new file mode 100644 index 0000000000..4eb76c66e2 --- /dev/null +++ b/src/govuk/settings/_warnings.scss @@ -0,0 +1,53 @@ +//// +/// @group settings/warnings +//// + +/// Suppressed warnings map +/// +/// This map is used to determine which deprecation warnings to **not** show +/// to users when compiling sass. This is in place for codebases that do not +/// have the necessary capacity to upgrade and remove the deprecation, +/// particularly if the deprecation is significant. For example, removal of +/// compatibility with legacy libraries such as govuk_elements. +/// +/// You can add to this map and define which warnings to suppress by appending to +/// it using the warning key, found in the warning message. For example: +/// +/// @example scss: +/// // warning message: +/// // $foobar is no longer supported. To silence this warning, update +/// // $govuk-suppressed-warnings with key: "foobar" +/// $govuk-suppressed-warnings: ( +/// foobar +/// ); +/// +/// @type List +/// @access public + +$govuk-suppressed-warnings: () !default; + +/// Warnings +/// +/// Acts as a wrapper for the built in `@warn` sass function +/// +/// We use this instead of using `@warn` for 3 reasons: +/// +/// - To check if a warning is being suppressed through `$govuk-suppressed-warnings`, +/// in which case we don't call `@warn` and printing the warning to the user +/// - To format the passed warning `$message` with the warning key at the end +/// - To prevent duplicate warnings by adding the passed `$key` to +/// `$govuk-suppressed-warnings` after `@warn` is called to ensure it only runs +/// once per sass compilation +/// +/// @param {String} $key - The key to be checked against `$govuk-suppressed-warnings` +/// and then passed to it to prevent multiple of the same warning. +/// @param {String} $message - The message to use when calling `@warn` +/// @access private + +@mixin _warning($key, $message) { + @if not index($govuk-suppressed-warnings, $key) { + @warn $message + " To silence this warning, update $govuk-suppressed-warnings " + + "with key: \"#{$key}\""; + $govuk-suppressed-warnings: append($govuk-suppressed-warnings, $key) !global; + } +} diff --git a/src/govuk/settings/warnings.test.js b/src/govuk/settings/warnings.test.js new file mode 100644 index 0000000000..e8c6ab48f2 --- /dev/null +++ b/src/govuk/settings/warnings.test.js @@ -0,0 +1,63 @@ +const sass = require('node-sass') +const { renderSass } = require('../../../lib/jest-helpers') + +// Create a mock warn function that we can use to override the native @warn +// function, that we can make assertions about post-render. +const mockWarnFunction = jest.fn() + .mockReturnValue(sass.NULL) + +const sassConfig = { + outputStyle: 'compressed', + functions: { + '@warn': mockWarnFunction + } +} + +describe('Warnings mixin', () => { + const sassBootstrap = '@import "settings/warnings";' + + afterEach(() => { + jest.clearAllMocks() + }) + + it('Fires a @warn with the message plus the key suffix text', async () => { + const sass = ` + ${sassBootstrap} + @include _warning('test', 'This is a warning.');` + + await renderSass({ data: sass, ...sassConfig }).then(() => { + // Expect our mocked @warn function to have been called once with a single + // argument, which should be the test message + return expect(mockWarnFunction.mock.calls[0][0].getValue()) + .toEqual( + 'This is a warning. To silence this warning, update ' + + '$govuk-suppressed-warnings with key: "test"' + ) + }) + }) + + it('Only fires one @warn per warning key', async () => { + const sass = ` + ${sassBootstrap} + @include _warning('test', 'This is a warning.'); + @include _warning('test', 'This is a warning.');` + + await renderSass({ data: sass, ...sassConfig }).then(() => { + // Expect our mocked @warn function to have been called once with a single + // argument, which should be the test message + return expect(mockWarnFunction.mock.calls.length).toEqual(1) + }) + }) + + it('Does not fire a @warn if the key is already in $govuk-suppressed-warnings', async () => { + const sass = ` + ${sassBootstrap} + + $govuk-suppressed-warnings: append($govuk-suppressed-warnings, 'test'); + @include _warning('test', 'This is a warning.');` + + await renderSass({ data: sass, ...sassConfig }).then(() => { + return expect(mockWarnFunction).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/govuk/tools/_compatibility.scss b/src/govuk/tools/_compatibility.scss index 54004a04b3..ba4aaf680b 100644 --- a/src/govuk/tools/_compatibility.scss +++ b/src/govuk/tools/_compatibility.scss @@ -42,8 +42,8 @@ /// suite of tools and settings @mixin govuk-compatibility($product) { - @warn "govuk-compatibility is deprecated. " + - "From version 5.0, GOV.UK Frontend will not support compatibility mode"; + @include _warning(compatibility-helper, "govuk-compatibility is deprecated. " + + "From version 5.0, GOV.UK Frontend will not support compatibility mode."); @include _govuk-compatibility($product) { @content; } diff --git a/src/govuk/tools/compatibility.test.js b/src/govuk/tools/compatibility.test.js index 941b821e1c..57e0bbd683 100644 --- a/src/govuk/tools/compatibility.test.js +++ b/src/govuk/tools/compatibility.test.js @@ -14,8 +14,13 @@ const sassConfig = { } describe('@mixin govuk-compatibility', () => { + // Import the warning mixin + const warningsImport = '@import "settings/warnings";' + it('does not output if the app is not marked as included', async () => { const sass = ` + ${warningsImport} + $_govuk-compatibility: (existing_app: false); @import "tools/compatibility"; @@ -33,6 +38,7 @@ describe('@mixin govuk-compatibility', () => { it('outputs if the app is not marked as included', async () => { const sass = ` + ${warningsImport} $_govuk-compatibility: (existing_app: true); @import "tools/compatibility"; @@ -50,6 +56,7 @@ describe('@mixin govuk-compatibility', () => { it('throws an exception if the app is not recognised', async () => { const sass = ` + ${warningsImport} $_govuk-compatibility: (existing_app: true); @import "tools/compatibility"; @@ -67,6 +74,7 @@ describe('@mixin govuk-compatibility', () => { it('outputs a deprecation warning when called', async () => { const sass = ` + ${warningsImport} $_govuk-compatibility: (existing_app: true); @import "tools/compatibility"; @@ -83,7 +91,8 @@ describe('@mixin govuk-compatibility', () => { return expect(mockWarnFunction.mock.calls[0][0].getValue()) .toEqual( 'govuk-compatibility is deprecated. From version 5.0, GOV.UK Frontend ' + - 'will not support compatibility mode' + 'will not support compatibility mode. To silence this warning, ' + + 'update $govuk-suppressed-warnings with key: "compatibility-helper"' ) }) }) diff --git a/tasks/sassdoc.js b/tasks/sassdoc.js index 8ecee7ebe7..429830c922 100644 --- a/tasks/sassdoc.js +++ b/tasks/sassdoc.js @@ -22,6 +22,7 @@ function buildSassdocs () { 'settings/media-queries': 'Settings / Media Queries', 'settings/spacing': 'Settings / Spacing', 'settings/typography': 'Settings / Typography', + 'settings/warnings': 'Settings / Warnings', tools: 'Tools', helpers: 'Helpers', overrides: 'Overrides',