Skip to content

Commit d628fef

Browse files
author
Christopher J Baker
authored
Update Renderer API (#101)
* update react-to-web-component * refactor * fix tests * fix
1 parent f9e5239 commit d628fef

File tree

18 files changed

+407
-693
lines changed

18 files changed

+407
-693
lines changed

.github/actions/test/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ runs:
1111
steps:
1212
- name: Test
1313
shell: bash
14-
run: npx nx test ${{ inputs.package }}
14+
run: npx nx test:ci ${{ inputs.package }}

nx.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"prettier",
1212
"depcheck",
1313
"test",
14+
"test:ci",
15+
"test:coverage",
1416
"clean",
1517
"build"
1618
]

packages/core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
"prettier": "prettier --check vite.config.ts src",
3535
"depcheck": "depcheck .",
3636
"dev": "vite",
37-
"test": "vitest run",
38-
"test:dev": "vitest",
37+
"test": "vitest",
38+
"test:ci": "vitest run",
3939
"test:coverage": "vitest run --coverage",
4040
"clean": "rm -rf tsconfig.tsbuildinfo dist",
4141
"build": "vite build"

packages/core/src/core.test.tsx

Lines changed: 79 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
import { describe, test, it, expect, vi, afterEach } from "vitest"
22
import matchers from "@testing-library/jest-dom/matchers"
3-
import React from "react"
43

54
import r2wc from "./core"
65

76
expect.extend(matchers)
87

9-
const mountCheck = vi.fn()
8+
const mount = vi.fn(() => ({ why: "context" }))
109
const unmount = vi.fn()
1110
const update = vi.fn()
12-
const onUpdated = vi.fn()
13-
14-
const mount = (el: HTMLElement, reactComponent: any, _props: any) => {
15-
mountCheck()
16-
return {
17-
reactContainer: el,
18-
component: reactComponent,
19-
}
20-
}
2111

