import { WarningMessage } from 'types/compiler' import { parseComponent } from '../src/parseComponent' describe('Single File Component parser', () => { it('should parse', () => { const res = parseComponent( ` <template> <div>hi</div> </template> <style src="./test.css"></style> <style lang="stylus" scoped> h1 color red h2 color green </style> <style module> h1 { font-weight: bold } </style> <style bool-attr val-attr="test"></style> <script> export default {} </script> <div> <style>nested should be ignored</style> </div> ` ) expect(res.template!.content.trim()).toBe('<div>hi</div>') expect(res.styles.length).toBe(4) expect(res.styles[0].src).toBe('./test.css') expect(res.styles[1].lang).toBe('stylus') expect(res.styles[1].scoped).toBe(true) expect(res.styles[1].content.trim()).toBe( 'h1\n color red\nh2\n color green' ) expect(res.styles[2].module).toBe(true) expect(res.styles[3].attrs['bool-attr']).toBe(true) expect(res.styles[3].attrs['val-attr']).toBe('test') expect(res.script!.content.trim()).toBe('export default {}') }) it('should parse template with closed input', () => { const res = parseComponent(` <template> <input type="text"/> </template> `) expect(res.template!.content.trim()).toBe('<input type="text"/>') }) it('should handle nested template', () => { const res = parseComponent(` <template> <div><template v-if="ok">hi</template></div> </template> `) expect(res.template!.content.trim()).toBe( '<div><template v-if="ok">hi</template></div>' ) }) it('deindent content', () => { const content = ` <template> <div></div> </template> <script> export default {} </script> <style> h1 { color: red } </style> ` const deindentDefault = parseComponent(content.trim(), { pad: false }) const deindentEnabled = parseComponent(content.trim(), { pad: false, deindent: true }) const deindentDisabled = parseComponent(content.trim(), { pad: false, deindent: false }) expect(deindentDefault.template!.content).toBe('\n<div></div>\n') expect(deindentDefault.script!.content).toBe( '\n export default {}\n ' ) expect(deindentDefault.styles[0].content).toBe('\nh1 { color: red }\n') expect(deindentEnabled.template!.content).toBe('\n<div></div>\n') expect(deindentEnabled.script!.content).toBe('\nexport default {}\n') expect(deindentEnabled.styles[0].content).toBe('\nh1 { color: red }\n') expect(deindentDisabled.template!.content).toBe( '\n <div></div>\n ' ) expect(deindentDisabled.script!.content).toBe( '\n export default {}\n ' ) expect(deindentDisabled.styles[0].content).toBe( '\n h1 { color: red }\n ' ) }) it('pad content', () => { const content = ` <template> <div></div> </template> <script> export default {} </script> <style> h1 { color: red } </style> ` const padDefault = parseComponent(content.trim(), { pad: true, deindent: true }) const padLine = parseComponent(content.trim(), { pad: 'line', deindent: true }) const padSpace = parseComponent(content.trim(), { pad: 'space', deindent: true }) expect(padDefault.script!.content).toBe( Array(3 + 1).join('//\n') + '\nexport default {}\n' ) expect(padDefault.styles[0].content).toBe( Array(6 + 1).join('\n') + '\nh1 { color: red }\n' ) expect(padLine.script!.content).toBe( Array(3 + 1).join('//\n') + '\nexport default {}\n' ) expect(padLine.styles[0].content).toBe( Array(6 + 1).join('\n') + '\nh1 { color: red }\n' ) expect(padSpace.script!.content).toBe( `<template> <div></div> </template> <script>`.replace(/./g, ' ') + '\nexport default {}\n' ) expect(padSpace.styles[0].content).toBe( `<template> <div></div> </template> <script> export default {} </script> <style>`.replace(/./g, ' ') + '\nh1 { color: red }\n' ) }) it('should handle template blocks with lang as special text', () => { const res = parseComponent( ` <template lang="pug"> div h1(v-if='1 < 2') hello </template> `, { deindent: true } ) expect(res.template!.content.trim()).toBe(`div\n h1(v-if='1 < 2') hello`) }) it('should handle component contains "<" only', () => { const res = parseComponent(` <template> <span><</span> </template> `) expect(res.template!.content.trim()).toBe(`<span><</span>`) }) it('should handle custom blocks without parsing them', () => { const res = parseComponent( ` <template> <div></div> </template> <example name="simple"> <my-button ref="button">Hello</my-button> </example> <example name="with props"> <my-button color="red">Hello</my-button> </example> <test name="simple" foo="bar"> export default function simple (vm) { describe('Hello', () => { it('should display Hello', () => { this.vm.$refs.button.$el.innerText.should.equal('Hello') })) })) } </test> <custom src="./x.json"></custom> ` ) expect(res.customBlocks.length).toBe(4) const simpleExample = res.customBlocks[0] expect(simpleExample.type).toBe('example') expect(simpleExample.content.trim()).toBe( '<my-button ref="button">Hello</my-button>' ) expect(simpleExample.attrs.name).toBe('simple') const withProps = res.customBlocks[1] expect(withProps.type).toBe('example') expect(withProps.content.trim()).toBe( '<my-button color="red">Hello</my-button>' ) expect(withProps.attrs.name).toBe('with props') const simpleTest = res.customBlocks[2] expect(simpleTest.type).toBe('test') expect(simpleTest.content.trim()) .toBe(`export default function simple (vm) { describe('Hello', () => { it('should display Hello', () => { this.vm.$refs.button.$el.innerText.should.equal('Hello') })) })) }`) expect(simpleTest.attrs.name).toBe('simple') expect(simpleTest.attrs.foo).toBe('bar') const customWithSrc = res.customBlocks[3] expect(customWithSrc.src).toBe('./x.json') }) // Regression #4289 it('accepts nested template tag', () => { const raw = `<div> <template v-if="true === true"> <section class="section"> <div class="container"> Should be shown </div> </section> </template> <template v-else> <p>Should not be shown</p> </template> </div>` const res = parseComponent(`<template>${raw}</template>`) expect(res.template!.content.trim()).toBe(raw) }) it('should not hang on trailing text', () => { const res = parseComponent(`<template>hi</`) expect(res.template!.content).toBe('hi') }) it('should collect errors with source range', () => { const res = parseComponent(`<template>hi</`, { outputSourceRange: true }) expect(res.errors.length).toBe(1) expect((res.errors[0] as WarningMessage).start).toBe(0) }) })