Skip to content

Commit 235f2f8

Browse files
committed
Add optional Polymer.onerror handler. Fixes #2556.
1 parent 0c21efc commit 235f2f8

File tree

4 files changed

+247
-2
lines changed

4 files changed

+247
-2
lines changed

polymer-onerror.html

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<script>
2+
(function() {
3+
4+
function onError(e) {
5+
if (window.Polymer.onerror) {
6+
window.Polymer.onerror(e);
7+
} else {
8+
throw e;
9+
}
10+
}
11+
12+
var createdCallback = Polymer.Base.createdCallback;
13+
Polymer.Base.createdCallback = function() {
14+
try {
15+
createdCallback.apply(this, arguments);
16+
} catch(e) {
17+
onError(e);
18+
}
19+
};
20+
21+
var attachedCallback = Polymer.Base.attachedCallback;
22+
Polymer.Base.attachedCallback = function() {
23+
try {
24+
attachedCallback.apply(this, arguments);
25+
} catch(e) {
26+
onError(e);
27+
}
28+
};
29+
30+
var detachedCallback = Polymer.Base.detachedCallback;
31+
Polymer.Base.detachedCallback = function() {
32+
try {
33+
detachedCallback.apply(this, arguments);
34+
} catch(e) {
35+
onError(e);
36+
}
37+
};
38+
39+
var attributeChangedCallback = Polymer.Base.attributeChangedCallback;
40+
Polymer.Base.attributeChangedCallback = function() {
41+
try {
42+
attributeChangedCallback.apply(this, arguments);
43+
} catch(e) {
44+
onError(e);
45+
}
46+
};
47+
48+
var listen = Polymer.Base._listen;
49+
var listenMap = new WeakMap();
50+
Polymer.Base._listen = function(node, eventName, handler) {
51+
var safeHandler = function() {
52+
try {
53+
handler.apply(this, arguments);
54+
} catch(e) {
55+
onError(e);
56+
}
57+
};
58+
listenMap.set(handler, safeHandler);
59+
listen.call(this, node, eventName, safeHandler);
60+
};
61+
62+
var unlisten = Polymer.Base._unlisten;
63+
Polymer.Base._unlisten = function(node, eventName, handler) {
64+
unlisten.call(this, node, eventName, listenMap.get(handler));
65+
};
66+
67+
var atEndOfMicrotask = Polymer.Async._atEndOfMicrotask;
68+
Polymer.Async._atEndOfMicrotask = function() {
69+
try {
70+
atEndOfMicrotask.apply(Polymer.Async, arguments);
71+
} catch(e) {
72+
onError(e);
73+
}
74+
};
75+
76+
})();
77+
</script>

src/lib/async.html

+3-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
};
6565

6666
new (window.MutationObserver || JsMutationObserver)
67-
(Polymer.Async._atEndOfMicrotask.bind(Polymer.Async))
68-
.observe(Polymer.Async._twiddle, {characterData: true});
67+
(function() {
68+
Polymer.Async._atEndOfMicrotask();
69+
}).observe(Polymer.Async._twiddle, {characterData: true});
6970

7071
</script>