22-
function flushPromises() {
12+
function wait() {
2313
return new Promise((resolve) => setImmediate(resolve))
2414
}
2515

@@ -28,40 +18,62 @@ describe("core", () => {
2818
document.body.innerHTML = ""
2919
})
3020

31-
it("mounts and unmounts for a functional component", async () => {
32-
function TestComponent() {
33-
return <div>hello</div>
34-
}
21+
it("mounts and unmounts in light mode", async () => {
22+
const ReactComponent: React.FC = () => <h1>Hello</h1>
3523

36-
const TestElement = r2wc(TestComponent, {}, { mount, unmount, update })
37-
customElements.define("test-func-element", TestElement)
24+
const WebComponent = r2wc(ReactComponent, {}, { mount, unmount, update })
25+
customElements.define("test-light", WebComponent)
3826

39-
const testEl = new TestElement()
27+
const element = new WebComponent()
4028

41-
document.body.appendChild(testEl)
42-
expect(mountCheck).toBeCalledTimes(1)
29+
document.body.appendChild(element)
30+
expect(mount).toBeCalledTimes(1)
4331

44-
document.body.removeChild(testEl)
32+
document.body.removeChild(element)
4533
expect(unmount).toBeCalledTimes(1)
34+
expect(unmount).toBeCalledWith({ why: "context" })
4635
})
4736

48-
it("mounts and unmounts for a class component", async () => {
49-
class TestComponent extends React.Component {
50-
render() {
51-
return <div>hello</div>
52-
}
53-
}
37+
it("mounts and unmounts in open shadow mode", async () => {
38+
const ReactComponent: React.FC = () => <h1>Hello</h1>
39+
40+
const WebComponent = r2wc(
41+
ReactComponent,
42+
{ shadow: "open" },
43+
{ mount, unmount, update },
44+
)
45+
customElements.define("test-shadow-open", WebComponent)
46+
47+
const element = new WebComponent()
5448

55-
const TestElement = r2wc(TestComponent, {}, { mount, unmount, update })
56-
customElements.define("test-element", TestElement)
49+
document.body.appendChild(element)
50+
expect(element).toHaveProperty("shadowRoot")
51+
expect(mount).toBeCalledTimes(1)
52+
53+
document.body.removeChild(element)
54+
expect(unmount).toBeCalledTimes(1)
55+
expect(unmount).toBeCalledWith({ why: "context" })
56+
})
57+
58+
it("mounts and unmounts in closed shadow mode", async () => {
59+
const ReactComponent: React.FC = () => <h1>Hello</h1>
60+
61+
const WebComponent = r2wc(
62+
ReactComponent,
63+
{ shadow: "closed" },
64+
{ mount, unmount, update },
65+
)
66+
customElements.define("test-shadow-closed", WebComponent)
5767

58-
const testEl = new TestElement()
68+
const element = new WebComponent()
5969

60-
document.body.appendChild(testEl)
61-
expect(mountCheck).toBeCalledTimes(1)
70+
document.body.appendChild(element)
71+
expect(element).toHaveProperty("shadowRoot")
72+
expect(mount).toBeCalledTimes(1)
6273

63-
document.body.removeChild(testEl)
74+
document.body.removeChild(element)
6475
expect(unmount).toBeCalledTimes(1)
76+
expect(unmount).toBeCalledWith({ why: "context" })
6577
})
6678

6779
test("updated attribute updates the component prop and the HTMLElement property", async () => {
@@ -72,7 +84,7 @@ describe("core", () => {
7284
const ButtonElement = r2wc(
7385
Button,
7486
{ props: ["text"] },
75-
{ mount, unmount, update, onUpdated },
87+
{ mount, unmount, update },
7688
)
7789

7890
customElements.define("test-button-element-attribute", ButtonElement)
@@ -81,20 +93,18 @@ describe("core", () => {
8193
body.innerHTML =
8294
"<test-button-element-attribute text='hello'></test-button-element-attribute>"
8395

84-
const testEl = body.querySelector(
96+
const element = body.querySelector(
8597
"test-button-element-attribute",
8698
) as HTMLElement & { text: string }
8799

88-
testEl.setAttribute("text", "world")
100+
element.setAttribute("text", "world")
89101

90-
await flushPromises()
102+
await wait()
91103

92-
expect(onUpdated).toBeCalledTimes(1)
93-
expect(testEl.text).toBe("world")
104+
expect(element.text).toBe("world")
94105
})
95106

96107
test("updated HTMLElement property updates the component prop and the HTMLElement attribute", async () => {
97-
expect.assertions(13)
98108
interface Props {
99109
text: string
100110
numProp: number
@@ -127,7 +137,7 @@ describe("core", () => {
127137
funcProp: "function",
128138
},
129139
},
130-
{ mount, unmount, update, onUpdated },
140+
{ mount, unmount, update },
131141
)
132142

133143
//@ts-ignore
@@ -147,33 +157,32 @@ describe("core", () => {
147157
body.innerHTML = `<test-button-element-property text='hello' obj-prop='{"greeting": "hello, world"}' arr-prop='["hello", "world"]' num-prop='240' bool-prop='true' func-prop='globalFn'>
148158
</test-button-element-property>`
149159

150-
const testEl = body.querySelector(
160+
const element = body.querySelector(
151161
"test-button-element-property",
152162
) as HTMLElement & Props
153163

154-
await flushPromises()
164+
await wait()
155165

156-
expect(testEl.text).toBe("hello")
157-
expect(testEl.numProp).toBe(240)
158-
expect(testEl.boolProp).toBe(true)
159-
expect(testEl.arrProp).toEqual(["hello", "world"])
160-
expect(testEl.objProp).toEqual({ greeting: "hello, world" })
161-
expect(testEl.funcProp).toBeInstanceOf(Function)
162-
expect(testEl.funcProp()).toBe(true)
166+
expect(element.text).toBe("hello")
167+
expect(element.numProp).toBe(240)
168+
expect(element.boolProp).toBe(true)
169+
expect(element.arrProp).toEqual(["hello", "world"])
170+
expect(element.objProp).toEqual({ greeting: "hello, world" })
171+
expect(element.funcProp).toBeInstanceOf(Function)
172+
expect(element.funcProp()).toBe(true)
163173

164-
testEl.text = "world"
165-
testEl.numProp = 100
166-
testEl.boolProp = false
174+
element.text = "world"
175+
element.numProp = 100
176+
element.boolProp = false
167177
//@ts-ignore
168-
testEl.funcProp = global.newFunc
178+
element.funcProp = global.newFunc
169179

170-
await flushPromises()
180+
await wait()
171181

172-
expect(onUpdated).toBeCalledTimes(4)
173-
expect(testEl.getAttribute("text")).toBe("world")
174-
expect(testEl.getAttribute("num-prop")).toBe("100")
175-
expect(testEl.getAttribute("bool-prop")).toBe("false")
176-
expect(testEl.getAttribute("func-prop")).toBe("newFunc")
182+
expect(element.getAttribute("text")).toBe("world")
183+
expect(element.getAttribute("num-prop")).toBe("100")
184+
expect(element.getAttribute("bool-prop")).toBe("false")
185+
expect(element.getAttribute("func-prop")).toBe("newFunc")
177186
})
178187

179188
test("sets HTML property not defined in props but found on HTML object", async () => {
@@ -184,25 +193,25 @@ describe("core", () => {
184193
const ButtonElement = r2wc(
185194
Button,
186195
{ props: ["text"] },
187-
{ mount, unmount, update, onUpdated },
196+
{ mount, unmount, update },
188197
)
189198

190199
customElements.define("test-button-element-non-prop", ButtonElement)
191200

192201
const body = document.body
193202
body.innerHTML = `<test-button-element-non-prop></test-button-element-non-prop>`
194203

195-
const testEl = body.querySelector(
204+
const element = body.querySelector(
196205
"test-button-element-non-prop",
197206
) as HTMLElement & { text: string }
198-
testEl.style.backgroundColor = "red"
199-
testEl.style.visibility = "hidden"
200-
testEl.id = "test-button-id"
207+
element.style.backgroundColor = "red"
208+
element.style.visibility = "hidden"
209+
element.id = "test-button-id"
201210

202-
await flushPromises()
211+
await wait()
203212

204-
expect(testEl).toHaveStyle("background-color: red;")
205-
expect(testEl).not.toBeVisible()
206-
expect(body.querySelector("#test-button-id")).toBe(testEl)
213+
expect(element).toHaveStyle("background-color: red;")
214+
expect(element).not.toBeVisible()
215+
expect(body.querySelector("#test-button-id")).toBe(element)
207216
})
208217
})

0 commit comments

Comments
 (0)