Merge remote-tracking branch 'upstream/master' into hmr-capture-state

pull/3822/head
rixo 6 years ago
commit 0239ff3965

@ -24,6 +24,7 @@ Also:
* Flush changes in newly attached block when using `{#await}` ([#3660](https://github.com/sveltejs/svelte/issues/3660)) * Flush changes in newly attached block when using `{#await}` ([#3660](https://github.com/sveltejs/svelte/issues/3660))
* Throw exception immediately when calling `createEventDispatcher()` after component instantiation ([#3667](https://github.com/sveltejs/svelte/pull/3667)) * Throw exception immediately when calling `createEventDispatcher()` after component instantiation ([#3667](https://github.com/sveltejs/svelte/pull/3667))
* Fix globals shadowing contextual template scope ([#3674](https://github.com/sveltejs/svelte/issues/3674)) * Fix globals shadowing contextual template scope ([#3674](https://github.com/sveltejs/svelte/issues/3674))
* Fix `<svelte:window>` bindings to stores ([#3832](https://github.com/sveltejs/svelte/issues/3832))
## 3.12.1 ## 3.12.1

@ -49,8 +49,6 @@
<!-- svelte-ignore a11y-autofocus --> <!-- svelte-ignore a11y-autofocus -->
<button autofocus on:click={close}>close modal</button> <button autofocus on:click={close}>close modal</button>
<a href="argh">argh</a>
</div> </div>
<style> <style>

@ -3,7 +3,6 @@
import flash from './flash.js'; import flash from './flash.js';
export let todo; export let todo;
export let toggle;
let div; let div;

@ -5,7 +5,6 @@
import flash from './flash.js'; import flash from './flash.js';
export let todo; export let todo;
export let toggle;
let div; let div;

@ -127,7 +127,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(b` component.partly_hoisted.push(b`
function ${id}() { function ${id}() {
${props.map(prop => b`$$invalidate('${prop.name}', ${prop.name} = @_window.${prop.value});`)} ${props.map(prop => component.invalidate(prop.name, x`${prop.name} = @_window.${prop.value}`))}
} }
`); `);
@ -167,7 +167,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(b` component.partly_hoisted.push(b`
function ${id}() { function ${id}() {
$$invalidate('${name}', ${name} = @_navigator.onLine); ${component.invalidate(name, x`${name} = @_navigator.onLine`)}
} }
`); `);

@ -5,6 +5,7 @@ import Block from '../../Block';
import MustacheTag from '../../../nodes/MustacheTag'; import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag'; import RawMustacheTag from '../../../nodes/RawMustacheTag';
import { Node } from 'estree'; import { Node } from 'estree';
import { changed } from './changed';
export default class Tag extends Wrapper { export default class Tag extends Wrapper {
node: MustacheTag | RawMustacheTag; node: MustacheTag | RawMustacheTag;
@ -39,10 +40,7 @@ export default class Tag extends Wrapper {
if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string
if (dependencies.length > 0) { if (dependencies.length > 0) {
let condition = x`#changed.${dependencies[0]}`; let condition = changed(dependencies);
for (let i = 1; i < dependencies.length; i += 1) {
condition = x`${condition} || #changed.${dependencies[i]}`;
}
if (block.has_outros) { if (block.has_outros) {
condition = x`!#current || ${condition}`; condition = x`!#current || ${condition}`;

@ -52,12 +52,19 @@ global.document = window.document;
global.navigator = window.navigator; global.navigator = window.navigator;
global.getComputedStyle = window.getComputedStyle; global.getComputedStyle = window.getComputedStyle;
global.requestAnimationFrame = null; // placeholder, filled in using set_raf global.requestAnimationFrame = null; // placeholder, filled in using set_raf
global.window = window;
// add missing ecmascript globals to window // add missing ecmascript globals to window
for (const key of Object.getOwnPropertyNames(global)) { for (const key of Object.getOwnPropertyNames(global)) {
window[key] = window[key] || global[key]; window[key] = window[key] || global[key];
} }
// implement mock scroll
window.scrollTo = function(pageXOffset, pageYOffset) {
window.pageXOffset = pageXOffset;
window.pageYOffset = pageYOffset;
};
export function env() { export function env() {
window.document.title = ''; window.document.title = '';
window.document.body.innerHTML = '<main></main>'; window.document.body.innerHTML = '<main></main>';
@ -204,3 +211,25 @@ export function spaces(i) {
while (i--) result += ' '; while (i--) result += ' ';
return result; return result;
} }
// fake timers
const original_set_timeout = global.setTimeout;
export function useFakeTimers() {
const callbacks = [];
global.setTimeout = function(fn) {
callbacks.push(fn);
};
return {
flush() {
callbacks.forEach(fn => fn());
callbacks.splice(0, callbacks.length);
},
removeFakeTimers() {
callbacks.splice(0, callbacks.length);
global.setTimeout = original_set_timeout;
}
};
}

@ -68,7 +68,7 @@ function instance($$self, $$props, $$invalidate) {
let { y } = $$props; let { y } = $$props;
function onwindowscroll() { function onwindowscroll() {
$$invalidate("y", y = window.pageYOffset); $$invalidate("y", y = window.pageYOffset)
} }
$$self.$set = $$props => { $$self.$set = $$props => {

@ -190,7 +190,7 @@ describe("runtime", () => {
if (typeof config.error === 'function') { if (typeof config.error === 'function') {
config.error(assert, err); config.error(assert, err);
} else { } else {
assert.equal(config.error, err.message); assert.equal(err.message, config.error);
} }
} else { } else {
throw err; throw err;

@ -1,5 +1,16 @@
export default { export default {
skip: true, // JSDOM...
ssrHtml: `
<select value='hullo'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
<select value='world'>
<option value='hullo'>Hullo</option>
<option value='world'>World</option>
</select>
`,
html: ` html: `
<select> <select>

@ -1,3 +1,6 @@
<script>
export let items;
</script>
{#each items as item} {#each items as item}
<select bind:value={item.value}> <select bind:value={item.value}>
<option value="hullo">Hullo</option> <option value="hullo">Hullo</option>

@ -1,49 +1,58 @@
export default { export default {
skip: true, // JSDOM
props: { props: {
selected: [ 'two', 'three' ] selected: [ 'two', 'three' ]
}, },
ssrHtml: `
<select multiple value="two,three">
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
<p>selected: two, three</p>
`,
html: ` html: `
<select multiple> <select multiple>
<option>one</option> <option value="one">one</option>
<option>two</option> <option value="two">two</option>
<option>three</option> <option value="three">three</option>
</select> </select>
<p>selected: two, three</p> <p>selected: two, three</p>
`, `,
test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const select = target.querySelector( 'select' ); const select = target.querySelector( 'select' );
const options = [ ...target.querySelectorAll( 'option' ) ]; const options = [ ...target.querySelectorAll( 'option' ) ];
const change = new window.Event( 'change' ); const change = new window.Event( 'change' );
options[1].selected = false; options[1].selected = false;
select.dispatchEvent( change ); await select.dispatchEvent( change );
assert.deepEqual( component.selected, [ 'three' ] ); assert.deepEqual( component.selected, [ 'three' ] );
assert.htmlEqual( target.innerHTML, ` assert.htmlEqual( target.innerHTML, `
<select multiple> <select multiple>
<option>one</option> <option value="one">one</option>
<option>two</option> <option value="two">two</option>
<option>three</option> <option value="three">three</option>
</select> </select>
<p>selected: three</p> <p>selected: three</p>
` ); ` );
options[0].selected = true; options[0].selected = true;
select.dispatchEvent( change ); await select.dispatchEvent( change );
assert.deepEqual( component.selected, [ 'one', 'three' ] ); assert.deepEqual( component.selected, [ 'one', 'three' ] );
assert.htmlEqual( target.innerHTML, ` assert.htmlEqual( target.innerHTML, `
<select multiple> <select multiple>
<option>one</option> <option value="one">one</option>
<option>two</option> <option value="two">two</option>
<option>three</option> <option value="three">three</option>
</select> </select>
<p>selected: one, three</p> <p>selected: one, three</p>
@ -57,9 +66,9 @@ export default {
assert.htmlEqual( target.innerHTML, ` assert.htmlEqual( target.innerHTML, `
<select multiple> <select multiple>
<option>one</option> <option value="one">one</option>
<option>two</option> <option value="two">two</option>
<option>three</option> <option value="three">three</option>
</select> </select>
<p>selected: one, two</p> <p>selected: one, two</p>

@ -1,5 +1,15 @@
export default { export default {
skip: true, // JSDOM
ssrHtml: `
<h1>Hello undefined!</h1>
<select>
<option value="Harry">Harry</option>
<optgroup label="Group">
<option value="World">World</option>
</optgroup>
</select>
`,
html: ` html: `
<h1>Hello Harry!</h1> <h1>Hello Harry!</h1>
@ -12,17 +22,17 @@ export default {
</select> </select>
`, `,
test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const select = target.querySelector('select'); const select = target.querySelector('select');
const options = [...target.querySelectorAll('option')]; const options = [...target.querySelectorAll('option')];
assert.deepEqual(options, select.options); assert.deepEqual(options, [...select.options]);
assert.equal(component.name, 'Harry'); assert.equal(component.name, 'Harry');
const change = new window.Event('change'); const change = new window.Event('change');
options[1].selected = true; options[1].selected = true;
select.dispatchEvent(change); await select.dispatchEvent(change);
assert.equal(component.name, 'World'); assert.equal(component.name, 'World');
assert.htmlEqual(target.innerHTML, ` assert.htmlEqual(target.innerHTML, `

@ -1,10 +1,37 @@
import { env, useFakeTimers } from "../../../helpers";
let clock;
export default { export default {
skip: true, // JSDOM before_test() {
clock = useFakeTimers();
const window = env();
Object.defineProperties(window, {
pageYOffset: {
value: 0,
configurable: true
},
pageXOffset: {
value: 0,
configurable: true
}
});
},
test({ assert, component, target, window }) { after_test() {
clock.removeFakeTimers();
clock = null;
},
async test({ assert, component, target, window }) {
assert.equal(window.pageYOffset, 0); assert.equal(window.pageYOffset, 0);
// clear the previous 'scrolling' state
clock.flush();
component.scrollY = 100; component.scrollY = 100;
clock.flush();
assert.equal(window.pageYOffset, 100); assert.equal(window.pageYOffset, 100);
} },
}; };

@ -1,16 +1,25 @@
export default { export default {
html: `<div>1024x768</div>`, html: `<div>1024x768</div>`,
skip: true, // some weird stuff happening with JSDOM 11 before_test() {
// skip: /^v4/.test(process.version), // node 4 apparently does some dumb stuff Object.defineProperties(window, {
innerWidth: {
value: 1024,
configurable: true
},
innerHeight: {
value: 768,
configurable: true
}
});
},
skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const event = new window.Event('resize'); const event = new window.Event('resize');
// JSDOM executes window event listeners with `global` rather than Object.defineProperties(window, {
// `window` (bug?) so we need to do this
Object.defineProperties(global, {
innerWidth: { innerWidth: {
value: 567, value: 567,
configurable: true configurable: true

@ -0,0 +1,29 @@
export default {
skip_if_ssr: true,
before_test() {
Object.defineProperties(window, {
pageYOffset: {
value: 0,
configurable: true,
},
});
},
async test({ assert, component, target, window }) {
assert.equal(window.pageYOffset, 0);
const event = new window.Event('scroll');
Object.defineProperties(window, {
pageYOffset: {
value: 234,
configurable: true,
},
});
await window.dispatchEvent(event);
assert.htmlEqual(
target.innerHTML,
`<p style="position: fixed; top: 1em; left: 1em;">scroll\ny\nis\n234.\n234\n*\n234\n=\n54756</p><div style="height: 9999px;"></div>`
);
},
};

@ -0,0 +1,15 @@
<script>
import { writable, derived } from 'svelte/store';
const y = writable(0);
const y_squared = derived(y, $y => $y * $y);
</script>
<svelte:window bind:scrollY={$y}/>
<p style="position: fixed; top: 1em; left: 1em;">
scroll y is {$y}. {$y} * {$y} = {$y_squared}
</p>
<div style="height: 9999px">
</div>

@ -1,16 +1,12 @@
export default { export default {
html: `<div>undefinedxundefined</div>`, html: `<div>undefinedxundefined</div>`,
skip: true, // some weird stuff happening with JSDOM 11
// skip: /^v4/.test(process.version), // node 4 apparently does some dumb stuff
skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason skip_if_ssr: true, // there's some kind of weird bug with this test... it compiles with the wrong require.extensions hook for some bizarre reason
async test({ assert, component, target, window }) { async test({ assert, component, target, window }) {
const event = new window.Event('resize'); const event = new window.Event('resize');
// JSDOM executes window event listeners with `global` rather than Object.defineProperties(window, {
// `window` (bug?) so we need to do this
Object.defineProperties(global, {
innerWidth: { innerWidth: {
value: 567, value: 567,
configurable: true configurable: true

@ -3,6 +3,6 @@
export let height; export let height;
</script> </script>
<svelte:window on:resize='{() => width = this.innerWidth, height = this.innerHeight}'/> <svelte:window on:resize={function () { width = this.innerWidth, height = this.innerHeight; }}/>
<div>{width}x{height}</div> <div>{width}x{height}</div>

@ -138,7 +138,7 @@ describe("ssr", () => {
if (typeof config.error === 'function') { if (typeof config.error === 'function') {
config.error(assert, err); config.error(assert, err);
} else { } else {
assert.equal(config.error, err.message); assert.equal(err.message, config.error);
} }
} else { } else {
showOutput(cwd, compileOptions); showOutput(cwd, compileOptions);

Loading…
Cancel
Save