diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index cad7e221700d..fef08b88ef27 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -316,7 +316,12 @@ export default class Block { properties.update = x`function #update(${ctx}, ${dirty}) { ${this.maintain_context && b`#ctx = ${ctx};`} - ${this.chunks.update} + + try { + ${this.chunks.update} + } catch (e) { + @handle_error(@get_current_component(), e); + } }`; } } @@ -370,6 +375,36 @@ export default class Block { } } + if (properties.create.type === 'FunctionExpression') { + properties.create.body.body = b` + try { + ${properties.create.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + + if (properties.mount.type === 'FunctionExpression') { + properties.mount.body.body = b` + try { + ${properties.mount.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + + if (properties.hydrate?.type === 'FunctionExpression') { + properties.hydrate.body.body = b` + try { + ${properties.hydrate.body.body} + } catch (e) { + @handle_error(@get_current_component(), e); + } + `; + } + const return_value: any = x`{ key: ${properties.key}, first: ${properties.first}, @@ -388,16 +423,55 @@ export default class Block { const block = dev && this.get_unique_name('block'); + const init_declarations = []; + const init_statements = []; + const init_functions = []; + + Array.from(this.variables.values()).forEach(({ id, init }) => { + init_declarations.push(b`let ${id};`); + + if (init) { + init_statements.push(b`${id} = ${init}`); + } + }); + + this.chunks.init.forEach(node => { + if (Array.isArray(node)) { + node.forEach((declaration: any) => { // TODO add type to this + if (declaration.type === 'FunctionDeclaration') { + init_declarations.push(b`let ${declaration.id};`); + init_functions.push(b`${declaration.id} = ${declaration}`); + } else if (declaration.type === 'VariableDeclaration') { + declaration.declarations.forEach(({ id, init }) => { + init_declarations.push(b`let ${id}`); // TODO declaration is not always `let` + init_statements.push(b`${id} = ${init}`); + }); + } else { + init_statements.push(declaration); + } + }); + } else { + init_statements.push(node); + } + }); + const body = b` ${this.chunks.declarations} - ${Array.from(this.variables.values()).map(({ id, init }) => { - return init - ? b`let ${id} = ${init}` - : b`let ${id}`; - })} + ${init_declarations} + + ${init_statements.length > 0 || init_functions.length > 0 + ? b` + try { + ${init_functions} - ${this.chunks.init} + ${init_statements} + } catch (e) { + @handle_error(@get_current_component(), e); + return; + }` + : '' + } ${dev ? b` @@ -452,7 +526,6 @@ export default class Block { render_listeners(chunk: string = '') { if (this.event_listeners.length > 0) { this.add_variable({ type: 'Identifier', name: '#mounted' }); - this.chunks.destroy.push(b`#mounted = false`); const dispose: Identifier = { type: 'Identifier', @@ -472,7 +545,11 @@ export default class Block { ); this.chunks.destroy.push( - b`${dispose}();` + b` + if (#mounted) { + ${dispose}(); + } + ` ); } else { this.chunks.mount.push(b` @@ -488,6 +565,8 @@ export default class Block { b`@run_all(${dispose});` ); } + + this.chunks.destroy.push(b`#mounted = false`); } } } diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index f74f4cdf1ccb..211390233d72 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -442,57 +442,108 @@ export default function dom( `; } - const return_value = { - type: 'ArrayExpression', - elements: renderer.initial_context.map(member => ({ - type: 'Identifier', - name: member.name - }) as Expression) - }; + const return_value_reference = b`let #return_values = []`; + + let instance_javascript_with_ctx = []; + const initializedIdentifiers = []; + + const add_variable_to_ctx = id => { + const index = renderer.initial_context.findIndex(member => member.name === id.name); + + if (index >= 0) { + instance_javascript_with_ctx.push(b`#return_values[${index}] = ${id};`[0]); + initializedIdentifiers.push(id.name); + } + }; + + const slot_definitions_present = component.slots.size || component.compile_options.dev || uses_slots; + + if (slot_definitions_present) { + add_variable_to_ctx({ type: 'Identifier', name: '#slots' }); + add_variable_to_ctx({ type: 'Identifier', name: '$$scope' }); + } + + if (instance_javascript === null) { + instance_javascript_with_ctx = instance_javascript; + } else { + instance_javascript.forEach(node => { + instance_javascript_with_ctx.push(node); + + if (Array.isArray(node) && node[0].type === 'VariableDeclaration') { + node[0].declarations.forEach(({ id }) => { + if (id.type === 'ObjectPattern') { + id.properties.forEach(property => add_variable_to_ctx(property.key)); + } else { + add_variable_to_ctx(id); + } + }); + } + + if (node.type === 'FunctionDeclaration') { + if (!initializedIdentifiers.includes(node.id.name)) { + add_variable_to_ctx(node.id); + } + } + }); + } + + + const instance_try_block: any = b` + try { + ${reactive_store_declarations} - body.push(b` - function ${definition}(${args}) { - ${injected.map(name => b`let ${name};`)} + ${reactive_store_subscriptions} - ${rest} + ${resubscribable_reactive_store_unsubscribers} - ${reactive_store_declarations} + ${instance_javascript_with_ctx} - ${reactive_store_subscriptions} + ${unknown_props_check} - ${resubscribable_reactive_store_unsubscribers} + ${renderer.binding_groups.size > 0 && b`const $$binding_groups = [${[...renderer.binding_groups.keys()].map(_ => x`[]`)}];`} - ${component.slots.size || component.compile_options.dev || uses_slots ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null} - ${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`} - ${compute_slots} + ${component.partly_hoisted} - ${instance_javascript} + ${set && b`$$self.$$set = ${set};`} - ${unknown_props_check} + ${capture_state && b`$$self.$capture_state = ${capture_state};`} - ${renderer.binding_groups.size > 0 && b`const $$binding_groups = [${[...renderer.binding_groups.keys()].map(_ => x`[]`)}];`} + ${inject_state && b`$$self.$inject_state = ${inject_state};`} - ${component.partly_hoisted} + ${/* before reactive declarations */ props_inject} - ${set && b`$$self.$$set = ${set};`} + ${reactive_declarations.length > 0 && b` + $$self.$$.update = () => { + ${reactive_declarations} + }; + `} - ${capture_state && b`$$self.$capture_state = ${capture_state};`} + ${fixed_reactive_declarations} - ${inject_state && b`$$self.$inject_state = ${inject_state};`} + ${uses_props && b`$$props = @exclude_internal_props($$props);`} - ${/* before reactive declarations */ props_inject} + return #return_values; + } + catch(e) { + $$self.$$.ctx = #return_values; + @handle_error($$self, e); + return #return_values; + } + `; - ${reactive_declarations.length > 0 && b` - $$self.$$.update = () => { - ${reactive_declarations} - }; - `} + body.push(b` + function ${definition}(${args}) { + ${injected.map(name => b`let ${name};`)} - ${fixed_reactive_declarations} + ${rest} + + ${slot_definitions_present ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null} + ${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`} + ${compute_slots} - ${uses_props && b`$$props = @exclude_internal_props($$props);`} + ${return_value_reference} - return ${return_value}; + ${instance_try_block} } `); } diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index fc65a9aa5e96..eec574478b8b 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -67,7 +67,7 @@ export default class EventHandlerWrapper { } block.event_listeners.push( - x`@listen(${target}, "${this.node.name}", ${snippet}, ${args})` + x`@listen(${target}, "${this.node.name}", @attach_error_handler(${target}, @get_current_component(), ${snippet}), ${args})` ); } } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index db26b6673c2c..300695efdc40 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -541,7 +541,7 @@ export default class ElementWrapper extends Wrapper { ); } else { block.event_listeners.push( - x`@listen(${this.var}, "${name}", ${callee})` + x`@listen(${this.var}, "${name}", @attach_error_handler(${this.var}, @get_current_component(), ${callee}))` ); } }); diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index e6eab33fbdee..4037e4f4b8b8 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -192,6 +192,10 @@ export default class InlineComponentWrapper extends Wrapper { component_opts.properties.push(p`$$inline: true`); } + if (block.type === 'slot') { + component_opts.properties.push(p`$$in_slot: true`); + } + const fragment_dependencies = new Set(this.slots.size ? ['$$scope'] : []); this.slots.forEach(slot => { slot.block.dependencies.forEach(name => { diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts index b57820beb3ed..a0d71c3bc14a 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_actions.ts @@ -40,7 +40,7 @@ export function add_action(block: Block, target: string, action: Action) { ); } else { block.event_listeners.push( - x`@action_destroyer(${id} = ${fn}.call(null, ${target}, ${snippet}))` + x`@action_destroyer(${id} = @attach_error_handler(null, @get_current_component(), ${fn}).call(null, ${target}, ${snippet}))` ); } diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index b35a6ce6ffee..6cfe0f061ed1 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -188,17 +188,19 @@ export default function ssr( return ${literal};`; - const blocks = [ - ...injected.map(name => b`let ${name};`), - rest, - slots, - ...reactive_store_declarations, - ...reactive_store_subscriptions, - instance_javascript, - ...parent_bindings, - css.code && b`$$result.css.add(#css);`, - main - ].filter(Boolean); + const blocks = [ + ...injected.map(name => b`let ${name};`), + rest, + slots, + ...reactive_store_declarations, + ...reactive_store_subscriptions, + instance_javascript, + ...parent_bindings, + css.code && b`$$result.css.add(#css);`, + main + ].filter(Boolean); + + const js = b` ${css.code ? b` @@ -212,7 +214,11 @@ export default function ssr( ${component.fully_hoisted} const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => { - ${blocks} + try { + ${blocks} + } catch (e) { + @handle_error(@get_current_component(), e); + } }); `; diff --git a/src/runtime/index.ts b/src/runtime/index.ts index 8e12f9f0eebb..054abe208a94 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -3,6 +3,7 @@ import './ambient'; export { onMount, onDestroy, + onError, beforeUpdate, afterUpdate, setContext, diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index e706928af305..bded4cc8fdd8 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -36,9 +36,11 @@ interface T$$ { context: Map; on_mount: any[]; on_destroy: any[]; + on_error: any[]; skip_bound: boolean; on_disconnect: any[]; - root:Element|ShadowRoot + root:Element|ShadowRoot; + parent_component: T$$; } export function bind(component, name, callback) { @@ -104,6 +106,41 @@ function make_dirty(component, i) { component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31)); } +export function attach_error_handler(that: any, component, fn) { + return (...rest) => { + try { + return fn.call(that, ...rest); + } catch (e) { + handle_error(component, e); + } + }; +} + +export function handle_error(component, e, skip = false) { + if (component.$$.on_error.length === 0 || skip) { + bubble_error(component, e); + } + + if (!skip && !e.unhandled) { + component.$$.on_error.forEach(handler => { + try { + handler(e); + } catch (e) { + bubble_error(component, e); + } + }); + } +} + +function bubble_error(component, e) { + if (component.$$.parent_component) { + handle_error(component.$$.parent_component, e, component.$$.in_slot); + } else { + e.unhandled = true; // TODO this is very gross + throw e; + } +} + export function init(component, options, instance, create_fragment, not_equal, props, append_styles, dirty = [-1]) { const parent_component = current_component; set_current_component(component); @@ -122,6 +159,7 @@ export function init(component, options, instance, create_fragment, not_equal, p on_mount: [], on_destroy: [], on_disconnect: [], + on_error: [], before_update: [], after_update: [], context: new Map(parent_component ? parent_component.$$.context : options.context || []), @@ -130,7 +168,9 @@ export function init(component, options, instance, create_fragment, not_equal, p callbacks: blank_object(), dirty, skip_bound: false, - root: options.target || parent_component.$$.root + root: options.target || parent_component.$$.root, + in_slot: options.$$in_slot || false, + parent_component }; append_styles && append_styles($$.root); diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index f563f6d099da..8768435d4b24 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -203,7 +203,9 @@ export function insert_hydration(target: NodeEx, node: NodeEx, anchor?: NodeEx) } export function detach(node: Node) { - node.parentNode.removeChild(node); + if (node.parentNode !== null) { + node.parentNode.removeChild(node); + } } export function destroy_each(iterations, detaching) { diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index bb3df3d29526..e69249faa785 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -27,6 +27,10 @@ export function onDestroy(fn: () => any) { get_current_component().$$.on_destroy.push(fn); } +export function onError(fn: () => any) { + get_current_component().$$.on_error.push(fn); +} + export function createEventDispatcher< EventMap extends {} = any >(): >(type: EventKey, detail?: EventMap[EventKey]) => void { diff --git a/src/runtime/internal/ssr.ts b/src/runtime/internal/ssr.ts index c64d88fa7553..f7d3616d024a 100644 --- a/src/runtime/internal/ssr.ts +++ b/src/runtime/internal/ssr.ts @@ -97,6 +97,8 @@ export function create_ssr_component(fn) { on_mount: [], before_update: [], after_update: [], + on_error: [], + parent_component, callbacks: blank_object() }; diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 8868e38ee29f..9e8b2057ca03 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -1,4 +1,6 @@ import { Readable } from 'svelte/store'; +import { attach_error_handler } from './Component'; +import { get_current_component } from './lifecycle'; export function noop() {} @@ -185,5 +187,5 @@ export function set_store_value(store, ret, value) { export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); export function action_destroyer(action_result) { - return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; + return action_result && is_function(action_result.destroy) ? attach_error_handler(action_result, get_current_component(), action_result.destroy) : noop; } diff --git a/test/runtime/samples/error-handling-action-destroy/_config.js b/test/runtime/samples/error-handling-action-destroy/_config.js new file mode 100644 index 000000000000..c43b64736de4 --- /dev/null +++ b/test/runtime/samples/error-handling-action-destroy/_config.js @@ -0,0 +1,9 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, false); + + component.visible = false; + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-action-destroy/main.svelte b/test/runtime/samples/error-handling-action-destroy/main.svelte new file mode 100644 index 000000000000..f9496ca8a232 --- /dev/null +++ b/test/runtime/samples/error-handling-action-destroy/main.svelte @@ -0,0 +1,22 @@ + + +{#if visible} +
+{/if} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-action-with-arguments/_config.js b/test/runtime/samples/error-handling-action-with-arguments/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-action-with-arguments/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-action-with-arguments/main.svelte b/test/runtime/samples/error-handling-action-with-arguments/main.svelte new file mode 100644 index 000000000000..f15ebcbac6c9 --- /dev/null +++ b/test/runtime/samples/error-handling-action-with-arguments/main.svelte @@ -0,0 +1,15 @@ + + +
\ No newline at end of file diff --git a/test/runtime/samples/error-handling-action/_config.js b/test/runtime/samples/error-handling-action/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-action/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-action/main.svelte b/test/runtime/samples/error-handling-action/main.svelte new file mode 100644 index 000000000000..14bdae809f80 --- /dev/null +++ b/test/runtime/samples/error-handling-action/main.svelte @@ -0,0 +1,15 @@ + + +
\ No newline at end of file diff --git a/test/runtime/samples/error-handling-anonymous-event/_config.js b/test/runtime/samples/error-handling-anonymous-event/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-anonymous-event/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-anonymous-event/main.svelte b/test/runtime/samples/error-handling-anonymous-event/main.svelte new file mode 100644 index 000000000000..f8b206e5bbca --- /dev/null +++ b/test/runtime/samples/error-handling-anonymous-event/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-attribute/_config.js b/test/runtime/samples/error-handling-attribute/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-attribute/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-attribute/main.svelte b/test/runtime/samples/error-handling-attribute/main.svelte new file mode 100644 index 000000000000..ad5e33248217 --- /dev/null +++ b/test/runtime/samples/error-handling-attribute/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-binding-reactive/_config.js b/test/runtime/samples/error-handling-binding-reactive/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-binding-reactive/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-binding-reactive/main.svelte b/test/runtime/samples/error-handling-binding-reactive/main.svelte new file mode 100644 index 000000000000..59881d269982 --- /dev/null +++ b/test/runtime/samples/error-handling-binding-reactive/main.svelte @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-binding/_config.js b/test/runtime/samples/error-handling-binding/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-binding/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-binding/main.svelte b/test/runtime/samples/error-handling-binding/main.svelte new file mode 100644 index 000000000000..917b1b462574 --- /dev/null +++ b/test/runtime/samples/error-handling-binding/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-bubble-to-parent/_config.js b/test/runtime/samples/error-handling-bubble-to-parent/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-bubble-to-parent/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-bubble-to-parent/child.svelte b/test/runtime/samples/error-handling-bubble-to-parent/child.svelte new file mode 100644 index 000000000000..19c327680a37 --- /dev/null +++ b/test/runtime/samples/error-handling-bubble-to-parent/child.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-bubble-to-parent/main.svelte b/test/runtime/samples/error-handling-bubble-to-parent/main.svelte new file mode 100644 index 000000000000..8a7621bd24c8 --- /dev/null +++ b/test/runtime/samples/error-handling-bubble-to-parent/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-catch-before-error/_config.js b/test/runtime/samples/error-handling-catch-before-error/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-catch-before-error/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-catch-before-error/main.svelte b/test/runtime/samples/error-handling-catch-before-error/main.svelte new file mode 100644 index 000000000000..f00560400380 --- /dev/null +++ b/test/runtime/samples/error-handling-catch-before-error/main.svelte @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-dynamic-component/_config.js b/test/runtime/samples/error-handling-dynamic-component/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-dynamic-component/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-dynamic-component/child.svelte b/test/runtime/samples/error-handling-dynamic-component/child.svelte new file mode 100644 index 000000000000..19c327680a37 --- /dev/null +++ b/test/runtime/samples/error-handling-dynamic-component/child.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-dynamic-component/main.svelte b/test/runtime/samples/error-handling-dynamic-component/main.svelte new file mode 100644 index 000000000000..5395fbb0d384 --- /dev/null +++ b/test/runtime/samples/error-handling-dynamic-component/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-each-block-non-array/_config.js b/test/runtime/samples/error-handling-each-block-non-array/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-each-block-non-array/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-each-block-non-array/main.svelte b/test/runtime/samples/error-handling-each-block-non-array/main.svelte new file mode 100644 index 000000000000..0a39d8a0b735 --- /dev/null +++ b/test/runtime/samples/error-handling-each-block-non-array/main.svelte @@ -0,0 +1,14 @@ + + +{#each a.b.c as item} + {item} +{/each} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-each-block-reactive-non-array/_config.js b/test/runtime/samples/error-handling-each-block-reactive-non-array/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-each-block-reactive-non-array/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-each-block-reactive-non-array/main.svelte b/test/runtime/samples/error-handling-each-block-reactive-non-array/main.svelte new file mode 100644 index 000000000000..b4fb0abca4bf --- /dev/null +++ b/test/runtime/samples/error-handling-each-block-reactive-non-array/main.svelte @@ -0,0 +1,20 @@ + + +{#each a as item} + {item} +{/each} + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-each-block/_config.js b/test/runtime/samples/error-handling-each-block/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-each-block/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-each-block/main.svelte b/test/runtime/samples/error-handling-each-block/main.svelte new file mode 100644 index 000000000000..0a39d8a0b735 --- /dev/null +++ b/test/runtime/samples/error-handling-each-block/main.svelte @@ -0,0 +1,14 @@ + + +{#each a.b.c as item} + {item} +{/each} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-event-correct-this/_config.js b/test/runtime/samples/error-handling-event-correct-this/_config.js new file mode 100644 index 000000000000..3a1e25bd22ef --- /dev/null +++ b/test/runtime/samples/error-handling-event-correct-this/_config.js @@ -0,0 +1,11 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + assert.equal(component.that, button); + } +}; diff --git a/test/runtime/samples/error-handling-event-correct-this/main.svelte b/test/runtime/samples/error-handling-event-correct-this/main.svelte new file mode 100644 index 000000000000..a8760ae348e3 --- /dev/null +++ b/test/runtime/samples/error-handling-event-correct-this/main.svelte @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-event/_config.js b/test/runtime/samples/error-handling-event/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-event/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-event/main.svelte b/test/runtime/samples/error-handling-event/main.svelte new file mode 100644 index 000000000000..18f89a2b2c68 --- /dev/null +++ b/test/runtime/samples/error-handling-event/main.svelte @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-if-block-reactive/_config.js b/test/runtime/samples/error-handling-if-block-reactive/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-if-block-reactive/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-if-block-reactive/main.svelte b/test/runtime/samples/error-handling-if-block-reactive/main.svelte new file mode 100644 index 000000000000..e3752f2d5eab --- /dev/null +++ b/test/runtime/samples/error-handling-if-block-reactive/main.svelte @@ -0,0 +1,24 @@ + + + + +{#if a.b.c === true} + Hello world +{/if} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-if-block-show-component/_config.js b/test/runtime/samples/error-handling-if-block-show-component/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-if-block-show-component/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-if-block-show-component/child.svelte b/test/runtime/samples/error-handling-if-block-show-component/child.svelte new file mode 100644 index 000000000000..19c327680a37 --- /dev/null +++ b/test/runtime/samples/error-handling-if-block-show-component/child.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-if-block-show-component/main.svelte b/test/runtime/samples/error-handling-if-block-show-component/main.svelte new file mode 100644 index 000000000000..dbfb508df34e --- /dev/null +++ b/test/runtime/samples/error-handling-if-block-show-component/main.svelte @@ -0,0 +1,21 @@ + + + + +{#if show} + +{/if} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-if-block/_config.js b/test/runtime/samples/error-handling-if-block/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-if-block/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-if-block/main.svelte b/test/runtime/samples/error-handling-if-block/main.svelte new file mode 100644 index 000000000000..e7f50afaf693 --- /dev/null +++ b/test/runtime/samples/error-handling-if-block/main.svelte @@ -0,0 +1,14 @@ + + +{#if a.b.c === true} + Hello world +{/if} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-keyed-each-block-reactive/_config.js b/test/runtime/samples/error-handling-keyed-each-block-reactive/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-keyed-each-block-reactive/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-keyed-each-block-reactive/main.svelte b/test/runtime/samples/error-handling-keyed-each-block-reactive/main.svelte new file mode 100644 index 000000000000..567c8273bd24 --- /dev/null +++ b/test/runtime/samples/error-handling-keyed-each-block-reactive/main.svelte @@ -0,0 +1,25 @@ + + + + +{#each a as item (item.a.b)} + {item} +{/each} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-keyed-each-block/_config.js b/test/runtime/samples/error-handling-keyed-each-block/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-keyed-each-block/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-keyed-each-block/main.svelte b/test/runtime/samples/error-handling-keyed-each-block/main.svelte new file mode 100644 index 000000000000..98c79c454bdb --- /dev/null +++ b/test/runtime/samples/error-handling-keyed-each-block/main.svelte @@ -0,0 +1,14 @@ + + +{#each a as item (item.a.b)} + {item} +{/each} \ No newline at end of file diff --git a/test/runtime/samples/error-handling-manually-bubble-to-parent/_config.js b/test/runtime/samples/error-handling-manually-bubble-to-parent/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-manually-bubble-to-parent/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-manually-bubble-to-parent/child.svelte b/test/runtime/samples/error-handling-manually-bubble-to-parent/child.svelte new file mode 100644 index 000000000000..36cedc81a479 --- /dev/null +++ b/test/runtime/samples/error-handling-manually-bubble-to-parent/child.svelte @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-manually-bubble-to-parent/main.svelte b/test/runtime/samples/error-handling-manually-bubble-to-parent/main.svelte new file mode 100644 index 000000000000..8a7621bd24c8 --- /dev/null +++ b/test/runtime/samples/error-handling-manually-bubble-to-parent/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-slotted-component/_config.js b/test/runtime/samples/error-handling-slotted-component/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-slotted-component/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-slotted-component/child.svelte b/test/runtime/samples/error-handling-slotted-component/child.svelte new file mode 100644 index 000000000000..19c327680a37 --- /dev/null +++ b/test/runtime/samples/error-handling-slotted-component/child.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-slotted-component/main.svelte b/test/runtime/samples/error-handling-slotted-component/main.svelte new file mode 100644 index 000000000000..6ad0d0ee88ea --- /dev/null +++ b/test/runtime/samples/error-handling-slotted-component/main.svelte @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-slotted-component/wrapper.svelte b/test/runtime/samples/error-handling-slotted-component/wrapper.svelte new file mode 100644 index 000000000000..8c813a7b0e30 --- /dev/null +++ b/test/runtime/samples/error-handling-slotted-component/wrapper.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-template-reactive/_config.js b/test/runtime/samples/error-handling-template-reactive/_config.js new file mode 100644 index 000000000000..773299e41517 --- /dev/null +++ b/test/runtime/samples/error-handling-template-reactive/_config.js @@ -0,0 +1,10 @@ +export default { + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-template-reactive/main.svelte b/test/runtime/samples/error-handling-template-reactive/main.svelte new file mode 100644 index 000000000000..425d59046a3f --- /dev/null +++ b/test/runtime/samples/error-handling-template-reactive/main.svelte @@ -0,0 +1,22 @@ + + +{a.b.c} + + \ No newline at end of file diff --git a/test/runtime/samples/error-handling-template/_config.js b/test/runtime/samples/error-handling-template/_config.js new file mode 100644 index 000000000000..fab5d76ee60e --- /dev/null +++ b/test/runtime/samples/error-handling-template/_config.js @@ -0,0 +1,5 @@ +export default { + test({ assert, component }) { + assert.equal(component.error, true); + } +}; diff --git a/test/runtime/samples/error-handling-template/main.svelte b/test/runtime/samples/error-handling-template/main.svelte new file mode 100644 index 000000000000..461211a87d26 --- /dev/null +++ b/test/runtime/samples/error-handling-template/main.svelte @@ -0,0 +1,12 @@ + + +{a.b.c} \ No newline at end of file