Skip to content

Commit

Permalink
[BUGFIX lts] Ensure errors in deferred component hooks can be recovered.
Browse files Browse the repository at this point in the history
Previously, any errors thrown during `didInsertElement` would leave the
running environment in an invalid state (`env.inTransaction` would be
`true` but `this._transaction` would have been nullified).

This commit ensures that we _always_ reset `inTransaction` if
`Environment.prototype.commit` is called. Thus avoiding an error RE:
"calling commit on null"...
  • Loading branch information
rwjblue committed Feb 14, 2018
1 parent 9da3a7e commit ab4a2e3
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
8 changes: 5 additions & 3 deletions packages/ember-glimmer/lib/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,11 @@ export default class Environment extends GlimmerEnvironment {
destroyedComponents[i].destroy();
}

super.commit();

this.inTransaction = false;
try {
super.commit();
} finally {
this.inTransaction = false;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,59 @@ moduleFor('Errors thrown during render', class extends RenderingTest {

this.assertText('hello');
}

['@test it can recover resets the transaction when an error is thrown during didInsertElement'](assert) {
let shouldThrow = true;
let FooBarComponent = Component.extend({
didInsertElement() {
this._super(...arguments);
if (shouldThrow) {
throw new Error('silly mistake!');
}
}
});

this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' });

assert.throws(() => {
this.render('{{#if switch}}{{#foo-bar}}{{foo-bar}}{{/foo-bar}}{{/if}}', { switch: true });
}, /silly mistake/);

assert.equal(this.env.inTransaction, false, 'should not be in a transaction even though an error was thrown');

this.assertText('hello');

this.runTask(() => set(this.context, 'switch', false));

this.assertText('');
}

['@test it can recover resets the transaction when an error is thrown during destroy'](assert) {
let shouldThrow = true;
let FooBarComponent = Component.extend({
destroy() {
this._super(...arguments);
if (shouldThrow) {
throw new Error('silly mistake!');
}
}
});

this.registerComponent('foo-bar', { ComponentClass: FooBarComponent, template: 'hello' });

this.render('{{#if switch}}{{#foo-bar}}{{foo-bar}}{{/foo-bar}}{{/if}}', { switch: true });

this.assertText('hello');

assert.throws(() => {
this.runTask(() => set(this.context, 'switch', false));
}, /silly mistake/);

this.assertText('');

shouldThrow = false;
this.runTask(() => set(this.context, 'switch', true));

this.assertText('hello');
}
});

0 comments on commit ab4a2e3

Please sign in to comment.