/* eslint-disable max-len */
import { compile } from '../'
import generate from '@babel/generator'
import { parse } from '@babel/parser'
/**
* Parses js-code to ast and compile again to js. Used to bring in a view that
* is obtained when compiling ast.
*/
const recompile = (jsCode: string): string =>
generate(parse(jsCode, { plugins: ['jsx'], sourceType: 'module' }).program).code
describe('elements', () => {
test('should convert simple div', () => {
expect(compile('
', false)).toBe(';')
})
test('should close self-closing elements', () => {
expect(compile('
', false)).toBe('
;')
expect(compile('', false)).toBe(';')
expect(compile('
', false)).toBe('
;')
})
test('should wrap multiple elements to fragment', () => {
expect(compile('', false)).toBe(';')
expect(compile('Some text ', false)).toBe('Some text ;')
expect(compile('', false)).toBe(
';'
)
})
})
describe('element values', () => {
test('should create literal value', () => {
expect(compile('Value
', false)).toBe('Value
;')
})
test('should create value with expression', () => {
expect(compile('Lorem {{ipsum}} dolor sit amet
')).toBe(
recompile('props => Lorem {props.ipsum} dolor sit amet
')
)
})
test('should escape curly braces in handlebars template', () => {
expect(compile('Lorem {ipsum} dolor sit {amet
')).toBe(
recompile(`props => Lorem {"{"}ipsum{"}"} dolor sit {"{"}amet
`)
)
})
})
describe('component support', () => {
test('should return component', () => {
expect(compile('')).toBe('props => ;')
})
test("shouldn't return component", () => {
expect(compile('', false)).toBe(';')
})
test('should add "props" prefix to variables in component', () => {
expect(compile('{{variable}}
')).toBe(recompile('props => {props.variable}
'))
})
test('shouldn\'t add "props" prefix to variables if it\'s not component', () => {
expect(compile('{{variable}}
', false)).toBe('{variable}
;')
})
test('should export component by default', () => {
expect(compile('{{variable}}
', { isModule: true, isComponent: true })).toBe(
recompile('export default props => {props.variable}
')
)
})
})
describe('element attributes', () => {
test('should convert simple text attribute', () => {
expect(compile('', false)).toBe(';')
})
test('should remove unsupported attribute', () => {
expect(compile('', false)).toBe(';')
})
test('should convert specific attribute name', () => {
expect(compile('', false)).toBe(';')
expect(compile('', false)).toBe(';')
expect(compile('', false)).toBe(';')
expect(compile('', false)).toBe(
';'
)
})
test('should convert attribute with statement', () => {
expect(compile('', false)).toBe(';')
expect(compile('', false)).toBe(';')
expect(compile('')).toBe(recompile('props => ;'))
})
xtest('should throw error when used reserved JavaScript words', () => {
// TODO
})
test('should convert attribute with concatenation statement', () => {
expect(compile('', false)).toBe(';')
expect(compile('', false)).toBe(';')
expect(compile('')).toBe(recompile('props => ;'))
expect(compile('')).toBe(recompile('props => ;'))
expect(compile('')).toBe(
recompile('props => ;')
)
expect(compile('Link', false)).toBe(
'Link;'
)
})
test('should convert the "styles" string to stylesObject', () => {
expect(compile('', false)).toBe(
recompile('')
)
})
test('should convert the "styles" string with variables to stylesObject', () => {
// Block of styles
expect(
compile(
'',
false
)
).toBe(
recompile(
``
)
)
// Trailing semicolon
expect(compile('', false)).toBe(
recompile(``)
)
// Expression in key
expect(compile('', false)).toBe(
recompile(``)
)
})
})
describe('comments', () => {
test('should convert comment in JSX code', () => {
expect(compile('{{~! comment ~}}
', false)).toBe(recompile('{/* comment */}
;'))
expect(compile('{{~!-- long-comment --~}}
', false)).toBe(recompile('{/* long-comment */}
;'))
expect(compile('{{! comment ~}}
', false)).toBe(recompile('{/* comment */}
;'))
expect(compile('{{!-- long-comment --~}}
', false)).toBe(recompile('{/* long-comment */}
;'))
expect(compile('{{~! comment }}
', false)).toBe(recompile('{/* comment */}
;'))
expect(compile('{{~!-- long-comment --}}
', false)).toBe(recompile('{/* long-comment */}
;'))
expect(compile('', false)).toBe(recompile('{/* html comment */}
;'))
})
test("shouldn't convert top-level comment", () => {
// Not supported currently
// expect(compile('{{!-- comment --}}')).toBe(recompile('/* comment */'))
expect(() => compile('{{!-- comment --}}')).toThrowError()
})
})
describe('block statements', () => {
describe('condition statement', () => {
test('should convert condition if-then ', () => {
expect(compile('')).toBe(
recompile('props => {Boolean(props.variable) &&
}
;')
)
})
test('should convert condition if-then-else ', () => {
expect(compile('{{#if variable}}
{{else}}
{{/if}}
')).toBe(
recompile('props => {Boolean(props.variable) ?
:
}
;')
)
})
test('should convert condition unless-then ', () => {
expect(compile('{{#unless variable}}
{{/unless}}
')).toBe(
recompile('props => {!Boolean(props.variable) &&
}
;')
)
})
test('should convert condition unless-then-else ', () => {
expect(compile('{{#unless variable}}
{{else}}
{{/unless}}
')).toBe(
recompile('props => {!Boolean(props.variable) ?
:
}
;')
)
})
test('should wrap multiple block children into fragment', () => {
expect(compile('')).toBe(
recompile('props => {Boolean(props.variable) &&
}
;')
)
})
test('should convert condition statement in root', () => {
expect(compile('{{#if variable}}{{else}}{{/if}}')).toBe(
recompile('props => Boolean(props.variable) ? : ;')
)
})
})
describe('each statement', () => {
test('each block statement', () => {
expect(compile('')).toBe(
'props => {props.list.map((item, i) =>
)}
;'
)
})
test('nested each block statements', () => {
expect(compile('{{#each list}}{{#each list.nested}}
{{/each}}{{/each}}
')).toBe(
'props => {props.list.map((item, i) =>
{item.list.nested.map((item, i) => )})}
;'
)
})
test('siblings each block statements with path expression - no component', () => {
expect(
compile(
'{{#each list}}
{{name}}
{{/each}}{{#each list}}
{{name}}
{{/each}}
',
false
)
).toBe(
'{list.map((item, i) =>
{item.name}
)}{list.map((item, i) =>
{item.name}
)}
;'
)
})
test('should wrap multiple block children into fragment with keys', () => {
expect(compile('{{#each list}}
Text{{/each}}
')).toBe(
'props => {props.list.map((item, i) =>
Text)}
;'
)
})
})
})
describe('include react import', () => {
test('with isModule true', () => {
expect(compile('', { isComponent: true, isModule: true, includeImport: true })).toBe(
'import React from "react";\nexport default (props => );'
)
})
test('with isModule false', () => {
expect(compile('', { isComponent: true, isModule: false, includeImport: true })).toBe(
'props => ;'
)
})
test('with isComponent false', () => {
expect(compile('', { isComponent: false, isModule: true, includeImport: true })).toBe(
'import React from "react";\nexport default ;'
)
})
})