This is repeated a few times in the current Ember documentation, so I feel like I must be missing something. Let's take the simplest example I found.
Why is the call to levelUp considered asynchronous to warrant wrapping it in the run loop?
incrementProperty is synchronous, and as far as I can tell, so is set (but I could be mistaken here)
player.js
import DS from 'ember-data';
export default DS.Model.extend({
level: DS.attr('number', { defaultValue: 0 }),
levelName: DS.attr('string', { defaultValue: 'Noob' }),
levelUp() {
let newLevel = this.incrementProperty('level');
if (newLevel === 5) {
this.set('levelName', 'Professional');
}
}
});
player-test.js
import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
moduleForModel('player', 'Unit | Model | player', {
// Specify the other units that are required for this test.
needs: []
});
test('should increment level when told to', function(assert) {
// this.subject aliases the createRecord method on the model
const player = this.subject({ level: 4 });
// wrap asynchronous call in run loop
Ember.run(() => player.levelUp());
assert.equal(player.get('level'), 5, 'level gets incremented');
assert.equal(player.get('levelName'), 'Professional', 'new level is called professional');
});
First of all, you are absolutely right. It is not well-described anywhere in the guides.
In testing mode, autorun is disabled. You can read further from the guides about this.
But changing the value in model triggers a run-loop. You can see that at this twiddle. The result is:
Assertion Failed: You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run
(By the way, both set
and incrementProperty
trigger this run-loop as your guess.)
Then here is the run loop source:
DS.attr
returns a computed property with set. set
function triggers an event.