@sitecore-feaas/clientside 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/build/components/FEAASComponent.js +69 -9
- package/build/components/FEAASComponent.js.map +1 -1
- package/build/components/FEAASElement.js +3 -0
- package/build/components/FEAASElement.js.map +1 -1
- package/build/ui/FEAAS.js +5 -0
- package/build/ui/FEAAS.js.map +1 -0
- package/build/ui/FEAASContext.js +9 -6
- package/build/ui/FEAASContext.js.map +1 -1
- package/build/ui/FEAASExternal.js +66 -4
- package/build/ui/FEAASExternal.js.map +1 -1
- package/build/ui/FEAASPicker.js +4 -0
- package/build/ui/FEAASPicker.js.map +1 -1
- package/build/ui/index.js +3 -4
- package/build/ui/index.js.map +1 -1
- package/build/ui/react.js.map +1 -1
- package/build/utils/fetch.js +26 -0
- package/build/utils/fetch.js.map +1 -0
- package/dist/browser/headless.cjs +6 -6
- package/dist/browser/headless.cjs.map +4 -4
- package/dist/browser/headless.esm.js +6 -6
- package/dist/browser/headless.esm.js.map +1 -1
- package/dist/browser/index.cjs +6 -6
- package/dist/browser/index.cjs.map +4 -4
- package/dist/browser/index.esm.js +6 -6
- package/dist/browser/index.esm.js.map +1 -1
- package/dist/browser/react.cjs +6 -6
- package/dist/browser/react.cjs.map +4 -4
- package/dist/browser/react.esm.js +6 -6
- package/dist/browser/react.esm.js.map +1 -1
- package/dist/node/headless.cjs +4 -4
- package/dist/node/headless.cjs.map +4 -4
- package/dist/node/headless.esm.js +4 -4
- package/dist/node/headless.esm.js.map +4 -4
- package/dist/node/index.cjs +4 -4
- package/dist/node/index.cjs.map +4 -4
- package/dist/node/index.esm.js +4 -4
- package/dist/node/index.esm.js.map +4 -4
- package/dist/node/react.cjs +4 -4
- package/dist/node/react.cjs.map +4 -4
- package/dist/node/react.esm.js +4 -4
- package/dist/node/react.esm.js.map +4 -4
- package/headless.cjs +4 -4
- package/headless.cjs.map +4 -4
- package/headless.js +4 -4
- package/headless.js.map +4 -4
- package/package.json +2 -2
- package/react.cjs +6 -6
- package/react.cjs.map +4 -4
- package/react.js +6 -6
- package/react.js.map +4 -4
- package/scripts/build.js +1 -1
- package/src/components/FEAASComponent.tsx +92 -8
- package/src/components/FEAASElement.tsx +13 -0
- package/src/ui/FEAAS.tsx +4 -0
- package/src/ui/FEAASContext.tsx +10 -1
- package/src/ui/FEAASExternal.tsx +73 -16
- package/src/ui/FEAASPicker.tsx +5 -2
- package/src/ui/index.ts +4 -4
- package/src/ui/react.tsx +5 -0
- package/src/utils/fetch.ts +44 -0
- package/test/FEAASComponent.test.tsx +1 -0
- package/test/FEAASComponent2.test.tsx +215 -0
- package/test/FEAASContext.test.tsx +3 -3
- package/test/FEAASExternal.test.tsx +1 -8
- package/test/fetch-data.ts +55 -0
- package/types/components/FEAASComponent.d.ts +30 -0
- package/types/components/FEAASComponent.d.ts.map +1 -1
- package/types/components/FEAASElement.d.ts +9 -1
- package/types/components/FEAASElement.d.ts.map +1 -1
- package/types/tsbuildinfo +1 -1
- package/types/ui/FEAAS.d.ts +5 -0
- package/types/ui/FEAAS.d.ts.map +1 -0
- package/types/ui/FEAASContext.d.ts +8 -0
- package/types/ui/FEAASContext.d.ts.map +1 -1
- package/types/ui/FEAASExternal.d.ts +54 -3
- package/types/ui/FEAASExternal.d.ts.map +1 -1
- package/types/ui/FEAASPicker.d.ts +4 -3
- package/types/ui/FEAASPicker.d.ts.map +1 -1
- package/types/ui/index.d.ts +1 -4
- package/types/ui/index.d.ts.map +1 -1
- package/types/ui/react.d.ts.map +1 -1
- package/types/ui/tsbuildinfo +1 -1
- package/types/utils/fetch.d.ts +9 -0
- package/types/utils/fetch.d.ts.map +1 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { FEAASComponent } from '../src/components/FEAASComponent.js'
|
|
3
|
+
import { clearFetchCache } from '../src/fetch.js'
|
|
4
|
+
|
|
5
|
+
const earliest = new Date(2000, 1, 1, 0, 0, 0)
|
|
6
|
+
const earlier = new Date(2000, 1, 2, 0, 0, 0)
|
|
7
|
+
const now = new Date(2000, 1, 2, 12, 0, 0)
|
|
8
|
+
|
|
9
|
+
describe('FEAAS component data', () => {
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
vi.setSystemTime(now)
|
|
12
|
+
FEAASComponent.register('feaas-component')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
document.write()
|
|
17
|
+
clearFetchCache()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const checkRaceCondition = async (promises: { promise: Promise<any>; name: string }[]) => {
|
|
21
|
+
const resolved: { promise: Promise<any>; name: string }[] = []
|
|
22
|
+
await Promise.all(
|
|
23
|
+
promises.map(async (p) => {
|
|
24
|
+
await p.promise
|
|
25
|
+
resolved.push(p)
|
|
26
|
+
})
|
|
27
|
+
)
|
|
28
|
+
expect(resolved.map(({ name }) => name)).to.eql(promises.map(({ name }) => name))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const staleCacheSpy = (dataDelay = 100, htmlDelay = 100, stylesDelay = 100) => {
|
|
32
|
+
return vi
|
|
33
|
+
.spyOn(global, 'fetch')
|
|
34
|
+
.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
|
|
35
|
+
if (url.includes('.css')) {
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, stylesDelay))
|
|
37
|
+
return new Response('YESTERDAY {}', {
|
|
38
|
+
headers: {
|
|
39
|
+
date: now.toUTCString(),
|
|
40
|
+
'last-modified': earliest.toUTCString()
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (url.includes('CDN')) {
|
|
46
|
+
await new Promise((resolve) => setTimeout(resolve, htmlDelay))
|
|
47
|
+
return new Response('C', {
|
|
48
|
+
headers: {
|
|
49
|
+
date: now.toUTCString(),
|
|
50
|
+
'last-modified': earlier.toUTCString()
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (url === 'http://my-url') {
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, dataDelay))
|
|
57
|
+
return new Response(JSON.stringify({ text: 'My new text' }), {})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (url === 'http://my-url2') {
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, dataDelay))
|
|
62
|
+
return new Response(JSON.stringify({ text: 'My new text2' }), {})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, htmlDelay))
|
|
66
|
+
return new Response('C', {
|
|
67
|
+
headers: {
|
|
68
|
+
date: now.toUTCString(),
|
|
69
|
+
'last-modified': earlier.toUTCString()
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe('Should render component using stale cache, no data initially, then data as object', async () => {
|
|
76
|
+
const runWithDelay = async (delays: number[]) => {
|
|
77
|
+
const spy = staleCacheSpy(delays[0], delays[1], delays[2])
|
|
78
|
+
document.body.innerHTML = `<feaas-component data-path="text" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>`
|
|
79
|
+
const component = document.body.firstElementChild as FEAASComponent
|
|
80
|
+
const updateCall = vi.spyOn(component, 'update')
|
|
81
|
+
await expect(component.whenDataReady).resolves.toEqual({})
|
|
82
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
83
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
84
|
+
expect(component.readyData).toEqual({})
|
|
85
|
+
expect(component.innerHTML).toEqual('C')
|
|
86
|
+
expect(spy).toHaveBeenCalledTimes(2)
|
|
87
|
+
await checkRaceCondition([
|
|
88
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
89
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
90
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
91
|
+
])
|
|
92
|
+
expect(updateCall).toHaveBeenCalledTimes(1)
|
|
93
|
+
component.setAttribute('data', '{"text": "this is text"}')
|
|
94
|
+
await expect(component.whenDataReady).resolves.toEqual({ text: 'this is text' })
|
|
95
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
96
|
+
expect(updateCall).toHaveBeenCalledTimes(2)
|
|
97
|
+
expect(component.innerHTML).toEqual('this is text')
|
|
98
|
+
expect(component.readyData).toEqual({ text: 'this is text' })
|
|
99
|
+
expect(spy).toHaveBeenCalledTimes(2)
|
|
100
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
101
|
+
await checkRaceCondition([
|
|
102
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
103
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
104
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
105
|
+
])
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
it('DATA -> HTML -> STYLESHEET', async () => await runWithDelay([100, 200, 300]))
|
|
109
|
+
it('DATA -> STYLESHEET -> HTML', async () => await runWithDelay([100, 300, 200]))
|
|
110
|
+
it('HTML -> DATA -> STYLESHEET', async () => await runWithDelay([200, 100, 300]))
|
|
111
|
+
it('STYLESHEET -> DATA -> HTML', async () => await runWithDelay([200, 300, 100]))
|
|
112
|
+
it('HTML -> STYLESHEET -> DATA', async () => await runWithDelay([300, 100, 200]))
|
|
113
|
+
it('STYLESHEET -> HTML -> DATA', async () => await runWithDelay([300, 200, 100]))
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe('Should render component using stale cache and data as object first, then settings', () => {
|
|
117
|
+
const runWithDelay = async (delays: number[]) => {
|
|
118
|
+
const spy = staleCacheSpy(delays[0], delays[1], delays[2])
|
|
119
|
+
document.body.innerHTML = `<feaas-component data='{"text": "this is text"}' data-path="text" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>`
|
|
120
|
+
const component = document.body.firstElementChild as FEAASComponent
|
|
121
|
+
const updateCall = vi.spyOn(component, 'update')
|
|
122
|
+
await expect(component.whenDataReady).resolves.toEqual({ text: 'this is text' })
|
|
123
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
124
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
125
|
+
expect(component.readyData).toEqual({ text: 'this is text' })
|
|
126
|
+
expect(component.innerHTML).toEqual('this is text')
|
|
127
|
+
expect(spy).toHaveBeenCalledTimes(2)
|
|
128
|
+
await checkRaceCondition([
|
|
129
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
130
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
131
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
132
|
+
])
|
|
133
|
+
expect(updateCall).toHaveBeenCalledTimes(1)
|
|
134
|
+
component.setAttribute('data', '{"jsonpath": "$", "url": "http://my-url"}')
|
|
135
|
+
await expect(component.whenDataReady).resolves.toEqual({ text: 'My new text' })
|
|
136
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
137
|
+
expect(updateCall).toHaveBeenCalledTimes(2)
|
|
138
|
+
expect(component.innerHTML).toEqual('My new text')
|
|
139
|
+
expect(component.readyData).toEqual({ text: 'My new text' })
|
|
140
|
+
expect(spy).toHaveBeenCalledTimes(3)
|
|
141
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
142
|
+
await checkRaceCondition([
|
|
143
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
144
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
145
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
146
|
+
])
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
it('DATA -> HTML -> STYLESHEET', async () => await runWithDelay([100, 200, 300]))
|
|
150
|
+
it('DATA -> STYLESHEET -> HTML', async () => await runWithDelay([100, 300, 200]))
|
|
151
|
+
it('HTML -> DATA -> STYLESHEET', async () => await runWithDelay([200, 100, 300]))
|
|
152
|
+
it('STYLESHEET -> DATA -> HTML', async () => await runWithDelay([200, 300, 100]))
|
|
153
|
+
it('HTML -> STYLESHEET -> DATA', async () => await runWithDelay([300, 100, 200]))
|
|
154
|
+
it('STYLESHEET -> HTML -> DATA', async () => await runWithDelay([300, 200, 100]))
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('Should render component using stale cache and data as settings', () => {
|
|
158
|
+
const runWithDelay = async (delays: number[]) => {
|
|
159
|
+
const spy = staleCacheSpy(delays[0], delays[1], delays[2])
|
|
160
|
+
document.body.innerHTML = `<feaas-component data='{ "jsonpath": "$", "url": "http://my-url" }' data-path="text" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>`
|
|
161
|
+
const component = document.body.firstElementChild as FEAASComponent
|
|
162
|
+
const updateCall = vi.spyOn(component, 'update')
|
|
163
|
+
await expect(component.whenDataReady).resolves.toEqual({ text: 'My new text' })
|
|
164
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
165
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
166
|
+
expect(component.readyData).toEqual({ text: 'My new text' })
|
|
167
|
+
expect(component.innerHTML).toEqual('My new text')
|
|
168
|
+
expect(spy).toHaveBeenCalledTimes(3)
|
|
169
|
+
await checkRaceCondition([
|
|
170
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
171
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
172
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
173
|
+
])
|
|
174
|
+
expect(updateCall).toHaveBeenCalledTimes(1)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
it('DATA -> HTML -> STYLESHEET', async () => await runWithDelay([100, 200, 300]))
|
|
178
|
+
it('DATA -> STYLESHEET -> HTML', async () => await runWithDelay([100, 300, 200]))
|
|
179
|
+
it('HTML -> DATA -> STYLESHEET', async () => await runWithDelay([200, 100, 300]))
|
|
180
|
+
it('STYLESHEET -> DATA -> HTML', async () => await runWithDelay([200, 300, 100]))
|
|
181
|
+
it('HTML -> STYLESHEET -> DATA', async () => await runWithDelay([300, 100, 200]))
|
|
182
|
+
it('STYLESHEET -> HTML -> DATA', async () => await runWithDelay([300, 200, 100]))
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
describe('Should render component using stale cache and data as mapping', () => {
|
|
186
|
+
const runWithDelay = async (delays: number[]) => {
|
|
187
|
+
const spy = staleCacheSpy(delays[0], delays[1], delays[2])
|
|
188
|
+
document.body.innerHTML = `<feaas-component data='{ "datasource-1": {"jsonpath": "$", "url": "http://my-url"}, "datasource-2": {"jsonpath": "$", "url": "http://my-url2"} }' data-path="datasource-2.text" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>`
|
|
189
|
+
const component = document.body.firstElementChild as FEAASComponent
|
|
190
|
+
const updateCall = vi.spyOn(component, 'update')
|
|
191
|
+
await expect(component.whenDataReady).resolves.toEqual({ 'datasource-1': { text: 'My new text' }, 'datasource-2': { text: 'My new text2' } })
|
|
192
|
+
await expect(component.whenRendered).resolves.toEqual(component)
|
|
193
|
+
await expect(component.whenLoaded).resolves.toBeTruthy()
|
|
194
|
+
expect(component.readyData).toEqual({ 'datasource-1': { text: 'My new text' }, 'datasource-2': { text: 'My new text2' } })
|
|
195
|
+
expect(component.innerHTML).toEqual('My new text2')
|
|
196
|
+
expect(spy).toHaveBeenCalledTimes(4)
|
|
197
|
+
await checkRaceCondition([
|
|
198
|
+
{ promise: component.whenDataReady, name: 'when data ready' },
|
|
199
|
+
{ promise: component.whenRendered, name: 'when rendered' },
|
|
200
|
+
{ promise: component.whenLoaded, name: 'when loaded' }
|
|
201
|
+
])
|
|
202
|
+
expect(updateCall).toHaveBeenCalledTimes(1)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
it('DATA -> HTML -> STYLESHEET', async () => await runWithDelay([100, 200, 300]))
|
|
206
|
+
it('DATA -> STYLESHEET -> HTML', async () => await runWithDelay([100, 300, 200]))
|
|
207
|
+
it('HTML -> DATA -> STYLESHEET', async () => await runWithDelay([200, 100, 300]))
|
|
208
|
+
it('STYLESHEET -> DATA -> HTML', async () => await runWithDelay([200, 300, 100]))
|
|
209
|
+
it('HTML -> STYLESHEET -> DATA', async () => await runWithDelay([300, 100, 200]))
|
|
210
|
+
it('STYLESHEET -> HTML -> DATA', async () => await runWithDelay([300, 200, 100]))
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
// TODO
|
|
214
|
+
it.skip('Should render component using non-stale cache and data as settings', async () => {})
|
|
215
|
+
})
|
|
@@ -40,7 +40,7 @@ describe('React', function () {
|
|
|
40
40
|
expect(spyLoad).toHaveBeenCalledTimes(1)
|
|
41
41
|
|
|
42
42
|
expect(component.outerHTML).toBe(
|
|
43
|
-
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net"><div><p>Context abc</p></div></feaas-context>'
|
|
43
|
+
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net" feaas-role="ui"><div><p>Context abc</p></div></feaas-context>'
|
|
44
44
|
)
|
|
45
45
|
})
|
|
46
46
|
it('should initiate loading without isolation', async () => {
|
|
@@ -71,7 +71,7 @@ describe('React', function () {
|
|
|
71
71
|
expect(spyLoad).toHaveBeenCalledTimes(1)
|
|
72
72
|
|
|
73
73
|
expect(component.outerHTML).toBe(
|
|
74
|
-
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net"><div><p>Context abc</p></div></feaas-context>'
|
|
74
|
+
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net" feaas-role="ui"><div><p>Context abc</p></div></feaas-context>'
|
|
75
75
|
)
|
|
76
76
|
})
|
|
77
77
|
it('should initiate loading with isolation', async () => {
|
|
@@ -102,7 +102,7 @@ describe('React', function () {
|
|
|
102
102
|
expect(spyLoad).toHaveBeenCalledTimes(1)
|
|
103
103
|
|
|
104
104
|
expect(component.outerHTML).toBe(
|
|
105
|
-
'<feaas-context src="test.js" library="abc" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net"></feaas-context>'
|
|
105
|
+
'<feaas-context src="test.js" library="abc" frontend="https://components.sitecorecloud.io" backend="https://components.sitecorecloud.io/api" cdn="https://feaas.blob.core.windows.net" feaas-role="ui"></feaas-context>'
|
|
106
106
|
)
|
|
107
107
|
expect(component.shadowRoot.innerHTML).toBe('<div><p>Context abc</p></div>')
|
|
108
108
|
})
|
|
@@ -37,6 +37,7 @@ describe('External', () => {
|
|
|
37
37
|
)
|
|
38
38
|
}
|
|
39
39
|
const typesComponentSchema = {
|
|
40
|
+
name: 'TypesComponent',
|
|
40
41
|
properties: {
|
|
41
42
|
stringProp: {
|
|
42
43
|
type: 'string'
|
|
@@ -66,14 +67,6 @@ describe('External', () => {
|
|
|
66
67
|
await expect(component.whenRendered).resolves.toEqual(component)
|
|
67
68
|
expect(component.innerHTML).toEqual('<div>Hello my name is Chuck and my tel is 45657890875643</div>')
|
|
68
69
|
})
|
|
69
|
-
it('can take functional component name as id', async () => {
|
|
70
|
-
Clientside.External.registerComponent(Hello)
|
|
71
|
-
document.body.innerHTML =
|
|
72
|
-
'<feaas-external id="external-component" class="-component" data-attributes-keys="first-name,telephone" first-name="Chuck" telephone="45657890875643" data-attributes="{"first-name":"Chuck","telephone":"45657890875643"}" data-external-id="Hello" contenteditable="false"></feaas-external>'
|
|
73
|
-
const component = document.getElementById('external-component') as FEAASExternal
|
|
74
|
-
await expect(component.whenRendered).resolves.toEqual(component)
|
|
75
|
-
expect(component.innerHTML).toEqual('<div>Hello my name is Chuck and my tel is 45657890875643</div>')
|
|
76
|
-
})
|
|
77
70
|
it('should return empty if component is not registered', async () => {
|
|
78
71
|
document.body.innerHTML =
|
|
79
72
|
'<feaas-external id="external-component" class="-component" data-external-id="NotRegisteredComponent" contenteditable="false"></feaas-external>'
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { vi, describe, it, expect } from 'vitest'
|
|
2
|
+
import { fetchData } from '../src/utils/fetch.js'
|
|
3
|
+
|
|
4
|
+
describe('Fetches data', () => {
|
|
5
|
+
it('fetches when passed data object', async () => {
|
|
6
|
+
const result = await fetchData({ hello: 'world' })
|
|
7
|
+
|
|
8
|
+
expect(result).toEqual({ hello: 'world' })
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('fetches when passed settings object', async () => {
|
|
12
|
+
const spy = vi.spyOn(global, 'fetch')
|
|
13
|
+
spy.mockImplementation(
|
|
14
|
+
async (url: string, options?: Parameters<typeof fetch>[1]) =>
|
|
15
|
+
new Response(JSON.stringify({ data: 'My data' }), {})
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const result = await fetchData({ jsonpath: '$', url: 'http://my-url' })
|
|
19
|
+
|
|
20
|
+
expect(result).toEqual({ data: 'My data' })
|
|
21
|
+
|
|
22
|
+
expect(spy).toHaveBeenCalledOnce()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('fetches when passed mapping object', async () => {
|
|
26
|
+
const spy = vi.spyOn(global, 'fetch')
|
|
27
|
+
spy.mockImplementation(async (url: string, options?: Parameters<typeof fetch>[1]) => {
|
|
28
|
+
if (url === 'http://my-url1') return new Response(JSON.stringify({ data: 'My data1' }), {})
|
|
29
|
+
if (url === 'http://my-url2') return new Response(JSON.stringify({ data: 'My data2' }), {})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const inputData = {
|
|
33
|
+
datasourceId1: { jsonpath: '$', url: 'http://my-url1' },
|
|
34
|
+
datasourceId2: { data: 'This is plain data' },
|
|
35
|
+
datasourceId3: { jsonpath: '$', url: 'http://my-url2' },
|
|
36
|
+
datasourceId4: { jsonpath: '$', url: 'http://bad-url' }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const result = await fetchData(inputData)
|
|
40
|
+
|
|
41
|
+
expect(result).to.have.property('datasourceId1')
|
|
42
|
+
expect((result as Record<keyof typeof inputData, any>).datasourceId1).toEqual({ data: 'My data1' })
|
|
43
|
+
|
|
44
|
+
expect(result).to.have.property('datasourceId2')
|
|
45
|
+
expect((result as Record<keyof typeof inputData, any>).datasourceId2).toEqual({ data: 'This is plain data' })
|
|
46
|
+
|
|
47
|
+
expect(result).to.have.property('datasourceId3')
|
|
48
|
+
expect((result as Record<keyof typeof inputData, any>).datasourceId3).toEqual({ data: 'My data2' })
|
|
49
|
+
|
|
50
|
+
expect(result).to.have.property('datasourceId4')
|
|
51
|
+
expect((result as Record<keyof typeof inputData, any>).datasourceId4).toEqual({})
|
|
52
|
+
|
|
53
|
+
expect(spy).toHaveBeenCalledTimes(3)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ControlledPromise } from '../utils/promise.js';
|
|
1
2
|
import { FEAASElement } from './FEAASElement.js';
|
|
2
3
|
export declare function FEAASComponentsProps(element: FEAASElement): {
|
|
3
4
|
data: any;
|
|
@@ -15,7 +16,33 @@ export declare function FEAASComponentsProps(element: FEAASElement): {
|
|
|
15
16
|
withStylesheet: boolean;
|
|
16
17
|
};
|
|
17
18
|
export type FEAASComponentsProps = ReturnType<typeof FEAASComponentsProps>;
|
|
19
|
+
/**
|
|
20
|
+
* - Initialization lifecycle:
|
|
21
|
+
* - - `set(props)`
|
|
22
|
+
* - - `scheduleRender()` - any attribute change causes render to schedule to next frame
|
|
23
|
+
* - - `whenRendered.restart()` - rendering promise is reset and will resolve after render
|
|
24
|
+
* - - `advance()` - called on next frame
|
|
25
|
+
* - - `if (isReadyToLoad()) => boolean` - check if component has all necessary properties to load
|
|
26
|
+
* - - `load() => payload` => component is loaded
|
|
27
|
+
* - - `onLoad?(payload)` => invoke loaded callback for cached version of a component
|
|
28
|
+
* - - `advance()` => going further in state machine
|
|
29
|
+
* - - `flush()` => flushes all react changes if needed
|
|
30
|
+
* - - `update()` => component-specific method (or react) to render changes to dom
|
|
31
|
+
* - - `render(payload, props)` => render means react
|
|
32
|
+
* - - `whenRendered.resolve()` - rendering promise is resolved after rendering
|
|
33
|
+
* - - IF CACHE WAS STALE - FETCH AND RENDER AGAIN
|
|
34
|
+
* - - `fetchByPassingCache()` - load up-to-date version of a component
|
|
35
|
+
* - - `onLoad(newPayload) `
|
|
36
|
+
* - - `advance()` => going further in state machine
|
|
37
|
+
* - - `flush()` => flushes all react changes if needed
|
|
38
|
+
* - - `update()` => component-specific method (or react) to render changes to dom
|
|
39
|
+
* - - `render(payload, props)` => render means react
|
|
40
|
+
* - - `whenRendered.resolve()` - rendering promise is resolved after rendering
|
|
41
|
+
* - - `whenLoaded.resolved()` - resolved after loading of up to date component
|
|
42
|
+
*/
|
|
18
43
|
export declare class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
|
|
44
|
+
readyData: any;
|
|
45
|
+
whenDataReady: ControlledPromise<any>;
|
|
19
46
|
static observedAttributes: string[];
|
|
20
47
|
defaultProps: Partial<{
|
|
21
48
|
data: any;
|
|
@@ -50,6 +77,7 @@ export declare class FEAASComponent extends FEAASElement<FEAASComponentsProps, s
|
|
|
50
77
|
withStylesheet: boolean;
|
|
51
78
|
};
|
|
52
79
|
attributeChangedCallback(name: string, oldValue: string, newValue: string): void;
|
|
80
|
+
fetchData(): Promise<void>;
|
|
53
81
|
getEditor(): any;
|
|
54
82
|
constructor();
|
|
55
83
|
edit(): boolean;
|
|
@@ -57,6 +85,8 @@ export declare class FEAASComponent extends FEAASElement<FEAASComponentsProps, s
|
|
|
57
85
|
isReadyToLoad(): boolean;
|
|
58
86
|
onLoad: (html: string) => void;
|
|
59
87
|
load(): Promise<string>;
|
|
88
|
+
alreadyRendered: boolean;
|
|
89
|
+
flush(): void;
|
|
60
90
|
update(): void;
|
|
61
91
|
}
|
|
62
92
|
declare global {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FEAASComponent.d.ts","sourceRoot":"","sources":["../../src/components/FEAASComponent.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY;;;;;;;;;;;;;;EA6BzD;
|
|
1
|
+
{"version":3,"file":"FEAASComponent.d.ts","sourceRoot":"","sources":["../../src/components/FEAASComponent.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY;;;;;;;;;;;;;;EA6BzD;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAE1E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,cAAe,SAAQ,YAAY,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAC5E,SAAS,EAAE,GAAG,CAAK;IACnB,aAAa,yBAGZ;IAED,MAAM,CAAC,kBAAkB,WAYxB;IAED,YAAY;;;;;;;;;;;;;;OAOsB;IAElC,YAAY,EAAE,OAAO,CAAA;IAErB,OAAO,CAAC,IAAI,EAAE,GAAG;IAIjB,QAAQ;;;;;;;;;;;;;;;IAIR,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAkB1E,SAAS;IAcf,SAAS,IAAI,GAAG;;IAkBhB,IAAI;IASJ,WAAW;IAaX,aAAa;IAMb,MAAM,SAAU,MAAM,UAGrB;IAEK,IAAI;IAkCV,eAAe,EAAE,OAAO,CAAA;IAExB,KAAK;IAML,MAAM;CAcP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,GAAG,CAAC;QACZ,UAAU,iBAAiB;YACzB,iBAAiB,EAAE;gBACjB,IAAI,CAAC,EAAE,GAAG,CAAA;gBACV,QAAQ,CAAC,EAAE,MAAM,CAAA;gBACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;gBACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;gBAClB,QAAQ,CAAC,EAAE,GAAG,CAAA;gBACd,uBAAuB,CAAC,EAAE;oBAAE,MAAM,EAAE,MAAM,CAAA;iBAAE,CAAA;gBAC5C,eAAe,CAAC,EAAE,MAAM,CAAA;gBACxB,iBAAiB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,EAAE,CAAA;aAC1C,GAAG,CACA;gBACE,kCAAkC;gBAClC,QAAQ,CAAC,EAAE,MAAM,CAAA;gBACjB,GAAG,CAAC,EAAE,MAAM,CAAA;gBACZ,OAAO,EAAE,MAAM,CAAA;gBACf,SAAS,EAAE,MAAM,CAAA;gBACjB,OAAO,CAAC,EAAE,MAAM,CAAA;gBAChB,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAA;aAC5C,GACD;gBAAE,GAAG,EAAE,MAAM,CAAA;aAAE,GACf;gBAAE,QAAQ,EAAE,MAAM,CAAA;aAAE,CACvB,CAAA;SACF;KACF;CACF;AAGD,OAAO,EAAE,cAAc,IAAI,SAAS,EAAE,oBAAoB,IAAI,cAAc,EAAE,CAAA"}
|
|
@@ -13,6 +13,14 @@ export interface ReactPayload {
|
|
|
13
13
|
ReactDOM: typeof ReactDOM;
|
|
14
14
|
ReactDOMClient: typeof ReactDOMClient;
|
|
15
15
|
}
|
|
16
|
+
declare global {
|
|
17
|
+
interface DocumentEventMap {
|
|
18
|
+
feaasMount: Event;
|
|
19
|
+
feaasUnmount: Event;
|
|
20
|
+
feaasLoad: Event;
|
|
21
|
+
feaasError: CustomEvent<Error>;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
16
24
|
/**
|
|
17
25
|
* FEAASElement is a superclass for FEAAS components with optional react support.
|
|
18
26
|
*
|
|
@@ -69,7 +77,7 @@ export declare class FEAASElement<Props = any, Payload = any> extends WebCompone
|
|
|
69
77
|
log(...args: any): void;
|
|
70
78
|
/** Nothing special happens on unmount, except setting a flag */
|
|
71
79
|
unmount(): void;
|
|
72
|
-
getParent(onlyFeaas?: boolean):
|
|
80
|
+
getParent(onlyFeaas?: boolean): Element;
|
|
73
81
|
getElements(root?: HTMLElement | ShadowRoot, onlyFeaas?: boolean): HTMLElement[];
|
|
74
82
|
/** Catch-all event handler that dispatches events to callback */
|
|
75
83
|
handleEvent(event: Event): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FEAASElement.d.ts","sourceRoot":"","sources":["../../src/components/FEAASElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAyB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAC3E,OAAO,KAAK,cAAc,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,QAAQ,MAAM,WAAW,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AAGnF,QAAA,IAAI,YAAY;;;CAOC,CAAA;AAEjB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,KAAK,CAAA;IACnB,QAAQ,EAAE,OAAO,QAAQ,CAAA;IACzB,cAAc,EAAE,OAAO,cAAc,CAAA;CACtC;
|
|
1
|
+
{"version":3,"file":"FEAASElement.d.ts","sourceRoot":"","sources":["../../src/components/FEAASElement.tsx"],"names":[],"mappings":"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"}
|