dynamic events: validate handler before executing (#4105)

pull/4164/head
David Kondrad 5 years ago committed by Conduitry
parent b59673155c
commit 8a596936d2

@ -30,7 +30,7 @@ export default class EventHandlerWrapper {
if (this.node.reassigned) {
block.maintain_context = true;
return x`function () { ${snippet}.apply(this, arguments); }`;
return x`function () { if (@is_function(${snippet})) ${snippet}.apply(this, arguments); }`;
}
return snippet;
}

@ -6,6 +6,7 @@ import {
element,
init,
insert,
is_function,
listen,
noop,
run_all,
@ -46,7 +47,7 @@ function create_fragment(ctx) {
listen(button0, "click", /*updateHandler1*/ ctx[2]),
listen(button1, "click", /*updateHandler2*/ ctx[3]),
listen(button2, "click", function () {
/*clickHandler*/ ctx[0].apply(this, arguments);
if (is_function(/*clickHandler*/ ctx[0])) /*clickHandler*/ ctx[0].apply(this, arguments);
})
];
},

@ -0,0 +1,56 @@
export default {
html: `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>0</p>
<button>click</button>
`,
async test({ assert, component, target, window }) {
const [updateButton1, updateButton2, button] = target.querySelectorAll(
'button'
);
const event = new window.MouseEvent('click');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
await button.dispatchEvent(event);
assert.equal(err, "", err);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>0</p>
<button>click</button>
`);
await updateButton1.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>1</p>
<button>click</button>
`);
await updateButton2.dispatchEvent(event);
await button.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>
<button>set handler 2</button>
</p>
<p>2</p>
<button>click</button>
`);
},
};

@ -0,0 +1,23 @@
<script>
let clickHandler = {};
let number = 0;
function updateHandler1(){
clickHandler.f = () => number = 1;
}
function updateHandler2(){
clickHandler.f = () => number = 2;
}
</script>
<p>
<button on:click={updateHandler1}>set handler 1</button>
<button on:click={updateHandler2}>set handler 2</button>
</p>
<p>{ number }</p>
<button on:click={clickHandler.f}>click</button>

@ -0,0 +1,28 @@
export default {
html: `<button>undef</button>
<button>null</button>
<button>invalid</button>`,
async test({ assert, component, target, window }) {
const [buttonUndef, buttonNull, buttonInvalid] = target.querySelectorAll(
'button'
);
const event = new window.MouseEvent('click');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
// All three should not throw if proper checking is done in runtime code
await buttonUndef.dispatchEvent(event);
assert.equal(err, "", err);
await buttonNull.dispatchEvent(event);
assert.equal(err, "", err);
await buttonInvalid.dispatchEvent(event);
assert.equal(err, "", err);
},
};

@ -0,0 +1,13 @@
<script>
let handlerUndef;
let handlerNull;
let handlerInvalid;
handlerUndef = undefined;
handlerNull = null;
handlerInvalid = 42;
</script>
<button on:click={handlerUndef}>undef</button>
<button on:click={handlerNull}>null</button>
<button on:click={handlerInvalid}>invalid</button>

@ -0,0 +1,16 @@
export default {
html: `
<button>0</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.equal(component.count, 1);
await button.dispatchEvent(event);
assert.equal(component.count, 1);
}
};

@ -0,0 +1,7 @@
<script>
let f;
export let count = 0;
f = () => count += 1;
</script>
<button on:click|once="{f}">{count}</button>

@ -0,0 +1,16 @@
export default {
html: `
<button>click me</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click', {
cancelable: true
});
await button.dispatchEvent(event);
assert.ok(component.default_was_prevented);
}
};

@ -0,0 +1,11 @@
<script>
export let default_was_prevented;
let f;
function handle_click(event) {
default_was_prevented = event.defaultPrevented;
}
f = handle_click;
</script>
<button on:click|preventDefault={f}>click me</button>

@ -0,0 +1,16 @@
export default {
html: `
<div>
<button>click me</button>
</div>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.ok(!component.inner_clicked);
},
};

@ -0,0 +1,13 @@
<script>
export let inner_clicked;
let f;
function handle_click(event) {
inner_clicked = true;
}
f = handle_click;
</script>
<div on:click|self={f}>
<button>click me</button>
</div>

@ -0,0 +1,19 @@
export default {
html: `
<div>
<button>click me</button>
</div>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click', {
bubbles: true
});
await button.dispatchEvent(event);
assert.ok(component.inner_clicked);
assert.ok(!component.outer_clicked);
}
};

@ -0,0 +1,20 @@
<script>
export let inner_clicked;
export let outer_clicked;
let f1;
let f2;
function handle_inner_click(event) {
inner_clicked = true;
}
function handle_outer_click(event) {
outer_clicked = true;
}
f1 = handle_inner_click;
f2 = handle_outer_click;
</script>
<div on:click={f2}>
<button on:click|stopPropagation={f1}>click me</button>
</div>

@ -0,0 +1,14 @@
export default {
html: `
<button>click me</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
await button.dispatchEvent(event);
assert.equal(component.clickHandlerOne, 1);
assert.equal(component.clickHandlerTwo, 1);
}
};

@ -0,0 +1,11 @@
<script>
export let clickHandlerOne = 0;
export let clickHandlerTwo = 0;
let f1;
let f2;
f1 = () => clickHandlerOne++;
f2 = () => clickHandlerTwo++;
</script>
<button on:click='{f1}' on:click='{f2}'>click me</button>

@ -14,8 +14,14 @@ export default {
);
const event = new window.MouseEvent('click');
let err = "";
window.addEventListener('error', (e) => {
e.preventDefault();
err = e.message;
});
await button.dispatchEvent(event);
assert.equal(err, "", err);
assert.htmlEqual(target.innerHTML, `
<p>
<button>set handler 1</button>

Loading…
Cancel
Save