@pyreon/core 0.11.5 → 0.11.6
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 +2 -2
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +33 -5
- package/lib/index.js.map +1 -1
- package/lib/jsx-dev-runtime.js.map +1 -1
- package/lib/jsx-runtime.js.map +1 -1
- package/lib/types/index.d.ts +145 -98
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/jsx-dev-runtime.d.ts +94 -94
- package/lib/types/jsx-runtime.d.ts +94 -94
- package/package.json +11 -11
- package/src/component.ts +2 -2
- package/src/context.ts +75 -4
- package/src/dynamic.ts +4 -4
- package/src/error-boundary.ts +10 -10
- package/src/for.ts +8 -2
- package/src/h.ts +4 -4
- package/src/index.ts +30 -27
- package/src/jsx-dev-runtime.ts +1 -1
- package/src/jsx-runtime.ts +108 -108
- package/src/lazy.ts +4 -4
- package/src/lifecycle.ts +6 -6
- package/src/portal.ts +2 -2
- package/src/show.ts +4 -4
- package/src/style.ts +51 -51
- package/src/suspense.ts +8 -8
- package/src/telemetry.ts +1 -1
- package/src/tests/component.test.ts +60 -60
- package/src/tests/context.test.ts +102 -102
- package/src/tests/core.test.ts +376 -376
- package/src/tests/cx.test.ts +34 -34
- package/src/tests/dynamic.test.ts +28 -28
- package/src/tests/error-boundary.test.ts +51 -51
- package/src/tests/for.test.ts +26 -26
- package/src/tests/h.test.ts +100 -100
- package/src/tests/jsx-compat.test.tsx +41 -41
- package/src/tests/lazy.test.ts +28 -28
- package/src/tests/lifecycle.test.ts +35 -35
- package/src/tests/map-array.test.ts +36 -36
- package/src/tests/portal.test.ts +21 -21
- package/src/tests/props-extended.test.ts +51 -51
- package/src/tests/props.test.ts +62 -62
- package/src/tests/ref.test.ts +20 -20
- package/src/tests/show.test.ts +94 -94
- package/src/tests/style.test.ts +101 -101
- package/src/tests/suspense.test.ts +44 -44
- package/src/tests/telemetry.test.ts +35 -35
package/src/tests/h.test.ts
CHANGED
|
@@ -1,200 +1,200 @@
|
|
|
1
|
-
import { EMPTY_PROPS, Fragment, h } from
|
|
2
|
-
import type { ComponentFn, VNode, VNodeChild } from
|
|
3
|
-
|
|
4
|
-
describe(
|
|
5
|
-
describe(
|
|
6
|
-
test(
|
|
7
|
-
const node = h(
|
|
8
|
-
expect(node.type).toBe(
|
|
1
|
+
import { EMPTY_PROPS, Fragment, h } from '../h'
|
|
2
|
+
import type { ComponentFn, VNode, VNodeChild } from '../types'
|
|
3
|
+
|
|
4
|
+
describe('h() — VNode creation', () => {
|
|
5
|
+
describe('basic element creation', () => {
|
|
6
|
+
test('creates VNode with string tag', () => {
|
|
7
|
+
const node = h('div', null)
|
|
8
|
+
expect(node.type).toBe('div')
|
|
9
9
|
expect(node.props).toBe(EMPTY_PROPS)
|
|
10
10
|
expect(node.children).toEqual([])
|
|
11
11
|
expect(node.key).toBeNull()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
test(
|
|
15
|
-
const node = h(
|
|
16
|
-
expect(node.props.id).toBe(
|
|
17
|
-
expect(node.props.class).toBe(
|
|
14
|
+
test('creates VNode with props', () => {
|
|
15
|
+
const node = h('div', { id: 'main', class: 'container' })
|
|
16
|
+
expect(node.props.id).toBe('main')
|
|
17
|
+
expect(node.props.class).toBe('container')
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
test(
|
|
21
|
-
const node1 = h(
|
|
22
|
-
const node2 = h(
|
|
20
|
+
test('null props becomes EMPTY_PROPS sentinel', () => {
|
|
21
|
+
const node1 = h('div', null)
|
|
22
|
+
const node2 = h('span', null)
|
|
23
23
|
// Both should use the same EMPTY_PROPS object (identity check)
|
|
24
24
|
expect(node1.props).toBe(node2.props)
|
|
25
25
|
expect(node1.props).toBe(EMPTY_PROPS)
|
|
26
26
|
})
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
-
describe(
|
|
30
|
-
test(
|
|
31
|
-
const node = h(
|
|
32
|
-
expect(node.key).toBe(
|
|
29
|
+
describe('key extraction', () => {
|
|
30
|
+
test('extracts string key from props', () => {
|
|
31
|
+
const node = h('li', { key: 'item-1' })
|
|
32
|
+
expect(node.key).toBe('item-1')
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
test(
|
|
36
|
-
const node = h(
|
|
35
|
+
test('extracts numeric key from props', () => {
|
|
36
|
+
const node = h('li', { key: 42 })
|
|
37
37
|
expect(node.key).toBe(42)
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
test(
|
|
41
|
-
const node = h(
|
|
40
|
+
test('key is null when not provided', () => {
|
|
41
|
+
const node = h('div', { class: 'x' })
|
|
42
42
|
expect(node.key).toBeNull()
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
test(
|
|
46
|
-
const node = h(
|
|
45
|
+
test('key is null for null props', () => {
|
|
46
|
+
const node = h('div', null)
|
|
47
47
|
expect(node.key).toBeNull()
|
|
48
48
|
})
|
|
49
49
|
|
|
50
|
-
test(
|
|
51
|
-
const node = h(
|
|
50
|
+
test('key 0 is preserved (falsy but valid)', () => {
|
|
51
|
+
const node = h('li', { key: 0 })
|
|
52
52
|
expect(node.key).toBe(0)
|
|
53
53
|
})
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
describe(
|
|
57
|
-
test(
|
|
58
|
-
const node = h(
|
|
59
|
-
expect(node.children).toEqual([
|
|
56
|
+
describe('children handling', () => {
|
|
57
|
+
test('string children', () => {
|
|
58
|
+
const node = h('p', null, 'hello')
|
|
59
|
+
expect(node.children).toEqual(['hello'])
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
test(
|
|
63
|
-
const node = h(
|
|
64
|
-
expect(node.children).toEqual([
|
|
62
|
+
test('multiple string children', () => {
|
|
63
|
+
const node = h('p', null, 'hello', ' ', 'world')
|
|
64
|
+
expect(node.children).toEqual(['hello', ' ', 'world'])
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
test(
|
|
68
|
-
const node = h(
|
|
67
|
+
test('number children', () => {
|
|
68
|
+
const node = h('span', null, 42)
|
|
69
69
|
expect(node.children).toEqual([42])
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
test(
|
|
73
|
-
const child = h(
|
|
74
|
-
const parent = h(
|
|
72
|
+
test('VNode children', () => {
|
|
73
|
+
const child = h('span', null, 'inner')
|
|
74
|
+
const parent = h('div', null, child)
|
|
75
75
|
expect(parent.children).toHaveLength(1)
|
|
76
|
-
expect((parent.children[0] as VNode).type).toBe(
|
|
76
|
+
expect((parent.children[0] as VNode).type).toBe('span')
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
test(
|
|
80
|
-
const child = h(
|
|
81
|
-
const getter = () =>
|
|
82
|
-
const node = h(
|
|
79
|
+
test('mixed children types', () => {
|
|
80
|
+
const child = h('em', null)
|
|
81
|
+
const getter = () => 'reactive'
|
|
82
|
+
const node = h('div', null, 'text', 42, child, null, undefined, true, false, getter)
|
|
83
83
|
expect(node.children).toHaveLength(8)
|
|
84
|
-
expect(node.children[0]).toBe(
|
|
84
|
+
expect(node.children[0]).toBe('text')
|
|
85
85
|
expect(node.children[1]).toBe(42)
|
|
86
|
-
expect((node.children[2] as VNode).type).toBe(
|
|
86
|
+
expect((node.children[2] as VNode).type).toBe('em')
|
|
87
87
|
expect(node.children[3]).toBeNull()
|
|
88
88
|
expect(node.children[4]).toBeUndefined()
|
|
89
89
|
expect(node.children[5]).toBe(true)
|
|
90
90
|
expect(node.children[6]).toBe(false)
|
|
91
|
-
expect(typeof node.children[7]).toBe(
|
|
91
|
+
expect(typeof node.children[7]).toBe('function')
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
test(
|
|
95
|
-
const getter = () =>
|
|
96
|
-
const node = h(
|
|
94
|
+
test('function children (reactive getters) are preserved', () => {
|
|
95
|
+
const getter = () => 'dynamic'
|
|
96
|
+
const node = h('div', null, getter)
|
|
97
97
|
expect(node.children).toHaveLength(1)
|
|
98
|
-
expect(typeof node.children[0]).toBe(
|
|
99
|
-
expect((node.children[0] as () => string)()).toBe(
|
|
98
|
+
expect(typeof node.children[0]).toBe('function')
|
|
99
|
+
expect((node.children[0] as () => string)()).toBe('dynamic')
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
-
test(
|
|
103
|
-
const node = h(
|
|
102
|
+
test('no children produces empty array', () => {
|
|
103
|
+
const node = h('br', null)
|
|
104
104
|
expect(node.children).toEqual([])
|
|
105
105
|
})
|
|
106
106
|
})
|
|
107
107
|
|
|
108
|
-
describe(
|
|
109
|
-
test(
|
|
110
|
-
const node = h(
|
|
108
|
+
describe('children flattening', () => {
|
|
109
|
+
test('flattens single-level array children', () => {
|
|
110
|
+
const node = h('ul', null, [h('li', null, 'a'), h('li', null, 'b')])
|
|
111
111
|
expect(node.children).toHaveLength(2)
|
|
112
|
-
expect((node.children[0] as VNode).type).toBe(
|
|
113
|
-
expect((node.children[1] as VNode).type).toBe(
|
|
112
|
+
expect((node.children[0] as VNode).type).toBe('li')
|
|
113
|
+
expect((node.children[1] as VNode).type).toBe('li')
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
test(
|
|
117
|
-
const node = h(
|
|
118
|
-
expect(node.children).toEqual([
|
|
116
|
+
test('flattens deeply nested arrays', () => {
|
|
117
|
+
const node = h('div', null, [[['deep']]] as unknown as VNodeChild)
|
|
118
|
+
expect(node.children).toEqual(['deep'])
|
|
119
119
|
})
|
|
120
120
|
|
|
121
|
-
test(
|
|
122
|
-
const node = h(
|
|
123
|
-
expect(node.children).toEqual([
|
|
121
|
+
test('flattens mixed nested/flat children', () => {
|
|
122
|
+
const node = h('div', null, 'flat', ['nested-a', 'nested-b'] as unknown as VNodeChild)
|
|
123
|
+
expect(node.children).toEqual(['flat', 'nested-a', 'nested-b'])
|
|
124
124
|
})
|
|
125
125
|
|
|
126
|
-
test(
|
|
126
|
+
test('fast path: no allocation when children have no nested arrays', () => {
|
|
127
127
|
// normalizeChildren returns as-is when no element is an array
|
|
128
|
-
const node = h(
|
|
129
|
-
expect(node.children).toEqual([
|
|
128
|
+
const node = h('div', null, 'a', 'b', 'c')
|
|
129
|
+
expect(node.children).toEqual(['a', 'b', 'c'])
|
|
130
130
|
expect(node.children).toHaveLength(3)
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
-
test(
|
|
134
|
-
const node = h(
|
|
135
|
-
expect(node.children).toEqual([
|
|
133
|
+
test('flattens multiple levels of nesting', () => {
|
|
134
|
+
const node = h('div', null, [['a', ['b', ['c']]]] as unknown as VNodeChild)
|
|
135
|
+
expect(node.children).toEqual(['a', 'b', 'c'])
|
|
136
136
|
})
|
|
137
137
|
})
|
|
138
138
|
|
|
139
|
-
describe(
|
|
140
|
-
test(
|
|
141
|
-
const Comp: ComponentFn<{ name: string }> = (props) => h(
|
|
142
|
-
const node = h(Comp, { name:
|
|
139
|
+
describe('component function type', () => {
|
|
140
|
+
test('accepts component function as type', () => {
|
|
141
|
+
const Comp: ComponentFn<{ name: string }> = (props) => h('span', null, props.name)
|
|
142
|
+
const node = h(Comp, { name: 'test' })
|
|
143
143
|
expect(node.type).toBe(Comp)
|
|
144
|
-
expect(node.props.name).toBe(
|
|
144
|
+
expect(node.props.name).toBe('test')
|
|
145
145
|
})
|
|
146
146
|
|
|
147
|
-
test(
|
|
148
|
-
const Comp: ComponentFn = () => h(
|
|
147
|
+
test('component with no props', () => {
|
|
148
|
+
const Comp: ComponentFn = () => h('div', null)
|
|
149
149
|
const node = h(Comp, null)
|
|
150
150
|
expect(node.type).toBe(Comp)
|
|
151
151
|
expect(node.props).toBe(EMPTY_PROPS)
|
|
152
152
|
})
|
|
153
153
|
|
|
154
|
-
test(
|
|
154
|
+
test('component with children rest args', () => {
|
|
155
155
|
const Comp: ComponentFn = () => null
|
|
156
|
-
const node = h(Comp, { id:
|
|
157
|
-
expect(node.children).toEqual([
|
|
156
|
+
const node = h(Comp, { id: 'x' }, 'child1', 'child2')
|
|
157
|
+
expect(node.children).toEqual(['child1', 'child2'])
|
|
158
158
|
})
|
|
159
159
|
})
|
|
160
160
|
|
|
161
|
-
describe(
|
|
162
|
-
test(
|
|
163
|
-
const node = h(Fragment, null,
|
|
161
|
+
describe('symbol type (Fragment)', () => {
|
|
162
|
+
test('Fragment as type', () => {
|
|
163
|
+
const node = h(Fragment, null, 'a', 'b')
|
|
164
164
|
expect(node.type).toBe(Fragment)
|
|
165
|
-
expect(node.children).toEqual([
|
|
165
|
+
expect(node.children).toEqual(['a', 'b'])
|
|
166
166
|
})
|
|
167
167
|
|
|
168
|
-
test(
|
|
169
|
-
const node = h(Fragment, null, h(
|
|
168
|
+
test('Fragment with VNode children', () => {
|
|
169
|
+
const node = h(Fragment, null, h('span', null, 'x'), h('em', null, 'y'))
|
|
170
170
|
expect(node.children).toHaveLength(2)
|
|
171
171
|
})
|
|
172
172
|
|
|
173
|
-
test(
|
|
174
|
-
const inner = h(Fragment, null,
|
|
175
|
-
const outer = h(Fragment, null, inner,
|
|
173
|
+
test('nested Fragments', () => {
|
|
174
|
+
const inner = h(Fragment, null, 'a', 'b')
|
|
175
|
+
const outer = h(Fragment, null, inner, 'c')
|
|
176
176
|
expect(outer.children).toHaveLength(2)
|
|
177
177
|
expect((outer.children[0] as VNode).type).toBe(Fragment)
|
|
178
178
|
})
|
|
179
179
|
})
|
|
180
180
|
})
|
|
181
181
|
|
|
182
|
-
describe(
|
|
183
|
-
test(
|
|
184
|
-
expect(typeof EMPTY_PROPS).toBe(
|
|
182
|
+
describe('EMPTY_PROPS', () => {
|
|
183
|
+
test('is a plain object', () => {
|
|
184
|
+
expect(typeof EMPTY_PROPS).toBe('object')
|
|
185
185
|
expect(EMPTY_PROPS).not.toBeNull()
|
|
186
186
|
})
|
|
187
187
|
|
|
188
|
-
test(
|
|
189
|
-
const a = h(
|
|
190
|
-
const b = h(
|
|
188
|
+
test('is the same reference for all null-prop VNodes', () => {
|
|
189
|
+
const a = h('div', null)
|
|
190
|
+
const b = h('span', null)
|
|
191
191
|
expect(a.props).toBe(b.props)
|
|
192
192
|
})
|
|
193
193
|
})
|
|
194
194
|
|
|
195
|
-
describe(
|
|
196
|
-
test(
|
|
197
|
-
expect(typeof Fragment).toBe(
|
|
198
|
-
expect(Fragment.toString()).toContain(
|
|
195
|
+
describe('Fragment', () => {
|
|
196
|
+
test('is a unique symbol', () => {
|
|
197
|
+
expect(typeof Fragment).toBe('symbol')
|
|
198
|
+
expect(Fragment.toString()).toContain('Pyreon.Fragment')
|
|
199
199
|
})
|
|
200
200
|
})
|
|
@@ -3,84 +3,84 @@
|
|
|
3
3
|
* Uses h() directly since core's vitest config doesn't have JSX transform.
|
|
4
4
|
* TypeScript already validates JSX types via typecheck (tsc --noEmit).
|
|
5
5
|
*/
|
|
6
|
-
import { createRef, Fragment, h } from
|
|
6
|
+
import { createRef, Fragment, h } from '../index'
|
|
7
7
|
|
|
8
|
-
describe(
|
|
9
|
-
test(
|
|
10
|
-
const el = h(
|
|
11
|
-
expect(el.type).toBe(
|
|
12
|
-
expect(el.props.class).toBe(
|
|
8
|
+
describe('JSX type compat (via h)', () => {
|
|
9
|
+
test('basic element', () => {
|
|
10
|
+
const el = h('div', { class: 'hello' }, 'world')
|
|
11
|
+
expect(el.type).toBe('div')
|
|
12
|
+
expect(el.props.class).toBe('hello')
|
|
13
13
|
})
|
|
14
14
|
|
|
15
|
-
test(
|
|
15
|
+
test('callback ref', () => {
|
|
16
16
|
let _captured: Element | null = null
|
|
17
17
|
const el = h(
|
|
18
|
-
|
|
18
|
+
'div',
|
|
19
19
|
{
|
|
20
20
|
ref: (e: Element) => {
|
|
21
21
|
_captured = e
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
|
-
|
|
24
|
+
'test',
|
|
25
25
|
)
|
|
26
|
-
expect(typeof el.props.ref).toBe(
|
|
26
|
+
expect(typeof el.props.ref).toBe('function')
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
-
test(
|
|
29
|
+
test('object ref', () => {
|
|
30
30
|
const myRef = createRef<HTMLDivElement>()
|
|
31
|
-
const el = h(
|
|
31
|
+
const el = h('div', { ref: myRef }, 'test')
|
|
32
32
|
expect(el.props.ref).toBe(myRef)
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
test(
|
|
36
|
-
const el = h(
|
|
37
|
-
expect(typeof el.props.class).toBe(
|
|
35
|
+
test('reactive class prop', () => {
|
|
36
|
+
const el = h('span', { class: () => 'active' }, 'hello')
|
|
37
|
+
expect(typeof el.props.class).toBe('function')
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
test(
|
|
41
|
-
const el = h(
|
|
42
|
-
expect(el.type).toBe(
|
|
43
|
-
expect(el.props.type).toBe(
|
|
40
|
+
test('input with typed props', () => {
|
|
41
|
+
const el = h('input', { type: 'text', value: 'test' })
|
|
42
|
+
expect(el.type).toBe('input')
|
|
43
|
+
expect(el.props.type).toBe('text')
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
test(
|
|
46
|
+
test('component with children', () => {
|
|
47
47
|
const MyComp = (props: { name: string; children?: unknown }) => {
|
|
48
|
-
return h(
|
|
48
|
+
return h('div', null, String(props.name))
|
|
49
49
|
}
|
|
50
|
-
const el = h(MyComp, { name:
|
|
51
|
-
expect(typeof el.type).toBe(
|
|
52
|
-
expect(el.props.name).toBe(
|
|
50
|
+
const el = h(MyComp, { name: 'test' }, 'child')
|
|
51
|
+
expect(typeof el.type).toBe('function')
|
|
52
|
+
expect(el.props.name).toBe('test')
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
test(
|
|
56
|
-
const el = h(Fragment, null,
|
|
55
|
+
test('fragment', () => {
|
|
56
|
+
const el = h(Fragment, null, 'fragment')
|
|
57
57
|
expect(el.type).toBe(Fragment)
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
test(
|
|
60
|
+
test('event handler', () => {
|
|
61
61
|
const handler = vi.fn()
|
|
62
|
-
const el = h(
|
|
62
|
+
const el = h('button', { onClick: handler }, 'click')
|
|
63
63
|
expect(el.props.onClick).toBe(handler)
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
test(
|
|
67
|
-
const el = h(
|
|
68
|
-
expect(el.props.style).toEqual({ color:
|
|
66
|
+
test('style as object', () => {
|
|
67
|
+
const el = h('div', { style: { color: 'red' } }, 'styled')
|
|
68
|
+
expect(el.props.style).toEqual({ color: 'red' })
|
|
69
69
|
})
|
|
70
70
|
|
|
71
|
-
test(
|
|
72
|
-
const el = h(
|
|
73
|
-
expect(el.props[
|
|
71
|
+
test('data attributes', () => {
|
|
72
|
+
const el = h('div', { 'data-testid': 'foo' }, 'test')
|
|
73
|
+
expect(el.props['data-testid']).toBe('foo')
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
-
test(
|
|
77
|
-
const el = h(
|
|
78
|
-
expect(el.props[
|
|
79
|
-
expect(el.props.role).toBe(
|
|
76
|
+
test('aria attributes', () => {
|
|
77
|
+
const el = h('div', { 'aria-label': 'close', role: 'button' })
|
|
78
|
+
expect(el.props['aria-label']).toBe('close')
|
|
79
|
+
expect(el.props.role).toBe('button')
|
|
80
80
|
})
|
|
81
81
|
|
|
82
|
-
test(
|
|
83
|
-
const el = h(
|
|
84
|
-
expect(el.key).toBe(
|
|
82
|
+
test('key prop', () => {
|
|
83
|
+
const el = h('li', { key: 'item-1' }, 'item')
|
|
84
|
+
expect(el.key).toBe('item-1')
|
|
85
85
|
})
|
|
86
86
|
})
|
package/src/tests/lazy.test.ts
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
import { h } from
|
|
2
|
-
import { lazy } from
|
|
3
|
-
import type { ComponentFn, Props, VNode } from
|
|
1
|
+
import { h } from '../h'
|
|
2
|
+
import { lazy } from '../lazy'
|
|
3
|
+
import type { ComponentFn, Props, VNode } from '../types'
|
|
4
4
|
|
|
5
|
-
describe(
|
|
6
|
-
test(
|
|
5
|
+
describe('lazy', () => {
|
|
6
|
+
test('returns a LazyComponent with __loading flag', () => {
|
|
7
7
|
const Comp = lazy<Props>(() => new Promise(() => {})) // never resolves
|
|
8
|
-
expect(typeof Comp).toBe(
|
|
9
|
-
expect(typeof Comp.__loading).toBe(
|
|
8
|
+
expect(typeof Comp).toBe('function')
|
|
9
|
+
expect(typeof Comp.__loading).toBe('function')
|
|
10
10
|
expect(Comp.__loading()).toBe(true)
|
|
11
11
|
})
|
|
12
12
|
|
|
13
|
-
test(
|
|
13
|
+
test('__loading returns true while loading', () => {
|
|
14
14
|
const Comp = lazy<Props>(() => new Promise(() => {}))
|
|
15
15
|
expect(Comp.__loading()).toBe(true)
|
|
16
16
|
})
|
|
17
17
|
|
|
18
|
-
test(
|
|
18
|
+
test('returns null while loading (component not yet available)', () => {
|
|
19
19
|
const Comp = lazy<Props>(() => new Promise(() => {}))
|
|
20
20
|
const result = Comp({})
|
|
21
21
|
expect(result).toBeNull()
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
test(
|
|
25
|
-
const Inner: ComponentFn<{ name: string }> = (props) => h(
|
|
24
|
+
test('resolves to the loaded component', async () => {
|
|
25
|
+
const Inner: ComponentFn<{ name: string }> = (props) => h('span', null, props.name)
|
|
26
26
|
const Comp = lazy(() => Promise.resolve({ default: Inner }))
|
|
27
27
|
|
|
28
28
|
await new Promise((r) => setTimeout(r, 0))
|
|
29
29
|
|
|
30
30
|
expect(Comp.__loading()).toBe(false)
|
|
31
|
-
const result = Comp({ name:
|
|
31
|
+
const result = Comp({ name: 'test' })
|
|
32
32
|
expect(result).not.toBeNull()
|
|
33
33
|
expect((result as VNode).type).toBe(Inner)
|
|
34
|
-
expect((result as VNode).props).toEqual({ name:
|
|
34
|
+
expect((result as VNode).props).toEqual({ name: 'test' })
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
test(
|
|
38
|
-
const Comp = lazy<Props>(() => Promise.reject(new Error(
|
|
37
|
+
test('throws on import error', async () => {
|
|
38
|
+
const Comp = lazy<Props>(() => Promise.reject(new Error('load failed')))
|
|
39
39
|
|
|
40
40
|
await new Promise((r) => setTimeout(r, 0))
|
|
41
41
|
|
|
42
42
|
expect(Comp.__loading()).toBe(false)
|
|
43
|
-
expect(() => Comp({})).toThrow(
|
|
43
|
+
expect(() => Comp({})).toThrow('load failed')
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
test(
|
|
47
|
-
const Comp = lazy<Props>(() => Promise.reject(
|
|
46
|
+
test('wraps non-Error rejection in Error', async () => {
|
|
47
|
+
const Comp = lazy<Props>(() => Promise.reject('string-error'))
|
|
48
48
|
|
|
49
49
|
await new Promise((r) => setTimeout(r, 0))
|
|
50
50
|
|
|
51
|
-
expect(() => Comp({})).toThrow(
|
|
51
|
+
expect(() => Comp({})).toThrow('string-error')
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
test(
|
|
54
|
+
test('wraps numeric rejection in Error', async () => {
|
|
55
55
|
const Comp = lazy<Props>(() => Promise.reject(404))
|
|
56
56
|
|
|
57
57
|
await new Promise((r) => setTimeout(r, 0))
|
|
58
58
|
|
|
59
|
-
expect(() => Comp({})).toThrow(
|
|
59
|
+
expect(() => Comp({})).toThrow('404')
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
test(
|
|
62
|
+
test('__loading is false after successful load', async () => {
|
|
63
63
|
const Inner: ComponentFn = () => null
|
|
64
64
|
const Comp = lazy(() => Promise.resolve({ default: Inner }))
|
|
65
65
|
|
|
@@ -68,16 +68,16 @@ describe("lazy", () => {
|
|
|
68
68
|
expect(Comp.__loading()).toBe(false)
|
|
69
69
|
})
|
|
70
70
|
|
|
71
|
-
test(
|
|
72
|
-
const Comp = lazy<Props>(() => Promise.reject(new Error(
|
|
71
|
+
test('__loading is false after failed load', async () => {
|
|
72
|
+
const Comp = lazy<Props>(() => Promise.reject(new Error('fail')))
|
|
73
73
|
|
|
74
74
|
expect(Comp.__loading()).toBe(true)
|
|
75
75
|
await new Promise((r) => setTimeout(r, 0))
|
|
76
76
|
expect(Comp.__loading()).toBe(false)
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
test(
|
|
80
|
-
const Inner: ComponentFn = () => h(
|
|
79
|
+
test('multiple calls after load return consistent results', async () => {
|
|
80
|
+
const Inner: ComponentFn = () => h('div', null, 'content')
|
|
81
81
|
const Comp = lazy(() => Promise.resolve({ default: Inner }))
|
|
82
82
|
|
|
83
83
|
await new Promise((r) => setTimeout(r, 0))
|
|
@@ -88,8 +88,8 @@ describe("lazy", () => {
|
|
|
88
88
|
expect((result2 as VNode).type).toBe(Inner)
|
|
89
89
|
})
|
|
90
90
|
|
|
91
|
-
test(
|
|
92
|
-
const Inner: ComponentFn<{ count: number }> = (props) => h(
|
|
91
|
+
test('passes props through to loaded component via h()', async () => {
|
|
92
|
+
const Inner: ComponentFn<{ count: number }> = (props) => h('span', null, String(props.count))
|
|
93
93
|
const Comp = lazy(() => Promise.resolve({ default: Inner }))
|
|
94
94
|
|
|
95
95
|
await new Promise((r) => setTimeout(r, 0))
|