Skip to content

Commit 2c69ad8

Browse files
committedNov 29, 2024·
test: update tests
improved names, remove duplication
1 parent 5175272 commit 2c69ad8

10 files changed

+632
-418
lines changed
 

‎test/process.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ import plugin from '../src/index.js';
44
const clean = html => html.replace(/(\n|\t)/g, '').trim();
55

66
export async function process(html, options) {
7-
return await posthtml([plugin(options)]).process(html).then(result => clean(result.html));
7+
const posthtmlOptions = options.parserOptions || {};
8+
return await posthtml([plugin(options)]).process(html, posthtmlOptions).then(result => clean(result.html));
89
}

‎test/test-attributes.js

+106-59
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,162 @@
1-
import { test, expect } from 'vitest'
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
3+
24
import plugin from '../src/index.js';
35
import posthtml from 'posthtml';
46
import pull from 'lodash/pull';
57

68
const clean = html => html.replace(/(\n|\t)/g, '').trim();
79

8-
test('Must merge and map attributes not props to first node', async () => {
10+
test('Maps and merges attributes (not props) to first node', async () => {
911
const actual = `<component src="components/component-mapped-attributes.html" data-something="Test an attribute" title="My Title" class="bg-light p-2" style="display: flex; font-size: 20px"></component>`;
1012
const expected = `<div class="text-dark m-3 bg-light p-2" style="background: red; display: flex; font-size: 20px" data-something="Test an attribute">My Title Default body</div>`;
1113

12-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
13-
14-
expect(html).toBe(expected);
14+
process(actual,
15+
{
16+
root: './test/templates',
17+
tag: 'component'
18+
}
19+
)
20+
.then(html => {
21+
expect(html).toBe(expected);
22+
});
1523
});
1624

17-
test('Must merge and map attributes not props to node with attribute "attributes" without style', async () => {
25+
test('Maps and merges attributes (not props) to node with attribute `attributes` without style', async () => {
1826
const actual = `<component src="components/component-mapped-attributes2.html" title="My Title" class="bg-light p-2" style="display: flex; font-size: 20px"></component>`;
1927
const expected = `<div class="mapped"><div class="text-dark m-3 bg-light p-2" style="display: flex; font-size: 20px">My Title Default body</div></div>`;
2028

21-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
22-
23-
expect(html).toBe(expected);
29+
process(actual,
30+
{
31+
root: './test/templates',
32+
tag: 'component'
33+
}
34+
)
35+
.then(html => {
36+
expect(html).toBe(expected);
37+
});
2438
});
2539

26-
test('Must merge and map attributes not props to node with attribute "attributes" without class', async () => {
40+
test('Maps and merges attributes (not props) to node with attribute `attributes` without class', async () => {
2741
const actual = `<component src="components/component-mapped-attributes3.html" title="My Title" class="bg-light p-2" style="display: block; font-size: 20px"></component>`;
2842
const expected = `<div class="mapped"><div style="border: 1px solid black; display: block; font-size: 20px" class="bg-light p-2">My Title Default body</div></div>`;
2943

30-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
31-
32-
expect(html).toBe(expected);
44+
process(actual,
45+
{
46+
root: './test/templates',
47+
tag: 'component'
48+
}
49+
)
50+
.then(html => {
51+
expect(html).toBe(expected);
52+
});
3353
});
3454

35-
test('Must not map attributes for component without any elements', async () => {
55+
test('Does not map attributes for components that have no elements', async () => {
3656
const actual = `<div><component src="components/component-without-elements.html" title="My Title" class="bg-light p-2" style="display: flex; font-size: 20px"></component></div>`;
3757
const expected = `<div>I am a component without any elements. Yeah, something uncommon but just for testing. My Title</div>`;
3858

39-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
40-
41-
expect(html).toBe(expected);
59+
process(actual,
60+
{
61+
root: './test/templates',
62+
tag: 'component'
63+
}
64+
)
65+
.then(html => {
66+
expect(html).toBe(expected);
67+
});
4268
});
4369

44-
test('Must override class and style attributes', async () => {
70+
test('Overrides class and style attributes', async () => {
4571
const actual = `<component src="components/component-mapped-attributes.html" override:class="override-class" override:style="background: black"></component>`;
4672
const expected = `<div class="override-class" style="background: black">Default title Default body</div>`;
4773

48-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
49-
50-
expect(html).toBe(expected);
74+
process(actual,
75+
{
76+
root: './test/templates',
77+
tag: 'component'
78+
}
79+
)
80+
.then(html => {
81+
expect(html).toBe(expected);
82+
});
5183
});
5284

53-
test('Must remove an attributes that has "undefined" or "null" value', async () => {
85+
test('Removes attributes containing `undefined` or `null` values', async () => {
5486
const actual = `<component src="components/remove-attributes.html" tabindex="-1">My button</component>`;
5587
const expected = `<button class="btn btn-primary" data-bs-dismiss="true" data-bs-backdrop="false" tabindex="-1">My button</button><div>works also in all nodes</div>`;
5688

57-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
58-
59-
expect(html).toBe(expected);
89+
process(actual,
90+
{
91+
root: './test/templates',
92+
tag: 'component'
93+
}
94+
)
95+
.then(html => {
96+
expect(html).toBe(expected);
97+
});
6098
});
6199

62-
test('Must override valid attributes', async () => {
100+
test('Overrides known attributes', async () => {
63101
const actual = `<component src="components/override-attributes.html" tabindex="-1" title="My button" custom-attribute="A custom attribute">My button</component>`;
64102
const expected = `<button tabindex="-1" custom-attribute="A custom attribute">My button</button>`;
65103

66-
const html = await posthtml([plugin({
67-
root: './test/templates',
68-
tag: 'component',
69-
elementAttributes: {
70-
BUTTON: attrs => {
71-
// Remove title
72-
pull(attrs, 'title');
104+
process(actual,
105+
{
106+
root: './test/templates',
107+
tag: 'component',
108+
elementAttributes: {
109+
BUTTON: attrs => {
110+
// Remove title
111+
pull(attrs, 'title');
73112

74-
// Add custom-attribute
75-
attrs.push('custom-attribute');
113+
// Add custom-attribute
114+
attrs.push('custom-attribute');
76115

77-
return attrs;
116+
return attrs;
117+
}
78118
}
79119
}
80-
})]).process(actual).then(result => clean(result.html));
81-
82-
expect(html).toBe(expected);
120+
)
121+
.then(html => {
122+
expect(html).toBe(expected);
123+
});
83124
});
84125

85-
test('Must work with tag without attributes', async () => {
126+
test('Works with tags that have no attributes', async () => {
86127
const actual = `<component src="components/override-attributes.html" tabindex="-1" title="My button" custom-attribute="A custom attribute">My button</component>`;
87128
const expected = `<button>My button</button>`;
88129

89-
const html = await posthtml([plugin({
90-
root: './test/templates',
91-
tag: 'component',
92-
elementAttributes: {
93-
BUTTON: _ => {
94-
// Return empty array means no attributes
95-
return [];
130+
process(actual,
131+
{
132+
root: './test/templates',
133+
tag: 'component',
134+
elementAttributes: {
135+
BUTTON: _ => {
136+
// Return empty array means no attributes
137+
return [];
138+
}
96139
}
97140
}
98-
})]).process(actual).then(result => clean(result.html));
99-
100-
expect(html).toBe(expected);
141+
)
142+
.then(html => {
143+
expect(html).toBe(expected);
144+
});
101145
});
102146

103-
test('Must use safelist and blocklist', async () => {
147+
test('Uses `safelist` and `blocklist`', async () => {
104148
const actual = `<component src="components/override-attributes.html" tabindex="-1" title="My button" custom-attribute="A custom attribute">My button</component>`;
105149
const expected = `<button custom-attribute="A custom attribute">My button</button>`;
106150

107-
const html = await posthtml([plugin({
108-
root: './test/templates',
109-
tag: 'component',
110-
safelistAttributes: ['custom-attribute'],
111-
blocklistAttributes: ['role', 'tabindex']
112-
})]).process(actual).then(result => clean(result.html));
113-
114-
expect(html).toBe(expected);
151+
process(actual,
152+
{
153+
root: './test/templates',
154+
tag: 'component',
155+
safelistAttributes: ['custom-attribute'],
156+
blocklistAttributes: ['role', 'tabindex'],
157+
}
158+
)
159+
.then(html => {
160+
expect(html).toBe(expected);
161+
});
115162
});

‎test/test-errors.js

+78-62
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,100 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
4-
5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must fail when namespace is unknown', async () => {
8-
const actual = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
9-
10-
await expect(() => posthtml([plugin({ root: './test/templates', strict: true })]).process(actual).then(result => clean(result.html)))
11-
.rejects.toThrow()
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
3+
4+
test('Throws if namespace is unknown', async () => {
5+
await expect(() => process(
6+
`<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`,
7+
{ root: './test/templates', strict: true }
8+
)).rejects.toThrow();
129
});
1310

14-
test('Must return node as-is when namespace is unknown with strict mode disabled', async () => {
15-
const actual = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
16-
const expected = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
17-
18-
const html = await posthtml([plugin({root: './test/templates', strict: false})]).process(actual).then(result => clean(result.html));
19-
20-
expect(html).toBe(expected);
11+
test('Throws when push tag missing name attribute', async () => {
12+
await expect(() => process(
13+
`<div><push></push></div>`,
14+
{
15+
root: './test/templates',
16+
strict: true
17+
}
18+
)).rejects.toThrow();
2119
});
2220

23-
test('Must return node as-is when namespace is empty with strict mode disabled', async () => {
24-
const actual = `<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`;
25-
const expected = `<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`;
26-
27-
const html = await posthtml([plugin({root: './test/templates', strict: false, namespaces: {name: 'empty-namespace', root: './test/templates/empty-namespace'}})]).process(actual).then(result => clean(result.html));
28-
29-
expect(html).toBe(expected);
21+
test('Throws when push tag missing name attribute value', async () => {
22+
await expect(() => process(
23+
`<div><push name></push></div>`,
24+
{ root: './test/templates', strict: true }
25+
)).rejects.toThrow();
3026
});
3127

32-
test('Must return node as-is when x-tag is not found with strict mode disabled', async () => {
33-
const actual = `<div><x-button>Submit</x-button></div>`;
34-
const expected = `<div><x-button>Submit</x-button></div>`;
35-
36-
const html = await posthtml([plugin({root: './test/templates/empty-root', strict: false})]).process(actual).then(result => clean(result.html));
37-
38-
expect(html).toBe(expected);
28+
test('Throws when component is not found (strict mode enabled)', async () => {
29+
await expect(() => process(
30+
`<div><component src="not-found.html">Submit</component></div>`,
31+
{
32+
root: './test/templates/empty-root',
33+
tag: 'component',
34+
strict: true,
35+
}
36+
)).rejects.toThrow();
3937
});
4038

41-
test('Must return node as-is when component is not found with strict mode disabled', async () => {
42-
const actual = `<div><component src="not-found.html">Submit</component></div>`;
43-
const expected = `<div><component src="not-found.html">Submit</component></div>`;
44-
45-
const html = await posthtml([plugin({tag: 'component', strict: false})]).process(actual).then(result => clean(result.html));
46-
47-
expect(html).toBe(expected);
39+
test('Throws when component is not found in namespace (strict mode enabled)', async () => {
40+
await expect(() => process(
41+
`<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`,
42+
{
43+
root: './test/templates',
44+
strict: true,
45+
namespaces: [
46+
{
47+
name: 'empty-namespace',
48+
root: './test/templates/empty-namespace',
49+
}
50+
]
51+
}
52+
)).rejects.toThrow();
4853
});
4954

50-
test('Must fail when component is not found with strict mode enabled', async () => {
51-
const actual = `<div><component src="not-found.html">Submit</component></div>`;
55+
test('Returns node as-is when namespace is unknown (strict mode disabled)', async () => {
56+
const actual = `<div><x-unknown-namespace::button>Submit</x-unknown-namespace::button></div>`;
5257

53-
await expect(() => posthtml([plugin({ root: './test/templates/empty-root', tag: 'component', strict: true })]).process(actual).then(result => clean(result.html)))
54-
.rejects.toThrow()
58+
process(actual, { root: './test/templates', strict: false })
59+
.then(html => {
60+
expect(html).toBe(actual);
61+
});
5562
});
5663

57-
test('Must fail when component is not found in defined namespace with strict mode enabled', async () => {
64+
test('Returns node as-is when namespace is empty (strict mode disabled)', async () => {
5865
const actual = `<div><x-empty-namespace::button>Submit</x-empty-namespace::button></div>`;
5966

60-
await expect(() => posthtml([
61-
plugin({root: './test/templates', strict: true, namespaces: [{name: 'empty-namespace', root: './test/templates/empty-namespace'}]})
62-
])
63-
.process(actual)
64-
.then(result => clean(result.html))
65-
).rejects.toThrow()
67+
process(actual,
68+
{
69+
root: './test/templates',
70+
strict: false,
71+
namespaces: [
72+
{
73+
name: 'empty-namespace',
74+
root: './test/templates/empty-namespace',
75+
}
76+
]
77+
}
78+
)
79+
.then(html => {
80+
expect(html).toBe(actual);
81+
});
6682
});
6783

68-
test('Must fail when push tag missing name attribute', async () => {
69-
const actual = `<div><push></push></div>`;
84+
test('Returns node as-is when x-tag is not found (strict mode disabled)', async () => {
85+
const actual = `<div><x-button>Submit</x-button></div>`;
7086

71-
await expect(() => posthtml([
72-
plugin({root: './test/templates', strict: true})
73-
])
74-
.process(actual)
75-
.then(result => clean(result.html))
76-
).rejects.toThrow();
87+
process(actual, { root: './test/templates/empty-root', strict: false })
88+
.then(html => {
89+
expect(html).toBe(actual);
90+
});
7791
});
7892

79-
test('Must fail when push tag missing name attribute value', async () => {
80-
const actual = `<div><push name></push></div>`;
93+
test('Returns node as-is when component is not found (strict mode disabled)', async () => {
94+
const actual = `<div><component src="not-found.html">Submit</component></div>`;
8195

82-
await expect(async () => posthtml([plugin({root: './test/templates', strict: true})]).process(actual).then(result => clean(result.html)))
83-
.rejects.toThrow();
96+
process(actual, { tag: 'component', strict: false })
97+
.then(html => {
98+
expect(html).toBe(actual);
99+
});
84100
});

‎test/test-locals.js

+127-66
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
4-
5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must process layout with props', async () => {
8-
const actual = `<component src="layouts/base-locals.html" props='{ "title": "My Page" }'><div>Content</div><fill:footer>Footer</fill:footer></component>`;
9-
const expected = `<html><head><title>My Page</title></head><body><main><div>Content</div></main><footer>Footer</footer></body></html>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
3+
4+
test('Works with props', async () => {
5+
process(
6+
`<component src="layouts/base-locals.html" props='{ "title": "My Page" }'><div>Content</div><fill:footer>Footer</fill:footer></component>`,
7+
{
8+
root: './test/templates',
9+
tag: 'component'
10+
}
11+
)
12+
.then(html => {
13+
expect(html).toBe(`<html><head><title>My Page</title></head><body><main><div>Content</div></main><footer>Footer</footer></body></html>`);
14+
});
1415
});
1516

16-
test('Must process attributes as props', async () => {
17-
const actual = `<component src="components/component-locals.html" title="My Component Title" body="Content"><fill:body prepend><span>Body</span></fill:body></component>`;
18-
const expected = `<div><h1>My Component Title</h1></div><div><span>Body</span>Content</div>`;
19-
20-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
21-
22-
expect(html).toBe(expected);
17+
test('Attributes as props', async () => {
18+
process(
19+
`<component src="components/component-locals.html" title="My Component Title" body="Content"><fill:body prepend><span>Body</span></fill:body></component>`,
20+
{
21+
root: './test/templates',
22+
tag: 'component'
23+
}
24+
)
25+
.then(html => {
26+
expect(html).toBe(`<div><h1>My Component Title</h1></div><div><span>Body</span>Content</div>`);
27+
});
2328
});
2429

25-
test('Must process component with props as JSON and string', async () => {
30+
test('JSON and string props', async () => {
2631
const actual = `<component src="components/component-locals-json-and-string.html"
2732
titles='{ "suptitle": "This is custom suptitle" }'
2833
title="Custom title from JSON and String"
@@ -31,95 +36,151 @@ test('Must process component with props as JSON and string', async () => {
3136
merge:props='{ "items": ["first item", "second item"] }'></component>`;
3237
const expected = `<div><div>myboolean is true</div><div><h1>Custom title from JSON and String</h1></div><div><span>another item</span><span>yet another</span><span>first item</span><span>second item</span></div><div><span>title: This is default main title</span><span>subtitle: This is default subtitle</span><span>suptitle: This is custom suptitle</span></div></div>`;
3338

34-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
35-
36-
expect(html).toBe(expected);
39+
process(actual,
40+
{
41+
root: './test/templates',
42+
tag: 'component'
43+
}
44+
)
45+
.then(html => {
46+
expect(html).toBe(expected);
47+
});
3748
});
3849

39-
test('Must process parent and child props via component', async () => {
50+
test('Parses parent and child props via component', async () => {
4051
const actual = `<x-parent aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
4152
const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>CHILD:<div> aBoolean value: true type: boolean aString value: My String Child type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
4253

43-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
44-
45-
expect(html).toBe(expected);
54+
process(actual,
55+
{
56+
root: './test/templates/components'
57+
}
58+
)
59+
.then(html => {
60+
expect(html).toBe(expected);
61+
});
4662
});
4763

48-
test('Must has access to $slots in script props', async () => {
64+
test('$slots is available in script `props`', async () => {
4965
const actual = `<x-script-locals><fill:filled>filled slot content...</fill:filled></x-script-locals>`;
5066
const expected = `{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","props":{}}}<div>{"filled":{"filled":true,"rendered":false,"tag":"fill:filled","attrs":{},"content":["filled slot content..."],"source":"filled slot content...","props":{}}}</div><div><h1>Default title</h1></div><div>filled slot content...</div>`;
5167

52-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
53-
54-
expect(html).toBe(expected);
68+
process(actual,
69+
{
70+
root: './test/templates/components'
71+
}
72+
)
73+
.then(html => {
74+
expect(html).toBe(expected);
75+
});
5576
});
5677

57-
test('Must pass props from parent to child via aware', async () => {
78+
test('Passes props from parent to child via `aware`', async () => {
5879
const actual = `<x-parent aware:aString="I am custom aString for PARENT via component (1)"><x-child></x-child></x-parent>`;
5980
const expected = `PARENT:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>CHILD:<div> aBoolean value: true type: boolean aString value: I am custom aString for PARENT via component (1) type: string aString2 value: I am not string 2 type: string anArray value: ["one","two","three"] type: object anObject value: {"one":"One","two":"Two","three":"Three"} type: object anArray2 value: ["one2","two2","three2"] type: object anObject2 value: {"one":"One2","two":"Two2","three":"Three2"} type: object</div>`;
6081

61-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
62-
63-
expect(html).toBe(expected);
82+
process(actual,
83+
{
84+
root: './test/templates/components'
85+
}
86+
)
87+
.then(html => {
88+
expect(html).toBe(expected);
89+
});
6490
});
6591

66-
test('Must process default, merged and override props', async () => {
92+
test('Works default, merged and overridden props', async () => {
6793
const actual = `<component src="components/component-locals-type.html"
6894
aStringOverride="My override string changed"
6995
anObjectOverride='{ "third": "Third override item", "fourth": "Fourth override item" }'
7096
anObjectMerged='{ "third": "Third merged item", "fourth": "Fourth merged item" }'></component>`;
7197

7298
const expected = `<div> <h1>anObjectDefault</h1> <p><strong>first</strong>: First default item</p> <p><strong>second</strong>: Second default item</p> <h1>anObjectOverride</h1> <p><strong>third</strong>: Third override item</p> <p><strong>fourth</strong>: Fourth override item</p> <h1>anObjectMerged</h1> <p><strong>first</strong>: First merged item</p> <p><strong>second</strong>: Second merged item</p> <p><strong>third</strong>: Third merged item</p> <p><strong>fourth</strong>: Fourth merged item</p> <h1>aStringDefault</h1> <p>My default string</p> <h1>aStringOverride</h1> <p>My override string changed</p></div>`;
7399

74-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
75-
76-
expect(html).toBe(expected);
100+
process(actual,
101+
{
102+
root: './test/templates',
103+
tag: 'component'
104+
}
105+
)
106+
.then(html => {
107+
expect(html).toBe(expected);
108+
});
77109
});
78110

79-
test('Must process slot with props', async () => {
80-
const actual = `<component src="components/slot-with-locals.html"><fill:name mySlotLocal=" Via Slot" prepend>My Local</fill:name></component>`;
81-
const expected = `<div>My Local Via Slot</div>`;
82-
83-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
84-
85-
expect(html).toBe(expected);
111+
test('Slot with props', async () => {
112+
process(
113+
`<component src="components/slot-with-locals.html"><fill:name mySlotLocal=" Via Slot" prepend>My Local</fill:name></component>`,
114+
{
115+
root: './test/templates',
116+
tag: 'component'
117+
}
118+
)
119+
.then(html => {
120+
expect(html).toBe(`<div>My Local Via Slot</div>`);
121+
});
86122
});
87123

88-
test('Must process props with custom options', async () => {
124+
test('Customized `props` options', async () => {
89125
const actual = `<component src="components/custom-props-options.html" title="My Component Title" body="Content" locals='{ "prop": "My prop via locals attribute" }'><fill:body slotProp="My slot prop" prepend><span>Body</span></fill:body></component>`;
90126
const expected = `<div><h1>My Component Title</h1></div><div><span>Body</span>Content-My slot prop</div><div>My prop via locals attribute</div>`;
91127

92-
const html = await posthtml([plugin({root: './test/templates', tag: 'component', propsScriptAttribute: 'locals', propsContext: 'locals', propsAttribute: 'locals', propsSlot: 'locals'})]).process(actual).then(result => clean(result.html));
93-
94-
expect(html).toBe(expected);
128+
process(actual,
129+
{
130+
root: './test/templates',
131+
tag: 'component',
132+
propsScriptAttribute: 'locals',
133+
propsContext: 'locals',
134+
propsAttribute: 'locals',
135+
propsSlot: 'locals'
136+
}
137+
)
138+
.then(html => {
139+
expect(html).toBe(expected);
140+
});
95141
});
96142

97-
test('Must process components with script file', async () => {
143+
test('Components with script file', async () => {
98144
const actual = `<component src="components/component-script-file.html" myStringProp="My custom string prop" myObjectProp='{ "one": "New one value", "three": "New third value" }'></component>`;
99145
const expected = `<div>A default string</div><div>My custom string prop</div><div>{"one":"New one value","three":"New third value"}</div>`;
100146

101-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
102-
103-
expect(html).toBe(expected);
147+
process(actual,
148+
{
149+
root: './test/templates',
150+
tag: 'component'
151+
}
152+
)
153+
.then(html => {
154+
expect(html).toBe(expected);
155+
});
104156
});
105157

106-
test('Must process components with invalid script file', async () => {
107-
const actual = `<component src="components/invalid-script-file.html"></component>`;
108-
const expected = `<div>Component content (undefined)</div>`;
109-
110-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
111-
112-
expect(html).toBe(expected);
158+
test('Components with invalid script file', async () => {
159+
process(
160+
`<component src="components/invalid-script-file.html"></component>`,
161+
{
162+
root: './test/templates',
163+
tag: 'component'
164+
}
165+
)
166+
.then(html => {
167+
expect(html).toBe(`<div>Component content (undefined)</div>`);
168+
});
113169
});
114170

115-
test('Must reset not nested aware props that it', async () => {
171+
test('Should reset non-nested aware props', async () => {
116172
const actual = `
117173
<x-parent-aware aware:myprop="I am aware prop"><x-child-aware></x-child-aware><x-child-aware></x-child-aware></x-parent-aware>
118174
<x-parent-aware><x-child-aware></x-child-aware></x-parent-aware>
119175
`;
120176
const expected = `<div><div>I am aware prop</div><div>I am aware prop</div></div><div><div>Default prop</div></div>`;
121177

122-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
123-
124-
expect(html).toBe(expected);
178+
process(actual,
179+
{
180+
root: './test/templates/components'
181+
}
182+
)
183+
.then(html => {
184+
expect(html).toBe(expected);
185+
});
125186
});

‎test/test-nested.js

+18-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
43

5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must process all nested component to html', async () => {
8-
const actual = `<div><x-nested-one></x-nested-one></div>`;
9-
const expected = `<div><div class="nested-one"><div class="nested-two"><div class="nested-three">Nested works!</div></div></div></div>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
4+
test('Nested components', async () => {
5+
process(
6+
`<div><x-nested-one></x-nested-one></div>`,
7+
{ root: './test/templates/components' }
8+
).then(html => {
9+
expect(html).toBe(`<div><div class="nested-one"><div class="nested-two"><div class="nested-three">Nested works!</div></div></div></div>`);
10+
});
1411
});
1512

16-
test('Must process all nested component with slots to html', async () => {
17-
const actual = `<x-nested-one-slot><x-nested-two-slot>yield content<fill:before2>nested-two before</fill:before2><fill:after2>nested-two after</fill:after2></x-nested-two-slot><fill:before>nested-one before</fill:before><fill:after>nested-one after</fill:after></x-nested-one-slot>`;
18-
const expected = `<div class="nested-one"><div class="nested-one-before">nested-one before</div><div class="nested-one-yield"><div class="nested-two"><div class="nested-two-before">nested-two before</div><div class="nested-two-yield">yield content</div><div class="nested-two-after">nested-two after</div></div></div><div class="nested-one-after">nested-one after</div></div>`;
19-
20-
const html = await posthtml([plugin({root: './test/templates/components'})]).process(actual).then(result => clean(result.html));
21-
22-
expect(html).toBe(expected);
13+
test('Nested component with slots', async () => {
14+
process(
15+
`<x-nested-one-slot><x-nested-two-slot>yield content<fill:before2>nested-two before</fill:before2><fill:after2>nested-two after</fill:after2></x-nested-two-slot><fill:before>nested-one before</fill:before><fill:after>nested-one after</fill:after></x-nested-one-slot>`,
16+
{
17+
root: './test/templates/components',
18+
}
19+
).then(html => {
20+
expect(html).toBe(`<div class="nested-one"><div class="nested-one-before">nested-one before</div><div class="nested-one-yield"><div class="nested-two"><div class="nested-two-before">nested-two before</div><div class="nested-two-yield">yield content</div><div class="nested-two-after">nested-two after</div></div></div><div class="nested-one-after">nested-one after</div></div>`);
21+
});
2322
});

‎test/test-options.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test, expect } from 'vitest'
1+
import { test, expect } from 'vitest';
22
import { process } from './process.js';
33

44
test('`fileExtension` as string', async () => {

‎test/test-plugins.js

+46-50
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,60 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
43

5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test.skip('Must work with posthtml-extend syntax', async () => {
8-
const actual = `<extends src="layouts/extend.html"><block name="content">My Content</block></extends>`;
9-
const expected = `<html><head><title>Extend Layout</title></head><body><main>My Content</main><footer>footer content</footer></body></html>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates', tagName: 'extends', attribute: 'src', slotTagName: 'block', fillTagName: 'block'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
4+
test('posthtml-include', async () => {
5+
process(
6+
`<component src="components/component-with-include.html"></component>`,
7+
{
8+
root: './test/templates',
9+
tag: 'component',
10+
attribute: 'src',
11+
plugins: [
12+
require('posthtml-include')({
13+
root: './test/templates',
14+
cwd: './test/templates',
15+
encoding: 'utf8'
16+
})
17+
]
18+
}
19+
)
20+
.then(html => {
21+
expect(html).toBe('<div><p>Included file</p></div>');
22+
});
1423
});
1524

16-
test.skip('Must work with posthtml-modules syntax', async () => {
17-
const actual = `<module href="components/module.html">My Module Content</module>`;
18-
const expected = `<div>My Module Content</div>`;
25+
// test.skip('Must work with posthtml-extend syntax', async () => {
26+
// const actual = `<extends src="layouts/extend.html"><block name="content">My Content</block></extends>`;
27+
// const expected = `<html><head><title>Extend Layout</title></head><body><main>My Content</main><footer>footer content</footer></body></html>`;
1928

20-
const html = await posthtml([plugin({root: './test/templates', tagName: 'module', attribute: 'href', slotTagName: 'content'})]).process(actual).then(result => clean(result.html));
29+
// const html = await posthtml([plugin({root: './test/templates', tag: 'extends', attribute: 'src', slot: 'block', fill: 'block'})]).process(actual).then(result => clean(result.html));
2130

22-
expect(html).toBe(expected);
23-
});
31+
// expect(html).toBe(expected);
32+
// });
2433

25-
test.skip('Must work with posthtml-extend and posthtml-modules syntax together', async () => {
26-
const actual = `<extends src="layouts/extend-with-module.html"><block name="content"><module href="components/module-with-extend.html">My Module Content</module></block></extends>`;
27-
const expected = `<html><head><title>Extend With Module Layout</title></head><body><main><div>My Module Content</div></main><footer>footer content</footer></body></html>`;
34+
// test.skip('Must work with posthtml-modules syntax', async () => {
35+
// const actual = `<module href="components/module.html">My Module Content</module>`;
36+
// const expected = `<div>My Module Content</div>`;
2837

29-
const html = await posthtml([plugin({root: './test/templates', tagNames: ['extends', 'module'], attributes: ['src', 'href'], slotTagName: 'block', fillTagName: 'block', fallbackSlotTagName: true})]).process(actual).then(result => clean(result.html));
38+
// const html = await posthtml([plugin({root: './test/templates', tagName: 'module', attribute: 'href', slotTagName: 'content'})]).process(actual).then(result => clean(result.html));
3039

31-
expect(html).toBe(expected);
32-
});
40+
// expect(html).toBe(expected);
41+
// });
3342

34-
// Unfortunately it's not working
35-
test.skip('Must include file using posthtml-modules', async () => {
36-
const actual = `<component src="components/component-with-module.html"></component>`;
37-
const expected = `<div><p>Module file</p></div>`;
43+
// test.skip('Must work with posthtml-extend and posthtml-modules syntax together', async () => {
44+
// const actual = `<extends src="layouts/extend-with-module.html"><block name="content"><module href="components/module-with-extend.html">My Module Content</module></block></extends>`;
45+
// const expected = `<html><head><title>Extend With Module Layout</title></head><body><main><div>My Module Content</div></main><footer>footer content</footer></body></html>`;
3846

39-
const html = await posthtml([plugin({root: './test/templates', tag: 'component', attribute: 'src', plugins: [require('posthtml-modules')({root: './test/templates'})]})]).process(actual).then(result => clean(result.html));
47+
// const html = await posthtml([plugin({root: './test/templates', tagNames: ['extends', 'module'], attributes: ['src', 'href'], slotTagName: 'block', fillTagName: 'block', fallbackSlotTagName: true})]).process(actual).then(result => clean(result.html));
4048

41-
expect(html).toBe(expected);
42-
});
49+
// expect(html).toBe(expected);
50+
// });
4351

44-
test('Must include file using posthtml-include', async () => {
45-
const actual = `<component src="components/component-with-include.html"></component>`;
46-
const expected = `<div><p>Included file</p></div>`;
52+
// // Unfortunately it's not working
53+
// test.skip('Must include file using posthtml-modules', async () => {
54+
// const actual = `<component src="components/component-with-module.html"></component>`;
55+
// const expected = `<div><p>Module file</p></div>`;
4756

48-
const html = await posthtml([
49-
plugin({
50-
root: './test/templates',
51-
tag: 'component',
52-
attribute: 'src',
53-
plugins: [
54-
require('posthtml-include')({
55-
root: './test/templates',
56-
cwd: './test/templates',
57-
encoding: 'utf8'
58-
})
59-
]
60-
})
61-
]).process(actual).then(result => clean(result.html));
57+
// const html = await posthtml([plugin({root: './test/templates', tag: 'component', attribute: 'src', plugins: [require('posthtml-modules')({root: './test/templates'})]})]).process(actual).then(result => clean(result.html));
6258

63-
expect(html).toBe(expected);
64-
});
59+
// expect(html).toBe(expected);
60+
// });

‎test/test-slots.js

+120-78
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,135 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
4-
5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must process with slots', async () => {
8-
const actual = `<component src="layouts/base.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
9-
const expected = `<html><head><title>Base Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
3+
4+
test('Slots', async () => {
5+
process(
6+
`<component src="layouts/base.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`,
7+
{
8+
root: './test/templates',
9+
tag: 'component'}
10+
)
11+
.then(html => {
12+
expect(html).toBe(`<html><head><title>Base Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`);
13+
});
1414
});
1515

16-
test('Must output default yield content when not provided', async () => {
17-
const actual = `<component src="components/component-default-yield.html"></component>`;
18-
const expected = `<div>Default yield</div>`;
19-
20-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
21-
22-
expect(html).toBe(expected);
16+
test('Outputs default `yield` content when not provided', async () => {
17+
process(
18+
`<component src="components/component-default-yield.html"></component>`,
19+
{
20+
root: './test/templates',
21+
tag: 'component'
22+
}
23+
)
24+
.then(html => {
25+
expect(html).toBe(`<div>Default yield</div>`);
26+
});
2327
});
2428

25-
test('Must process the same component multiple times', async () => {
26-
const actual = `<component src="components/component.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component><component src="components/component.html"><fill:title>Title 2</fill:title><fill:body>Body 2</fill:body></component>`;
27-
const expected = `<div>Title</div><div>Body</div><div>Title 2</div><div>Body 2</div>`;
28-
29-
const html = await posthtml([plugin({root: './test/templates/', tag: 'component'})]).process(actual).then(result => clean(result.html));
30-
31-
expect(html).toBe(expected);
29+
test('Processes the same component multiple times', async () => {
30+
process(
31+
`<component src="components/component.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component><component src="components/component.html"><fill:title>Title 2</fill:title><fill:body>Body 2</fill:body></component>`,
32+
{
33+
root: './test/templates',
34+
tag: 'component'
35+
}
36+
)
37+
.then(html => {
38+
expect(html).toBe(`<div>Title</div><div>Body</div><div>Title 2</div><div>Body 2</div>`);
39+
});
3240
});
3341

34-
test('Must process multiple time a slot with aware attribute', async () => {
35-
// With aware
36-
let actual = `<component src="components/component-multiple-slot.html"><fill:title aware>Title</fill:title><fill:body>Body</fill:body></component>`;
37-
let expected = `<div>Title</div><div>Body</div><div>Title</div>`;
38-
39-
let html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
40-
41-
expect(html).toBe(expected);
42-
43-
// Without aware
44-
actual = `<component src="components/component-multiple-slot.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component>`;
45-
expected = `<div>Title</div><div>Body</div><div></div>`;
46-
47-
html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
48-
49-
expect(html).toBe(expected);
42+
test('Multiple slots with `aware`', async () => {
43+
// With `aware`
44+
process(
45+
`<component src="components/component-multiple-slot.html"><fill:title aware>Title</fill:title><fill:body>Body</fill:body></component>`,
46+
{
47+
root: './test/templates',
48+
tag: 'component'
49+
}
50+
)
51+
.then(html => {
52+
expect(html).toBe(`<div>Title</div><div>Body</div><div>Title</div>`);
53+
});
54+
55+
// Without `aware`
56+
process(
57+
`<component src="components/component-multiple-slot.html"><fill:title>Title</fill:title><fill:body>Body</fill:body></component>`,
58+
{
59+
root: './test/templates',
60+
tag: 'component'
61+
}
62+
)
63+
.then(html => {
64+
expect(html).toBe(`<div>Title</div><div>Body</div><div></div>`);
65+
});
5066
});
5167

52-
test('Must process append and prepend content to slot', async () => {
53-
const actual = `<component src="components/component-append-prepend.html"><fill:title append><span>Append</span></fill:title><fill:body prepend><span>Prepend</span></fill:body></component>`;
54-
const expected = `<div>Title<span>Append</span></div><div><span>Prepend</span>Body</div>`;
55-
56-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
57-
58-
expect(html).toBe(expected);
68+
test('Slots with `append` and `prepend` attributes', async () => {
69+
process(
70+
`<component src="components/component-append-prepend.html"><fill:title append><span>Append</span></fill:title><fill:body prepend><span>Prepend</span></fill:body></component>`,
71+
{
72+
root: './test/templates',
73+
tag: 'component'
74+
}
75+
)
76+
.then(html => {
77+
expect(html).toBe(`<div>Title<span>Append</span></div><div><span>Prepend</span>Body</div>`);
78+
});
5979
});
6080

61-
test('Must process slots conditional rendering by using slot name', async () => {
62-
let actual = `<component src="layouts/slot-condition.html"><h1>Content</h1></component>`;
63-
let expected = `<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><p>There is not footer defined.</p></body></html>`;
64-
65-
let html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
66-
67-
expect(html).toBe(expected);
68-
69-
actual = `<component src="layouts/slot-condition.html"><h1>Content</h1><fill:footer>There is now footer defined</fill:footer></component>`;
70-
expected = `<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><footer>There is now footer defined</footer></body></html>`;
71-
72-
html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
73-
74-
expect(html).toBe(expected);
81+
test('Conditional rendering of slots based on slot name', async () => {
82+
process(
83+
`<component src="layouts/slot-condition.html"><h1>Content</h1></component>`,
84+
{
85+
root: './test/templates',
86+
tag: 'component'
87+
}
88+
)
89+
.then(html => {
90+
expect(html).toBe(`<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><p>There is not footer defined.</p></body></html>`);
91+
});
92+
93+
process(
94+
`<component src="layouts/slot-condition.html"><h1>Content</h1><fill:footer>There is now footer defined</fill:footer></component>`,
95+
{
96+
root: './test/templates',
97+
tag: 'component'
98+
}
99+
)
100+
.then(html => {
101+
expect(html).toBe(`<html><head><title>Slot Condition Layout</title></head><body><main><h1>Content</h1></main><footer>There is now footer defined</footer></body></html>`);
102+
});
75103
});
76104

77-
test('Must render slots using $slots props', async () => {
78-
const actual = `<component src="layouts/base-render-slots-locals.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`;
79-
const expected = `<html><head><title>Base Render Slots Locals Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`;
80-
81-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
82-
83-
expect(html).toBe(expected);
105+
test('Render slots using `$slots` props', async () => {
106+
process(
107+
`<component src="layouts/base-render-slots-locals.html"><div>Main content</div><fill:header><h1>My header</h1></fill:header><fill:footer>My footer</fill:footer></component>`,
108+
{
109+
root: './test/templates',
110+
tag: 'component'
111+
}
112+
)
113+
.then(html => {
114+
expect(html).toBe(`<html><head><title>Base Render Slots Locals Layout</title></head><body><header><h1>My header</h1></header><main><div>Main content</div></main><footer>My footer</footer></body></html>`);
115+
});
84116
});
85117

86-
test('Must merge global props passed via expressions.locals', async () => {
87-
const actual = `<component src="layouts/global-locals.html" anArray='["third", "fourth"]'><div>Main content</div></component>`;
88-
const expected = `<html><head><title>My page title</title></head><body><main><div>Main content</div></main><span>first</span><span>second</span><span>third</span><span>fourth</span></body></html>`;
89-
90-
const html = await posthtml([plugin({root: './test/templates', tag: 'component', expressions: {locals: {title: 'My page title', anArray: ['first', 'second']}}})]).process(actual).then(result => clean(result.html));
91-
92-
expect(html).toBe(expected);
118+
test('Merges global props passed via `expressions.locals`', async () => {
119+
process(
120+
`<component src="layouts/global-locals.html" anArray='["third", "fourth"]'><div>Main content</div></component>`,
121+
{
122+
root: './test/templates',
123+
tag: 'component',
124+
expressions: {
125+
locals: {
126+
title: 'My page title',
127+
anArray: ['first', 'second']
128+
}
129+
}
130+
}
131+
)
132+
.then(html => {
133+
expect(html).toBe(`<html><head><title>My page title</title></head><body><main><div>Main content</div></main><span>first</span><span>second</span><span>third</span><span>fourth</span></body></html>`);
134+
});
93135
});

‎test/test-stacks.js

+24-19
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
43

5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must process stacks and push', async () => {
8-
const actual = `<component src="layouts/base.html"><div>Main content</div><push name="head"><meta name="pushed" content="Content pushed"></push></component>`;
9-
const expected = `<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
4+
test('`stack` and `push` tags', async () => {
5+
process(
6+
`<component src="layouts/base.html"><div>Main content</div><push name="head"><meta name="pushed" content="Content pushed"></push></component>`,
7+
{
8+
root: './test/templates',
9+
tag: 'component'
10+
}
11+
)
12+
.then(html => {
13+
expect(html).toBe(`<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`);
14+
});
1415
});
1516

16-
test('Must prepend push on stack once', async () => {
17-
const actual = `<component src="layouts/base.html"><div>Main content</div><push name="head" prepend once><meta name="pushed" content="Content pushed"></push><push name="head" prepend once><meta name="pushed" content="Content pushed"></push></component>`;
18-
const expected = `<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`;
19-
20-
const html = await posthtml([plugin({root: './test/templates', tag: 'component'})]).process(actual).then(result => clean(result.html));
21-
22-
expect(html).toBe(expected);
17+
test('`prepend` and `once` attributes on `push` tag', async () => {
18+
process(
19+
`<component src="layouts/base.html"><div>Main content</div><push name="head" prepend once><meta name="pushed" content="Content pushed"></push><push name="head" prepend once><meta name="pushed" content="Content pushed"></push></component>`,
20+
{
21+
root: './test/templates',
22+
tag: 'component'
23+
}
24+
)
25+
.then(html => {
26+
expect(html).toBe(`<html><head><title>Base Layout</title><meta name="pushed" content="Content pushed"></head><body><header></header><main><div>Main content</div></main><footer>footer content</footer></body></html>`);
27+
});
2328
});

‎test/test-x-tag.js

+110-63
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,125 @@
1-
import { test, expect } from 'vitest'
2-
import plugin from '../src/index.js';
3-
import posthtml from 'posthtml';
4-
5-
const clean = html => html.replace(/(\n|\t)/g, '').trim();
6-
7-
test('Must process component with x-tag', async () => {
8-
const actual = `<x-modal></x-modal>`;
9-
const expected = `<div>Modal</div>`;
10-
11-
const html = await posthtml([plugin({root: './test/templates', folders: 'components'})]).process(actual).then(result => clean(result.html));
12-
13-
expect(html).toBe(expected);
1+
import { test, expect } from 'vitest';
2+
import { process } from './process.js';
3+
4+
test('x-tag', async () => {
5+
process('<x-modal></x-modal>', {root: './test/templates', folders: 'components'})
6+
.then(html => {
7+
expect(html).toBe('<div>Modal</div>');
8+
});
149
});
1510

16-
test('Must process component with namespace', async () => {
17-
const actual = `<x-dark::button>My button</x-dark::button>`;
18-
const expected = `<button class="bg-dark text-light">My button</button>`;
19-
20-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components'}]})]).process(actual).then(result => clean(result.html));
21-
22-
expect(html).toBe(expected);
11+
test('x-tag self-closing', async () => {
12+
process(
13+
'<p>first</p><x-modal /><p>last</p>',
14+
{
15+
root: './test/templates',
16+
folders: 'components',
17+
parserOptions: {
18+
recognizeSelfClosing: true
19+
}
20+
}
21+
)
22+
.then(html => {
23+
expect(html).toBe('<p>first</p><div>Modal</div><p>last</p>');
24+
});
2325
});
2426

25-
test('Must process component with namespace using index file', async () => {
26-
const actual = `<x-dark::label></x-dark::label>`;
27-
const expected = `<label class="bg-dark text-light">My Dark Label</label>`;
28-
29-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components'}]})]).process(actual).then(result => clean(result.html));
30-
31-
expect(html).toBe(expected);
27+
test('x-tag with namespace', async () => {
28+
process(
29+
'<x-dark::button>My button</x-dark::button>',
30+
{
31+
root: './test/templates',
32+
namespaces: [{
33+
name: 'dark',
34+
root: './test/templates/dark/components'
35+
}]
36+
}
37+
)
38+
.then(html => {
39+
expect(html).toBe('<button class="bg-dark text-light">My button</button>');
40+
});
3241
});
3342

34-
test(`Must process component with namespace's fallback path`, async () => {
35-
const actual = `<x-dark::modal></x-dark::modal>`;
36-
const expected = `<div>Modal</div>`;
37-
38-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', fallback: './test/templates/components'}]})]).process(actual).then(result => clean(result.html));
39-
40-
expect(html).toBe(expected);
43+
test('x-tag with namespace (index file)', async () => {
44+
process(
45+
'<x-dark::label></x-dark::label>',
46+
{
47+
root: './test/templates',
48+
namespaces: [{
49+
name: 'dark',
50+
root: './test/templates/dark/components'
51+
}]
52+
}
53+
)
54+
.then(html => {
55+
expect(html).toBe('<label class="bg-dark text-light">My Dark Label</label>');
56+
});
4157
});
4258

43-
test(`Must process component with namespace's fallback path using index file`, async () => {
44-
const actual = `<x-dark::form></x-dark::form>`;
45-
const expected = `<form>My Form</form>`;
46-
47-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', fallback: './test/templates/components'}]})]).process(actual).then(result => clean(result.html));
48-
49-
expect(html).toBe(expected);
59+
test('x-tag with namespace `fallback` path', async () => {
60+
process(
61+
'<x-dark::modal></x-dark::modal>',
62+
{
63+
root: './test/templates',
64+
namespaces: [{
65+
name: 'dark',
66+
root: './test/templates/dark/components',
67+
fallback: './test/templates/components'
68+
}]
69+
}
70+
)
71+
.then(html => {
72+
expect(html).toBe('<div>Modal</div>');
73+
});
5074
});
5175

52-
test(`Must process component with namespace's custom path`, async () => {
53-
const actual = `<x-dark::button>My button</x-dark::button>`;
54-
const expected = `<button class="bg-dark-custom text-light-custom">My button</button>`;
55-
56-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', custom: './test/templates/custom/dark/components'}]})]).process(actual).then(result => clean(result.html));
57-
58-
expect(html).toBe(expected);
76+
test('x-tag with namespace `fallback` path (index file)', async () => {
77+
process(
78+
'<x-dark::form></x-dark::form>',
79+
{
80+
root: './test/templates',
81+
namespaces: [{
82+
name: 'dark',
83+
root: './test/templates/dark/components',
84+
fallback: './test/templates/components'
85+
}]
86+
}
87+
)
88+
.then(html => {
89+
expect(html).toBe('<form>My Form</form>');
90+
});
5991
});
6092

61-
test(`Must process component with namespace's custom path using index file`, async () => {
62-
const actual = `<x-dark::label></x-dark::label>`;
63-
const expected = `<label>My Label</label>`;
64-
65-
const html = await posthtml([plugin({root: './test/templates', namespaces: [{name: 'dark', root: './test/templates/dark/components', custom: './test/templates/custom/dark/components'}]})]).process(actual).then(result => clean(result.html));
66-
67-
expect(html).toBe(expected);
93+
test('x-tag with namespace `custom` path', async () => {
94+
process(
95+
'<x-dark::button>My button</x-dark::button>',
96+
{
97+
root: './test/templates',
98+
namespaces: [{
99+
name: 'dark',
100+
root: './test/templates/dark/components',
101+
custom: './test/templates/custom/dark/components'
102+
}]
103+
}
104+
)
105+
.then(html => {
106+
expect(html).toBe('<button class="bg-dark-custom text-light-custom">My button</button>');
107+
});
68108
});
69109

70-
test('Must process self-closing component x-tag', async () => {
71-
const actual = `<p>first</p><x-modal /><p>last</p>`;
72-
const expected = `<p>first</p><div>Modal</div><p>last</p>`;
73-
74-
const html = await posthtml([plugin({root: './test/templates', folders: 'components'})])
75-
.process(actual, {recognizeSelfClosing: true}).then(result => clean(result.html));
76-
77-
expect(html).toBe(expected);
110+
test('x-tag with namespace `custom` path (index file)', async () => {
111+
process(
112+
'<x-dark::label></x-dark::label>',
113+
{
114+
root: './test/templates',
115+
namespaces: [{
116+
name: 'dark',
117+
root: './test/templates/dark/components',
118+
custom: './test/templates/custom/dark/components'
119+
}]
120+
}
121+
)
122+
.then(html => {
123+
expect(html).toBe('<label>My Label</label>');
124+
});
78125
});

0 commit comments

Comments
 (0)
Please sign in to comment.