import { parse } from 'compiler/parser/index' import { extend } from 'shared/util' import { baseOptions } from 'web/compiler/options' import { isIE, isEdge } from 'core/util/env' describe('parser', () => { it('simple element', () => { const ast = parse('
hello world
{{msg}}
{{msg}}
hello world
', baseOptions) expect(ast.if).toBe('show') expect(ast.ifConditions[0].exp).toBe('show') }) it('v-else-if directive syntax', () => { const ast = parse( 'hello
elseifworld
hello
world
world
world
world
', baseOptions) expect(ast.once).toBe(true) }) it('slot tag single syntax', () => { const ast = parse('hello world
', baseOptions) expect(ast.slotTarget).toBe('"one"') }) it('component properties', () => { const ast = parse('hello world
', baseOptions) expect(ast1.staticClass).toBe('"class1"') // dynamic const ast2 = parse('hello world
', baseOptions) expect(ast2.classBinding).toBe('class1') // interpolation warning parse('hello world
', baseOptions) expect( 'Interpolation inside attributes has been removed' ).toHaveBeenWarned() }) it('style binding', () => { const ast = parse('hello world
', baseOptions) expect(ast.styleBinding).toBe('error') }) it('attribute with v-bind', () => { const ast = parse( '', baseOptions ) expect(ast.attrsList[0].name).toBe('type') expect(ast.attrsList[0].value).toBe('text') expect(ast.attrsList[1].name).toBe('name') expect(ast.attrsList[1].value).toBe('field1') expect(ast.attrsMap['type']).toBe('text') expect(ast.attrsMap['name']).toBe('field1') expect(ast.attrs[0].name).toBe('type') expect(ast.attrs[0].value).toBe('"text"') expect(ast.attrs[1].name).toBe('name') expect(ast.attrs[1].value).toBe('"field1"') expect(ast.props[0].name).toBe('value') expect(ast.props[0].value).toBe('msg') }) it('empty v-bind expression', () => { parse('', baseOptions) expect( 'The value for a v-bind expression cannot be empty. Found in "v-bind:empty-msg"' ).toHaveBeenWarned() }) if (process.env.VBIND_PROP_SHORTHAND) { it('v-bind.prop shorthand syntax', () => { const ast = parse('', baseOptions) expect(ast.props).toEqual([{ name: 'id', value: 'foo', dynamic: false }]) }) it('v-bind.prop shorthand syntax w/ modifiers', () => { const ast = parse('', baseOptions) expect(ast.props).toEqual([{ name: 'id', value: 'foo', dynamic: false }]) }) it('v-bind.prop shorthand dynamic argument', () => { const ast = parse('', baseOptions) expect(ast.props).toEqual([{ name: 'id', value: 'foo', dynamic: true }]) }) } // This only works for string templates. // In-DOM templates will be malformed before Vue can parse it. describe('parse and warn invalid dynamic arguments', () => { ;[ ``, ``, ``, `hello world
', baseOptions) expect('duplicate attribute').toHaveBeenWarned() }) } it('custom delimiter', () => { const ast = parse( '{msg}
', extend({ delimiters: ['{', '}'] }, baseOptions) ) expect(ast.children[0].expression).toBe('_s(msg)') }) it('not specified getTagNamespace option', () => { const options = extend({}, baseOptions) delete options.getTagNamespace const ast = parse('', options) expect(ast.tag).toBe('svg') expect(ast.ns).toBeUndefined() }) it('not specified mustUseProp', () => { const options = extend({}, baseOptions) delete options.mustUseProp const ast = parse('', options) expect(ast.props).toBeUndefined() }) it('use prop when prop modifier was explicitly declared', () => { const ast = parse( ' tag', function () {
const options = extend({}, baseOptions)
const ast = parse(
' \nhi\n
',
options
)
const code = ast.children[0]
expect(code.children[0].type).toBe(3)
expect(code.children[0].text).toBe(' \n')
expect(code.children[2].type).toBe(3)
expect(code.children[2].text).toBe('\n ')
const span = ast.children[1]
expect(span.children[0].type).toBe(3)
expect(span.children[0].text).toBe(' ')
})
// #5992
it('ignore the first newline in tag', function () {
const options = extend({}, baseOptions)
const ast = parse(
'\nabc
\ndef\n\nabc
',
options
)
const pre = ast.children[0]
expect(pre.children[0].type).toBe(3)
expect(pre.children[0].text).toBe('abc')
const text = ast.children[1]
expect(text.type).toBe(3)
expect(text.text).toBe('\ndef')
const pre2 = ast.children[2]
expect(pre2.children[0].type).toBe(3)
expect(pre2.children[0].text).toBe('\nabc')
})
it('keep first newline after unary tag in ', () => {
const options = extend({}, baseOptions)
const ast = parse('abc\ndef
', options)
expect(ast.children[1].type).toBe(1)
expect(ast.children[1].tag).toBe('input')
expect(ast.children[2].type).toBe(3)
expect(ast.children[2].text).toBe('\ndef')
})
it('forgivingly handle < in plain text', () => {
const options = extend({}, baseOptions)
const ast = parse('1 < 2 < 3
', options)
expect(ast.tag).toBe('p')
expect(ast.children.length).toBe(1)
expect(ast.children[0].type).toBe(3)
expect(ast.children[0].text).toBe('1 < 2 < 3')
})
it('IE conditional comments', () => {
const options = extend({}, baseOptions)
const ast = parse(
`
`,
options
)
expect(ast.tag).toBe('div')
expect(ast.children.length).toBe(0)
})
it('parse content in textarea as text', () => {
const options = extend({}, baseOptions)
const whitespace = parse(
`
`,
options
)
expect(whitespace.tag).toBe('textarea')
expect(whitespace.children.length).toBe(1)
expect(whitespace.children[0].type).toBe(3)
// textarea is whitespace sensitive
expect(whitespace.children[0].text).toBe(` Test 1
test2
`)
const comment = parse('', options)
expect(comment.tag).toBe('textarea')
expect(comment.children.length).toBe(1)
expect(comment.children[0].type).toBe(3)
expect(comment.children[0].text).toBe('')
})
// #5526
it('should not decode text in script tags', () => {
const options = extend({}, baseOptions)
const ast = parse(
``,
options
)
expect(ast.children[0].text).toBe(`><`)
})
it('should ignore comments', () => {
const options = extend({}, baseOptions)
const ast = parse(`123`, options)
expect(ast.tag).toBe('div')
expect(ast.children.length).toBe(1)
expect(ast.children[0].type).toBe(3)
expect(ast.children[0].text).toBe('123')
})
it('should kept comments', () => {
const options = extend(
{
comments: true
},
baseOptions
)
const ast = parse(`123`, options)
expect(ast.tag).toBe('div')
expect(ast.children.length).toBe(2)
expect(ast.children[0].type).toBe(3)
expect(ast.children[0].text).toBe('123')
expect(ast.children[1].type).toBe(3) // parse comment with ASTText
expect(ast.children[1].isComment).toBe(true) // parse comment with ASTText
expect(ast.children[1].text).toBe('comment here')
})
// #9407
it('should parse templates with comments anywhere', () => {
const options = extend(
{
comments: true
},
baseOptions
)
const ast = parse(`123`, options)
expect(ast.tag).toBe('div')
expect(ast.children.length).toBe(1)
})
// #8103
it('should allow CRLFs in string interpolations', () => {
const ast = parse(`{{\r\nmsg\r\n}}
`, baseOptions)
expect(ast.children[0].expression).toBe('_s(msg)')
})
it('preserveWhitespace: false', () => {
const options = extend(
{
preserveWhitespace: false
},
baseOptions
)
const ast = parse(
'\n Welcome to Vue.js world \n .\n Have fun!\n
',
options
)
expect(ast.tag).toBe('p')
expect(ast.children.length).toBe(4)
expect(ast.children[0].type).toBe(3)
expect(ast.children[0].text).toBe('\n Welcome to ')
expect(ast.children[1].tag).toBe('b')
expect(ast.children[1].children[0].text).toBe('Vue.js')
expect(ast.children[2].tag).toBe('i')
expect(ast.children[2].children[0].text).toBe('world')
expect(ast.children[3].tag).toBe('span')
expect(ast.children[3].children[0].text).toBe('.\n Have fun!\n')
})
const condenseOptions = extend(
{
whitespace: 'condense',
// should be ignored when whitespace is specified
preserveWhitespace: false
},
baseOptions
)
it(`whitespace: 'condense'`, () => {
const options = extend({}, condenseOptions)
const ast = parse(
'\n Welcome to Vue.js world \n .\n Have fun!\n
',
options
)
expect(ast.tag).toBe('p')
expect(ast.children.length).toBe(5)
expect(ast.children[0].type).toBe(3)
expect(ast.children[0].text).toBe(' Welcome to ')
expect(ast.children[1].tag).toBe('b')
expect(ast.children[1].children[0].text).toBe('Vue.js')
expect(ast.children[2].type).toBe(3)
// should condense inline whitespace into single space
expect(ast.children[2].text).toBe(' ')
expect(ast.children[3].tag).toBe('i')
expect(ast.children[3].children[0].text).toBe('world')
// should have removed the whitespace node between tags that contains newlines
expect(ast.children[4].tag).toBe('span')
expect(ast.children[4].children[0].text).toBe('. Have fun! ')
})
it(`maintains with whitespace: 'condense'`, () => {
const options = extend({}, condenseOptions)
const ast = parse(' ', options)
const code = ast.children[0]
expect(code.type).toBe(3)
expect(code.text).toBe('\xA0')
})
it(`preserve whitespace in tag with whitespace: 'condense'`, function () {
const options = extend({}, condenseOptions)
const ast = parse(
' \nhi\n
',
options
)
const code = ast.children[0]
expect(code.children[0].type).toBe(3)
expect(code.children[0].text).toBe(' \n')
expect(code.children[2].type).toBe(3)
expect(code.children[2].text).toBe('\n ')
const span = ast.children[1]
expect(span.children[0].type).toBe(3)
expect(span.children[0].text).toBe(' ')
})
it(`ignore the first newline in tag with whitespace: 'condense'`, function () {
const options = extend({}, condenseOptions)
const ast = parse(
'\nabc
\ndef\n\nabc
',
options
)
const pre = ast.children[0]
expect(pre.children[0].type).toBe(3)
expect(pre.children[0].text).toBe('abc')
const text = ast.children[1]
expect(text.type).toBe(3)
expect(text.text).toBe(' def')
const pre2 = ast.children[2]
expect(pre2.children[0].type).toBe(3)
expect(pre2.children[0].text).toBe('\nabc')
})
it(`keep first newline after unary tag in with whitespace: 'condense'`, () => {
const options = extend({}, condenseOptions)
const ast = parse('abc\ndef
', options)
expect(ast.children[1].type).toBe(1)
expect(ast.children[1].tag).toBe('input')
expect(ast.children[2].type).toBe(3)
expect(ast.children[2].text).toBe('\ndef')
})
// #10152
it('not warn when scoped slot used inside of dynamic component on regular element', () => {
parse(
`
`,
baseOptions
)
expect(
'v-slot can only be used on components or '
).not.toHaveBeenWarned()
parse(
``,
baseOptions
)
expect(
` can only appear at the root level inside the receiving the component`
).not.toHaveBeenWarned()
})
})