test/unit/onerror-elements.html

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<dom-module id="x-listener-throws">
2+
<template>
3+
<div id="child" on-childerror="childThrows"></div>
4+
</template>
5+
</dom-module>
6+
7+
<script>
8+
Polymer({
9+
is: 'x-created-throws',
10+
created: function() {
11+
throw new Error('error in created');
12+
}
13+
});
14+
Polymer({
15+
is: 'x-attached-throws',
16+
attached: function() {
17+
throw new Error('error in attached');
18+
}
19+
});
20+
Polymer({
21+
is: 'x-detached-throws',
22+
attached: function() {
23+
throw new Error('error in detached');
24+
}
25+
});
26+
Polymer({
27+
is: 'x-attribute-throws',
28+
attributeChanged: function() {
29+
throw new Error('error in attributeChanged');
30+
}
31+
});
32+
Polymer({
33+
is: 'x-listener-throws',
34+
listeners: {
35+
hosterror: 'hostThrows'
36+
},
37+
hostThrows: function() {
38+
throw new Error('host listener throws');
39+
},
40+
childThrows: function() {
41+
throw new Error('child listener throws');
42+
},
43+
throwChild: function() {
44+
this.fire('childerror', {}, {node: this.$.child});
45+
},
46+
throwHost: function() {
47+
this.fire('hosterror');
48+
}
49+
});
50+
Polymer({
51+
is: 'x-async-throws',
52+
throwAsync: function() {
53+
this.async(function() {
54+
throw new Error('async throws');
55+
});
56+
}
57+
});
58+
Polymer({
59+
is: 'x-node-observer-throws',
60+
ready: function() {
61+
Polymer.dom(this).observeNodes(this.throwNodeObserver.bind(this));
62+
},
63+
throwNodeObserver: function() {
64+
throw new Error('observe nodes throws');
65+
}
66+
});
67+
</script>
68+

test/unit/onerror.html

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<!doctype html>
2+
<!--
3+
@license
4+
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
5+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
6+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
7+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
8+
Code distributed by Google as part of the polymer project is also
9+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
10+
-->
11+
<html>
12+
<head>
13+
<meta charset="utf-8">
14+
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
15+
<script src="../../../web-component-tester/browser.js"></script>
16+
<link rel="import" href="../../polymer.html">
17+
<link rel="import" href="../../polymer-onerror.html">
18+
<link rel="import" href="onerror-elements.html">
19+
</head>
20+
<body>
21+
22+
<script>
23+
24+
suite('callbacks', function() {
25+
26+
test('created callback throws', function(done) {
27+
Polymer.onerror = sinon.spy();
28+
document.createElement('x-created-throws');
29+
setTimeout(function() {
30+
assert.isTrue(Polymer.onerror.calledOnce);
31+
done();
32+
});
33+
});
34+
35+
test('attached callback throws', function(done) {
36+
Polymer.onerror = sinon.spy();
37+
var el = document.createElement('x-attached-throws');
38+
document.body.appendChild(el);
39+
setTimeout(function() {
40+
assert.isTrue(Polymer.onerror.calledOnce);
41+
done();
42+
});
43+
});
44+
45+
test('attributeChanged callback throws', function(done) {
46+
Polymer.onerror = sinon.spy();
47+
var el = document.createElement('x-attribute-throws');
48+
el.setAttribute('foo', 'bar');
49+
setTimeout(function() {
50+
assert.isTrue(Polymer.onerror.calledOnce);
51+
done();
52+
});
53+
});
54+
55+
test('host listener throws', function(done) {
56+
Polymer.onerror = sinon.spy();
57+
var el = document.createElement('x-listener-throws');
58+
el.throwHost();
59+
setTimeout(function() {
60+
assert.isTrue(Polymer.onerror.calledOnce);
61+
done();
62+
});
63+
});
64+
65+
test('child listener throws', function(done) {
66+
Polymer.onerror = sinon.spy();
67+
var el = document.createElement('x-listener-throws');
68+
el.throwChild();
69+
setTimeout(function() {
70+
assert.isTrue(Polymer.onerror.calledOnce);
71+
done();
72+
});
73+
});
74+
75+
test('async callback throws', function(done) {
76+
Polymer.onerror = sinon.spy();
77+
var el = document.createElement('x-async-throws');
78+
el.throwAsync();
79+
setTimeout(function() {
80+
assert.isTrue(Polymer.onerror.calledOnce);
81+
done();
82+
});
83+
});
84+
85+
test('node observer callback throws', function(done) {
86+
Polymer.onerror = sinon.spy();
87+
var el = document.createElement('x-node-observer-throws');
88+
el.appendChild(document.createElement('div'));
89+
setTimeout(function() {
90+
assert.isTrue(Polymer.onerror.calledOnce);
91+
done();
92+
});
93+
});
94+
95+
});
96+
97+
</script>
98+
</body>
99+
</html>

0 commit comments

Comments
 (0)