support Fragment

This commit is contained in:
Amour1688 2020-05-17 16:36:38 +08:00
parent 9608e0afca
commit 68da671c5a
6 changed files with 90 additions and 13 deletions

View File

@ -24,7 +24,7 @@ const App = defineComponent(() => {
}; };
return () => ( return () => (
<div> <>
Foo {count.value} Foo {count.value}
<SuperButton <SuperButton
buttonText="VueComponent" buttonText="VueComponent"
@ -33,7 +33,7 @@ const App = defineComponent(() => {
click: inc, click: inc,
}} }}
/> />
</div> </>
); );
}); });

View File

@ -26,7 +26,6 @@
"@babel/helper-module-imports": "^7.8.3", "@babel/helper-module-imports": "^7.8.3",
"@babel/plugin-syntax-jsx": "^7.8.3", "@babel/plugin-syntax-jsx": "^7.8.3",
"@babel/types": "^7.9.6", "@babel/types": "^7.9.6",
"@vue/babel-preset-jsx": "^1.1.2",
"html-tags": "^3.1.0", "html-tags": "^3.1.0",
"svg-tags": "^1.0.0" "svg-tags": "^1.0.0"
}, },

View File

@ -0,0 +1,28 @@
const syntaxJsx = require('@babel/plugin-syntax-jsx').default;
const t = require('@babel/types');
const helperModuleImports = require('@babel/helper-module-imports');
const transformFragment = (path, { name }) => {
const children = path.get('children') || [];
return t.jsxElement(
t.jsxOpeningElement(t.jsxIdentifier(name), []),
t.jsxClosingElement(t.jsxIdentifier(name)),
children.map(({ node }) => node),
false,
);
};
module.exports = () => ({
name: 'babel-sugar-fragment',
inherits: syntaxJsx,
visitor: {
JSXFragment: {
enter(path, state) {
if (!state.vueFragment) {
state.vueFragment = helperModuleImports.addNamed(path, 'Fragment', 'vue');
}
path.replaceWith(transformFragment(path, state.vueFragment));
},
},
},
});

View File

@ -1,7 +1,9 @@
const babelPluginTransformVueJsx = require('./babel-plugin-transform-vue-jsx'); const babelPluginTransformVueJsx = require('./babel-plugin-transform-vue-jsx');
const babelSugarFragment = require('./babel-sugar-fragment');
module.exports = () => ({ module.exports = () => ({
plugins: [ plugins: [
babelPluginTransformVueJsx, babelPluginTransformVueJsx,
babelSugarFragment,
], ],
}); });

View File

@ -1,5 +1,14 @@
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
test('should render with render function', () => {
const wrapper = shallowMount({
render() {
return <div>123</div>;
},
});
expect(wrapper.text()).toBe('123');
});
test('should render with setup', () => { test('should render with setup', () => {
const wrapper = shallowMount({ const wrapper = shallowMount({
setup() { setup() {
@ -44,17 +53,26 @@ test('should not fallthrough with inheritAttrs: false', () => {
expect(wrapper.text()).toBe('1'); expect(wrapper.text()).toBe('1');
}); });
test('Fragment', () => {
const Child = () => <div>123</div>;
test('should render', () => { Child.inheritAttrs = false;
const App = {
render() { const wrapper = shallowMount({
return <div>1234</div>; setup() {
return () => (
<>
<Child />
<div>456</div>
</>
);
}, },
}; });
const wrapper = shallowMount(App);
expect(wrapper.html()).toBe('<div>1234</div>'); expect(wrapper.html()).toBe('<div>123</div><div>456</div>');
}); });
test('xlink:href', () => { test('xlink:href', () => {
const wrapper = shallowMount({ const wrapper = shallowMount({
setup() { setup() {
@ -119,6 +137,27 @@ test('domProps input[value]', () => {
expect(wrapper.html()).toBe('<input type="text">'); expect(wrapper.html()).toBe('<input type="text">');
}); });
test('domProps input[checked]', () => {
const val = 'foo';
const wrapper = shallowMount({
setup() {
return () => <input checked={val} />;
},
});
expect(wrapper.componentVM);
});
test('domProps option[selected]', () => {
const val = 'foo';
const wrapper = shallowMount({
render() {
return <option selected={val} />;
},
});
expect(wrapper);
});
test('Spread (single object expression)', () => { test('Spread (single object expression)', () => {
const props = { const props = {
innerHTML: 123, innerHTML: 123,
@ -132,7 +171,7 @@ test('Spread (single object expression)', () => {
expect(wrapper.html()).toBe('<div other="1">123</div>'); expect(wrapper.html()).toBe('<div other="1">123</div>');
}); });
test('Spread (mixed)', () => { test('Spread (mixed)', async () => {
const calls = []; const calls = [];
const data = { const data = {
id: 'hehe', id: 'hehe',
@ -143,7 +182,7 @@ test('Spread (mixed)', () => {
class: ['a', 'b'], class: ['a', 'b'],
}; };
shallowMount({ const wrapper = shallowMount({
setup() { setup() {
return () => ( return () => (
<div <div
@ -151,9 +190,17 @@ test('Spread (mixed)', () => {
{...data} {...data}
class={{ c: true }} class={{ c: true }}
onClick={() => calls.push(4)} onClick={() => calls.push(4)}
hook-insert={() => calls.push(2)}
/> />
); );
}, },
}); });
expect(wrapper.attributes('id')).toBe('hehe');
expect(wrapper.attributes('href')).toBe('huhu');
expect(wrapper.text()).toBe('2');
expect(wrapper.classes()).toEqual(expect.arrayContaining(['a', 'b', 'c']));
await wrapper.trigger('click');
expect(calls).toEqual(expect.arrayContaining([3, 4]));
}); });

1
test/setup.js Normal file
View File

@ -0,0 +1 @@
import 'regenerator-runtime/runtime';