@pyreon/document-primitives 0.24.5 → 0.24.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/lib/index.d.ts +6 -6
- package/package.json +17 -19
- package/src/DocumentPreview.ts +0 -48
- package/src/__tests__/document-primitives.browser.test.ts +0 -253
- package/src/__tests__/manifest-snapshot.test.ts +0 -45
- package/src/__tests__/primitives-attrs.test.ts +0 -517
- package/src/__tests__/primitives.test.ts +0 -104
- package/src/__tests__/reactivity.test.ts +0 -415
- package/src/__tests__/useDocumentExport.test.ts +0 -366
- package/src/index.ts +0 -37
- package/src/manifest.ts +0 -388
- package/src/primitives/DocButton.ts +0 -37
- package/src/primitives/DocCode.ts +0 -18
- package/src/primitives/DocColumn.ts +0 -11
- package/src/primitives/DocDivider.ts +0 -21
- package/src/primitives/DocDocument.ts +0 -69
- package/src/primitives/DocHeading.ts +0 -33
- package/src/primitives/DocImage.ts +0 -23
- package/src/primitives/DocLink.ts +0 -15
- package/src/primitives/DocList.ts +0 -15
- package/src/primitives/DocListItem.ts +0 -15
- package/src/primitives/DocPage.ts +0 -21
- package/src/primitives/DocPageBreak.ts +0 -11
- package/src/primitives/DocQuote.ts +0 -17
- package/src/primitives/DocRow.ts +0 -19
- package/src/primitives/DocSection.ts +0 -23
- package/src/primitives/DocSpacer.ts +0 -11
- package/src/primitives/DocTable.ts +0 -57
- package/src/primitives/DocText.ts +0 -31
- package/src/theme.ts +0 -37
- package/src/useDocumentExport.ts +0 -84
|
@@ -1,415 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fine-grained reactivity tests for every document-primitive that
|
|
3
|
-
* accepts children or data props.
|
|
4
|
-
*
|
|
5
|
-
* **Why the `as any` casts**: rocketstyle's component prop type
|
|
6
|
-
* collapses children to `VNodeChildAtom` (the singular form) inside
|
|
7
|
-
* its child slot, even though `VNodeChild` already covers
|
|
8
|
-
* `VNodeChild[]`. This is a recurring DX paper-cut tracked as item
|
|
9
|
-
* R1 in the post-flow-PR catalog. The casts here aren't covering a
|
|
10
|
-
* runtime bug — they're a type-level workaround that lets us pass
|
|
11
|
-
* function children through `h(DocPrimitive, ...)` without
|
|
12
|
-
* fighting TS. When R1 lands, the casts can be removed.
|
|
13
|
-
*
|
|
14
|
-
* Proves the load-bearing claim of the resume-builder showcase: when
|
|
15
|
-
* a rocketstyle document primitive is given a function child like
|
|
16
|
-
* `<DocText>{() => signal()}</DocText>`, the function passes through
|
|
17
|
-
* rocketstyle untouched and is treated by Pyreon's runtime as a
|
|
18
|
-
* reactive children accessor. The text node patches in place when
|
|
19
|
-
* the signal changes — the parent component does NOT re-render.
|
|
20
|
-
*
|
|
21
|
-
* Without this guarantee, the resume builder's "single tree, two
|
|
22
|
-
* render targets" design degrades to a top-down re-render on every
|
|
23
|
-
* keystroke, defeating the entire reason to use document-primitives
|
|
24
|
-
* for the live preview.
|
|
25
|
-
*
|
|
26
|
-
* The tests are organised by what each primitive wraps:
|
|
27
|
-
*
|
|
28
|
-
* • TEXT-BASED — wraps `@pyreon/elements/Text`. The function child
|
|
29
|
-
* becomes a reactive text node. Tests assert that mutating the
|
|
30
|
-
* signal updates `container.textContent` AND that the parent
|
|
31
|
-
* component runs exactly once across multiple mutations.
|
|
32
|
-
*
|
|
33
|
-
* • ELEMENT/CONTAINER — wraps `@pyreon/elements/Element`. Function
|
|
34
|
-
* children inside the container are still reactive (same
|
|
35
|
-
* mechanism — rocketstyle passes children through unmodified).
|
|
36
|
-
* Tests assert mutation propagation through nested children.
|
|
37
|
-
*
|
|
38
|
-
* • LEAF — primitives with no children (Divider, Spacer, PageBreak,
|
|
39
|
-
* Image). These take props only. Tests verify that the primitive
|
|
40
|
-
* mounts cleanly and produces the right tag, with no children
|
|
41
|
-
* surface to be reactive against.
|
|
42
|
-
*
|
|
43
|
-
* • DATA-DRIVEN — DocTable receives `columns`/`rows` as attrs, not
|
|
44
|
-
* JSX children. Tests verify the primitive mounts with array
|
|
45
|
-
* props.
|
|
46
|
-
*/
|
|
47
|
-
import { h } from '@pyreon/core'
|
|
48
|
-
import { signal } from '@pyreon/reactivity'
|
|
49
|
-
import { initTestConfig, mountAndExpectOnce, mountReactive } from '@pyreon/test-utils'
|
|
50
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
51
|
-
|
|
52
|
-
import DocButton from '../primitives/DocButton'
|
|
53
|
-
import DocCode from '../primitives/DocCode'
|
|
54
|
-
import DocColumn from '../primitives/DocColumn'
|
|
55
|
-
import DocDivider from '../primitives/DocDivider'
|
|
56
|
-
import DocDocument from '../primitives/DocDocument'
|
|
57
|
-
import DocHeading from '../primitives/DocHeading'
|
|
58
|
-
import DocImage from '../primitives/DocImage'
|
|
59
|
-
import DocLink from '../primitives/DocLink'
|
|
60
|
-
import DocList from '../primitives/DocList'
|
|
61
|
-
import DocListItem from '../primitives/DocListItem'
|
|
62
|
-
import DocPage from '../primitives/DocPage'
|
|
63
|
-
import DocPageBreak from '../primitives/DocPageBreak'
|
|
64
|
-
import DocQuote from '../primitives/DocQuote'
|
|
65
|
-
import DocRow from '../primitives/DocRow'
|
|
66
|
-
import DocSection from '../primitives/DocSection'
|
|
67
|
-
import DocSpacer from '../primitives/DocSpacer'
|
|
68
|
-
import DocTable from '../primitives/DocTable'
|
|
69
|
-
import DocText from '../primitives/DocText'
|
|
70
|
-
|
|
71
|
-
let cleanup: () => void
|
|
72
|
-
beforeAll(() => {
|
|
73
|
-
cleanup = initTestConfig()
|
|
74
|
-
})
|
|
75
|
-
afterAll(() => cleanup())
|
|
76
|
-
|
|
77
|
-
// ─── Text-based primitives ──────────────────────────────────────────
|
|
78
|
-
//
|
|
79
|
-
// All wrap `@pyreon/elements/Text`. Function children render as text
|
|
80
|
-
// nodes that the runtime patches in place when their signal source
|
|
81
|
-
// changes. The "parent runs once" contract is asserted via
|
|
82
|
-
// mountAndExpectOnce.
|
|
83
|
-
|
|
84
|
-
describe('text-based primitives — function children patch text nodes', () => {
|
|
85
|
-
it('DocText patches its text node when the signal changes', () => {
|
|
86
|
-
const name = signal('Aisha')
|
|
87
|
-
const { container, cleanup: c } = mountReactive(h(DocText as any, null, () => name()))
|
|
88
|
-
expect(container.textContent).toBe('Aisha')
|
|
89
|
-
name.set('Marcus')
|
|
90
|
-
expect(container.textContent).toBe('Marcus')
|
|
91
|
-
name.set('Priya')
|
|
92
|
-
expect(container.textContent).toBe('Priya')
|
|
93
|
-
c()
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
it('DocText parent component runs once across multiple mutations', () => {
|
|
97
|
-
const headline = signal('Senior Engineer')
|
|
98
|
-
const { container, parentCalls, cleanup: c } = mountAndExpectOnce(
|
|
99
|
-
() => h(DocText as any, null, () => headline()),
|
|
100
|
-
() => {
|
|
101
|
-
headline.set('Staff Engineer')
|
|
102
|
-
headline.set('Principal Engineer')
|
|
103
|
-
headline.set('Distinguished Engineer')
|
|
104
|
-
headline.set('Fellow')
|
|
105
|
-
headline.set('CTO')
|
|
106
|
-
},
|
|
107
|
-
)
|
|
108
|
-
expect(parentCalls()).toBe(1)
|
|
109
|
-
expect(container.textContent).toBe('CTO')
|
|
110
|
-
c()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('DocHeading patches its text node when the signal changes', () => {
|
|
114
|
-
const title = signal('Resume')
|
|
115
|
-
const { container, cleanup: c } = mountReactive(
|
|
116
|
-
h(DocHeading as any, { level: 'h1' }, () => title()),
|
|
117
|
-
)
|
|
118
|
-
expect(container.textContent).toBe('Resume')
|
|
119
|
-
title.set('Curriculum Vitae')
|
|
120
|
-
expect(container.textContent).toBe('Curriculum Vitae')
|
|
121
|
-
c()
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('DocHeading parent runs once across mutations', () => {
|
|
125
|
-
const title = signal('A')
|
|
126
|
-
const { parentCalls, cleanup: c } = mountAndExpectOnce(
|
|
127
|
-
() => h(DocHeading as any, { level: 'h2' }, () => title()),
|
|
128
|
-
() => {
|
|
129
|
-
title.set('B')
|
|
130
|
-
title.set('C')
|
|
131
|
-
},
|
|
132
|
-
)
|
|
133
|
-
expect(parentCalls()).toBe(1)
|
|
134
|
-
c()
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
it('DocCode patches its text node when the signal changes', () => {
|
|
138
|
-
const snippet = signal('const x = 1')
|
|
139
|
-
const { container, cleanup: c } = mountReactive(
|
|
140
|
-
h(DocCode as any, { language: 'typescript' }, () => snippet()),
|
|
141
|
-
)
|
|
142
|
-
expect(container.textContent).toBe('const x = 1')
|
|
143
|
-
snippet.set('const y = 2')
|
|
144
|
-
expect(container.textContent).toBe('const y = 2')
|
|
145
|
-
c()
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
it('DocLink patches its text node when the signal changes', () => {
|
|
149
|
-
const label = signal('Click here')
|
|
150
|
-
const { container, cleanup: c } = mountReactive(
|
|
151
|
-
h(DocLink as any, { href: 'https://example.com' }, () => label()),
|
|
152
|
-
)
|
|
153
|
-
expect(container.textContent).toBe('Click here')
|
|
154
|
-
label.set('Visit us')
|
|
155
|
-
expect(container.textContent).toBe('Visit us')
|
|
156
|
-
c()
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
it('DocListItem patches its text node when the signal changes', () => {
|
|
160
|
-
const item = signal('First task')
|
|
161
|
-
const { container, cleanup: c } = mountReactive(h(DocListItem as any, null, () => item()))
|
|
162
|
-
expect(container.textContent).toBe('First task')
|
|
163
|
-
item.set('Second task')
|
|
164
|
-
expect(container.textContent).toBe('Second task')
|
|
165
|
-
c()
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it('DocButton patches its text node when the signal changes', () => {
|
|
169
|
-
const cta = signal('Sign up')
|
|
170
|
-
const { container, cleanup: c } = mountReactive(
|
|
171
|
-
h(DocButton as any, { variant: 'primary' }, () => cta()),
|
|
172
|
-
)
|
|
173
|
-
expect(container.textContent).toBe('Sign up')
|
|
174
|
-
cta.set('Get started')
|
|
175
|
-
expect(container.textContent).toBe('Get started')
|
|
176
|
-
c()
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
// ─── Element/container primitives ───────────────────────────────────
|
|
181
|
-
//
|
|
182
|
-
// All wrap `@pyreon/elements/Element`. Function children INSIDE the
|
|
183
|
-
// container (typically wrapped in a text-bearing primitive like
|
|
184
|
-
// DocText) are still reactive — rocketstyle passes children through
|
|
185
|
-
// unmodified, so the reactive accessor lands at whatever level the
|
|
186
|
-
// consumer puts it.
|
|
187
|
-
|
|
188
|
-
describe('container primitives — function children inside containers stay reactive', () => {
|
|
189
|
-
it('DocDocument propagates reactive children through to text leaves', () => {
|
|
190
|
-
const title = signal('Original')
|
|
191
|
-
const { container, cleanup: c } = mountReactive(
|
|
192
|
-
h(
|
|
193
|
-
DocDocument as any,
|
|
194
|
-
{ title: 'My Doc' },
|
|
195
|
-
h(DocText as any, null, () => title()),
|
|
196
|
-
),
|
|
197
|
-
)
|
|
198
|
-
expect(container.textContent).toBe('Original')
|
|
199
|
-
title.set('Updated')
|
|
200
|
-
expect(container.textContent).toBe('Updated')
|
|
201
|
-
c()
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
it('DocDocument parent runs once across nested signal mutations', () => {
|
|
205
|
-
const body = signal('a')
|
|
206
|
-
const { parentCalls, cleanup: c } = mountAndExpectOnce(
|
|
207
|
-
() =>
|
|
208
|
-
h(
|
|
209
|
-
DocDocument as any,
|
|
210
|
-
{ title: 'X' },
|
|
211
|
-
h(DocText as any, null, () => body()),
|
|
212
|
-
),
|
|
213
|
-
() => {
|
|
214
|
-
body.set('b')
|
|
215
|
-
body.set('c')
|
|
216
|
-
body.set('d')
|
|
217
|
-
},
|
|
218
|
-
)
|
|
219
|
-
expect(parentCalls()).toBe(1)
|
|
220
|
-
c()
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
it('DocPage propagates reactive children through to text leaves', () => {
|
|
224
|
-
const heading = signal('Page 1')
|
|
225
|
-
const { container, cleanup: c } = mountReactive(
|
|
226
|
-
h(
|
|
227
|
-
DocPage as any,
|
|
228
|
-
{ size: 'A4' },
|
|
229
|
-
h(DocHeading as any, { level: 'h1' }, () => heading()),
|
|
230
|
-
),
|
|
231
|
-
)
|
|
232
|
-
expect(container.textContent).toBe('Page 1')
|
|
233
|
-
heading.set('Page 2')
|
|
234
|
-
expect(container.textContent).toBe('Page 2')
|
|
235
|
-
c()
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
it('DocSection propagates reactive children', () => {
|
|
239
|
-
const text = signal('section A')
|
|
240
|
-
const { container, cleanup: c } = mountReactive(
|
|
241
|
-
h(DocSection as any, null, h(DocText as any, null, () => text())),
|
|
242
|
-
)
|
|
243
|
-
expect(container.textContent).toBe('section A')
|
|
244
|
-
text.set('section B')
|
|
245
|
-
expect(container.textContent).toBe('section B')
|
|
246
|
-
c()
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
it('DocRow propagates reactive children', () => {
|
|
250
|
-
const inline = signal('one')
|
|
251
|
-
const { container, cleanup: c } = mountReactive(
|
|
252
|
-
h(DocRow as any, null, h(DocText as any, null, () => inline())),
|
|
253
|
-
)
|
|
254
|
-
expect(container.textContent).toBe('one')
|
|
255
|
-
inline.set('two')
|
|
256
|
-
expect(container.textContent).toBe('two')
|
|
257
|
-
c()
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
it('DocColumn propagates reactive children', () => {
|
|
261
|
-
const col = signal('left')
|
|
262
|
-
const { container, cleanup: c } = mountReactive(
|
|
263
|
-
h(DocColumn as any, { width: '50%' }, h(DocText as any, null, () => col())),
|
|
264
|
-
)
|
|
265
|
-
expect(container.textContent).toBe('left')
|
|
266
|
-
col.set('right')
|
|
267
|
-
expect(container.textContent).toBe('right')
|
|
268
|
-
c()
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
it('DocList propagates reactive children to nested DocListItem', () => {
|
|
272
|
-
const first = signal('Apple')
|
|
273
|
-
const { container, cleanup: c } = mountReactive(
|
|
274
|
-
h(
|
|
275
|
-
DocList as any,
|
|
276
|
-
null,
|
|
277
|
-
h(DocListItem as any, null, () => first()),
|
|
278
|
-
),
|
|
279
|
-
)
|
|
280
|
-
expect(container.textContent).toBe('Apple')
|
|
281
|
-
first.set('Banana')
|
|
282
|
-
expect(container.textContent).toBe('Banana')
|
|
283
|
-
c()
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
it('DocList parent runs once when ordered list items mutate', () => {
|
|
287
|
-
const item = signal('a')
|
|
288
|
-
const { parentCalls, cleanup: c } = mountAndExpectOnce(
|
|
289
|
-
() =>
|
|
290
|
-
h(
|
|
291
|
-
DocList as any,
|
|
292
|
-
{ ordered: true },
|
|
293
|
-
h(DocListItem as any, null, () => item()),
|
|
294
|
-
),
|
|
295
|
-
() => {
|
|
296
|
-
item.set('b')
|
|
297
|
-
item.set('c')
|
|
298
|
-
},
|
|
299
|
-
)
|
|
300
|
-
expect(parentCalls()).toBe(1)
|
|
301
|
-
c()
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
it('DocQuote propagates reactive children', () => {
|
|
305
|
-
const quote = signal('Hello')
|
|
306
|
-
const { container, cleanup: c } = mountReactive(
|
|
307
|
-
h(DocQuote as any, null, h(DocText as any, null, () => quote())),
|
|
308
|
-
)
|
|
309
|
-
expect(container.textContent).toBe('Hello')
|
|
310
|
-
quote.set('World')
|
|
311
|
-
expect(container.textContent).toBe('World')
|
|
312
|
-
c()
|
|
313
|
-
})
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
// ─── Leaf primitives ────────────────────────────────────────────────
|
|
317
|
-
//
|
|
318
|
-
// No children, no reactive surface. The contract here is just "the
|
|
319
|
-
// primitive mounts cleanly without throwing." A consumer that drops
|
|
320
|
-
// these into a tree shouldn't need to worry about them — they're
|
|
321
|
-
// inert dividers / spacers / page breaks. Image is also leaf because
|
|
322
|
-
// its data lives in attrs (`src`, `alt`, etc.) not children.
|
|
323
|
-
|
|
324
|
-
describe('leaf primitives — mount cleanly with no children', () => {
|
|
325
|
-
it('DocDivider mounts and produces an hr tag', () => {
|
|
326
|
-
const { container, cleanup: c } = mountReactive(h(DocDivider as any, null))
|
|
327
|
-
expect(container.querySelector('hr')).not.toBeNull()
|
|
328
|
-
c()
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
it('DocSpacer mounts cleanly', () => {
|
|
332
|
-
const { container, cleanup: c } = mountReactive(h(DocSpacer as any, { height: 32 }))
|
|
333
|
-
expect(container.querySelector('div')).not.toBeNull()
|
|
334
|
-
c()
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
it('DocPageBreak mounts cleanly', () => {
|
|
338
|
-
const { container, cleanup: c } = mountReactive(h(DocPageBreak as any, null))
|
|
339
|
-
expect(container.querySelector('div')).not.toBeNull()
|
|
340
|
-
c()
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
it('DocImage mounts and produces an img tag with the src attr', () => {
|
|
344
|
-
const { container, cleanup: c } = mountReactive(
|
|
345
|
-
h(DocImage as any, { src: 'https://example.com/x.png', alt: 'X' }),
|
|
346
|
-
)
|
|
347
|
-
const img = container.querySelector('img')
|
|
348
|
-
expect(img).not.toBeNull()
|
|
349
|
-
c()
|
|
350
|
-
})
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
// ─── Data-driven primitives ─────────────────────────────────────────
|
|
354
|
-
//
|
|
355
|
-
// DocTable takes `columns`/`rows` as attrs rather than JSX children.
|
|
356
|
-
// The browser render is intentionally minimal — DocTable produces a
|
|
357
|
-
// bare `<table>` element with theme styling, and the data lives in
|
|
358
|
-
// `_documentProps` for the document-export pipeline to consume.
|
|
359
|
-
// There's no DOM-level "mutate signal → assert text" contract here
|
|
360
|
-
// because the data never reaches the DOM.
|
|
361
|
-
//
|
|
362
|
-
// What we DO assert: the primitive mounts cleanly. Before this test
|
|
363
|
-
// existed, DocTable's `rows` and `columns` props collided with
|
|
364
|
-
// HTMLTableElement's read-only DOM properties of the same name —
|
|
365
|
-
// the runtime crashed with `TypeError: Cannot set property rows of
|
|
366
|
-
// [object Object] which has only a getter` whenever any consumer
|
|
367
|
-
// tried to mount a table. The fix was a `filter` option on
|
|
368
|
-
// rocketstyle's `.attrs()` that strips export-only props from the
|
|
369
|
-
// DOM forwarding. See `DocTable.ts` for the inline rationale.
|
|
370
|
-
|
|
371
|
-
describe('data-driven primitives — DocTable mounts cleanly', () => {
|
|
372
|
-
it('mounts with columns and rows arrays', () => {
|
|
373
|
-
const { container, cleanup: c } = mountReactive(
|
|
374
|
-
h(DocTable as any, {
|
|
375
|
-
columns: [{ header: 'Name' }, { header: 'Age' }],
|
|
376
|
-
rows: [
|
|
377
|
-
['Alice', 30],
|
|
378
|
-
['Bob', 25],
|
|
379
|
-
],
|
|
380
|
-
}),
|
|
381
|
-
)
|
|
382
|
-
expect(container.querySelector('table')).not.toBeNull()
|
|
383
|
-
c()
|
|
384
|
-
})
|
|
385
|
-
|
|
386
|
-
it('mounts with empty arrays (regression: no crash on empty rows)', () => {
|
|
387
|
-
const { container, cleanup: c } = mountReactive(
|
|
388
|
-
h(DocTable as any, { columns: [], rows: [] }),
|
|
389
|
-
)
|
|
390
|
-
expect(container.querySelector('table')).not.toBeNull()
|
|
391
|
-
c()
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
it('does not forward columns/rows to the DOM (would crash table.rows is read-only)', () => {
|
|
395
|
-
// The fix: rocketstyle's `filter` option on `.attrs()` strips
|
|
396
|
-
// these props before they reach the DOM forwarding step. Without
|
|
397
|
-
// the filter, the runtime would call `tableEl.rows = [...]`
|
|
398
|
-
// which throws on HTMLTableElement.
|
|
399
|
-
//
|
|
400
|
-
// This test exists to make the regression unmissable: if anyone
|
|
401
|
-
// removes the filter option in DocTable.ts, this test (and the
|
|
402
|
-
// two above) will start crashing again with the exact same
|
|
403
|
-
// error message that originally surfaced the bug.
|
|
404
|
-
const { container, cleanup: c } = mountReactive(
|
|
405
|
-
h(DocTable as any, { columns: [{ header: 'X' }], rows: [['y']] }),
|
|
406
|
-
)
|
|
407
|
-
const table = container.querySelector('table') as HTMLTableElement | null
|
|
408
|
-
expect(table).not.toBeNull()
|
|
409
|
-
// The native `rows` is a read-only HTMLCollection of <tr>. We
|
|
410
|
-
// shouldn't have polluted it with our prop array. (If we had,
|
|
411
|
-
// mount would have already crashed above.)
|
|
412
|
-
expect(table?.rows.length).toBe(0)
|
|
413
|
-
c()
|
|
414
|
-
})
|
|
415
|
-
})
|