mirror of https://github.com/sveltejs/svelte
commit
15fa8ad0cc
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let selection = '';
|
||||
|
||||
const handleSelectionChange = (e) => selection = document.getSelection();
|
||||
</script>
|
||||
|
||||
<svelte:document on:selectionchange={handleSelectionChange} />
|
||||
|
||||
<p>Select this text to fire events</p>
|
||||
<p>Selection: {selection}</p>
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"title": "<svelte:document>"
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
---
|
||||
title: <svelte:body>
|
||||
---
|
||||
|
||||
Similar to `<svelte:window>`, the `<svelte:body>` element allows you to listen for events that fire on `document.body`. This is useful with the `mouseenter` and `mouseleave` events, which don't fire on `window`.
|
||||
|
||||
Add the `mouseenter` and `mouseleave` handlers to the `<svelte:body>` tag:
|
||||
|
||||
```html
|
||||
<svelte:body
|
||||
on:mouseenter={handleMouseenter}
|
||||
on:mouseleave={handleMouseleave}
|
||||
/>
|
||||
```
|
||||
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let selection = '';
|
||||
|
||||
const handleSelectionChange = (e) => selection = document.getSelection();
|
||||
</script>
|
||||
|
||||
<svelte:body />
|
||||
|
||||
<p>Select this text to fire events</p>
|
||||
<p>Selection: {selection}</p>
|
||||
@ -0,0 +1,10 @@
|
||||
<script>
|
||||
let selection = '';
|
||||
|
||||
const handleSelectionChange = (e) => selection = document.getSelection();
|
||||
</script>
|
||||
|
||||
<svelte:document on:selectionchange={handleSelectionChange} />
|
||||
|
||||
<p>Select this text to fire events</p>
|
||||
<p>Selection: {selection}</p>
|
||||
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: <svelte:document>
|
||||
---
|
||||
|
||||
Similar to `<svelte:window>`, the `<svelte:document>` element allows you to listen for events that fire on `document`. This is useful with events like `selectionchange`, which doesn't fire on `window`.
|
||||
|
||||
Add the `selectionchange` handler to the `<svelte:document>` tag:
|
||||
|
||||
```html
|
||||
<svelte:document on:selectionchange={handleSelectionChange} />
|
||||
```
|
||||
|
||||
> Avoid `mouseenter` and `mouseleave` handlers on this element, these events are not fired on `document` in all browsers. Use `<svelte:body>` for this instead.
|
||||
@ -0,0 +1,14 @@
|
||||
---
|
||||
title: <svelte:body>
|
||||
---
|
||||
|
||||
Similar to `<svelte:window>` and `<svelte:document>`, the `<svelte:body>` element allows you to listen for events that fire on `document.body`. This is useful with the `mouseenter` and `mouseleave` events, which don't fire on `window`.
|
||||
|
||||
Add the `mouseenter` and `mouseleave` handlers to the `<svelte:body>` tag:
|
||||
|
||||
```html
|
||||
<svelte:body
|
||||
on:mouseenter={handleMouseenter}
|
||||
on:mouseleave={handleMouseleave}
|
||||
/>
|
||||
```
|
||||
@ -0,0 +1,41 @@
|
||||
import Node from './shared/Node';
|
||||
import EventHandler from './EventHandler';
|
||||
import Action from './Action';
|
||||
import Component from '../Component';
|
||||
import TemplateScope from './shared/TemplateScope';
|
||||
import { Element } from '../../interfaces';
|
||||
import compiler_warnings from '../compiler_warnings';
|
||||
|
||||
export default class Document extends Node {
|
||||
type: 'Document';
|
||||
handlers: EventHandler[] = [];
|
||||
actions: Action[] = [];
|
||||
|
||||
constructor(component: Component, parent: Node, scope: TemplateScope, info: Element) {
|
||||
super(component, parent, scope, info);
|
||||
|
||||
info.attributes.forEach((node) => {
|
||||
if (node.type === 'EventHandler') {
|
||||
this.handlers.push(new EventHandler(component, this, scope, node));
|
||||
} else if (node.type === 'Action') {
|
||||
this.actions.push(new Action(component, this, scope, node));
|
||||
} else {
|
||||
// TODO there shouldn't be anything else here...
|
||||
}
|
||||
});
|
||||
|
||||
this.validate();
|
||||
}
|
||||
|
||||
private validate() {
|
||||
const handlers_map = new Set();
|
||||
|
||||
this.handlers.forEach(handler => (
|
||||
handlers_map.add(handler.name)
|
||||
));
|
||||
|
||||
if (handlers_map.has('mouseenter') || handlers_map.has('mouseleave')) {
|
||||
this.component.warn(this, compiler_warnings.avoid_mouse_events_on_document);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import Block from '../Block';
|
||||
import Wrapper from './shared/Wrapper';
|
||||
import { x } from 'code-red';
|
||||
import Document from '../../nodes/Document';
|
||||
import { Identifier } from 'estree';
|
||||
import EventHandler from './Element/EventHandler';
|
||||
import add_event_handlers from './shared/add_event_handlers';
|
||||
import { TemplateNode } from '../../../interfaces';
|
||||
import Renderer from '../Renderer';
|
||||
import add_actions from './shared/add_actions';
|
||||
|
||||
export default class DocumentWrapper extends Wrapper {
|
||||
node: Document;
|
||||
handlers: EventHandler[];
|
||||
|
||||
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: TemplateNode) {
|
||||
super(renderer, block, parent, node);
|
||||
this.handlers = this.node.handlers.map(handler => new EventHandler(handler, this));
|
||||
}
|
||||
|
||||
render(block: Block, _parent_node: Identifier, _parent_nodes: Identifier) {
|
||||
add_event_handlers(block, x`@_document`, this.handlers);
|
||||
add_actions(block, x`@_document`, this.node.actions);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
// Utilities for managing contenteditable nodes
|
||||
import Attribute from '../nodes/Attribute';
|
||||
import Element from '../nodes/Element';
|
||||
|
||||
export const CONTENTEDITABLE_BINDINGS = [
|
||||
'textContent',
|
||||
'innerHTML',
|
||||
'innerText'
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns true if node is an 'input' or 'textarea'.
|
||||
* @param {Element} node The element to be checked
|
||||
*/
|
||||
function is_input_or_textarea(node: Element): boolean {
|
||||
return node.name === 'textarea' || node.name === 'input';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given attribute is 'contenteditable'.
|
||||
* @param {Attribute} attribute A node.attribute
|
||||
*/
|
||||
function is_attr_contenteditable(attribute: Attribute): boolean {
|
||||
return attribute.name === 'contenteditable';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any of a node's attributes are 'contentenditable'.
|
||||
* @param {Element} node The element to be checked
|
||||
*/
|
||||
export function has_contenteditable_attr(node: Element): boolean {
|
||||
return node.attributes.some(is_attr_contenteditable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if node is not textarea or input, but has 'contenteditable' attribute.
|
||||
* @param {Element} node The element to be tested
|
||||
*/
|
||||
export function is_contenteditable(node: Element): boolean {
|
||||
return !is_input_or_textarea(node) && has_contenteditable_attr(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a given binding/node is contenteditable.
|
||||
* @param {string} name A binding or node name to be checked
|
||||
*/
|
||||
export function is_name_contenteditable(name: string): boolean {
|
||||
return CONTENTEDITABLE_BINDINGS.includes(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contenteditable attribute from the node (if it exists).
|
||||
* @param {Element} node The element to get the attribute from
|
||||
*/
|
||||
export function get_contenteditable_attr(node: Element): Attribute | undefined {
|
||||
return node.attributes.find(is_attr_contenteditable);
|
||||
}
|
||||
@ -1,60 +0,0 @@
|
||||
/* generated by Svelte vX.Y.Z */
|
||||
import {
|
||||
SvelteComponent,
|
||||
detach,
|
||||
element,
|
||||
init,
|
||||
insert,
|
||||
noop,
|
||||
safe_not_equal,
|
||||
set_data,
|
||||
space,
|
||||
text
|
||||
} from "svelte/internal";
|
||||
|
||||
function create_fragment(ctx) {
|
||||
let h1;
|
||||
let t3;
|
||||
let t4;
|
||||
|
||||
return {
|
||||
c() {
|
||||
h1 = element("h1");
|
||||
h1.textContent = `Hello ${name}!`;
|
||||
t3 = space();
|
||||
t4 = text(/*foo*/ ctx[0]);
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, h1, anchor);
|
||||
insert(target, t3, anchor);
|
||||
insert(target, t4, anchor);
|
||||
},
|
||||
p(ctx, [dirty]) {
|
||||
if (dirty & /*foo*/ 1) set_data(t4, /*foo*/ ctx[0]);
|
||||
},
|
||||
i: noop,
|
||||
o: noop,
|
||||
d(detaching) {
|
||||
if (detaching) detach(h1);
|
||||
if (detaching) detach(t3);
|
||||
if (detaching) detach(t4);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let name = 'world';
|
||||
|
||||
function instance($$self) {
|
||||
let foo;
|
||||
$: foo = name + name;
|
||||
return [foo];
|
||||
}
|
||||
|
||||
class Component extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
init(this, options, instance, create_fragment, safe_not_equal, {});
|
||||
}
|
||||
}
|
||||
|
||||
export default Component;
|
||||
@ -1,7 +0,0 @@
|
||||
<script>
|
||||
let name = 'world';
|
||||
$: foo = name + name;
|
||||
</script>
|
||||
|
||||
<h1>Hello {name}!</h1>
|
||||
{foo}
|
||||
@ -0,0 +1,24 @@
|
||||
export default {
|
||||
html: `
|
||||
<p style="font-size: 32px; color: red; background-color: green; border-color: green;"></p>
|
||||
`,
|
||||
|
||||
test({ assert, target, window, component }) {
|
||||
const p = target.querySelector('p');
|
||||
const styles = window.getComputedStyle(p);
|
||||
assert.equal(styles.color, 'rgb(255, 0, 0)');
|
||||
assert.equal(styles.fontSize, '32px');
|
||||
assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)');
|
||||
assert.equal(styles.borderColor, 'rgb(0, 128, 0)');
|
||||
|
||||
component.foo = 'font-size: 50px; color: green;'; // Update style attribute
|
||||
{
|
||||
const p = target.querySelector('p');
|
||||
const styles = window.getComputedStyle(p);
|
||||
assert.equal(styles.color, 'rgb(255, 0, 0)');
|
||||
assert.equal(styles.fontSize, '32px');
|
||||
assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)');
|
||||
assert.equal(styles.borderColor, 'rgb(0, 128, 0)');
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
export let foo = "font-size: 20px; color: blue;";
|
||||
let baz = "red"; // static value
|
||||
let bar = "32"; // static value interpolated
|
||||
export let bg = "gre"; // dynamic value interpolated/cached
|
||||
export let borderColor = "green"; // dynamic value non-cached
|
||||
</script>
|
||||
|
||||
<p
|
||||
style:font-size="{bar}px"
|
||||
style:color={baz}
|
||||
style="{foo}"
|
||||
style:background-color="{bg}en"
|
||||
style:border-color={borderColor}
|
||||
/>
|
||||
@ -0,0 +1,14 @@
|
||||
export default {
|
||||
html: '<div></div>',
|
||||
|
||||
async test({ assert, target, window }) {
|
||||
const visibility = new window.Event('visibilitychange');
|
||||
|
||||
await window.document.dispatchEvent(visibility);
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>
|
||||
<div class="tooltip">Perform an Action</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
let container;
|
||||
function tooltip(node, text) {
|
||||
let tooltip = null;
|
||||
|
||||
function onVisibilityChange() {
|
||||
tooltip = document.createElement('div');
|
||||
tooltip.classList.add('tooltip');
|
||||
tooltip.textContent = text;
|
||||
container.appendChild(tooltip);
|
||||
}
|
||||
|
||||
node.addEventListener('visibilitychange', onVisibilityChange);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
node.removeEventListener('visibilitychange', onVisibilityChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:document use:tooltip="{'Perform an Action'}" />
|
||||
<div bind:this={container} />
|
||||
@ -0,0 +1,32 @@
|
||||
export default {
|
||||
async test({ assert, component, target }) {
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>propA: 3</p>
|
||||
<p>propB: 7</p>
|
||||
<p>num: 3</p>
|
||||
<p>rest: {"prop3":{"prop9":9,"prop10":10}}</p>
|
||||
<p>propZ: 5</p>
|
||||
<p>propY: 6</p>
|
||||
<p>rest: {"propX":7,"propW":8}</p>
|
||||
`
|
||||
);
|
||||
|
||||
await (component.object = Promise.resolve({ prop1: 'one', prop2: 'two', prop3: { prop7: 'seven' }, prop4: { prop10: 'ten' }}));
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>propA: seven</p>
|
||||
<p>propB: ten</p>
|
||||
<p>num: 5</p>
|
||||
<p>rest: {"prop1":"one","prop2":"two"}</p>
|
||||
<p>propZ: 5</p>
|
||||
<p>propY: 6</p>
|
||||
<p>rest: {"propX":7,"propW":8}</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
export let object = Promise.resolve({ prop1: { prop4: 2, prop5: 3 }, prop2: { prop6: 5, prop7: 6, prop8: 7 }, prop3: { prop9: 9, prop10: 10 } });
|
||||
const objectReject = Promise.reject({ propZ: 5, propY: 6, propX: 7, propW: 8 });
|
||||
|
||||
let num = 1;
|
||||
const prop = 'prop';
|
||||
</script>
|
||||
|
||||
{#await object then { [`prop${num++}`]: { [`prop${num + 3}`]: propA }, [`prop${num++}`]: { [`prop${num + 5}`]: propB }, ...rest }}
|
||||
<p>propA: {propA}</p>
|
||||
<p>propB: {propB}</p>
|
||||
<p>num: {num}</p>
|
||||
<p>rest: {JSON.stringify(rest)}</p>
|
||||
{/await}
|
||||
|
||||
{#await objectReject then value}
|
||||
resolved
|
||||
{:catch { [`${prop}Z`]: propZ, [`${prop}Y`]: propY, ...rest }}
|
||||
<p>propZ: {propZ}</p>
|
||||
<p>propY: {propY}</p>
|
||||
<p>rest: {JSON.stringify(rest)}</p>
|
||||
{/await}
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
export default {
|
||||
props: {
|
||||
thePromise: new Promise(_ => {})
|
||||
},
|
||||
|
||||
html: `
|
||||
loading...
|
||||
`,
|
||||
|
||||
async test({ assert, component, target }) {
|
||||
await (component.thePromise = Promise.resolve([10, 11, 12, 13, 14, 15]));
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>[1] 11</p>
|
||||
<p>[3] 13</p>
|
||||
<p>[4] 14</p>
|
||||
`
|
||||
);
|
||||
|
||||
await (component.thePromise = Promise.resolve({ 1: 21, 3: 23, 4: 24 }));
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>[1] 21</p>
|
||||
<p>[3] 23</p>
|
||||
<p>[4] 24</p>
|
||||
`
|
||||
);
|
||||
|
||||
try {
|
||||
await (component.thePromise = Promise.reject([30, 31, 32, 33, 34, 35]));
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>[0] 30</p>
|
||||
<p>[2] 32</p>
|
||||
<p>[5] 35</p>
|
||||
`
|
||||
);
|
||||
|
||||
try {
|
||||
await (component.thePromise = Promise.reject({ 0: 40, 2: 42, 5: 45 }));
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>[0] 40</p>
|
||||
<p>[2] 42</p>
|
||||
<p>[5] 45</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,15 @@
|
||||
<script>
|
||||
export let thePromise;
|
||||
</script>
|
||||
|
||||
{#await thePromise}
|
||||
loading...
|
||||
{:then { 1: a, 3: b, 4: c }}
|
||||
<p>[1] {a}</p>
|
||||
<p>[3] {b}</p>
|
||||
<p>[4] {c}</p>
|
||||
{:catch { 0: d, 2: e, 5: f }}
|
||||
<p>[0] {d}</p>
|
||||
<p>[2] {e}</p>
|
||||
<p>[5] {f}</p>
|
||||
{/await}
|
||||
@ -0,0 +1,17 @@
|
||||
export default {
|
||||
async test({ assert, target }) {
|
||||
await Promise.resolve();
|
||||
|
||||
assert.htmlEqual(
|
||||
target.innerHTML,
|
||||
`
|
||||
<p>prop-1: 1</p>
|
||||
<p>prop4: 4</p>
|
||||
<p>rest: {"prop2":2,"prop-3":3}</p>
|
||||
<p>prop-7: 7</p>
|
||||
<p>prop6: 6</p>
|
||||
<p>rest: {"prop-5":5,"prop8":8}</p>
|
||||
`
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,19 @@
|
||||
<script>
|
||||
const object = Promise.resolve({ 'prop-1': 1, 'prop2': 2, 'prop-3': 3, 'prop4': 4 });
|
||||
const objectReject = Promise.reject({ 'prop-5': 5, 'prop6': 6, 'prop-7': 7, 'prop8': 8 });
|
||||
</script>
|
||||
|
||||
{#await object then { 'prop-1': prop1, 'prop4': fourthProp, ...rest }}
|
||||
<p>prop-1: {prop1}</p>
|
||||
<p>prop4: {fourthProp}</p>
|
||||
<p>rest: {JSON.stringify(rest)}</p>
|
||||
{/await}
|
||||
|
||||
{#await objectReject then value}
|
||||
resolved
|
||||
{:catch { 'prop-7': prop7, 'prop6': sixthProp, ...rest }}
|
||||
<p>prop-7: {prop7}</p>
|
||||
<p>prop6: {sixthProp}</p>
|
||||
<p>rest: {JSON.stringify(rest)}</p>
|
||||
{/await}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
export default {
|
||||
props: {
|
||||
name: 'world'
|
||||
},
|
||||
|
||||
ssrHtml: `
|
||||
<editor contenteditable="true">world</editor>
|
||||
<p>hello world</p>
|
||||
`,
|
||||
|
||||
async test({ assert, component, target, window }) {
|
||||
// JSDom doesn't support innerText yet, so the test is not ideal
|
||||
// https://github.com/jsdom/jsdom/issues/1245
|
||||
const el = target.querySelector('editor');
|
||||
assert.equal(el.innerText, 'world');
|
||||
|
||||
const event = new window.Event('input');
|
||||
el.innerText = 'everybody';
|
||||
await el.dispatchEvent(event);
|
||||
assert.equal(component.name, 'everybody');
|
||||
|
||||
component.name = 'goodbye';
|
||||
assert.equal(el.innerText, 'goodbye');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
<script>
|
||||
export let name;
|
||||
</script>
|
||||
|
||||
<editor contenteditable="true" bind:innerText={name} />
|
||||
<p>hello {name}</p>
|
||||
@ -0,0 +1,40 @@
|
||||
export default {
|
||||
async test({ assert, target, component, window }) {
|
||||
const button = target.querySelector('button');
|
||||
const clickEvent = new window.Event('click');
|
||||
const changeEvent = new window.Event('change');
|
||||
|
||||
const [input1, input2] = target.querySelectorAll('input[type="checkbox"]');
|
||||
function validate_inputs(v1, v2) {
|
||||
assert.equal(input1.checked, v1);
|
||||
assert.equal(input2.checked, v2);
|
||||
}
|
||||
|
||||
assert.deepEqual(component.test, []);
|
||||
validate_inputs(false, false);
|
||||
|
||||
component.test = ['a', 'b'];
|
||||
validate_inputs(true, true);
|
||||
|
||||
input1.checked = false;
|
||||
await input1.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, ['b']);
|
||||
|
||||
input2.checked = false;
|
||||
await input2.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, []);
|
||||
|
||||
input1.checked = true;
|
||||
input2.checked = true;
|
||||
await input1.dispatchEvent(changeEvent);
|
||||
await input2.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, ['b', 'a']);
|
||||
|
||||
await button.dispatchEvent(clickEvent);
|
||||
assert.deepEqual(component.test, ['b', 'a']); // should it be ['a'] only? valid arguments for both outcomes
|
||||
|
||||
input1.checked = false;
|
||||
await input1.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, []);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let test = [];
|
||||
let hidden = false
|
||||
</script>
|
||||
|
||||
<button on:click={() => hidden = !hidden}>
|
||||
{hidden ? "show" : "hide"} b
|
||||
</button>
|
||||
|
||||
<label>a <input type="checkbox" bind:group={test} value="a" /></label>
|
||||
{#if !hidden}
|
||||
<label>b <input type="checkbox" bind:group={test} value="b" /></label>
|
||||
{/if}
|
||||
<label>c <input value="just here, so b is not the last input" /></label>
|
||||
@ -0,0 +1,34 @@
|
||||
export default {
|
||||
async test({ assert, target, component, window }) {
|
||||
const button = target.querySelector('button');
|
||||
const clickEvent = new window.Event('click');
|
||||
const changeEvent = new window.Event('change');
|
||||
|
||||
const [input1, input2] = target.querySelectorAll('input[type="radio"]');
|
||||
function validate_inputs(v1, v2) {
|
||||
assert.equal(input1.checked, v1);
|
||||
assert.equal(input2.checked, v2);
|
||||
}
|
||||
|
||||
component.test = 'a';
|
||||
validate_inputs(true, false);
|
||||
|
||||
component.test = 'b';
|
||||
validate_inputs(false, true);
|
||||
|
||||
input1.checked = true;
|
||||
await input1.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, 'a');
|
||||
|
||||
input2.checked = true;
|
||||
await input2.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, 'b');
|
||||
|
||||
await button.dispatchEvent(clickEvent);
|
||||
assert.deepEqual(component.test, 'b'); // should it be undefined? valid arguments for both outcomes
|
||||
|
||||
input1.checked = true;
|
||||
await input1.dispatchEvent(changeEvent);
|
||||
assert.deepEqual(component.test, 'a');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let test;
|
||||
let hidden = false
|
||||
</script>
|
||||
|
||||
<button on:click={() => hidden = !hidden}>
|
||||
{hidden ? "show" : "hide"} b
|
||||
</button>
|
||||
|
||||
<label>a <input type="radio" bind:group={test} value="a" /></label>
|
||||
{#if !hidden}
|
||||
<label>b <input type="radio" bind:group={test} value="b" /></label>
|
||||
{/if}
|
||||
<label>c <input value="just here, so b is not the last input" /></label>
|
||||
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
html: `
|
||||
<p>4, 12, 60</p>
|
||||
`,
|
||||
|
||||
async test({ component, target, assert }) {
|
||||
component.permutation = [2, 3, 1];
|
||||
await (component.promise1 = Promise.resolve({length: 1, width: 2, height: 3}));
|
||||
try {
|
||||
await (component.promise2 = Promise.reject({length: 97, width: 98, height: 99}));
|
||||
} catch (e) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p>2, 11, 2</p>
|
||||
<p>9506, 28811, 98</p>
|
||||
`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
export let promise1 = {length: 5, width: 3, height: 4};
|
||||
export let promise2 = {length: 12, width: 5, height: 13};
|
||||
export let permutation = [1, 2, 3];
|
||||
|
||||
function calculate(length, width, height) {
|
||||
return {
|
||||
'1-Dimensions': [length, width, height],
|
||||
'2-Dimensions': [length * width, width * height, length * height],
|
||||
'3-Dimensions': [length * width * height, length + width + height, length * width + width * height + length * height]
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await promise1 then { length, width, height }}
|
||||
{@const [a, b, c] = permutation}
|
||||
{@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
|
||||
<p>{first}, {second}, {third}</p>
|
||||
{/await}
|
||||
|
||||
{#await promise2 catch { length, width, height }}
|
||||
{@const [a, b, c] = permutation}
|
||||
{@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
|
||||
<p>{first}, {second}, {third}</p>
|
||||
{/await}
|
||||
@ -0,0 +1,19 @@
|
||||
export default {
|
||||
html: '<div>12 120 70, 30+4=34</div>',
|
||||
async test({ component, target, assert }) {
|
||||
component.promise1 = Promise.resolve({width: 5, height: 6});
|
||||
component.promise2 = Promise.reject({width: 6, height: 7});
|
||||
|
||||
await Promise.resolve();
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>30 300 110, 50+6=56</div>
|
||||
<div>42 420 130, 60+7=67</div>
|
||||
`);
|
||||
|
||||
component.constant = 20;
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<div>30 600 220, 100+6=106</div>
|
||||
<div>42 840 260, 120+7=127</div>
|
||||
`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
export let promise1 = {width: 3, height: 4};
|
||||
export let promise2 = {width: 5, height: 7};
|
||||
export let constant = 10;
|
||||
|
||||
function calculate(width, height, constant) {
|
||||
return { 'the-area': width * height, 'the-volume': width * height * constant };
|
||||
}
|
||||
</script>
|
||||
|
||||
{#await promise1 then { width, height }}
|
||||
{@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)}
|
||||
{@const perimeter = (width + height) * constant}
|
||||
{@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]}
|
||||
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||
{/await}
|
||||
|
||||
{#await promise2 catch { width, height }}
|
||||
{@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)}
|
||||
{@const perimeter = (width + height) * constant}
|
||||
{@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]}
|
||||
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||
{/await}
|
||||
@ -0,0 +1,15 @@
|
||||
export default {
|
||||
html: `
|
||||
<button>6, 12, 8, 24</button>
|
||||
<button>45, 35, 63, 315</button>
|
||||
<button>60, 48, 80, 480</button>
|
||||
`,
|
||||
|
||||
async test({ component, target, assert }) {
|
||||
component.boxes = [{ length: 10, width: 20, height: 30 }];
|
||||
|
||||
assert.htmlEqual(target.innerHTML,
|
||||
'<button>200, 600, 300, 6000</button>'
|
||||
);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,42 @@
|
||||
<script>
|
||||
export let boxes = [
|
||||
{length: 2, width: 3, height: 4},
|
||||
{length: 9, width: 5, height: 7},
|
||||
{length: 10, width: 6, height: 8}
|
||||
];
|
||||
|
||||
function calculate(length, width, height) {
|
||||
return {
|
||||
twoDimensions: {
|
||||
bottomArea: length * width,
|
||||
sideArea1: width * height,
|
||||
sideArea2: length * height
|
||||
},
|
||||
threeDimensions: {
|
||||
volume: length * width * height
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export let dimension = 'Dimensions';
|
||||
function changeDimension() {
|
||||
dimension = 'DIMENSIONS';
|
||||
}
|
||||
|
||||
let area = 'Area';
|
||||
</script>
|
||||
|
||||
{#each boxes as { length, width, height }}
|
||||
{@const {
|
||||
[`two${dimension}`]: {
|
||||
i = 1,
|
||||
[`bottom${area}`]: bottom,
|
||||
[`side${area}${i++}`]: sideone,
|
||||
[`side${area}${i++}`]: sidetwo
|
||||
},
|
||||
[`three${dimension}`]: {
|
||||
volume
|
||||
}
|
||||
} = calculate(length, width, height)}
|
||||
<button on:click={changeDimension}>{bottom}, {sideone}, {sidetwo}, {volume}</button>
|
||||
{/each}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue