ripple 0.3.9 → 0.3.10
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/CHANGELOG.md +12 -0
- package/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +25 -15
- package/src/compiler/phases/2-analyze/index.js +35 -88
- package/src/compiler/phases/2-analyze/prune.js +13 -5
- package/src/compiler/phases/3-transform/client/index.js +188 -56
- package/src/compiler/phases/3-transform/server/index.js +62 -40
- package/src/compiler/types/index.d.ts +9 -1
- package/src/compiler/types/parse.d.ts +2 -0
- package/src/compiler/utils.js +101 -1
- package/src/runtime/element.js +39 -0
- package/src/runtime/internal/client/composite.js +10 -6
- package/src/runtime/internal/client/expression.js +218 -0
- package/src/runtime/internal/client/index.js +4 -0
- package/src/runtime/internal/client/portal.js +12 -6
- package/src/runtime/internal/server/index.js +26 -1
- package/tests/client/basic/basic.components.test.ripple +85 -87
- package/tests/client/basic/basic.errors.test.ripple +4 -8
- package/tests/client/basic/basic.rendering.test.ripple +23 -8
- package/tests/client/capture-error.js +12 -0
- package/tests/client/compiler/compiler.basic.test.ripple +76 -6
- package/tests/client/composite/composite.props.test.ripple +1 -3
- package/tests/client/composite/composite.render.test.ripple +45 -13
- package/tests/client/css/global-additional-cases.test.ripple +3 -3
- package/tests/client/svg.test.ripple +4 -4
- package/tests/hydration/basic.test.js +23 -0
- package/tests/hydration/compiled/client/basic.js +118 -66
- package/tests/hydration/compiled/client/composite.js +90 -37
- package/tests/hydration/compiled/client/events.js +18 -18
- package/tests/hydration/compiled/client/for.js +62 -62
- package/tests/hydration/compiled/client/head.js +10 -10
- package/tests/hydration/compiled/client/hmr.js +13 -10
- package/tests/hydration/compiled/client/html.js +274 -236
- package/tests/hydration/compiled/client/if-children.js +41 -35
- package/tests/hydration/compiled/client/if.js +2 -2
- package/tests/hydration/compiled/client/mixed-control-flow.js +12 -12
- package/tests/hydration/compiled/client/nested-control-flow.js +46 -46
- package/tests/hydration/compiled/client/portal.js +8 -8
- package/tests/hydration/compiled/client/reactivity.js +14 -14
- package/tests/hydration/compiled/client/return.js +2 -2
- package/tests/hydration/compiled/client/try.js +4 -4
- package/tests/hydration/compiled/server/basic.js +64 -31
- package/tests/hydration/compiled/server/composite.js +62 -29
- package/tests/hydration/compiled/server/hmr.js +24 -37
- package/tests/hydration/compiled/server/html.js +472 -611
- package/tests/hydration/compiled/server/if-children.js +77 -103
- package/tests/hydration/compiled/server/portal.js +8 -8
- package/tests/hydration/components/basic.ripple +15 -5
- package/tests/hydration/components/composite.ripple +13 -1
- package/tests/hydration/components/hmr.ripple +1 -3
- package/tests/hydration/components/html.ripple +13 -35
- package/tests/hydration/components/if-children.ripple +4 -8
- package/tests/hydration/composite.test.js +11 -0
- package/tests/server/basic.attributes.test.ripple +50 -0
- package/tests/server/basic.components.test.ripple +22 -28
- package/tests/server/basic.test.ripple +12 -0
- package/tests/server/compiler.test.ripple +25 -8
- package/tests/server/composite.props.test.ripple +1 -3
- package/tests/server/style-identifier.test.ripple +2 -4
- package/types/index.d.ts +9 -2
|
@@ -70,9 +70,7 @@ describe('basic client > errors', () => {
|
|
|
70
70
|
|
|
71
71
|
expect(() => {
|
|
72
72
|
compile(code, 'test.ripple');
|
|
73
|
-
}).toThrow(
|
|
74
|
-
'`children` cannot be rendered using text interpolation. Use `<children />` instead.',
|
|
75
|
-
);
|
|
73
|
+
}).not.toThrow();
|
|
76
74
|
});
|
|
77
75
|
|
|
78
76
|
it('should throw error for interpolating props.children as text', () => {
|
|
@@ -84,9 +82,7 @@ describe('basic client > errors', () => {
|
|
|
84
82
|
|
|
85
83
|
expect(() => {
|
|
86
84
|
compile(code, 'test.ripple');
|
|
87
|
-
}).toThrow(
|
|
88
|
-
'`children` cannot be rendered using text interpolation. Use `<children />` instead.',
|
|
89
|
-
);
|
|
85
|
+
}).not.toThrow();
|
|
90
86
|
});
|
|
91
87
|
|
|
92
88
|
it('should throw error for calling children as a function', () => {
|
|
@@ -99,7 +95,7 @@ describe('basic client > errors', () => {
|
|
|
99
95
|
expect(() => {
|
|
100
96
|
compile(code, 'test.ripple');
|
|
101
97
|
}).toThrow(
|
|
102
|
-
'`children` cannot be called like a regular function.
|
|
98
|
+
'`children` cannot be called like a regular function. Render it with `{children}` or `{props.children}` instead.',
|
|
103
99
|
);
|
|
104
100
|
});
|
|
105
101
|
|
|
@@ -113,7 +109,7 @@ describe('basic client > errors', () => {
|
|
|
113
109
|
expect(() => {
|
|
114
110
|
compile(code, 'test.ripple');
|
|
115
111
|
}).toThrow(
|
|
116
|
-
'`children` cannot be called like a regular function.
|
|
112
|
+
'`children` cannot be called like a regular function. Render it with `{children}` or `{props.children}` instead.',
|
|
117
113
|
);
|
|
118
114
|
});
|
|
119
115
|
|
|
@@ -15,9 +15,9 @@ describe('basic client > rendering & text', () => {
|
|
|
15
15
|
|
|
16
16
|
it('renders semi-dynamic text', () => {
|
|
17
17
|
component Basic() {
|
|
18
|
-
let
|
|
18
|
+
let message = 'Hello World';
|
|
19
19
|
|
|
20
|
-
<div>{
|
|
20
|
+
<div>{message}</div>
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
render(Basic);
|
|
@@ -25,18 +25,33 @@ describe('basic client > rendering & text', () => {
|
|
|
25
25
|
expect(container).toMatchSnapshot();
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
+
it('renders explicit text interpolation without creating HTML', () => {
|
|
29
|
+
component Basic() {
|
|
30
|
+
let markup = '<span>Not HTML</span>';
|
|
31
|
+
|
|
32
|
+
<div>{text markup}</div>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
render(Basic);
|
|
36
|
+
|
|
37
|
+
const div = container.querySelector('div');
|
|
38
|
+
|
|
39
|
+
expect(div.textContent).toBe('<span>Not HTML</span>');
|
|
40
|
+
expect(div.querySelector('span')).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
|
|
28
43
|
it('renders dynamic text', () => {
|
|
29
44
|
component Basic() {
|
|
30
|
-
let &[
|
|
45
|
+
let &[message] = track('Hello World');
|
|
31
46
|
|
|
32
47
|
<button
|
|
33
48
|
onClick={() => {
|
|
34
|
-
|
|
49
|
+
message = 'Hello Ripple';
|
|
35
50
|
}}
|
|
36
51
|
>
|
|
37
52
|
{'Change Text'}
|
|
38
53
|
</button>
|
|
39
|
-
<div>{
|
|
54
|
+
<div>{message}</div>
|
|
40
55
|
}
|
|
41
56
|
|
|
42
57
|
render(Basic);
|
|
@@ -70,13 +85,13 @@ describe('basic client > rendering & text', () => {
|
|
|
70
85
|
it('renders tick template literal for nested children', () => {
|
|
71
86
|
component Child({ level, children }: { level: number; children: any }) {
|
|
72
87
|
if (level == 1) {
|
|
73
|
-
<h1
|
|
88
|
+
<h1>{children}</h1>
|
|
74
89
|
}
|
|
75
90
|
if (level == 2) {
|
|
76
|
-
<h2
|
|
91
|
+
<h2>{children}</h2>
|
|
77
92
|
}
|
|
78
93
|
if (level == 3) {
|
|
79
|
-
<h3
|
|
94
|
+
<h3>{children}</h3>
|
|
80
95
|
}
|
|
81
96
|
}
|
|
82
97
|
|
|
@@ -44,6 +44,40 @@ describe('compiler > basics', () => {
|
|
|
44
44
|
).toEqual(style3);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
it('parses explicit text interpolation and reserves the text keyword', () => {
|
|
48
|
+
const source = `export component App() {
|
|
49
|
+
const markup = '<span>Not HTML</span>';
|
|
50
|
+
|
|
51
|
+
<div>{markup}</div>
|
|
52
|
+
<div>{text markup}</div>
|
|
53
|
+
}`;
|
|
54
|
+
|
|
55
|
+
const ast = parse(source);
|
|
56
|
+
const component_node = (ast.body[0] as AST.ExportNamedDeclaration).declaration as unknown as AST.Component;
|
|
57
|
+
const elements = component_node.body.filter((node) => node.type === 'Element') as AST.Element[];
|
|
58
|
+
const expression = elements[0].children[0] as AST.Node & { expression: AST.Expression };
|
|
59
|
+
const explicit_text = elements[1].children[0] as AST.TextNode;
|
|
60
|
+
|
|
61
|
+
expect(elements).toHaveLength(2);
|
|
62
|
+
expect(expression.type).toBe('RippleExpression');
|
|
63
|
+
expect((expression.expression as AST.Identifier).name).toBe('markup');
|
|
64
|
+
expect(explicit_text.type).toBe('Text');
|
|
65
|
+
expect((explicit_text.expression as AST.Identifier).name).toBe('markup');
|
|
66
|
+
|
|
67
|
+
const { js } = compile(source, 'text-directive.ripple', { mode: 'client' });
|
|
68
|
+
expect(js.code).not.toContain('_$_.html');
|
|
69
|
+
|
|
70
|
+
const invalid_source = `export component App() {
|
|
71
|
+
const text = 'plain';
|
|
72
|
+
|
|
73
|
+
<div>{text}</div>
|
|
74
|
+
}`;
|
|
75
|
+
|
|
76
|
+
expect(() => parse(invalid_source)).toThrow(
|
|
77
|
+
'"text" is a Ripple keyword and must be used in the form {text some_value}',
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
47
81
|
it('renders without crashing', () => {
|
|
48
82
|
component App() {
|
|
49
83
|
let foo: Record<string, number>;
|
|
@@ -433,16 +467,16 @@ export component App() {
|
|
|
433
467
|
const code = `
|
|
434
468
|
component Card(props) {
|
|
435
469
|
<div class="card">
|
|
436
|
-
|
|
470
|
+
{props.children}
|
|
437
471
|
</div>
|
|
438
472
|
}
|
|
439
473
|
|
|
440
474
|
export component App() {
|
|
441
|
-
<Card>
|
|
442
475
|
component children() {
|
|
443
476
|
<p>{'Card content here'}</p>
|
|
444
477
|
}
|
|
445
|
-
|
|
478
|
+
|
|
479
|
+
<Card {children} />
|
|
446
480
|
|
|
447
481
|
const test = 5;
|
|
448
482
|
|
|
@@ -452,7 +486,7 @@ export component App() {
|
|
|
452
486
|
expect(() => compile(code, 'test.ripple')).not.toThrow();
|
|
453
487
|
});
|
|
454
488
|
|
|
455
|
-
it('
|
|
489
|
+
it('rejects component declarations inside composite children', () => {
|
|
456
490
|
const source = `
|
|
457
491
|
export component App() {
|
|
458
492
|
<ark.div class="host-class" data-value="42">
|
|
@@ -461,12 +495,48 @@ export component App() {
|
|
|
461
495
|
}
|
|
462
496
|
</ark.div>
|
|
463
497
|
}
|
|
498
|
+
`;
|
|
499
|
+
|
|
500
|
+
expect(() => compile_to_volar_mappings(source, 'test.ripple')).toThrow(
|
|
501
|
+
/Component declarations cannot be used inside composite component children/,
|
|
502
|
+
);
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('preserves explicit component props in Volar mappings', () => {
|
|
506
|
+
const source = `
|
|
507
|
+
export component App() {
|
|
508
|
+
component asChild({ children, href, ...rest }: { href: string; [key: string]: any }) {
|
|
509
|
+
<a id="aschild-anchor" {href} {...rest} data-extra="yes">{'Link'}</a>
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
<ark.div class="host-class" data-value="42" {asChild} />
|
|
513
|
+
}
|
|
464
514
|
`;
|
|
465
515
|
const result = compile_to_volar_mappings(source, 'test.ripple').code;
|
|
466
516
|
|
|
467
|
-
expect(result).toContain('<ark.div class="host-class" data-value="42" asChild={');
|
|
517
|
+
expect(result).toContain('<ark.div class="host-class" data-value="42" asChild={asChild}');
|
|
468
518
|
expect(result).not.toContain('children={() =>');
|
|
469
|
-
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it('merges explicit children prop with implicit children in client output', () => {
|
|
522
|
+
const source = `
|
|
523
|
+
component Card(props) {
|
|
524
|
+
<div>{props.children}</div>
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export component App() {
|
|
528
|
+
const fallback = 'fallback';
|
|
529
|
+
|
|
530
|
+
<Card children={fallback}>
|
|
531
|
+
<span>{'content'}</span>
|
|
532
|
+
</Card>
|
|
533
|
+
}
|
|
534
|
+
`;
|
|
535
|
+
|
|
536
|
+
const result = compile(source, 'test.ripple', { mode: 'client' }).js.code;
|
|
537
|
+
|
|
538
|
+
expect((result.match(/children:/g) || []).length).toBe(1);
|
|
539
|
+
expect(result).toContain('children: _$_.normalize_children(fallback) ?? _$_.ripple_element(');
|
|
470
540
|
});
|
|
471
541
|
|
|
472
542
|
it('should not error on `this` MemberExpression with a UpdateExpression', () => {
|
|
@@ -107,9 +107,7 @@ describe('composite > props', () => {
|
|
|
107
107
|
|
|
108
108
|
it('correctly retains prop accessors and reactivity when using rest props', () => {
|
|
109
109
|
component Button(&{ children, ...rest }: Props) {
|
|
110
|
-
<button {...rest}>
|
|
111
|
-
<@children />
|
|
112
|
-
</button>
|
|
110
|
+
<button {...rest}>{children}</button>
|
|
113
111
|
<style>
|
|
114
112
|
.on {
|
|
115
113
|
color: blue;
|
|
@@ -32,20 +32,22 @@ describe('composite > render', () => {
|
|
|
32
32
|
component Button({ A, B, children }: { A: () => void; B: () => void; children: () => void }) {
|
|
33
33
|
<div>
|
|
34
34
|
<A />
|
|
35
|
-
|
|
35
|
+
{children}
|
|
36
36
|
<B />
|
|
37
37
|
</div>
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
component App() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
component A() {
|
|
42
|
+
<div>{'I am A'}</div>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
component B() {
|
|
46
|
+
<div>{'I am B'}</div>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
<Button {A} {B}>
|
|
45
50
|
<div>{'other text'}</div>
|
|
46
|
-
component B() {
|
|
47
|
-
<div>{'I am B'}</div>
|
|
48
|
-
}
|
|
49
51
|
</Button>
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -62,21 +64,51 @@ describe('composite > render', () => {
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
component Child({ children, ...rest }: { children: string; class: string }) {
|
|
65
|
-
<button {...rest}>
|
|
66
|
-
<children />
|
|
67
|
-
</button>
|
|
67
|
+
<button {...rest}>{children}</button>
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
render(App);
|
|
71
71
|
expect(container).toMatchSnapshot();
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
it('renders explicit text around children', () => {
|
|
75
|
+
component Frame({ children }) {
|
|
76
|
+
<div class="frame">
|
|
77
|
+
{text 'before'}
|
|
78
|
+
{children}
|
|
79
|
+
{text 'after'}
|
|
80
|
+
</div>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
component App() {
|
|
84
|
+
<Frame>
|
|
85
|
+
<span class="middle">{'middle'}</span>
|
|
86
|
+
</Frame>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
render(App);
|
|
90
|
+
|
|
91
|
+
const frame = /** @type {HTMLDivElement} */ (container.querySelector('.frame'));
|
|
92
|
+
const nodes = Array.from(frame.childNodes).filter(
|
|
93
|
+
(node) => node.nodeType !== Node.COMMENT_NODE,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(nodes).toHaveLength(3);
|
|
97
|
+
expect(nodes[0].nodeType).toBe(Node.TEXT_NODE);
|
|
98
|
+
expect(nodes[0].textContent).toBe('before');
|
|
99
|
+
expect((/** @type {HTMLElement} */ (nodes[1])).outerHTML).toBe(
|
|
100
|
+
'<span class="middle">middle</span>',
|
|
101
|
+
);
|
|
102
|
+
expect(nodes[2].nodeType).toBe(Node.TEXT_NODE);
|
|
103
|
+
expect(nodes[2].textContent).toBe('after');
|
|
104
|
+
});
|
|
105
|
+
|
|
74
106
|
it('preserves distinct scoped ripple hashes for wrapper and child content', () => {
|
|
75
107
|
component App() {
|
|
76
108
|
component Wrapper({ children }) {
|
|
77
109
|
<div class="green">
|
|
78
110
|
{'Wrapper'}
|
|
79
|
-
|
|
111
|
+
{children}
|
|
80
112
|
</div>
|
|
81
113
|
|
|
82
114
|
<style>
|
|
@@ -141,7 +173,7 @@ describe('composite > render', () => {
|
|
|
141
173
|
[key: string]: any;
|
|
142
174
|
}) {
|
|
143
175
|
<div {...props}>
|
|
144
|
-
|
|
176
|
+
{children}
|
|
145
177
|
// @ts-expect-error - intentionally testing behavior when a component is undefined
|
|
146
178
|
<NonExistent />
|
|
147
179
|
</div>
|
|
@@ -353,7 +353,7 @@ export component Test({ children }) {
|
|
|
353
353
|
<div>
|
|
354
354
|
<p class="before">{'before'}</p>
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
{children}
|
|
357
357
|
|
|
358
358
|
<p class="foo">
|
|
359
359
|
<span>{'foo'}</span>
|
|
@@ -379,8 +379,8 @@ export component Test({ children }) {
|
|
|
379
379
|
const { css } = compile(source, 'test.ripple');
|
|
380
380
|
|
|
381
381
|
expect(css).toMatch(/\.before\.ripple-[a-z0-9]+ \+ \.foo:where\(\.ripple-[a-z0-9]+\) {/);
|
|
382
|
-
expect((css.match(/\.x\ /g) || []).length).toBe(
|
|
383
|
-
expect((css.match(/\(unused\) :global\(\.x\) /g) || []).length).toBe(
|
|
382
|
+
expect((css.match(/\.x\ /g) || []).length).toBe(0);
|
|
383
|
+
expect((css.match(/\(unused\) :global\(\.x\) /g) || []).length).toBe(6);
|
|
384
384
|
expect(css).toContain('(unused) :global(.x) + .bar {');
|
|
385
385
|
});
|
|
386
386
|
|
|
@@ -234,7 +234,7 @@ describe('SVG namespace handling', () => {
|
|
|
234
234
|
it('should render SVG with children as svg elements', () => {
|
|
235
235
|
component SVG({ children }: PropsWithChildren<{}>) {
|
|
236
236
|
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
237
|
-
|
|
237
|
+
{children}
|
|
238
238
|
</svg>
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -285,7 +285,7 @@ describe('SVG namespace handling', () => {
|
|
|
285
285
|
it('should render SVG with children as dynamic elements', () => {
|
|
286
286
|
component SVG({ children }: PropsWithChildren<{}>) {
|
|
287
287
|
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
288
|
-
|
|
288
|
+
{children}
|
|
289
289
|
</svg>
|
|
290
290
|
}
|
|
291
291
|
|
|
@@ -308,7 +308,7 @@ describe('SVG namespace handling', () => {
|
|
|
308
308
|
it('should render SVG with children as dynamic components', () => {
|
|
309
309
|
component SVG({ children }: PropsWithChildren<{}>) {
|
|
310
310
|
<svg width={20} height={20} fill="blue" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
311
|
-
|
|
311
|
+
{children}
|
|
312
312
|
</svg>
|
|
313
313
|
}
|
|
314
314
|
|
|
@@ -336,7 +336,7 @@ describe('SVG namespace handling', () => {
|
|
|
336
336
|
component SVG({ children }: PropsWithChildren<{}>) {
|
|
337
337
|
let &[tag] = track('svg');
|
|
338
338
|
<@tag width={100} height={50} fill="red" viewBox="0 0 30 10" preserveAspectRatio="none">
|
|
339
|
-
|
|
339
|
+
{children}
|
|
340
340
|
</@tag>
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { flushSync } from 'ripple';
|
|
2
3
|
import { hydrateComponent, container } from '../setup-hydration.js';
|
|
3
4
|
|
|
4
5
|
// Import server-compiled components
|
|
@@ -59,6 +60,28 @@ describe('hydration > basic', () => {
|
|
|
59
60
|
expect(container.innerHTML).toBeHtml('<div>42</div><span>COMPUTED</span>');
|
|
60
61
|
});
|
|
61
62
|
|
|
63
|
+
it('restores text children after hydrating away initial server text', async () => {
|
|
64
|
+
await hydrateComponent(
|
|
65
|
+
ServerComponents.TextPropWithToggle,
|
|
66
|
+
ClientComponents.TextPropWithToggle,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(container.querySelector('.text-prop')?.textContent).toBe('');
|
|
70
|
+
|
|
71
|
+
/** @type {any} */ (container.querySelector('.show-text'))?.click();
|
|
72
|
+
flushSync();
|
|
73
|
+
|
|
74
|
+
expect(container.querySelector('.text-prop')?.textContent).toBe('hello');
|
|
75
|
+
|
|
76
|
+
// Verify text is placed between hydration markers, not before anchor
|
|
77
|
+
const innerHTML = container.querySelector('.text-prop')?.innerHTML ?? '';
|
|
78
|
+
const textIndex = innerHTML.indexOf('hello');
|
|
79
|
+
const startMarker = innerHTML.indexOf('<!--[-->');
|
|
80
|
+
const endMarker = innerHTML.indexOf('<!--]-->');
|
|
81
|
+
expect(textIndex).toBeGreaterThan(startMarker);
|
|
82
|
+
expect(textIndex).toBeLessThan(endMarker);
|
|
83
|
+
});
|
|
84
|
+
|
|
62
85
|
it('hydrates static child component followed by sibling content', async () => {
|
|
63
86
|
await hydrateComponent(
|
|
64
87
|
ServerComponents.StaticChildWithSiblings,
|