test('a handler that throws does not take the page with it', () => {
reported.length = 0;
const [count, setCount] = signal(0);
const shown = el('span', {}, [text(count)]);
const bad = el('button', {}, []);
const good = el('button', {}, []);
on(bad, 'click', () => {
throw new Error('the handler failed');
});
on(good, 'click', () => setCount(count() + 1));
bad.fire('click');
assert.equal(reported.length, 1, 'the failure was reported once');
assert.equal(String(reported[0].message), 'the handler failed', 'the original error');
good.fire('click');
assert.equal(html(shown), '<span>1</span>', 'the rest of the page still works');
assert.equal(reported.length, 1, 'a working handler reports nothing');
});
test('the writes a handler made before it threw stand', () => {
reported.length = 0;
const [name, setName] = signal('before');
const shown = el('span', {}, [text(name)]);
const node = el('button', {}, []);
on(node, 'click', () => {
setName('after');
throw new Error('half way');
});
node.fire('click');
assert.equal(reported.length, 1, 'reported');
assert.equal(html(shown), '<span>after</span>', 'the write before the throw stands');
});
test('a binding that throws during a handler is contained the same way', () => {
reported.length = 0;
const [n, setN] = signal(0);
const [other, setOther] = signal('a');
const survivor = el('span', {}, [text(other)]);
effect(() => {
if (n() > 0) throw new Error('a binding failed');
});
const node = el('button', {}, []);
on(node, 'click', () => {
setN(1);
setOther('b');
});
node.fire('click');
assert.equal(reported.length, 1, 'the binding failure was reported');
assert.equal(html(survivor), '<span>b</span>', 'the other binding in the same batch ran');
});
test('a handler attached through el is contained too', () => {
reported.length = 0;
const node = el('button', {
onclick: () => {
throw new Error('through el');
},
}, []);
node.fire('click');
assert.equal(reported.length, 1, 'el must not have its own listener');
assert.equal(String(reported[0].message), 'through el');
});