feat(javascript): support jest-each template string (#4423)

* feat(javascript): support jest-each

* test: add trailing newline

* fix: there can be no trailing newline

* refactor: simplify regex

* refactor: Array.from

* refactor

* fix: print quasis safely
master
Ika 2018-05-06 14:52:34 +08:00 committed by GitHub
parent 5776c8405a
commit 7e81a613b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 356 additions and 0 deletions

View File

@ -30,6 +30,7 @@ const breakParent = docBuilders.breakParent;
const lineSuffixBoundary = docBuilders.lineSuffixBoundary;
const addAlignmentToDoc = docBuilders.addAlignmentToDoc;
const dedent = docBuilders.dedent;
const printDocToString = doc.printer.printDocToString;
const docUtils = doc.utils;
const willBreak = docUtils.willBreak;
@ -2054,6 +2055,122 @@ function printPathNoParens(path, options, print, args) {
return join(literalline, n.value.raw.split(/\r?\n/g));
case "TemplateLiteral": {
const expressions = path.map(print, "expressions");
const parentNode = path.getParentNode();
/**
* describe.each`table`(name, fn)
* describe.only.each`table`(name, fn)
* describe.skip.each`table`(name, fn)
* test.each`table`(name, fn)
* test.only.each`table`(name, fn)
* test.skip.each`table`(name, fn)
*
* Ref: https://github.com/facebook/jest/pull/6102
*/
const jestEachTriggerRegex = /^[xf]?(describe|it|test)$/;
if (
parentNode.type === "TaggedTemplateExpression" &&
parentNode.quasi === n &&
parentNode.tag.type === "MemberExpression" &&
parentNode.tag.property.type === "Identifier" &&
parentNode.tag.property.name === "each" &&
((parentNode.tag.object.type === "Identifier" &&
jestEachTriggerRegex.test(parentNode.tag.object.name)) ||
(parentNode.tag.object.type === "MemberExpression" &&
parentNode.tag.object.property.type === "Identifier" &&
(parentNode.tag.object.property.name === "only" ||
parentNode.tag.object.property.name === "skip") &&
parentNode.tag.object.object.type === "Identifier" &&
jestEachTriggerRegex.test(parentNode.tag.object.object.name)))
) {
/**
* a | b | expected
* ${1} | ${1} | ${2}
* ${1} | ${2} | ${3}
* ${2} | ${1} | ${3}
*/
const headerNames = n.quasis[0].value.raw.trim().split(/\s*\|\s*/);
if (
headerNames.length > 1 ||
headerNames.some(headerName => headerName.length !== 0)
) {
const stringifiedExpressions = expressions.map(
doc =>
"${" +
printDocToString(
doc,
Object.assign({}, options, { printWidth: Infinity })
).formatted +
"}"
);
const tableBody = [{ hasLineBreak: false, cells: [] }];
for (let i = 1; i < n.quasis.length; i++) {
const row = tableBody[tableBody.length - 1];
const correspondingExpression = stringifiedExpressions[i - 1];
row.cells.push(correspondingExpression);
if (correspondingExpression.indexOf("\n") !== -1) {
row.hasLineBreak = true;
}
if (n.quasis[i].value.raw.indexOf("\n") !== -1) {
tableBody.push({ hasLineBreak: false, cells: [] });
}
}
const maxColumnCount = tableBody.reduce(
(maxColumnCount, row) => Math.max(maxColumnCount, row.cells.length),
headerNames.length
);
const maxColumnWidths = Array.from(
new Array(maxColumnCount),
() => 0
);
const table = [{ cells: headerNames }].concat(
tableBody.filter(row => row.cells.length !== 0)
);
table.filter(row => !row.hasLineBreak).forEach(row => {
row.cells.forEach((cell, index) => {
maxColumnWidths[index] = Math.max(
maxColumnWidths[index],
privateUtil.getStringWidth(cell)
);
});
});
parts.push(
"`",
indent(
concat([
hardline,
join(
hardline,
table.map(row =>
join(
" | ",
row.cells.map(
(cell, index) =>
row.hasLineBreak
? cell
: cell +
" ".repeat(
maxColumnWidths[index] -
privateUtil.getStringWidth(cell)
)
)
)
)
)
])
),
hardline,
"`"
);
return concat(parts);
}
}
parts.push("`");

View File

@ -102,6 +102,202 @@ function x() {
`;
exports[`jest-each.js 1`] = `
describe.each\`
a|b|expected
\${11 } | \${ 1 }|\${222}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3}
\`('$a + $b', ({a, b, expected}) => {
test(\`returns \${expected}\`, () => {
expect(a + b).toBe(expected);
});
test(\`returned value not be greater than \${expected}\`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(\`returned value not be less than \${expected}\`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
describe.only.each\`
a|b|expected
\${11 } | \${ 1 }|\${222}|\${'unknown column 1'}|\${'unknown column 2'}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3} |\${'unknown column xyz'}
\`
describe.only.each\`
||
\${11 } | \${ 1 }|\${222}|\${'unknown column 1'}|\${'unknown column 2'}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3} |\${'unknown column xyz'}
\`
describe.each\`a | b | expected
\${1} | \${1} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
// an example to demo multiline quasi
describe.each\`a | b | expected
\${11111111111} | \${a().b().c().d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
describe.each\`
a | b | expected
\${11} | \${1} | \${222}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3}
\`("$a + $b", ({ a, b, expected }) => {
test(\`returns \${expected}\`, () => {
expect(a + b).toBe(expected);
});
test(\`returned value not be greater than \${expected}\`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(\`returned value not be less than \${expected}\`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
describe.only.each\`
a | b | expected
\${11} | \${1} | \${222} | \${"unknown column 1"} | \${"unknown column 2"}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3} | \${"unknown column xyz"}
\`;
describe.only.each\`
| |
\${11} | \${1} | \${222} | \${"unknown column 1"} | \${"unknown column 2"}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3} | \${"unknown column xyz"}
\`;
describe.each\`
a | b | expected
\${1} | \${1} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}
\`;
// an example to demo multiline quasi
describe.each\`
a | b | expected
\${11111111111} | \${a()
.b()
.c()
.d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}
\`;
`;
exports[`jest-each.js 2`] = `
describe.each\`
a|b|expected
\${11 } | \${ 1 }|\${222}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3}
\`('$a + $b', ({a, b, expected}) => {
test(\`returns \${expected}\`, () => {
expect(a + b).toBe(expected);
});
test(\`returned value not be greater than \${expected}\`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(\`returned value not be less than \${expected}\`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
describe.only.each\`
a|b|expected
\${11 } | \${ 1 }|\${222}|\${'unknown column 1'}|\${'unknown column 2'}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3} |\${'unknown column xyz'}
\`
describe.only.each\`
||
\${11 } | \${ 1 }|\${222}|\${'unknown column 1'}|\${'unknown column 2'}
\${1-1}|\${2+2}|\${ 3333}
\${2+1+2}|\${1111}|\${3} |\${'unknown column xyz'}
\`
describe.each\`a | b | expected
\${1} | \${1} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
// an example to demo multiline quasi
describe.each\`a | b | expected
\${11111111111} | \${a().b().c().d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
describe.each\`
a | b | expected
\${11} | \${1} | \${222}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3}
\`("$a + $b", ({ a, b, expected }) => {
test(\`returns \${expected}\`, () => {
expect(a + b).toBe(expected);
});
test(\`returned value not be greater than \${expected}\`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(\`returned value not be less than \${expected}\`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
describe.only.each\`
a | b | expected
\${11} | \${1} | \${222} | \${"unknown column 1"} | \${"unknown column 2"}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3} | \${"unknown column xyz"}
\`;
describe.only.each\`
| |
\${11} | \${1} | \${222} | \${"unknown column 1"} | \${"unknown column 2"}
\${1 - 1} | \${2 + 2} | \${3333}
\${2 + 1 + 2} | \${1111} | \${3} | \${"unknown column xyz"}
\`;
describe.each\`
a | b | expected
\${1} | \${1} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}
\`;
// an example to demo multiline quasi
describe.each\`
a | b | expected
\${11111111111} | \${a()
.b()
.c()
.d()} | \${2}
\${1} | \${2} | \${3}
\${2} | \${1} | \${3}
\`;
`;
exports[`test_declarations.js 1`] = `
// Shouldn't break

View File

@ -0,0 +1,43 @@
describe.each`
a|b|expected
${11 } | ${ 1 }|${222}
${1-1}|${2+2}|${ 3333}
${2+1+2}|${1111}|${3}
`('$a + $b', ({a, b, expected}) => {
test(`returns ${expected}`, () => {
expect(a + b).toBe(expected);
});
test(`returned value not be greater than ${expected}`, () => {
expect(a + b).not.toBeGreaterThan(expected);
});
test(`returned value not be less than ${expected}`, () => {
expect(a + b).not.toBeLessThan(expected);
});
});
describe.only.each`
a|b|expected
${11 } | ${ 1 }|${222}|${'unknown column 1'}|${'unknown column 2'}
${1-1}|${2+2}|${ 3333}
${2+1+2}|${1111}|${3} |${'unknown column xyz'}
`
describe.only.each`
||
${11 } | ${ 1 }|${222}|${'unknown column 1'}|${'unknown column 2'}
${1-1}|${2+2}|${ 3333}
${2+1+2}|${1111}|${3} |${'unknown column xyz'}
`
describe.each`a | b | expected
${1} | ${1} | ${2}
${1} | ${2} | ${3}
${2} | ${1} | ${3}`
// an example to demo multiline quasi
describe.each`a | b | expected
${11111111111} | ${a().b().c().d()} | ${2}
${1} | ${2} | ${3}
${2} | ${1} | ${3}`