test('array arguments are passed correctly to action', function(assert) { assert.expect(3); let first = 'foo'; let second = [3, 5]; let third = [4, 9]; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(second, third); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action outerSubmit first)}} `), innerComponent, value: '', outerSubmit(actualFirst, actualSecond, actualThird) { assert.equal(actualFirst, first, 'action has the correct first arg'); assert.equal(actualSecond, second, 'action has the correct second arg'); assert.equal(actualThird, third, 'action has the correct third arg'); } }).create(); runAppend(outerComponent); run(function() { outerComponent.set('first', first); outerComponent.set('second', second); }); innerComponent.fireAction(); });
test('should have the correct action target', function() { owner.register('component:x-outer', EmberComponent.extend({ layout: compile('{{#x-middle}}{{view innerView dismiss="dismiss"}}{{/x-middle}}'), actions: { dismiss: function() { ok(true, 'We handled the action in the right place'); } }, innerView: EmberComponent.extend({ elementId: 'x-inner' }) })); owner.register('component:x-middle', EmberComponent.extend({ actions: { dismiss: function() { throw new Error('action was not supposed to go here'); } } })); view = EmberView.extend({ [OWNER]: owner, template: compile('{{x-outer}}') }).create(); runAppend(view); run(function() { EmberView.views['x-inner'].sendAction('dismiss'); }); });
test('action can create closures over actions with target', function(assert) { assert.expect(1); innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action 'outerAction' target=otherComponent)}} `), innerComponent, otherComponent: computed(function() { return { actions: { outerAction(actualFirst, actualSecond) { assert.ok(true, 'action called on otherComponent'); } } }; }) }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('mut values can be wrapped in actions, are settable with a curry', function(assert) { assert.expect(1); var newValue = 'trollin trek'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action (mut outerMut) '${newValue}')}} `), innerComponent, outerMut: 'patient peter' }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); assert.equal(outerComponent.get('outerMut'), newValue, 'mut value is set'); }); });
test('action can create closures over actions', function(assert) { assert.expect(3); var first = 'raging robert'; var second = 'mild machty'; var returnValue = 'butch brian'; innerComponent = EmberComponent.extend({ fireAction() { var actualReturnedValue = this.attrs.submit(second); assert.equal(actualReturnedValue, returnValue, 'return value is present'); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action 'outerAction' '${first}')}} `), innerComponent, actions: { outerAction(actualFirst, actualSecond) { assert.equal(actualFirst, first, 'first argument is correct'); assert.equal(actualSecond, second, 'second argument is correct'); return returnValue; } } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('action will read the value of a first property', function(assert) { assert.expect(1); let newValue = 'irate igor'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit({ readProp: newValue }); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action outerAction value="readProp")}} `), innerComponent, outerAction(actualNewValue) { assert.equal(actualNewValue, newValue, 'property is read'); } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
QUnit.test('events should stop propagating if the view is destroyed', function() { var parentComponentReceived, receivedEvent; owner.register('component:x-foo', Component.extend({ layout: compile('<input id="is-done" type="checkbox" />'), change(evt) { receivedEvent = true; run(() => { get(this, 'parentView').destroy(); }); } })); let parentComponent = Component.extend({ [OWNER]: owner, layout: compile('{{x-foo}}'), change(evt) { parentComponentReceived = true; } }).create(); runAppend(parentComponent); ok(jQuery('#is-done').length, 'precond - component is in the DOM'); jQuery('#is-done').trigger('change'); ok(!jQuery('#is-done').length, 'precond - component is not in the DOM'); ok(receivedEvent, 'calls change method when a child element is changed'); ok(!parentComponentReceived, 'parent component does not receive the event'); });
test('action will read the value of a curried first argument property', function(assert) { assert.expect(1); let newValue = 'kissing kris'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action outerAction objectArgument value="readProp")}} `), innerComponent, objectArgument: { readProp: newValue }, outerAction(actualNewValue) { assert.equal(actualNewValue, newValue, 'property is read'); } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('arguments to action are passed, curry', function(assert) { assert.expect(4); let first = 'mitch'; let second = 'martin'; let third = 'matt'; let fourth = 'wacky wycats'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(fourth); } }).create(); outerComponent = EmberComponent.extend({ third, layout: compile(` {{view innerComponent submit=(action (action outerSubmit "${first}") "${second}" third)}} `), innerComponent, outerSubmit(actualFirst, actualSecond, actualThird, actualFourth) { assert.equal(actualFirst, first, 'action has the correct first arg'); assert.equal(actualSecond, second, 'action has the correct second arg'); assert.equal(actualThird, third, 'action has the correct third arg'); assert.equal(actualFourth, fourth, 'action has the correct fourth arg'); } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('arguments to action are bound', function(assert) { assert.expect(1); let value = 'lazy leah'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit(); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action outerSubmit value)}} `), innerComponent, value: '', outerSubmit(actualValue) { assert.equal(actualValue, value, 'action has the correct first arg'); } }).create(); runAppend(outerComponent); run(function() { outerComponent.set('value', value); }); innerComponent.fireAction(); });
test('value can be used with action over actions', function(assert) { assert.expect(1); let newValue = 'yelping yehuda'; innerComponent = EmberComponent.extend({ fireAction() { this.attrs.submit({ readProp: newValue }); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(` {{view innerComponent submit=(action 'outerAction' value="readProp")}} `), innerComponent, outerContent: { readProp: newValue }, actions: { outerAction(actualValue) { assert.equal(actualValue, newValue, 'value is read'); } } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('action value is returned', function(assert) { assert.expect(1); var returnedValue = 'terrible tom'; innerComponent = EmberComponent.extend({ fireAction() { var actualReturnedValue = this.attrs.submit(); assert.equal(actualReturnedValue, returnedValue, 'action can return to caller'); } }).create(); outerComponent = EmberComponent.extend({ layout: compile('{{view innerComponent submit=(action outerSubmit)}}'), innerComponent, outerSubmit() { return returnedValue; } }).create(); runAppend(outerComponent); run(function() { innerComponent.fireAction(); }); });
test('instrumented action should return value', function(assert) { assert.expect(1); var returnedValue = 'Chris P is so krispy'; registerTemplate('components/inner-component', '<button id="instrument-button" {{action "fireAction"}}>What it do</button>'); registerComponent('inner-component', EmberComponent.extend({ actions: { fireAction() { var actualReturnedValue = this.attrs.submit(); assert.equal(actualReturnedValue, returnedValue, 'action can return to caller'); } } })); registerTemplate('components/outer-component', '{{inner-component submit=(action outerSubmit)}}'); registerComponent('outer-component', EmberComponent.extend({ innerComponent, outerSubmit() { return returnedValue; } })); view = appendViewFor(`{{outer-component}}`); view.$('#instrument-button').trigger('click'); });
test('interaction event subscriber should be passed target', function(assert) { assert.expect(2); subscriber = subscribe('interaction.ember-action', { before(name, timestamp, payload) { assert.equal(payload.target.get('myProperty'), 'outer-thing', 'instrumentation subscriber before function was passed target'); }, after(name, timestamp, payload) { assert.equal(payload.target.get('myProperty'), 'outer-thing', 'instrumentation subscriber after function was passed target'); } }); registerTemplate('components/inner-component', '<button id="instrument-button" {{action "fireAction"}}>What it do</button>'); registerComponent('inner-component', EmberComponent.extend({ myProperty: 'inner-thing', actions: { fireAction() { this.attrs.submit(); } } })); registerTemplate('components/outer-component', '{{inner-component submit=(action outerSubmit)}}'); registerComponent('outer-component', EmberComponent.extend({ myProperty: 'outer-thing', innerComponent, outerSubmit() {} })); view = appendViewFor(`{{outer-component}}`); view.$('#instrument-button').trigger('click'); });
test('interaction event subscriber should be passed parameters', function(assert) { assert.expect(2); let actionParam = 'So krispy'; subscriber = subscribe('interaction.ember-action', { before(name, timestamp, payload) { assert.equal(payload.args[0], actionParam, 'instrumentation subscriber before function was passed closure action parameters'); }, after(name, timestamp, payload) { assert.equal(payload.args[0], actionParam, 'instrumentation subscriber after function was passed closure action parameters'); } }); registerTemplate('components/inner-component', '<button id="instrument-button" {{action "fireAction"}}>What it do</button>'); registerComponent('inner-component', EmberComponent.extend({ actions: { fireAction() { this.attrs.submit(actionParam); } } })); registerTemplate('components/outer-component', '{{inner-component submit=(action outerSubmit)}}'); registerComponent('outer-component', EmberComponent.extend({ innerComponent, outerSubmit() {} })); view = appendViewFor(`{{outer-component}}`); view.$('#instrument-button').trigger('click'); });
test('action should fire interaction event', function(assert) { assert.expect(2); subscriber = subscribe('interaction.ember-action', { before() { assert.ok(true, 'instrumentation subscriber was called'); } }); registerTemplate('components/inner-component', '<button id="instrument-button" {{action "fireAction"}}>What it do</button>'); registerComponent('inner-component', EmberComponent.extend({ actions: { fireAction() { this.attrs.submit(); } } })); registerTemplate('components/outer-component', '{{inner-component submit=(action outerSubmit)}}'); registerComponent('outer-component', EmberComponent.extend({ innerComponent, outerSubmit() { assert.ok(true, 'action is called'); } })); view = appendViewFor(`{{outer-component}}`); view.$('#instrument-button').trigger('click'); });
test('objects that define INVOKE can be casted to actions', function(assert) { assert.expect(2); innerComponent = EmberComponent.extend({ fireAction() { assert.equal(this.attrs.submit(4, 5, 6), 123); } }).create(); outerComponent = EmberComponent.extend({ layout: compile(`{{view innerComponent submit=(action submitTask 1 2 3)}}`), innerComponent, foo: 123, submitTask: computed(function() { return { [INVOKE]: (...args) => { assert.deepEqual(args, [1, 2, 3, 4, 5, 6]); return this.foo; } }; }) }).create(); runAppend(outerComponent); innerComponent.fireAction(); });
test('[#12718] a nice error is shown when a bound action function is undefined and it is passed as attrs.foo', function(assert) { registerComponent('inner-component', EmberComponent.extend({ [OWNER]: owner })); registerTemplate('components/inner-component', '<button id="inner-button" {{action (action attrs.external-action)}}>Click me</button>'); view = EmberComponent.extend({ layout: compile('{{inner-component}}'), [OWNER]: owner }).create(); throws(function() { runAppend(view); }, /Action passed is null or undefined in \(action [^)]*\) from .*\./); });
test('an error is triggered when bound action function is undefined', function(assert) { assert.expect(1); innerComponent = EmberComponent.extend({ }).create(); outerComponent = EmberComponent.extend({ layout: compile('{{view innerComponent submit=(action somethingThatIsUndefined)}}'), innerComponent }).create(); throws(function() { runAppend(outerComponent); }, /An action could not be made for `somethingThatIsUndefined` in .*\. Please confirm that you are using either a quoted action name \(i\.e\. `\(action 'somethingThatIsUndefined'\)`\) or a function available in .*\./); });
test('boots an engine, instantiates its application controller, and renders its application template', function(assert) { assert.expect(3); chatEngineResolutions = { 'template:application': compile('<h2>Chat here</h2>') }; chatEngineResolutions['controller:application'] = Controller.extend({ init: function() { this._super(); assert.ok(true, 'engine\'s application controller has been instantiated'); let engineInstance = getOwner(this); assert.strictEqual(getEngineParent(engineInstance), appInstance, 'engine instance has appInstance as its parent'); } }); let component = Component.extend({ [OWNER]: appInstance, layout: compile('{{mount "chat"}}'), didInsertElement() { assert.equal(this.$().text(), 'Chat here', 'engine\'s application template has rendered properly'); } }).create(); runAppend(component); });
QUnit.test('assertion for routes without isRouteFactory property', function() { application.FooRoute = Component.extend(); expectAssertion(function() { registry.resolve(`route:foo`); }, /to resolve to an Ember.Route/, 'Should assert'); });
test('instanceInitializers can augment an the customEvents hash', function(assert) { assert.expect(1); run(App, 'destroy'); var ApplicationSubclass = Application.extend(); ApplicationSubclass.instanceInitializer({ name: 'customize-things', initialize(application) { application.customEvents = { herky: 'jerky' }; } }); setupApp(ApplicationSubclass); App.FooBarComponent = Component.extend({ jerky() { assert.ok(true, 'fired the event!'); } }); TEMPLATES['application'] = compile(`{{foo-bar}}`); TEMPLATES['components/foo-bar'] = compile(`<div id='herky-thingy'></div>`); run(App, 'advanceReadiness'); run(function() { jQuery('#herky-thingy').trigger('herky'); }); });
test('Inside a yield, the target points at the original target', function() { var watted = false; var component = EmberComponent.extend({ boundText: 'inner', truthy: true, obj: {}, layout: compile('<div>{{boundText}}</div><div>{{#if truthy}}{{yield}}{{/if}}</div>') }); view = EmberView.create({ controller: { boundText: 'outer', truthy: true, wat() { watted = true; }, component: component }, template: compile('{{#if truthy}}{{#view component}}{{#if truthy}}<div {{action "wat"}} class="wat">{{boundText}}</div>{{/if}}{{/view}}{{/if}}') }); runAppend(view); run(function() { view.$('.wat').click(); }); equal(watted, true, 'The action was called on the right context'); });
expectAssertion(function() { component = EmberComponent.extend({ [OWNER]: owner, layout: compile('{{view \'foo\'}}') }).create(); runAppend(component); }, /Using the `{{view "string"}}` helper/);
expectAssertion(() => { Component.extend({ elementId: 'test', classNameBindings: computed(function() { return ['className']; }) }).create(); }, /Only arrays are allowed/i);
expectAssertion(() => { Component.extend({ elementId: 'test', classNames: computed(function() { return ['className']; }) }).create(); }, /Only arrays of static class strings.*For dynamic classes/i);
ignoreAssertion(function() { component = EmberComponent.extend({ [OWNER]: owner, layout: compile('{{#view \'foo\'}}I am foo{{/view}}') }).create(); runAppend(component); });
QUnit.test('throws an error if `this._super` is not called from `init`', function() { let TestComponent = Component.extend({ init() { } }); expectAssertion(function() { TestComponent.create(); }, /You must call `this._super\(...arguments\);` when implementing `init` in a component. Please update .* to call `this._super` from `init`/); });
function appendViewFor(template, moduleName='', hash={}) { let view = EmberComponent.extend({ layout: compile(template, { moduleName }), [OWNER]: owner }).create(hash); runAppend(view); return view; }
test('asserts that the specified engine is registered', function(assert) { assert.expect(1); let component = Component.extend({ [OWNER]: appInstance, layout: compile('{{mount "does-not-exist"}}') }).create(); expectAssertion(() => { runAppend(component); }, /You used `{{mount 'does-not-exist'}}`, but the engine 'does-not-exist' can not be found./i); });