From dd0ff865258bc64a26fd2a12f47e53742a3afd81 Mon Sep 17 00:00:00 2001 From: George Treviranus Date: Sat, 15 May 2021 12:07:50 -0700 Subject: [PATCH 1/3] updates base class to set firstRender to false immediately to prevent double mounts --- src/__tests__/fixtures/accessor-fixture.js | 2 +- src/__tests__/fixtures/basic-fixture.js | 2 +- src/__tests__/fixtures/lifecycle-fixture.js | 2 +- src/__tests__/upgraded-element.spec.js | 66 +++++++++------------ src/internal.js | 4 +- src/upgraded-element.js | 14 +++-- 6 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/__tests__/fixtures/accessor-fixture.js b/src/__tests__/fixtures/accessor-fixture.js index a7744ef..9a3b3da 100644 --- a/src/__tests__/fixtures/accessor-fixture.js +++ b/src/__tests__/fixtures/accessor-fixture.js @@ -5,7 +5,7 @@ import { UpgradedElement, register } from "../.." * can't unregister custom elements from the DOM, even between tests. * @param {string} id */ -export function accessorFixture(id) { +export function createAccessorFixture(id) { class TestElement extends UpgradedElement { constructor() { super() diff --git a/src/__tests__/fixtures/basic-fixture.js b/src/__tests__/fixtures/basic-fixture.js index c16e174..e899726 100644 --- a/src/__tests__/fixtures/basic-fixture.js +++ b/src/__tests__/fixtures/basic-fixture.js @@ -6,7 +6,7 @@ import { UpgradedElement, register } from "../.." * @param {string} id * @param {{content: string, properties: Object, styles: string}} */ -export function basicFixture(id, options = {}) { +export function createBasicFixture(id, options = {}) { class TestElement extends UpgradedElement { constructor() { super() diff --git a/src/__tests__/fixtures/lifecycle-fixture.js b/src/__tests__/fixtures/lifecycle-fixture.js index 012469d..8e88315 100644 --- a/src/__tests__/fixtures/lifecycle-fixture.js +++ b/src/__tests__/fixtures/lifecycle-fixture.js @@ -5,7 +5,7 @@ import { UpgradedElement, register } from "../.." * can't unregister custom elements from the DOM, even between tests. * @param {string} id */ -export function lifecycleFixture(id, wait = false) { +export function createLifecycleFixture(id, wait = false) { class TestElement extends UpgradedElement { constructor() { super() diff --git a/src/__tests__/upgraded-element.spec.js b/src/__tests__/upgraded-element.spec.js index 5ece810..500639a 100644 --- a/src/__tests__/upgraded-element.spec.js +++ b/src/__tests__/upgraded-element.spec.js @@ -1,25 +1,24 @@ -import { basicFixture } from "./fixtures/basic-fixture" -import { accessorFixture } from "./fixtures/accessor-fixture" -import { lifecycleFixture } from "./fixtures/lifecycle-fixture" +import { createBasicFixture } from "./fixtures/basic-fixture" +import { createAccessorFixture } from "./fixtures/accessor-fixture" +import { createLifecycleFixture } from "./fixtures/lifecycle-fixture" import { getElement } from "./fixtures/get-element" import * as external from "../external" window.requestAnimationFrame = jest.fn().mockImplementation((fn) => fn()) -window.cancelAnimationFrame = jest.fn().mockImplementation((fn) => fn()) describe("UpgradedElement", () => { afterEach(() => (document.innerHTML = "")) it("upgrades the element", () => { // Given - basicFixture("upgraded") + createBasicFixture("upgraded") // Then expect(getElement("upgraded").hasAttribute("element-id")).toBe(true) }) it("creates a shadow root", () => { // Given - basicFixture("creates-shadow") + createBasicFixture("creates-shadow") // Then expect(getElement("creates-shadow").shadowRoot).not.toBeNull() }) @@ -27,7 +26,7 @@ describe("UpgradedElement", () => { it("renders styles to shadow root", () => { // Given const styles = "div { display: block; }" - basicFixture("styles", { styles }) + createBasicFixture("styles", { styles }) // Then expect( getElement("styles").shadowRoot.querySelector("style") @@ -40,7 +39,7 @@ describe("UpgradedElement", () => { it("assigns slots, if given", () => { // Given const slotName = "main" - basicFixture("slotted", { + createBasicFixture("slotted", { slotName, content: ``, }) @@ -56,7 +55,7 @@ describe("UpgradedElement", () => { const properties = { testProp1: { default: "foo" }, } - basicFixture("props", { properties }) + createBasicFixture("props", { properties }) // Then expect(getElement("props").testProp1).toEqual( properties.testProp1.default @@ -69,7 +68,7 @@ describe("UpgradedElement", () => { testProp1: { default: "foo" }, } const nextValue = "bar" - basicFixture("val-change", { properties }) + createBasicFixture("val-change", { properties }) // When getElement("val-change").testProp1 = nextValue // Then @@ -81,7 +80,7 @@ describe("UpgradedElement", () => { it("doesn't upgrade properties if accessors already exist", () => { // Given - accessorFixture("no-upgrade") + createAccessorFixture("no-upgrade") // Then expect(getElement("no-upgrade").count).toEqual(1) }) @@ -96,7 +95,7 @@ describe("UpgradedElement", () => { safe: true, }, } - basicFixture("safe-upgrade", { properties }) + createBasicFixture("safe-upgrade", { properties }) // Then const nextValue = "<span>unsafe</span>" expect(getElement("safe-upgrade").safeString).toEqual(nextValue) @@ -111,7 +110,7 @@ describe("UpgradedElement", () => { safe: true, }, } - basicFixture("safe-change", { properties }) + createBasicFixture("safe-change", { properties }) // When getElement("safe-change").safeString = "&hello" // Then @@ -126,7 +125,7 @@ describe("UpgradedElement", () => { const properties = { reflectedProp: { reflected: true }, } - basicFixture("reflect-one", { properties }) + createBasicFixture("reflect-one", { properties }) // Then const element = getElement("reflect-one") expect(element.hasAttribute("reflected-prop")).toBe(true) @@ -138,7 +137,7 @@ describe("UpgradedElement", () => { const properties = { reflectedProp: { default: "foo", reflected: true }, } - basicFixture("reflect-two", { properties }) + createBasicFixture("reflect-two", { properties }) // Then const element = getElement("reflect-two") expect(element.hasAttribute("reflected-prop")).toBe(true) @@ -150,7 +149,7 @@ describe("UpgradedElement", () => { const properties = { reflectedProp: { default: "foo", reflected: true }, } - basicFixture("reflect-three", { properties }) + createBasicFixture("reflect-three", { properties }) const element = getElement("reflect-three") element.reflectedProp = "bar" // Then @@ -162,7 +161,7 @@ describe("UpgradedElement", () => { const properties = { reflectedProp: { default: "foo", reflected: true }, } - basicFixture("reflect-four", { properties }) + createBasicFixture("reflect-four", { properties }) const element = getElement("reflect-four") element.reflectedProp = undefined // Then @@ -185,7 +184,7 @@ describe("UpgradedElement", () => { default: "foo", }, } - basicFixture("upgrade-type-warn", { properties }) + createBasicFixture("upgrade-type-warn", { properties }) // Then expect(console.warn).toBeCalledWith(warningMessage) }) @@ -198,7 +197,7 @@ describe("UpgradedElement", () => { default: true, }, } - basicFixture("change-type-warn", { properties }) + createBasicFixture("change-type-warn", { properties }) // When getElement("change-type-warn").testProp1 = "foo" // Then @@ -212,7 +211,7 @@ describe("UpgradedElement", () => { describe("lifecycle methods", () => { it("calls elementPropertyChanged", () => { - const Cls = lifecycleFixture("prop-changed") + const Cls = createLifecycleFixture("prop-changed") Cls.prototype[external.elementPropertyChanged] = jest.fn() getElement("prop-changed").testProp = true expect(Cls.prototype[external.elementPropertyChanged]).toBeCalledWith( @@ -223,7 +222,7 @@ describe("UpgradedElement", () => { }) it("calls elementAttributeChanged", () => { - const Cls = lifecycleFixture("attr-changed") + const Cls = createLifecycleFixture("attr-changed") Cls.prototype[external.elementAttributeChanged] = jest.fn() getElement("attr-changed").testProp = true expect(Cls.prototype[external.elementAttributeChanged]).toBeCalledWith( @@ -234,54 +233,45 @@ describe("UpgradedElement", () => { }) it("calls elementDidUpdate", () => { - const Cls = lifecycleFixture("update") + const Cls = createLifecycleFixture("update") Cls.prototype[external.elementDidUpdate] = jest.fn() getElement("update").testProp = true expect(Cls.prototype[external.elementDidUpdate]).toBeCalled() }) - // whyyyyy - // eslint-disable-next-line jest/no-disabled-tests - it.skip("calls elementDidUpdate if property updates in elementDidMount", async () => { - const [init, Cls] = lifecycleFixture("mount-update", true) - Cls.prototype[external.elementDidUpdate] = jest.fn() + it("calls elementDidUpdate if property updates in elementDidMount", async () => { + const [init, Cls] = createLifecycleFixture("mount-update", true) Cls.prototype[external.elementDidMount] = () => { getElement("mount-update").testProp = true } - // Cls.prototype[external.elementDidMount] = () => { - // console.log("Mounted!") - // getElement("mount-update").testProp = true - // } - // Cls.prototype[external.elementDidUpdate] = () => { - // console.log("Updated!") - // } + Cls.prototype[external.elementDidUpdate] = jest.fn() init() expect(Cls.prototype[external.elementDidUpdate]).toBeCalled() }) it("calls elementDidConnect", () => { - const [init, Cls] = lifecycleFixture("connect", true) + const [init, Cls] = createLifecycleFixture("connect", true) Cls.prototype[external.elementDidConnect] = jest.fn() init() expect(Cls.prototype[external.elementDidConnect]).toBeCalled() }) it("calls elementDidMount", () => { - const [init, Cls] = lifecycleFixture("mount", true) + const [init, Cls] = createLifecycleFixture("mount", true) Cls.prototype[external.elementDidMount] = jest.fn() init() expect(Cls.prototype[external.elementDidMount]).toBeCalled() }) it("calls elementWillUnmount", () => { - const Cls = lifecycleFixture("unmount") + const Cls = createLifecycleFixture("unmount") Cls.prototype[external.elementWillUnmount] = jest.fn() document.body.removeChild(getElement("unmount")) expect(Cls.prototype[external.elementWillUnmount]).toBeCalled() }) it("recalls elementDidMount if the component is disconnected and then reconnected", async () => { - const [init, Cls] = lifecycleFixture("remount", true) + const [init, Cls] = createLifecycleFixture("remount", true) Cls.prototype[external.elementDidMount] = jest.fn() init() const fixture = getElement("remount") diff --git a/src/internal.js b/src/internal.js index 0e1ba4f..5028f20 100644 --- a/src/internal.js +++ b/src/internal.js @@ -16,6 +16,6 @@ export const runLifecycle = Symbol("#runLifecycle") export const performUpgrade = Symbol("#performUpgrade") export const upgradeProperty = Symbol("#upgradeProperty") export const renderStyles = Symbol("#renderStyles") -export const getInitialRenderState = Symbol("#getInitialRenderState") -export const getNextRenderState = Symbol("#getNextRenderState") +export const setInitialRenderState = Symbol("#setInitialRenderState") +export const setNextRenderState = Symbol("#setNextRenderState") export const renderDOM = Symbol("#renderDOM") diff --git a/src/upgraded-element.js b/src/upgraded-element.js index cbe4104..4343317 100644 --- a/src/upgraded-element.js +++ b/src/upgraded-element.js @@ -220,18 +220,17 @@ export class UpgradedElement extends HTMLElement { * Create a virtual DOM from the external `render` method and patch * it into the shadow root. Triggers `elementDidMount`, if defined. */ - [internal.getInitialRenderState]() { + [internal.setInitialRenderState]() { this[internal.vDOM] = this[internal.getVDOM]() render(this[internal.vDOM], this[internal.shadowRoot]) this[internal.runLifecycle](external.elementDidMount) - this[internal.isFirstRender] = false } /** * All renders after initial render: * Create a new vdom and patch the existing one. */ - [internal.getNextRenderState]() { + [internal.setNextRenderState]() { let nextVDOM = this[internal.getVDOM]() patch(nextVDOM, this[internal.vDOM]) this[internal.runLifecycle](external.elementDidUpdate) @@ -242,8 +241,11 @@ export class UpgradedElement extends HTMLElement { * Runs either a new render or diffs the existing virtual DOM to a new one. */ [internal.renderDOM]() { - return this[internal.isFirstRender] - ? this[internal.getInitialRenderState]() - : this[internal.getNextRenderState]() + if (this[internal.isFirstRender]) { + this[internal.isFirstRender] = false + this[internal.setInitialRenderState]() + } else { + this[internal.setNextRenderState]() + } } } From 654415ef47d75f9b02fbf5131af3ff16d431077b Mon Sep 17 00:00:00 2001 From: George Treviranus Date: Sat, 15 May 2021 13:33:38 -0700 Subject: [PATCH 2/3] 0.6.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24aa155..6ee46ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "upgraded-element", - "version": "0.6.2", + "version": "0.6.3", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.6.2", + "version": "0.6.3", "license": "MIT", "dependencies": { "omdomdom": "^0.2.0" diff --git a/package.json b/package.json index 64b2cd1..14d0b15 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "upgraded-element", - "version": "0.6.2", + "version": "0.6.3", "description": "A simple base class for using Web Components", "main": "lib/upgraded-element.cjs.min.js", "module": "lib/upgraded-element.es.min.js", From 06f35c6eda9e21cc5119c20b892461375dc21703 Mon Sep 17 00:00:00 2001 From: George Treviranus Date: Sat, 15 May 2021 13:33:42 -0700 Subject: [PATCH 3/3] [npm publish] update metadata & cdn tags --- README.md | 8 ++++---- demo/index.html | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b4b6619..678ed5c 100644 --- a/README.md +++ b/README.md @@ -44,16 +44,16 @@ $ yarn i upgraded-element ``` diff --git a/demo/index.html b/demo/index.html index 63e88bf..8cd8b64 100644 --- a/demo/index.html +++ b/demo/index.html @@ -38,15 +38,15 @@