aboutsummaryrefslogtreecommitdiff
path: root/dev/lib/handlebars/src/spec/index.helpers.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'dev/lib/handlebars/src/spec/index.helpers.test.ts')
-rw-r--r--dev/lib/handlebars/src/spec/index.helpers.test.ts958
1 files changed, 0 insertions, 958 deletions
diff --git a/dev/lib/handlebars/src/spec/index.helpers.test.ts b/dev/lib/handlebars/src/spec/index.helpers.test.ts
deleted file mode 100644
index 4cfa39bb..00000000
--- a/dev/lib/handlebars/src/spec/index.helpers.test.ts
+++ /dev/null
@@ -1,958 +0,0 @@
-/*
- * This file is forked from the handlebars project (https://github.com/handlebars-lang/handlebars.js),
- * and may include modifications made by Elasticsearch B.V.
- * Elasticsearch B.V. licenses this file to you under the MIT License.
- * See `packages/kbn-handlebars/LICENSE` for more information.
- */
-
-import Handlebars, { type HelperOptions } from '../..';
-import { expectTemplate } from '../__jest__/test_bench';
-
-beforeEach(() => {
- global.kbnHandlebarsEnv = Handlebars.create();
-});
-
-afterEach(() => {
- global.kbnHandlebarsEnv = null;
-});
-
-describe('helpers', () => {
- it('helper with complex lookup$', () => {
- expectTemplate('{{#goodbyes}}{{{link ../prefix}}}{{/goodbyes}}')
- .withInput({
- prefix: '/root',
- goodbyes: [{ text: 'Goodbye', url: 'goodbye' }],
- })
- .withHelper('link', function (this: any, prefix) {
- return '<a href="' + prefix + '/' + this.url + '">' + this.text + '</a>';
- })
- .toCompileTo('<a href="/root/goodbye">Goodbye</a>');
- });
-
- it('helper for raw block gets raw content', () => {
- expectTemplate('{{{{raw}}}} {{test}} {{{{/raw}}}}')
- .withInput({ test: 'hello' })
- .withHelper('raw', function (options: HelperOptions) {
- return options.fn();
- })
- .toCompileTo(' {{test}} ');
- });
-
- it('helper for raw block gets parameters', () => {
- expectTemplate('{{{{raw 1 2 3}}}} {{test}} {{{{/raw}}}}')
- .withInput({ test: 'hello' })
- .withHelper('raw', function (a, b, c, options: HelperOptions) {
- const ret = options.fn() + a + b + c;
- return ret;
- })
- .toCompileTo(' {{test}} 123');
- });
-
- describe('raw block parsing (with identity helper-function)', () => {
- function runWithIdentityHelper(template: string, expected: string) {
- expectTemplate(template)
- .withHelper('identity', function (options: HelperOptions) {
- return options.fn();
- })
- .toCompileTo(expected);
- }
-
- it('helper for nested raw block gets raw content', () => {
- runWithIdentityHelper(
- '{{{{identity}}}} {{{{b}}}} {{{{/b}}}} {{{{/identity}}}}',
- ' {{{{b}}}} {{{{/b}}}} '
- );
- });
-
- it('helper for nested raw block works with empty content', () => {
- runWithIdentityHelper('{{{{identity}}}}{{{{/identity}}}}', '');
- });
-
- it.skip('helper for nested raw block works if nested raw blocks are broken', () => {
- // This test was introduced in 4.4.4, but it was not the actual problem that lead to the patch release
- // The test is deactivated, because in 3.x this template cases an exception and it also does not work in 4.4.3
- // If anyone can make this template work without breaking everything else, then go for it,
- // but for now, this is just a known bug, that will be documented.
- runWithIdentityHelper(
- '{{{{identity}}}} {{{{a}}}} {{{{ {{{{/ }}}} }}}} {{{{/identity}}}}',
- ' {{{{a}}}} {{{{ {{{{/ }}}} }}}} '
- );
- });
-
- it('helper for nested raw block closes after first matching close', () => {
- runWithIdentityHelper(
- '{{{{identity}}}}abc{{{{/identity}}}} {{{{identity}}}}abc{{{{/identity}}}}',
- 'abc abc'
- );
- });
-
- it('helper for nested raw block throw exception when with missing closing braces', () => {
- const string = '{{{{a}}}} {{{{/a';
- expectTemplate(string).toThrow();
- });
- });
-
- it('helper block with identical context', () => {
- expectTemplate('{{#goodbyes}}{{name}}{{/goodbyes}}')
- .withInput({ name: 'Alan' })
- .withHelper('goodbyes', function (this: any, options: HelperOptions) {
- let out = '';
- const byes = ['Goodbye', 'goodbye', 'GOODBYE'];
- for (let i = 0, j = byes.length; i < j; i++) {
- out += byes[i] + ' ' + options.fn(this) + '! ';
- }
- return out;
- })
- .toCompileTo('Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
- });
-
- it('helper block with complex lookup expression', () => {
- expectTemplate('{{#goodbyes}}{{../name}}{{/goodbyes}}')
- .withInput({ name: 'Alan' })
- .withHelper('goodbyes', function (options: HelperOptions) {
- let out = '';
- const byes = ['Goodbye', 'goodbye', 'GOODBYE'];
- for (let i = 0, j = byes.length; i < j; i++) {
- out += byes[i] + ' ' + options.fn({}) + '! ';
- }
- return out;
- })
- .toCompileTo('Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
- });
-
- it('helper with complex lookup and nested template', () => {
- expectTemplate('{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}')
- .withInput({
- prefix: '/root',
- goodbyes: [{ text: 'Goodbye', url: 'goodbye' }],
- })
- .withHelper('link', function (this: any, prefix, options: HelperOptions) {
- return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
- })
- .toCompileTo('<a href="/root/goodbye">Goodbye</a>');
- });
-
- it('helper with complex lookup and nested template in VM+Compiler', () => {
- expectTemplate('{{#goodbyes}}{{#link ../prefix}}{{text}}{{/link}}{{/goodbyes}}')
- .withInput({
- prefix: '/root',
- goodbyes: [{ text: 'Goodbye', url: 'goodbye' }],
- })
- .withHelper('link', function (this: any, prefix, options: HelperOptions) {
- return '<a href="' + prefix + '/' + this.url + '">' + options.fn(this) + '</a>';
- })
- .toCompileTo('<a href="/root/goodbye">Goodbye</a>');
- });
-
- it('helper returning undefined value', () => {
- expectTemplate(' {{nothere}}')
- .withHelpers({
- nothere() {},
- })
- .toCompileTo(' ');
-
- expectTemplate(' {{#nothere}}{{/nothere}}')
- .withHelpers({
- nothere() {},
- })
- .toCompileTo(' ');
- });
-
- it('block helper', () => {
- expectTemplate('{{#goodbyes}}{{text}}! {{/goodbyes}}cruel {{world}}!')
- .withInput({ world: 'world' })
- .withHelper('goodbyes', function (options: HelperOptions) {
- return options.fn({ text: 'GOODBYE' });
- })
- .toCompileTo('GOODBYE! cruel world!');
- });
-
- it('block helper staying in the same context', () => {
- expectTemplate('{{#form}}<p>{{name}}</p>{{/form}}')
- .withInput({ name: 'Yehuda' })
- .withHelper('form', function (this: any, options: HelperOptions) {
- return '<form>' + options.fn(this) + '</form>';
- })
- .toCompileTo('<form><p>Yehuda</p></form>');
- });
-
- it('block helper should have context in this', () => {
- function link(this: any, options: HelperOptions) {
- return '<a href="/people/' + this.id + '">' + options.fn(this) + '</a>';
- }
-
- expectTemplate('<ul>{{#people}}<li>{{#link}}{{name}}{{/link}}</li>{{/people}}</ul>')
- .withInput({
- people: [
- { name: 'Alan', id: 1 },
- { name: 'Yehuda', id: 2 },
- ],
- })
- .withHelper('link', link)
- .toCompileTo(
- '<ul><li><a href="/people/1">Alan</a></li><li><a href="/people/2">Yehuda</a></li></ul>'
- );
- });
-
- it('block helper for undefined value', () => {
- expectTemplate("{{#empty}}shouldn't render{{/empty}}").toCompileTo('');
- });
-
- it('block helper passing a new context', () => {
- expectTemplate('{{#form yehuda}}<p>{{name}}</p>{{/form}}')
- .withInput({ yehuda: { name: 'Yehuda' } })
- .withHelper('form', function (context, options: HelperOptions) {
- return '<form>' + options.fn(context) + '</form>';
- })
- .toCompileTo('<form><p>Yehuda</p></form>');
- });
-
- it('block helper passing a complex path context', () => {
- expectTemplate('{{#form yehuda/cat}}<p>{{name}}</p>{{/form}}')
- .withInput({ yehuda: { name: 'Yehuda', cat: { name: 'Harold' } } })
- .withHelper('form', function (context, options: HelperOptions) {
- return '<form>' + options.fn(context) + '</form>';
- })
- .toCompileTo('<form><p>Harold</p></form>');
- });
-
- it('nested block helpers', () => {
- expectTemplate('{{#form yehuda}}<p>{{name}}</p>{{#link}}Hello{{/link}}{{/form}}')
- .withInput({
- yehuda: { name: 'Yehuda' },
- })
- .withHelper('link', function (this: any, options: HelperOptions) {
- return '<a href="' + this.name + '">' + options.fn(this) + '</a>';
- })
- .withHelper('form', function (context, options: HelperOptions) {
- return '<form>' + options.fn(context) + '</form>';
- })
- .toCompileTo('<form><p>Yehuda</p><a href="Yehuda">Hello</a></form>');
- });
-
- it('block helper inverted sections', () => {
- const string = "{{#list people}}{{name}}{{^}}<em>Nobody's here</em>{{/list}}";
- function list(this: any, context: any, options: HelperOptions) {
- if (context.length > 0) {
- let out = '<ul>';
- for (let i = 0, j = context.length; i < j; i++) {
- out += '<li>';
- out += options.fn(context[i]);
- out += '</li>';
- }
- out += '</ul>';
- return out;
- } else {
- return '<p>' + options.inverse(this) + '</p>';
- }
- }
-
- // the meaning here may be kind of hard to catch, but list.not is always called,
- // so we should see the output of both
- expectTemplate(string)
- .withInput({ people: [{ name: 'Alan' }, { name: 'Yehuda' }] })
- .withHelpers({ list })
- .toCompileTo('<ul><li>Alan</li><li>Yehuda</li></ul>');
-
- expectTemplate(string)
- .withInput({ people: [] })
- .withHelpers({ list })
- .toCompileTo("<p><em>Nobody's here</em></p>");
-
- expectTemplate('{{#list people}}Hello{{^}}{{message}}{{/list}}')
- .withInput({
- people: [],
- message: "Nobody's here",
- })
- .withHelpers({ list })
- .toCompileTo('<p>Nobody&#x27;s here</p>');
- });
-
- it('pathed lambas with parameters', () => {
- const hash = {
- helper: () => 'winning',
- };
- // @ts-expect-error
- hash.hash = hash;
-
- const helpers = {
- './helper': () => 'fail',
- };
-
- expectTemplate('{{./helper 1}}').withInput(hash).withHelpers(helpers).toCompileTo('winning');
- expectTemplate('{{hash/helper 1}}').withInput(hash).withHelpers(helpers).toCompileTo('winning');
- });
-
- describe('helpers hash', () => {
- it('providing a helpers hash', () => {
- expectTemplate('Goodbye {{cruel}} {{world}}!')
- .withInput({ cruel: 'cruel' })
- .withHelpers({
- world() {
- return 'world';
- },
- })
- .toCompileTo('Goodbye cruel world!');
-
- expectTemplate('Goodbye {{#iter}}{{cruel}} {{world}}{{/iter}}!')
- .withInput({ iter: [{ cruel: 'cruel' }] })
- .withHelpers({
- world() {
- return 'world';
- },
- })
- .toCompileTo('Goodbye cruel world!');
- });
-
- it('in cases of conflict, helpers win', () => {
- expectTemplate('{{{lookup}}}')
- .withInput({ lookup: 'Explicit' })
- .withHelpers({
- lookup() {
- return 'helpers';
- },
- })
- .toCompileTo('helpers');
-
- expectTemplate('{{lookup}}')
- .withInput({ lookup: 'Explicit' })
- .withHelpers({
- lookup() {
- return 'helpers';
- },
- })
- .toCompileTo('helpers');
- });
-
- it('the helpers hash is available is nested contexts', () => {
- expectTemplate('{{#outer}}{{#inner}}{{helper}}{{/inner}}{{/outer}}')
- .withInput({ outer: { inner: { unused: [] } } })
- .withHelpers({
- helper() {
- return 'helper';
- },
- })
- .toCompileTo('helper');
- });
-
- it('the helper hash should augment the global hash', () => {
- kbnHandlebarsEnv!.registerHelper('test_helper', function () {
- return 'found it!';
- });
-
- expectTemplate('{{test_helper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}')
- .withInput({ cruel: 'cruel' })
- .withHelpers({
- world() {
- return 'world!';
- },
- })
- .toCompileTo('found it! Goodbye cruel world!!');
- });
- });
-
- describe('registration', () => {
- it('unregisters', () => {
- deleteAllKeys(kbnHandlebarsEnv!.helpers);
-
- kbnHandlebarsEnv!.registerHelper('foo', function () {
- return 'fail';
- });
- expect(kbnHandlebarsEnv!.helpers.foo).toBeDefined();
- kbnHandlebarsEnv!.unregisterHelper('foo');
- expect(kbnHandlebarsEnv!.helpers.foo).toBeUndefined();
- });
-
- it('allows multiple globals', () => {
- const ifHelper = kbnHandlebarsEnv!.helpers.if;
- deleteAllKeys(kbnHandlebarsEnv!.helpers);
-
- kbnHandlebarsEnv!.registerHelper({
- if: ifHelper,
- world() {
- return 'world!';
- },
- testHelper() {
- return 'found it!';
- },
- });
-
- expectTemplate('{{testHelper}} {{#if cruel}}Goodbye {{cruel}} {{world}}!{{/if}}')
- .withInput({ cruel: 'cruel' })
- .toCompileTo('found it! Goodbye cruel world!!');
- });
-
- it('fails with multiple and args', () => {
- expect(() => {
- kbnHandlebarsEnv!.registerHelper(
- // @ts-expect-error TypeScript is complaining about the invalid input just as the thrown error
- {
- world() {
- return 'world!';
- },
- testHelper() {
- return 'found it!';
- },
- },
- {}
- );
- }).toThrow('Arg not supported with multiple helpers');
- });
- });
-
- it('decimal number literals work', () => {
- expectTemplate('Message: {{hello -1.2 1.2}}')
- .withHelper('hello', function (times, times2) {
- if (typeof times !== 'number') {
- times = 'NaN';
- }
- if (typeof times2 !== 'number') {
- times2 = 'NaN';
- }
- return 'Hello ' + times + ' ' + times2 + ' times';
- })
- .toCompileTo('Message: Hello -1.2 1.2 times');
- });
-
- it('negative number literals work', () => {
- expectTemplate('Message: {{hello -12}}')
- .withHelper('hello', function (times) {
- if (typeof times !== 'number') {
- times = 'NaN';
- }
- return 'Hello ' + times + ' times';
- })
- .toCompileTo('Message: Hello -12 times');
- });
-
- describe('String literal parameters', () => {
- it('simple literals work', () => {
- expectTemplate('Message: {{hello "world" 12 true false}}')
- .withHelper('hello', function (param, times, bool1, bool2) {
- if (typeof times !== 'number') {
- times = 'NaN';
- }
- if (typeof bool1 !== 'boolean') {
- bool1 = 'NaB';
- }
- if (typeof bool2 !== 'boolean') {
- bool2 = 'NaB';
- }
- return 'Hello ' + param + ' ' + times + ' times: ' + bool1 + ' ' + bool2;
- })
- .toCompileTo('Message: Hello world 12 times: true false');
- });
-
- it('using a quote in the middle of a parameter raises an error', () => {
- expectTemplate('Message: {{hello wo"rld"}}').toThrow(Error);
- });
-
- it('escaping a String is possible', () => {
- expectTemplate('Message: {{{hello "\\"world\\""}}}')
- .withHelper('hello', function (param) {
- return 'Hello ' + param;
- })
- .toCompileTo('Message: Hello "world"');
- });
-
- it("it works with ' marks", () => {
- expectTemplate('Message: {{{hello "Alan\'s world"}}}')
- .withHelper('hello', function (param) {
- return 'Hello ' + param;
- })
- .toCompileTo("Message: Hello Alan's world");
- });
- });
-
- describe('multiple parameters', () => {
- it('simple multi-params work', () => {
- expectTemplate('Message: {{goodbye cruel world}}')
- .withInput({ cruel: 'cruel', world: 'world' })
- .withHelper('goodbye', function (cruel, world) {
- return 'Goodbye ' + cruel + ' ' + world;
- })
- .toCompileTo('Message: Goodbye cruel world');
- });
-
- it('block multi-params work', () => {
- expectTemplate('Message: {{#goodbye cruel world}}{{greeting}} {{adj}} {{noun}}{{/goodbye}}')
- .withInput({ cruel: 'cruel', world: 'world' })
- .withHelper('goodbye', function (cruel, world, options: HelperOptions) {
- return options.fn({ greeting: 'Goodbye', adj: cruel, noun: world });
- })
- .toCompileTo('Message: Goodbye cruel world');
- });
- });
-
- describe('hash', () => {
- it('helpers can take an optional hash', () => {
- expectTemplate('{{goodbye cruel="CRUEL" world="WORLD" times=12}}')
- .withHelper('goodbye', function (options: HelperOptions) {
- return (
- 'GOODBYE ' +
- options.hash.cruel +
- ' ' +
- options.hash.world +
- ' ' +
- options.hash.times +
- ' TIMES'
- );
- })
- .toCompileTo('GOODBYE CRUEL WORLD 12 TIMES');
- });
-
- it('helpers can take an optional hash with booleans', () => {
- function goodbye(options: HelperOptions) {
- if (options.hash.print === true) {
- return 'GOODBYE ' + options.hash.cruel + ' ' + options.hash.world;
- } else if (options.hash.print === false) {
- return 'NOT PRINTING';
- } else {
- return 'THIS SHOULD NOT HAPPEN';
- }
- }
-
- expectTemplate('{{goodbye cruel="CRUEL" world="WORLD" print=true}}')
- .withHelper('goodbye', goodbye)
- .toCompileTo('GOODBYE CRUEL WORLD');
-
- expectTemplate('{{goodbye cruel="CRUEL" world="WORLD" print=false}}')
- .withHelper('goodbye', goodbye)
- .toCompileTo('NOT PRINTING');
- });
-
- it('block helpers can take an optional hash', () => {
- expectTemplate('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}')
- .withHelper('goodbye', function (this: any, options: HelperOptions) {
- return (
- 'GOODBYE ' +
- options.hash.cruel +
- ' ' +
- options.fn(this) +
- ' ' +
- options.hash.times +
- ' TIMES'
- );
- })
- .toCompileTo('GOODBYE CRUEL world 12 TIMES');
- });
-
- it('block helpers can take an optional hash with single quoted stings', () => {
- expectTemplate('{{#goodbye cruel="CRUEL" times=12}}world{{/goodbye}}')
- .withHelper('goodbye', function (this: any, options: HelperOptions) {
- return (
- 'GOODBYE ' +
- options.hash.cruel +
- ' ' +
- options.fn(this) +
- ' ' +
- options.hash.times +
- ' TIMES'
- );
- })
- .toCompileTo('GOODBYE CRUEL world 12 TIMES');
- });
-
- it('block helpers can take an optional hash with booleans', () => {
- function goodbye(this: any, options: HelperOptions) {
- if (options.hash.print === true) {
- return 'GOODBYE ' + options.hash.cruel + ' ' + options.fn(this);
- } else if (options.hash.print === false) {
- return 'NOT PRINTING';
- } else {
- return 'THIS SHOULD NOT HAPPEN';
- }
- }
-
- expectTemplate('{{#goodbye cruel="CRUEL" print=true}}world{{/goodbye}}')
- .withHelper('goodbye', goodbye)
- .toCompileTo('GOODBYE CRUEL world');
-
- expectTemplate('{{#goodbye cruel="CRUEL" print=false}}world{{/goodbye}}')
- .withHelper('goodbye', goodbye)
- .toCompileTo('NOT PRINTING');
- });
- });
-
- describe('helperMissing', () => {
- it('if a context is not found, helperMissing is used', () => {
- expectTemplate('{{hello}} {{link_to world}}').toThrow(/Missing helper: "link_to"/);
- });
-
- it('if a context is not found, custom helperMissing is used', () => {
- expectTemplate('{{hello}} {{link_to world}}')
- .withInput({ hello: 'Hello', world: 'world' })
- .withHelper('helperMissing', function (mesg, options: HelperOptions) {
- if (options.name === 'link_to') {
- return new Handlebars.SafeString('<a>' + mesg + '</a>');
- }
- })
- .toCompileTo('Hello <a>world</a>');
- });
-
- it('if a value is not found, custom helperMissing is used', () => {
- expectTemplate('{{hello}} {{link_to}}')
- .withInput({ hello: 'Hello', world: 'world' })
- .withHelper('helperMissing', function (options: HelperOptions) {
- if (options.name === 'link_to') {
- return new Handlebars.SafeString('<a>winning</a>');
- }
- })
- .toCompileTo('Hello <a>winning</a>');
- });
- });
-
- describe('knownHelpers', () => {
- it('Known helper should render helper', () => {
- expectTemplate('{{hello}}')
- .withCompileOptions({
- knownHelpers: { hello: true },
- })
- .withHelper('hello', function () {
- return 'foo';
- })
- .toCompileTo('foo');
- });
-
- it('Unknown helper in knownHelpers only mode should be passed as undefined', () => {
- expectTemplate('{{typeof hello}}')
- .withCompileOptions({
- knownHelpers: { typeof: true },
- knownHelpersOnly: true,
- })
- .withHelper('typeof', function (arg) {
- return typeof arg;
- })
- .withHelper('hello', function () {
- return 'foo';
- })
- .toCompileTo('undefined');
- });
-
- it('Builtin helpers available in knownHelpers only mode', () => {
- expectTemplate('{{#unless foo}}bar{{/unless}}')
- .withCompileOptions({
- knownHelpersOnly: true,
- })
- .toCompileTo('bar');
- });
-
- it('Field lookup works in knownHelpers only mode', () => {
- expectTemplate('{{foo}}')
- .withCompileOptions({
- knownHelpersOnly: true,
- })
- .withInput({ foo: 'bar' })
- .toCompileTo('bar');
- });
-
- it('Conditional blocks work in knownHelpers only mode', () => {
- expectTemplate('{{#foo}}bar{{/foo}}')
- .withCompileOptions({
- knownHelpersOnly: true,
- })
- .withInput({ foo: 'baz' })
- .toCompileTo('bar');
- });
-
- it('Invert blocks work in knownHelpers only mode', () => {
- expectTemplate('{{^foo}}bar{{/foo}}')
- .withCompileOptions({
- knownHelpersOnly: true,
- })
- .withInput({ foo: false })
- .toCompileTo('bar');
- });
-
- it('Functions are bound to the context in knownHelpers only mode', () => {
- expectTemplate('{{foo}}')
- .withCompileOptions({
- knownHelpersOnly: true,
- })
- .withInput({
- foo() {
- return this.bar;
- },
- bar: 'bar',
- })
- .toCompileTo('bar');
- });
-
- it('Unknown helper call in knownHelpers only mode should throw', () => {
- expectTemplate('{{typeof hello}}')
- .withCompileOptions({ knownHelpersOnly: true })
- .toThrow(Error);
- });
- });
-
- describe('blockHelperMissing', () => {
- it('lambdas are resolved by blockHelperMissing, not handlebars proper', () => {
- expectTemplate('{{#truthy}}yep{{/truthy}}')
- .withInput({
- truthy() {
- return true;
- },
- })
- .toCompileTo('yep');
- });
-
- it('lambdas resolved by blockHelperMissing are bound to the context', () => {
- expectTemplate('{{#truthy}}yep{{/truthy}}')
- .withInput({
- truthy() {
- return this.truthiness();
- },
- truthiness() {
- return false;
- },
- })
- .toCompileTo('');
- });
- });
-
- describe('name field', () => {
- const helpers = {
- blockHelperMissing(...args: any[]) {
- return 'missing: ' + args[args.length - 1].name;
- },
- helperMissing(...args: any[]) {
- return 'helper missing: ' + args[args.length - 1].name;
- },
- helper(...args: any[]) {
- return 'ran: ' + args[args.length - 1].name;
- },
- };
-
- it('should include in ambiguous mustache calls', () => {
- expectTemplate('{{helper}}').withHelpers(helpers).toCompileTo('ran: helper');
- });
-
- it('should include in helper mustache calls', () => {
- expectTemplate('{{helper 1}}').withHelpers(helpers).toCompileTo('ran: helper');
- });
-
- it('should include in ambiguous block calls', () => {
- expectTemplate('{{#helper}}{{/helper}}').withHelpers(helpers).toCompileTo('ran: helper');
- });
-
- it('should include in simple block calls', () => {
- expectTemplate('{{#./helper}}{{/./helper}}')
- .withHelpers(helpers)
- .toCompileTo('missing: ./helper');
- });
-
- it('should include in helper block calls', () => {
- expectTemplate('{{#helper 1}}{{/helper}}').withHelpers(helpers).toCompileTo('ran: helper');
- });
-
- it('should include in known helper calls', () => {
- expectTemplate('{{helper}}')
- .withCompileOptions({
- knownHelpers: { helper: true },
- knownHelpersOnly: true,
- })
- .withHelpers(helpers)
- .toCompileTo('ran: helper');
- });
-
- it('should include full id', () => {
- expectTemplate('{{#foo.helper}}{{/foo.helper}}')
- .withInput({ foo: {} })
- .withHelpers(helpers)
- .toCompileTo('missing: foo.helper');
- });
-
- it('should include full id if a hash is passed', () => {
- expectTemplate('{{#foo.helper bar=baz}}{{/foo.helper}}')
- .withInput({ foo: {} })
- .withHelpers(helpers)
- .toCompileTo('helper missing: foo.helper');
- });
- });
-
- describe('name conflicts', () => {
- it('helpers take precedence over same-named context properties', () => {
- expectTemplate('{{goodbye}} {{cruel world}}')
- .withHelper('goodbye', function (this: any) {
- return this.goodbye.toUpperCase();
- })
- .withHelper('cruel', function (world) {
- return 'cruel ' + world.toUpperCase();
- })
- .withInput({
- goodbye: 'goodbye',
- world: 'world',
- })
- .toCompileTo('GOODBYE cruel WORLD');
- });
-
- it('helpers take precedence over same-named context properties$', () => {
- expectTemplate('{{#goodbye}} {{cruel world}}{{/goodbye}}')
- .withHelper('goodbye', function (this: any, options: HelperOptions) {
- return this.goodbye.toUpperCase() + options.fn(this);
- })
- .withHelper('cruel', function (world) {
- return 'cruel ' + world.toUpperCase();
- })
- .withInput({
- goodbye: 'goodbye',
- world: 'world',
- })
- .toCompileTo('GOODBYE cruel WORLD');
- });
-
- it('Scoped names take precedence over helpers', () => {
- expectTemplate('{{this.goodbye}} {{cruel world}} {{cruel this.goodbye}}')
- .withHelper('goodbye', function (this: any) {
- return this.goodbye.toUpperCase();
- })
- .withHelper('cruel', function (world) {
- return 'cruel ' + world.toUpperCase();
- })
- .withInput({
- goodbye: 'goodbye',
- world: 'world',
- })
- .toCompileTo('goodbye cruel WORLD cruel GOODBYE');
- });
-
- it('Scoped names take precedence over block helpers', () => {
- expectTemplate('{{#goodbye}} {{cruel world}}{{/goodbye}} {{this.goodbye}}')
- .withHelper('goodbye', function (this: any, options: HelperOptions) {
- return this.goodbye.toUpperCase() + options.fn(this);
- })
- .withHelper('cruel', function (world) {
- return 'cruel ' + world.toUpperCase();
- })
- .withInput({
- goodbye: 'goodbye',
- world: 'world',
- })
- .toCompileTo('GOODBYE cruel WORLD goodbye');
- });
- });
-
- describe('block params', () => {
- it('should take presedence over context values', () => {
- expectTemplate('{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{value}}')
- .withInput({ value: 'foo' })
- .withHelper('goodbyes', function (options: HelperOptions) {
- expect(options.fn.blockParams).toEqual(1);
- return options.fn({ value: 'bar' }, { blockParams: [1, 2] });
- })
- .toCompileTo('1foo');
- });
-
- it('should take presedence over helper values', () => {
- expectTemplate('{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{value}}')
- .withHelper('value', function () {
- return 'foo';
- })
- .withHelper('goodbyes', function (options: HelperOptions) {
- expect(options.fn.blockParams).toEqual(1);
- return options.fn({}, { blockParams: [1, 2] });
- })
- .toCompileTo('1foo');
- });
-
- it('should not take presedence over pathed values', () => {
- expectTemplate('{{#goodbyes as |value|}}{{./value}}{{/goodbyes}}{{value}}')
- .withInput({ value: 'bar' })
- .withHelper('value', function () {
- return 'foo';
- })
- .withHelper('goodbyes', function (this: any, options: HelperOptions) {
- expect(options.fn.blockParams).toEqual(1);
- return options.fn(this, { blockParams: [1, 2] });
- })
- .toCompileTo('barfoo');
- });
-
- it('should take presednece over parent block params', () => {
- let value: number;
- expectTemplate(
- '{{#goodbyes as |value|}}{{#goodbyes}}{{value}}{{#goodbyes as |value|}}{{value}}{{/goodbyes}}{{/goodbyes}}{{/goodbyes}}{{value}}',
- {
- beforeEach() {
- value = 1;
- },
- }
- )
- .withInput({ value: 'foo' })
- .withHelper('goodbyes', function (options: HelperOptions) {
- return options.fn(
- { value: 'bar' },
- {
- blockParams: options.fn.blockParams === 1 ? [value++, value++] : undefined,
- }
- );
- })
- .toCompileTo('13foo');
- });
-
- it('should allow block params on chained helpers', () => {
- expectTemplate('{{#if bar}}{{else goodbyes as |value|}}{{value}}{{/if}}{{value}}')
- .withInput({ value: 'foo' })
- .withHelper('goodbyes', function (options: HelperOptions) {
- expect(options.fn.blockParams).toEqual(1);
- return options.fn({ value: 'bar' }, { blockParams: [1, 2] });
- })
- .toCompileTo('1foo');
- });
- });
-
- describe('built-in helpers malformed arguments ', () => {
- it('if helper - too few arguments', () => {
- expectTemplate('{{#if}}{{/if}}').toThrow(/#if requires exactly one argument/);
- });
-
- it('if helper - too many arguments, string', () => {
- expectTemplate('{{#if test "string"}}{{/if}}').toThrow(/#if requires exactly one argument/);
- });
-
- it('if helper - too many arguments, undefined', () => {
- expectTemplate('{{#if test undefined}}{{/if}}').toThrow(/#if requires exactly one argument/);
- });
-
- it('if helper - too many arguments, null', () => {
- expectTemplate('{{#if test null}}{{/if}}').toThrow(/#if requires exactly one argument/);
- });
-
- it('unless helper - too few arguments', () => {
- expectTemplate('{{#unless}}{{/unless}}').toThrow(/#unless requires exactly one argument/);
- });
-
- it('unless helper - too many arguments', () => {
- expectTemplate('{{#unless test null}}{{/unless}}').toThrow(
- /#unless requires exactly one argument/
- );
- });
-
- it('with helper - too few arguments', () => {
- expectTemplate('{{#with}}{{/with}}').toThrow(/#with requires exactly one argument/);
- });
-
- it('with helper - too many arguments', () => {
- expectTemplate('{{#with test "string"}}{{/with}}').toThrow(
- /#with requires exactly one argument/
- );
- });
- });
-
- describe('the lookupProperty-option', () => {
- it('should be passed to custom helpers', () => {
- expectTemplate('{{testHelper}}')
- .withHelper('testHelper', function testHelper(this: any, options: HelperOptions) {
- return options.lookupProperty(this, 'testProperty');
- })
- .withInput({ testProperty: 'abc' })
- .toCompileTo('abc');
- });
- });
-});
-
-function deleteAllKeys(obj: { [key: string]: any }) {
- for (const key of Object.keys(obj)) {
- delete obj[key];
- }
-}