diff --git a/package-lock.json b/package-lock.json index e35aadf4..235b5114 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7339,9 +7339,9 @@ } }, "jasmine-core": { - "version": "2.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", - "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.1.0.tgz", + "integrity": "sha1-pHheE11d9lAk38kiSVPfWFvSdmw=", "dev": true }, "js-tokens": { diff --git a/package.json b/package.json index 42752053..74ddf992 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "eslint-config-airbnb-base": "^12.1.0", "eslint-loader": "^2.0.0", "eslint-plugin-import": "^2.9.0", - "jasmine-core": "^2.99", + "jasmine-core": "^3.1.0", "karma": "^2.0.0", "karma-chrome-launcher": "^2.0.0", "karma-coverage": "^1.1.1", diff --git a/src/cache.js b/src/cache.js index 84914922..9c657c1c 100644 --- a/src/cache.js +++ b/src/cache.js @@ -53,7 +53,13 @@ export function get(target, key, getter) { context = entry; entry.deps = []; - entry.value = getter(target, entry.value); + + try { + entry.value = getter(target, entry.value); + } catch (e) { + context = null; + throw e; + } context = parentContext; diff --git a/src/render.js b/src/render.js index 5217bfff..c4c51a6a 100644 --- a/src/render.js +++ b/src/render.js @@ -11,26 +11,39 @@ function update(iterator, startTime) { } else { const { done, value: target } = iterator.next(); const nextTime = performance.now(); + const next = () => update(iterator, nextTime); if (done) { queue.clear(); } else if (map.has(target)) { const key = map.get(target); const prevFn = cache.get(target); - const nextFn = target[key]; + let nextFn; - if (nextFn !== prevFn) { - cache.set(target, nextFn); + try { + nextFn = target[key]; - Promise.resolve().then(() => { - nextFn(); - update(iterator, nextTime); - }); - } else { - update(iterator, nextTime); + if (nextFn !== prevFn) { + cache.set(target, nextFn); + + Promise.resolve().then(() => { + try { + nextFn(); + next(); + } catch (e) { + next(); + throw e; + } + }); + } else { + next(); + } + } catch (e) { + next(); + throw e; } } else { - update(iterator, nextTime); + next(); } } } diff --git a/test/spec/render.js b/test/spec/render.js index 25c5e2d7..003563a5 100644 --- a/test/spec/render.js +++ b/test/spec/render.js @@ -103,4 +103,44 @@ describe('render:', () => { }); })); }); + + it('catches error inside of the passed function', (done) => { + define('test-render-throws-in-render', { + render: () => { + throw Error(); + }, + }); + + let throwEl; + + Promise.resolve().then(() => { + throwEl = document.createElement('test-render-throws-in-render'); + document.body.appendChild(throwEl); + }).catch(() => {}); + + tree(el => resolveRender(() => { + expect(el.shadowRoot.children[0].textContent).toBe('0'); + document.body.removeChild(throwEl); + done(); + })); + }); + + it('catches error inside of the returned function', (done) => { + define('test-render-throws-in-callback', { + render: () => () => { throw Error; }, + }); + + let throwEl; + + Promise.resolve().then(() => { + throwEl = document.createElement('test-render-throws-in-callback'); + document.body.appendChild(throwEl); + }).catch(() => {}); + + tree(el => resolveRender(() => { + expect(el.shadowRoot.children[0].textContent).toBe('0'); + document.body.removeChild(throwEl); + done(); + })); + }); });