diff --git a/packages/@glimmer/integration-tests/lib/suites/components.ts b/packages/@glimmer/integration-tests/lib/suites/components.ts
index baf7877140..afe8bb805b 100644
--- a/packages/@glimmer/integration-tests/lib/suites/components.ts
+++ b/packages/@glimmer/integration-tests/lib/suites/components.ts
@@ -886,4 +886,52 @@ export class BasicComponents extends RenderTest {
this.assertHTML('', 'destroys correctly');
}
+
+ @test({ kind: 'fragment' })
+ 'throwing an error during rendering gives a readable error stack'(assert: Assert) {
+ let originalConsoleError = console.error;
+
+ console.error = (message: string) => {
+ this.assert.ok(
+ message.match(/Error occurred while rendering:(\n\nBar\n {2}Foo)?/),
+ 'message logged'
+ );
+ };
+
+ try {
+ assert.expect(7);
+
+ this.registerComponent(
+ 'Glimmer',
+ 'Foo',
+ 'Hello',
+ class extends EmberishGlimmerComponent {
+ constructor(args: EmberishGlimmerArgs) {
+ super(args);
+ throw new Error('something went wrong!');
+ }
+ }
+ );
+
+ this.registerComponent('Basic', 'Bar', '
');
+
+ this.render('{{#if showing}}{{/if}}', {
+ showing: false,
+ });
+
+ this.assert.throws(() => {
+ this.rerender({ showing: true });
+ }, /something went wrong!/);
+
+ this.assertHTML(
+ '',
+ 'values rendered before the error rendered correctly'
+ );
+ this.destroy();
+
+ this.assertHTML('', 'destroys correctly');
+ } finally {
+ console.error = originalConsoleError;
+ }
+ }
}
diff --git a/packages/@glimmer/runtime/lib/vm/append.ts b/packages/@glimmer/runtime/lib/vm/append.ts
index fb03ac0e5b..c3977a6d92 100644
--- a/packages/@glimmer/runtime/lib/vm/append.ts
+++ b/packages/@glimmer/runtime/lib/vm/append.ts
@@ -568,7 +568,7 @@ export default class VM implements PublicVM, InternalVM {
elements.popBlock();
}
- resetTracking();
+ console.error(`\n\nError occurred while rendering:\n\n${resetTracking()}\n\n`);
}
}
} else {
diff --git a/packages/@glimmer/runtime/lib/vm/update.ts b/packages/@glimmer/runtime/lib/vm/update.ts
index b66bf8f3fd..312ebf79a8 100644
--- a/packages/@glimmer/runtime/lib/vm/update.ts
+++ b/packages/@glimmer/runtime/lib/vm/update.ts
@@ -52,7 +52,7 @@ export default class UpdatingVM {
hasErrored = false;
} finally {
if (hasErrored) {
- resetTracking();
+ console.error(`\n\nError occurred while rendering:\n\n${resetTracking()}\n\n`);
}
}
} else {
diff --git a/packages/@glimmer/validator/lib/debug.ts b/packages/@glimmer/validator/lib/debug.ts
index ade6323855..75c6d42403 100644
--- a/packages/@glimmer/validator/lib/debug.ts
+++ b/packages/@glimmer/validator/lib/debug.ts
@@ -10,7 +10,7 @@ export let runInTrackingTransaction:
| ((fn: () => void, debuggingContext?: string | false) => void);
export let deprecateMutationsInTrackingTransaction: undefined | ((fn: () => void) => void);
-export let resetTrackingTransaction: undefined | (() => void);
+export let resetTrackingTransaction: undefined | (() => string);
export let setTrackingTransactionEnv:
| undefined
| ((env: {
@@ -99,8 +99,16 @@ if (DEBUG) {
};
resetTrackingTransaction = () => {
+ let stack = '';
+
+ if (TRANSACTION_STACK.length > 0) {
+ stack = logTrackingStack!(TRANSACTION_STACK[TRANSACTION_STACK.length - 1]);
+ }
+
TRANSACTION_STACK = [];
CONSUMED_TAGS = null;
+
+ return stack;
};
/**
diff --git a/packages/@glimmer/validator/lib/tracking.ts b/packages/@glimmer/validator/lib/tracking.ts
index be1c5ec266..ddd2f1e464 100644
--- a/packages/@glimmer/validator/lib/tracking.ts
+++ b/packages/@glimmer/validator/lib/tracking.ts
@@ -110,7 +110,7 @@ export function endUntrackFrame(): void {
}
// This function is only for handling errors and resetting to a valid state
-export function resetTracking(): void {
+export function resetTracking(): string | void {
while (OPEN_TRACK_FRAMES.length > 0) {
OPEN_TRACK_FRAMES.pop();
}
@@ -118,7 +118,7 @@ export function resetTracking(): void {
CURRENT_TRACKER = null;
if (DEBUG) {
- unwrap(resetTrackingTransaction)();
+ return unwrap(resetTrackingTransaction)();
}
}