190 lines
5.9 KiB
JavaScript
190 lines
5.9 KiB
JavaScript
import fs from 'fs';
|
|
import { exec } from 'child_process';
|
|
import { execCommand, FileTestHelper } from 'cli-testlab';
|
|
import Handlebars from '../../lib/index.js';
|
|
|
|
const cli = 'node ./bin/handlebars.js';
|
|
|
|
expect.extend({
|
|
toEqualWithRelaxedSpace(received, expected) {
|
|
const normalize = (str) =>
|
|
typeof str === 'string'
|
|
? str
|
|
.replace(/\r\n/g, '\n')
|
|
.split('\n')
|
|
.map((line) => line.replace(/\s+/g, ' ').trim())
|
|
.filter((line) => line.length > 0)
|
|
.join('\n')
|
|
.trim()
|
|
: str;
|
|
|
|
const normalizedReceived = normalize(received);
|
|
const normalizedExpected = normalize(expected);
|
|
const pass = normalizedReceived === normalizedExpected;
|
|
|
|
return {
|
|
pass,
|
|
message: () =>
|
|
`Expected output to match with relaxed whitespace.\n\n` +
|
|
`Expected:\n${normalizedExpected}\n\nReceived:\n${normalizedReceived}`,
|
|
};
|
|
},
|
|
});
|
|
|
|
function expectedFile(specPath) {
|
|
return fs.readFileSync(specPath, 'utf-8');
|
|
}
|
|
|
|
describe('bin/handlebars', function () {
|
|
describe('help and version', function () {
|
|
it('--help displays help menu', async function () {
|
|
const result = await execCommand(`${cli} --help`);
|
|
expect(result.stdout).toEqualWithRelaxedSpace(
|
|
expectedFile('./spec/expected/help.menu.txt')
|
|
);
|
|
});
|
|
|
|
it('no arguments displays help menu', async function () {
|
|
const result = await execCommand(`${cli}`);
|
|
expect(result.stdout).toEqualWithRelaxedSpace(
|
|
expectedFile('./spec/expected/help.menu.txt')
|
|
);
|
|
});
|
|
|
|
it('-v prints the compiler version', async function () {
|
|
await execCommand(`${cli} -v`, {
|
|
expectedOutput: Handlebars.VERSION,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('namespace', function () {
|
|
it('-n sets custom namespace', async function () {
|
|
const result = await execCommand(
|
|
`${cli} -n CustomNamespace.templates spec/artifacts/empty.handlebars`
|
|
);
|
|
expect(result.stdout).toEqualWithRelaxedSpace(
|
|
expectedFile('./spec/expected/empty.namespace.js')
|
|
);
|
|
});
|
|
|
|
it('--namespace sets custom namespace', async function () {
|
|
const result = await execCommand(
|
|
`${cli} --namespace CustomNamespace.templates spec/artifacts/empty.handlebars`
|
|
);
|
|
expect(result.stdout).toEqualWithRelaxedSpace(
|
|
expectedFile('./spec/expected/empty.namespace.js')
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('file output', function () {
|
|
let files;
|
|
|
|
beforeEach(function () {
|
|
files = new FileTestHelper({ basePath: '.' });
|
|
files.createDir('tmp');
|
|
});
|
|
|
|
afterEach(function () {
|
|
files.cleanup();
|
|
});
|
|
|
|
it('-f writes output to a file', async function () {
|
|
const outputFile = 'tmp/cli-test-output.js';
|
|
files.registerForCleanup(outputFile);
|
|
|
|
await execCommand(
|
|
`${cli} -f ${outputFile} spec/artifacts/empty.handlebars`
|
|
);
|
|
|
|
expect(files.fileExists(outputFile)).toBe(true);
|
|
const content = files.getFileTextContent(outputFile);
|
|
expect(content).toMatch(/template\(/);
|
|
});
|
|
|
|
it('--map writes source map and appends sourceMappingURL', async function () {
|
|
const mapFile = 'tmp/cli-test-source.map';
|
|
files.registerForCleanup(mapFile);
|
|
|
|
const result = await execCommand(
|
|
`${cli} -i "<div>1</div>" -m -N test --map ${mapFile}`
|
|
);
|
|
|
|
expect(result.stdout).toContain('sourceMappingURL=');
|
|
expect(files.fileExists(mapFile)).toBe(true);
|
|
const parsed = JSON.parse(files.getFileTextContent(mapFile));
|
|
expect(parsed).toHaveProperty('version', 3);
|
|
expect(parsed).toHaveProperty('sources');
|
|
expect(parsed).toHaveProperty('mappings');
|
|
});
|
|
});
|
|
|
|
describe('template options', function () {
|
|
it('-e sets custom extension', async function () {
|
|
const result = await execCommand(
|
|
`${cli} -e hbs ./spec/artifacts/non.default.extension.hbs`
|
|
);
|
|
expect(result.stdout).toMatch(/template\(/);
|
|
});
|
|
|
|
it('-p compiles as partial', async function () {
|
|
const result = await execCommand(
|
|
`${cli} -p ./spec/artifacts/partial.template.handlebars`
|
|
);
|
|
expect(result.stdout).toMatch(/Handlebars\.partials/);
|
|
});
|
|
|
|
it('-r strips root from template names', async function () {
|
|
const result = await execCommand(
|
|
`${cli} spec/artifacts/partial.template.handlebars -r spec`
|
|
);
|
|
expect(result.stdout).toMatch(/template\(/);
|
|
});
|
|
|
|
it('-b strips BOM', async function () {
|
|
const result = await execCommand(
|
|
`${cli} ./spec/artifacts/bom.handlebars -b`
|
|
);
|
|
expect(result.stdout).toMatch(/template\(/);
|
|
});
|
|
|
|
it('-k -o sets known helpers only', async function () {
|
|
const result = await execCommand(
|
|
`${cli} spec/artifacts/known.helpers.handlebars -k someHelper -k anotherHelper -o`
|
|
);
|
|
expect(result.stdout).toMatch(/template\(/);
|
|
});
|
|
});
|
|
|
|
describe('inline templates', function () {
|
|
it('-i compiles inline template', async function () {
|
|
const result = await execCommand(
|
|
`${cli} -i "<div>hello</div>" -N myTemplate`
|
|
);
|
|
expect(result.stdout).toContain("templates['myTemplate']");
|
|
});
|
|
|
|
it('-i compiles simple unnamed inline template', async function () {
|
|
const result = await execCommand(`${cli} -i "<div>hello</div>"`);
|
|
// Unnamed single template defaults to simple mode
|
|
expect(result.stdout).toMatch(/function/);
|
|
});
|
|
});
|
|
|
|
describe('error handling', function () {
|
|
it('should not produce unhandled promise rejections on async errors', async function () {
|
|
const { stderr } = await new Promise((resolve) => {
|
|
exec(
|
|
`node --unhandled-rejections=warn ./bin/handlebars.js -i "<div>test</div>" -N test --map /nonexistent/dir/test.map`,
|
|
(error, stdout, stderr) => {
|
|
resolve({ exitCode: error ? error.code : 0, stderr });
|
|
}
|
|
);
|
|
});
|
|
|
|
expect(stderr).not.toMatch(/unhandled/i);
|
|
});
|
|
});
|
|
});
|