react-templates/test/src/rt.invalid.unit.js

118 lines
6.5 KiB
JavaScript

'use strict'
const reactTemplates = require('../../src/reactTemplates')
const testUtils = require('./utils/testUtils')
const _ = require('lodash')
const path = require('path')
const RTCodeError = reactTemplates.RTCodeError
const assert = require('assert')
const cli = require('../../src/cli')
const context = require('../../src/context')
const omitStack = err => _.omit(err, 'stack', 'toIssue')
/**
* @param {ERR} err
* @return {ERR}
*/
function normalizeError(err) {
if (err) {
err.msg = err.msg.replace(/\r/g, '')
}
return err
}
/**
* @typedef {{index: number, line: number, column: number, msg: string, level: string, file: string}} ERR
*/
/**
* @param {RTCodeError} err
* @param {string} file
* @return {ERR}
*/
function errorEqualMessage(err, file) {
return {
index: err.index,
line: err.line,
column: err.column,
startOffset: err.startOffset,
endOffset: err.endOffset,
msg: err.message,
level: 'ERROR',
file
}
}
describe('utils', () => {
describe('#convertText', () => {
const dataPath = path.resolve(__dirname, '..', 'data', 'invalid')
const invalidFiles = [
// {file: 'sortByDragListItemRowExamples.rt', issue: new RTCodeError('x', 0, 160, 1, 1)}
{file: 'if-with-scope/invalid-if-scope-1.rt', issue: new RTCodeError("invalid scope mapping used in if part 'this.bar(activeUsers.length)'", 0, 160, 1, 1)},
{file: 'if-with-scope/invalid-if-scope-2.rt', issue: new RTCodeError("invalid scope mapping used in if part 'this.bar[activeUsers || 0]'", 0, 158, 1, 1)},
{
file: 'if-with-scope/invalid-if-scope-3.rt',
issue: new RTCodeError("invalid scope mapping used in if part 'this.foo + activeUsers.length > this.bar'", 0, 172, 1, 1)
},
{file: 'if-with-scope/invalid-if-scope-4.rt', issue: new RTCodeError("invalid scope mapping used in if part 'getCurrentActiveUsers().length'", 0, 170, 1, 1)},
{file: 'if-with-scope/invalid-if-scope-5.rt', issue: new RTCodeError("invalid scope mapping used in if part 'this.bar({activeUsers})'", 0, 155, 1, 1)},
{file: 'invalid-scope.rt', issue: new RTCodeError("invalid scope part 'a in a in a'", 0, 35, 1, 1)},
{file: 'invalid-html.rt', issue: new RTCodeError('Document should have a root element', -1, -1, -1, -1)},
{file: 'invalid-exp.rt', issue: new RTCodeError("Failed to parse text '\n {z\n'", 5, 13, 1, 6)},
{
file: 'invalid-lambda.rt',
issue: new RTCodeError("when using 'on' events, use lambda '(p1,p2)=>body' notation or 'this.handler'; otherwise use {} to return a callback function. error: [onClick='']", 0, 23, 1, 1)
},
{
file: 'invalid-autobind.rt',
issue: new RTCodeError("'this.handler' syntax allowed only when the --autobind is on, use {} to return a callback function.", 0, 132, 1, 1)
},
// {file: 'invalid-js.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 0, 32, 1, 1)}, bug interduced due to scope parsing
{file: 'invalid-single-root.rt', issue: new RTCodeError('Document should have no more than a single root element', 12, 23, 2, 1)},
{file: 'invalid-repeat-1.rt', issue: new RTCodeError("rt-repeat invalid 'in' expression 'a in b in c'", 9, 44, 2, 4)},
{file: 'invalid-repeat-2.rt', issue: new RTCodeError("root element may not have a 'rt-repeat' attribute", 0, 39, 1, 1)},
{file: 'invalid-rt-require-1.rt', issue: new RTCodeError("'rt-require' needs 'dependency' and 'as' attributes", 0, 14, 1, 1)},
{file: 'invalid-rt-require-2.rt', issue: new RTCodeError("'rt-require' may have no children", 0, 32, 1, 1)},
// {file: 'invalid-rt-require-duplicate.rt', issue: new RTCodeError("Line 1: Strict mode function may not have duplicate parameter names", 64, -1, -1, -1), options: {modules: 'amd'}},
{file: 'invalid-rt-import-1.rt', issue: new RTCodeError("'*' imports must have an 'as' attribute", 0, 36, 1, 1)},
{file: 'invalid-rt-import-2.rt', issue: new RTCodeError("default imports must have an 'as' attribute", 0, 42, 1, 1)},
{file: 'invalid-rt-import-3.rt', issue: new RTCodeError("'rt-import' needs 'name' and 'from' attributes", 0, 13, 1, 1)},
{file: 'invalid-rt-import-4.rt', issue: new RTCodeError("'rt-import' must be a toplevel node", 9, 54, 2, 4)},
{file: 'invalid-rt-template-1.rt', issue: new RTCodeError("'rt-template' should have a single non-text element as direct child", 9, 88, 2, 4)},
{file: 'invalid-rt-template-2.rt', issue: new RTCodeError("'rt-template' should have a single non-text element as direct child", 9, 90, 2, 4)},
{file: 'invalid-brace.rt', issue: new RTCodeError('Unexpected end of input', 128, 163, 5, 11)},
{file: 'invalid-style-1.rt', issue: new RTCodeError('Unexpected token ILLEGAL', 10, 39, 2, 5)},
{file: 'invalid-style-2.rt', issue: new RTCodeError('style attribute keys cannot contain { } expressions', 35, 68, 2, 5)},
{file: 'invalid-virtual-1.rt', issue: new RTCodeError('Document should not have <rt-virtual> as root element', 0, 60, 1, 1)},
{file: 'invalid-virtual-2.rt', issue: new RTCodeError("<rt-virtual> may not contain attributes other than 'rt-scope', 'rt-if' and 'rt-repeat'", 9, 119, 2, 4)}
]
it('should convert text successfully', () => {
invalidFiles.forEach(testFile => {
const filename = path.join(dataPath, testFile.file)
const html = testUtils.readFileNormalized(filename)
let error = null
try {
reactTemplates.convertTemplateToReact(html)
} catch (e) {
error = e
}
assert.deepEqual(omitStack(error), omitStack(testFile.issue), 'Expect convertTemplateToReact to throw an error')
})
invalidFiles.forEach(check)
function check(testFile) {
context.clear()
const filename = path.join(dataPath, testFile.file)
const options = {format: 'json', force: true}
cli.handleSingleFile(_.assign(options, testFile.options), filename)
assert.deepEqual(normalizeError(context.getMessages()[0]), errorEqualMessage(testFile.issue, filename), `Expect cli to produce valid output messages ${testFile.file}`)
}
})
})
})