From cee40e558818c318bbeb2976736f0e52f2422a9d Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Wed, 1 Feb 2023 10:19:16 +0100 Subject: [PATCH] chore(@lion/ui): all tests side effect free wrt localize --- .changeset/four-wolves-do.md | 61 +++++++++++++++++++ .../calendar/test/lion-calendar.test.js | 8 ++- .../form-core/test/lion-field.test.js | 6 +- .../test/form-validation-integrations.test.js | 21 ++++--- .../input-date/test/lion-input-date.test.js | 10 +-- .../localize/src/getLocalizeManager.js | 2 +- .../localize/test/getLocalizeManager.test.js | 1 + 7 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 .changeset/four-wolves-do.md diff --git a/.changeset/four-wolves-do.md b/.changeset/four-wolves-do.md new file mode 100644 index 000000000..2fdee7f3d --- /dev/null +++ b/.changeset/four-wolves-do.md @@ -0,0 +1,61 @@ +--- +'@lion/ui': minor +--- + +Side-effect-free alternative for `localize` (the globally shared instance of LocalizeManager). +When this function is imported, no side-effect happened yet, i.e. no global instance was registered yet. +The side effect-free approach generates: + +- smaller, optimized bundles +- a predictable loading order, that allows for: + - deduping strategies when multiple instances of the localizeManager are on a page + - providing a customized extension of LocalizeManager + +Also see: https://github.com/ing-bank/lion/discussions/1861 + +Use it like this: + +```js +function myFunction() { + // note that 'localizeManager' is the same as former 'localize' + const localizeManager = getLocalizeManger(); + // ... +} +``` + +In a class, we advise a shared instance: + +```js +class MyClass { + constructor() { + this._localizeManager = getLocalizeManger(); + } + // ... +} +``` + +Make sure to always call this method inside a function or class (otherwise side effects are created) + +Do you want to register your own LocalizeManager? +Make sure it's registered before anyone called `getLocalizeManager()` + +```js +import { singletonManager } from 'singleton-manager'; +import { getLocalizeManger } from '@lion/ui/localize-no-side-effects.js'; + +// First register your own LocalizeManager (for deduping or other reasons) +singletonManager.set('lion/ui::localize::0.x', class MyLocalizeManager extends LocalizeManager {}); + +// Now, all your code gets the right instance +export function myFn() { + const localizeManager = getLocalizeManager(); + // ... +} + +export class myClass() { + constructor() { + this._localizeManager = getLocalizeManager(); + // ... + } +} +``` diff --git a/packages/ui/components/calendar/test/lion-calendar.test.js b/packages/ui/components/calendar/test/lion-calendar.test.js index f300eb9c8..aceaf0c88 100644 --- a/packages/ui/components/calendar/test/lion-calendar.test.js +++ b/packages/ui/components/calendar/test/lion-calendar.test.js @@ -1,5 +1,5 @@ import { html } from 'lit'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { localizeTearDown } from '@lion/ui/localize-test-helpers.js'; import { expect, fixture as _fixture } from '@open-wc/testing'; import sinon from 'sinon'; @@ -15,6 +15,8 @@ import { CalendarObject, DayObject } from '@lion/ui/calendar-test-helpers.js'; const fixture = /** @type {(arg: TemplateResult) => Promise} */ (_fixture); describe('', () => { + const localizeManager = getLocalizeManager(); + beforeEach(() => { localizeTearDown(); }); @@ -1348,7 +1350,7 @@ describe('', () => { await el.updateComplete; expect(elObj.activeMonth).to.equal('décembre'); - localize.locale = 'cs-CZ'; + localizeManager.locale = 'cs-CZ'; await el.updateComplete; expect(elObj.activeMonth).to.equal('décembre'); @@ -1391,7 +1393,7 @@ describe('', () => { 'Sat', ]); - localize.locale = 'nl-NL'; + localizeManager.locale = 'nl-NL'; await el.localizeNamespacesLoaded; await el.updateComplete; expect(elObj.nextMonthButtonEl?.getAttribute('aria-label')).to.equal( diff --git a/packages/ui/components/form-core/test/lion-field.test.js b/packages/ui/components/form-core/test/lion-field.test.js index b312918f3..195d3c787 100644 --- a/packages/ui/components/form-core/test/lion-field.test.js +++ b/packages/ui/components/form-core/test/lion-field.test.js @@ -2,7 +2,7 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { Required, Validator } from '@lion/ui/form-core.js'; import '@lion/ui/define/lion-field.js'; import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { localizeTearDown } from '@lion/ui/localize-test-helpers.js'; import { expect, @@ -52,6 +52,8 @@ function getSlot(el, slot) { } describe('', () => { + const localizeManager = getLocalizeManager(); + it(`puts a unique id "${tagString}-[hash]" on the native input`, async () => { const el = /** @type {LionField} */ (await fixture(html`<${tag}>${inputSlot}`)); // @ts-ignore allow protected accessors in tests @@ -219,7 +221,7 @@ describe('', () => { beforeEach(() => { // Reset and preload validation translations localizeTearDown(); - localize.addData('en-GB', 'lion-validate', { + localizeManager.addData('en-GB', 'lion-validate', { error: { hasX: 'This is error message for hasX', }, diff --git a/packages/ui/components/form-integrations/test/form-validation-integrations.test.js b/packages/ui/components/form-integrations/test/form-validation-integrations.test.js index 1b98d9f0e..3b404cdf4 100644 --- a/packages/ui/components/form-integrations/test/form-validation-integrations.test.js +++ b/packages/ui/components/form-integrations/test/form-validation-integrations.test.js @@ -1,12 +1,13 @@ import { DefaultSuccess, Required, Validator } from '@lion/ui/form-core.js'; import { getFormControlMembers } from '@lion/ui/form-core-test-helpers.js'; import { LionInput } from '@lion/ui/input.js'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { loadDefaultFeedbackMessages } from '@lion/ui/validate-messages.js'; import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing'; import sinon from 'sinon'; describe('Form Validation Integrations', () => { + const localizeManager = getLocalizeManager(); const lightDom = ''; before(() => { loadDefaultFeedbackMessages(); @@ -126,11 +127,11 @@ describe('Form Validation Integrations', () => { } async updateLabel() { - this.label = localize.msg('test-default-label:label'); + this.label = localizeManager.msg('test-default-label:label'); } async setDefaultLabel() { - localize.loadNamespace({ + localizeManager.loadNamespace({ 'test-default-label': /** @param {string} locale */ async locale => { switch (locale) { case 'nl-NL': @@ -143,11 +144,11 @@ describe('Form Validation Integrations', () => { this.boundUpdateLabel = this.updateLabel.bind(this); // localeChanged is fired AFTER localize has finished loading missing translations - // so no need to await localize.loadingComplete - localize.addEventListener('localeChanged', this.boundUpdateLabel); + // so no need to await localizeManager.loadingComplete + localizeManager.addEventListener('localeChanged', this.boundUpdateLabel); // Wait for it to complete when updating the label for the first time - await localize.loadingComplete; + await localizeManager.loadingComplete; this.boundUpdateLabel(); } } @@ -167,15 +168,15 @@ describe('Form Validation Integrations', () => { const { _feedbackNode } = getFormControlMembers(el); expect(_feedbackNode.feedbackData?.[0].message).to.equal('Please enter a(n) Text.'); - localize.locale = 'nl-NL'; - await localize.loadingComplete; + localizeManager.locale = 'nl-NL'; + await localizeManager.loadingComplete; await el.updateComplete; await el.feedbackComplete; expect(el.label).to.equal('Tekst'); expect(_feedbackNode.feedbackData?.[0].message).to.equal('Vul een Tekst in.'); - localize.locale = 'en-GB'; - await localize.loadingComplete; + localizeManager.locale = 'en-GB'; + await localizeManager.loadingComplete; await el.updateComplete; await el.feedbackComplete; expect(el.label).to.equal('Text'); diff --git a/packages/ui/components/input-date/test/lion-input-date.test.js b/packages/ui/components/input-date/test/lion-input-date.test.js index 1dd10986c..035d138d0 100644 --- a/packages/ui/components/input-date/test/lion-input-date.test.js +++ b/packages/ui/components/input-date/test/lion-input-date.test.js @@ -1,5 +1,5 @@ import { html } from 'lit'; -import { localize } from '@lion/ui/localize.js'; +import { getLocalizeManager } from '@lion/ui/localize-no-side-effects.js'; import { localizeTearDown } from '@lion/ui/localize-test-helpers.js'; import { MaxDate } from '@lion/ui/form-core.js'; import { expect, fixture as _fixture } from '@open-wc/testing'; @@ -13,6 +13,8 @@ import '@lion/ui/define/lion-input-date.js'; const fixture = /** @type {(arg: TemplateResult) => Promise} */ (_fixture); describe('', () => { + const localizeManager = getLocalizeManager(); + beforeEach(() => { localizeTearDown(); }); @@ -84,13 +86,13 @@ describe('', () => { }); it('uses global locale when formatOptions.locale is not defined', async () => { - localize.locale = 'fr-FR'; + localizeManager.locale = 'fr-FR'; const el = await fixture(html` `); expect(el.formattedValue).to.equal('15/06/2017'); - localize.locale = 'en-US'; + localizeManager.locale = 'en-US'; const el2 = await fixture(html` `); @@ -105,7 +107,7 @@ describe('', () => { > `); expect(el.formattedValue).to.equal('15/06/2017'); // british - localize.locale = 'en-US'; + localizeManager.locale = 'en-US'; await el.updateComplete; expect(el.formattedValue).to.equal('15/06/2017'); // should stay british }); diff --git a/packages/ui/components/localize/src/getLocalizeManager.js b/packages/ui/components/localize/src/getLocalizeManager.js index 42306960b..86314328f 100644 --- a/packages/ui/components/localize/src/getLocalizeManager.js +++ b/packages/ui/components/localize/src/getLocalizeManager.js @@ -16,7 +16,7 @@ import { LocalizeManager } from './LocalizeManager.js'; * ```js * function myFunction() { * // note that 'localizeManager' is the same as former 'localize' - * const localize = getLocalizeManger(); + * const localizeManager = getLocalizeManger(); * // ... * } * ``` diff --git a/packages/ui/components/localize/test/getLocalizeManager.test.js b/packages/ui/components/localize/test/getLocalizeManager.test.js index 3fe4c2f39..45a287c93 100644 --- a/packages/ui/components/localize/test/getLocalizeManager.test.js +++ b/packages/ui/components/localize/test/getLocalizeManager.test.js @@ -6,6 +6,7 @@ import { getLocalizeManager } from '../src/getLocalizeManager.js'; describe('getLocalizeManager', () => { beforeEach(() => { + // @ts-ignore singletonManager._map.clear(); });