From 8e7b5d5aab55788f07cc894e8e72489b13bdfc1f Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Sun, 25 Jul 2021 20:51:12 -0700 Subject: [PATCH] fix: fix setting props before element upgrade (#194) * fix: fix setting props before element upgrade fixes #190 * fix: better test and logic * fix: fix re-setting --- src/picker/PickerElement.js | 28 ++++++++++------ test/spec/picker/upgrade.test.js | 56 ++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 test/spec/picker/upgrade.test.js diff --git a/src/picker/PickerElement.js b/src/picker/PickerElement.js index e814394..c71faff 100644 --- a/src/picker/PickerElement.js +++ b/src/picker/PickerElement.js @@ -5,6 +5,16 @@ import enI18n from '../picker/i18n/en.js' import styles from 'emoji-picker-element-styles' import Database from './ImportedDatabase' +const PROPS = [ + 'customEmoji', + 'customCategorySorting', + 'database', + 'dataSource', + 'i18n', + 'locale', + 'skinToneEmoji' +] + export default class PickerElement extends HTMLElement { constructor (props) { performance.mark('initialLoad') @@ -23,6 +33,13 @@ export default class PickerElement extends HTMLElement { i18n: enI18n, ...props } + // Handle properties set before the element was upgraded + for (const prop of PROPS) { + if (prop !== 'database' && Object.hasOwnProperty.call(this, prop)) { + this._ctx[prop] = this[prop] + delete this[prop] + } + } this._dbFlush() // wait for a flush before creating the db, in case the user calls e.g. a setter or setAttribute } @@ -85,18 +102,9 @@ export default class PickerElement extends HTMLElement { } } -const props = [ - 'customEmoji', - 'customCategorySorting', - 'database', - 'dataSource', - 'i18n', - 'locale', - 'skinToneEmoji' -] const definitions = {} -for (const prop of props) { +for (const prop of PROPS) { definitions[prop] = { get () { if (prop === 'database') { diff --git a/test/spec/picker/upgrade.test.js b/test/spec/picker/upgrade.test.js new file mode 100644 index 0000000..78e1285 --- /dev/null +++ b/test/spec/picker/upgrade.test.js @@ -0,0 +1,56 @@ +import { + basicAfterEach, + basicBeforeEach, + FR_EMOJI, + mockFrenchDataSource, + tick +} from '../shared' +import { getByRole, waitFor } from '@testing-library/dom' + +describe('upgrade tests', () => { + beforeEach(async () => { + basicBeforeEach() + mockFrenchDataSource() + }) + afterEach(async () => { + basicAfterEach() + }) + + test('setting props and attributes before upgrade', async () => { + const div = document.createElement('div') + document.body.appendChild(div) + div.innerHTML = '' + + const picker = div.querySelector('emoji-picker') + picker.dataSource = FR_EMOJI + picker.skinToneEmoji = '👍' + + expect(picker.shadowRoot).toBeNull() + + await tick(20) + + expect(fetch).not.toHaveBeenCalled() + + await import('../../../src/picker/PickerElement') + + await waitFor(() => expect(getByRole(picker.shadowRoot, 'menuitem', { name: /😀/ })).toBeVisible()) + + const container = picker.shadowRoot + + expect(fetch).toHaveBeenCalledTimes(1) + expect(fetch).toHaveBeenLastCalledWith(FR_EMOJI, undefined) + + expect(getByRole(container, 'button', { name: /Choose a skin tone/ }).innerHTML).toContain('👍') + + expect(picker.locale).toEqual('fr') + expect(picker.dataSource).toEqual(FR_EMOJI) + + // The setter should now work as expected + picker.skinToneEmoji = '✌' + + await waitFor(() => expect(getByRole(container, 'button', { name: /Choose a skin tone/ }).innerHTML).toContain('✌')) + + document.body.removeChild(div) + await tick(20) + }) +})