|
1 | 1 | import { transform } from '@babel/core'; |
2 | 2 | import transformJsxToTaggedTemplatesPlugin from '../src/index.mjs'; |
3 | 3 |
|
| 4 | +function compile(code, { plugins = [], ...options } = {}) { |
| 5 | + return transform(code, { |
| 6 | + babelrc: false, |
| 7 | + plugins: [ |
| 8 | + ...plugins, |
| 9 | + [transformJsxToTaggedTemplatesPlugin, options] |
| 10 | + ] |
| 11 | + }).code; |
| 12 | +} |
| 13 | + |
4 | 14 | describe('babel-plugin-transform-jsx-to-tagged-templates', () => { |
5 | | - test('basic transformation', () => { |
6 | | - expect( |
7 | | - transform('(<div />);', { |
8 | | - babelrc: false, |
9 | | - plugins: [ |
10 | | - transformJsxToTaggedTemplatesPlugin |
11 | | - ] |
12 | | - }).code |
13 | | - ).toBe('html`<div/>`;'); |
| 15 | + describe('elements and text', () => { |
| 16 | + test('single named element', () => { |
| 17 | + expect( |
| 18 | + compile('(<div />);') |
| 19 | + ).toBe('html`<div/>`;'); |
| 20 | + |
| 21 | + expect( |
| 22 | + compile('(<div>a</div>);') |
| 23 | + ).toBe('html`<div>a</div>`;'); |
| 24 | + }); |
14 | 25 |
|
15 | | - expect( |
16 | | - transform('(<span>a</span>);', { |
17 | | - babelrc: false, |
18 | | - plugins: [ |
19 | | - transformJsxToTaggedTemplatesPlugin |
20 | | - ] |
21 | | - }).code |
22 | | - ).toBe('html`<span>a</span>`;'); |
| 26 | + test('single component element', () => { |
| 27 | + expect( |
| 28 | + compile('(<Foo />);') |
| 29 | + ).toBe('html`<${Foo}/>`;'); |
23 | 30 |
|
24 | | - expect( |
25 | | - transform('(<div>hello</div>);', { |
26 | | - babelrc: false, |
27 | | - plugins: [ |
28 | | - transformJsxToTaggedTemplatesPlugin |
29 | | - ] |
30 | | - }).code |
31 | | - ).toBe('html`<div>hello</div>`;'); |
| 31 | + expect( |
| 32 | + compile('(<Foo>a</Foo>);') |
| 33 | + ).toBe('html`<${Foo}>a</${Foo}>`;'); |
| 34 | + }); |
32 | 35 | }); |
33 | 36 |
|
34 | | - test('nested children transformation', () => { |
35 | | - expect( |
36 | | - transform('const Foo = () => <div class="foo" draggable>\n <h1>Hello</h1>\n <p>world.</p>\n</div>;', { |
37 | | - babelrc: false, |
38 | | - plugins: [ |
39 | | - transformJsxToTaggedTemplatesPlugin |
40 | | - ] |
41 | | - }).code |
42 | | - ).toBe('const Foo = () => html`<div class="foo" draggable>\n <h1>Hello</h1>\n <p>world.</p>\n</div>`;'); |
| 37 | + describe('options.html = true', () => { |
| 38 | + test('use explicit end tags instead of self-closing', () => { |
| 39 | + expect( |
| 40 | + compile('(<div />);', { html: true }) |
| 41 | + ).toBe('html`<div></div>`;'); |
| 42 | + |
| 43 | + expect( |
| 44 | + compile('(<div a />);', { html: true }) |
| 45 | + ).toBe('html`<div a></div>`;'); |
| 46 | + |
| 47 | + expect( |
| 48 | + compile('(<a>b</a>);', { html: true }) |
| 49 | + ).toBe('html`<a>b</a>`;'); |
| 50 | + }); |
43 | 51 | }); |
44 | 52 |
|
45 | 53 | describe('props', () => { |
46 | 54 | test('static values', () => { |
47 | 55 | expect( |
48 | | - transform('(<div a="a" b="bb" c d />);', { |
49 | | - babelrc: false, |
50 | | - plugins: [ |
51 | | - transformJsxToTaggedTemplatesPlugin |
52 | | - ] |
53 | | - }).code |
| 56 | + compile('(<div a="a" b="bb" c d />);') |
54 | 57 | ).toBe('html`<div a="a" b="bb" c d/>`;'); |
55 | 58 | }); |
56 | 59 |
|
57 | 60 | test('expression values', () => { |
58 | 61 | expect( |
59 | | - transform('const Foo = (props, a) => <div a={a} b={"b"} c={{}} d={props.d} e />;', { |
60 | | - babelrc: false, |
61 | | - plugins: [ |
62 | | - transformJsxToTaggedTemplatesPlugin |
63 | | - ] |
64 | | - }).code |
| 62 | + compile('const Foo = (props, a) => <div a={a} b={"b"} c={{}} d={props.d} e />;') |
65 | 63 | ).toBe('const Foo = (props, a) => html`<div a=${a} b=${"b"} c=${{}} d=${props.d} e/>`;'); |
66 | 64 | }); |
67 | 65 | }); |
68 | 66 |
|
69 | | - test('whitespace', () => { |
70 | | - expect( |
71 | | - transform('const Foo = props => <div a b> a <em> b </em> c <strong> d </strong> e </div>;', { |
72 | | - babelrc: false, |
73 | | - plugins: [ |
74 | | - transformJsxToTaggedTemplatesPlugin |
75 | | - ] |
76 | | - }).code |
77 | | - ).toBe('const Foo = props => html`<div a b> a <em> b </em> c <strong> d </strong> e </div>`;'); |
78 | | - }); |
| 67 | + describe('nesting', () => { |
| 68 | + test('element children are merged into one template', () => { |
| 69 | + expect( |
| 70 | + compile('const Foo = () => <div class="foo" draggable>\n <h1>Hello</h1>\n <p>world.</p>\n</div>;') |
| 71 | + ).toBe('const Foo = () => html`<div class="foo" draggable><h1>Hello</h1><p>world.</p></div>`;'); |
| 72 | + }); |
79 | 73 |
|
80 | | - test('nested templates', () => { |
81 | | - expect( |
82 | | - transform('const Foo = props => <ul>{props.items.map(item =>\n <li>\n {item}\n </li>\n)}</ul>;', { |
83 | | - babelrc: false, |
84 | | - plugins: [ |
85 | | - transformJsxToTaggedTemplatesPlugin |
86 | | - ] |
87 | | - }).code |
88 | | - ).toBe('const Foo = props => html`<ul>${props.items.map(item => html`<li>\n ${item}\n </li>`)}</ul>`;'); |
| 74 | + test('inter-element whitespace is collapsed', () => { |
| 75 | + expect( |
| 76 | + compile('const Foo = props => <div a b> a <em> b </em> c <strong> d </strong> e </div>;') |
| 77 | + ).toBe('const Foo = props => html`<div a b>a<em>b</em>c<strong>d</strong>e</div>`;'); |
| 78 | + }); |
| 79 | + |
| 80 | + test('nested JSX Expressions produce nested templates', () => { |
| 81 | + expect( |
| 82 | + compile('const Foo = props => <ul>{props.items.map(item =>\n <li>\n {item}\n </li>\n)}</ul>;') |
| 83 | + ).toBe('const Foo = props => html`<ul>${props.items.map(item => html`<li>${item}</li>`)}</ul>`;'); |
| 84 | + }); |
89 | 85 | }); |
90 | 86 |
|
91 | | - test('integration with babel-plugin-jsx-pragmatic', () => { |
92 | | - expect( |
93 | | - transform('const Foo = props => <div>hello</div>;', { |
94 | | - babelrc: false, |
95 | | - plugins: [ |
96 | | - ['babel-plugin-jsx-pragmatic', { |
97 | | - // module to import: |
98 | | - module: 'lit-html', |
99 | | - // the name of the export to use: |
100 | | - export: 'html', |
101 | | - // whatever you specified for the "tag" option: |
102 | | - import: '$$html' |
103 | | - }], |
104 | | - [transformJsxToTaggedTemplatesPlugin, { |
105 | | - tag: '$$html' |
106 | | - }] |
107 | | - ] |
108 | | - }).code |
109 | | - ).toBe('import { html as $$html } from "lit-html";\n\nconst Foo = props => $$html`<div>hello</div>`;'); |
| 87 | + describe('integration with babel-plugin-jsx-pragmatic', () => { |
| 88 | + test('JSX is still identified and import added', () => { |
| 89 | + expect( |
| 90 | + compile('const Foo = props => <div>hello</div>;', { |
| 91 | + tag: '$$html', |
| 92 | + plugins: [ |
| 93 | + ['babel-plugin-jsx-pragmatic', { |
| 94 | + // module to import: |
| 95 | + module: 'lit-html', |
| 96 | + // the name of the export to use: |
| 97 | + export: 'html', |
| 98 | + // whatever you specified for the "tag" option: |
| 99 | + import: '$$html' |
| 100 | + }] |
| 101 | + ] |
| 102 | + }) |
| 103 | + ).toBe('import { html as $$html } from "lit-html";\n\nconst Foo = props => $$html`<div>hello</div>`;'); |
| 104 | + }); |
110 | 105 | }); |
111 | 106 | }); |
0 commit comments