diff --git a/src/compile/render-ssr/handlers/Element.ts b/src/compile/render-ssr/handlers/Element.ts index 5aec6fb6b50b..138203f539b0 100644 --- a/src/compile/render-ssr/handlers/Element.ts +++ b/src/compile/render-ssr/handlers/Element.ts @@ -112,6 +112,16 @@ export default function(node, renderer, options) { }); } + node.bindings.forEach(binding => { + const { name, value: { snippet } } = binding; + + if (name === 'group') { + // TODO server-render group bindings + } else { + openingTag += ' ${(v => v ? ("' + name + '" + (v === true ? "" : "=" + JSON.stringify(v))) : "")(' + snippet + ')}'; + } + }); + if (addClassAttribute) { openingTag += `\${((v) => v ? ' class="' + v + '"' : '')([${classExpr}].join(' ').trim())}`; } diff --git a/test/runtime/index.js b/test/runtime/index.js index c16d5164dd37..690bf8c9ab5b 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -165,7 +165,7 @@ describe("runtime", () => { }); } else { component.destroy(); - assert.equal(target.innerHTML, ""); + assert.htmlEqual(target.innerHTML, ""); } }) .catch(err => { diff --git a/test/runtime/samples/binding-input-checkbox-deep-contextual/_config.js b/test/runtime/samples/binding-input-checkbox-deep-contextual/_config.js index 81a1b4fdc18c..491ae7f83458 100644 --- a/test/runtime/samples/binding-input-checkbox-deep-contextual/_config.js +++ b/test/runtime/samples/binding-input-checkbox-deep-contextual/_config.js @@ -8,7 +8,28 @@ export default { }, html: ` -
one
two
three
one
+two
+three
+1 completed
+ `, + + ssrHtml: ` +one
+two
+three
+1 completed
`, diff --git a/test/runtime/samples/binding-input-checkbox/_config.js b/test/runtime/samples/binding-input-checkbox/_config.js index ba943e5d77a2..c76f36e46b6a 100644 --- a/test/runtime/samples/binding-input-checkbox/_config.js +++ b/test/runtime/samples/binding-input-checkbox/_config.js @@ -3,7 +3,15 @@ export default { foo: true }, - html: `\ntrue
`, + html: ` + +true
+ `, + + ssrHtml: ` + +true
+ `, test ( assert, component, target, window ) { const input = target.querySelector( 'input' ); diff --git a/test/runtime/samples/binding-input-number/_config.js b/test/runtime/samples/binding-input-number/_config.js index 66e0df8a35ea..5563a9da036c 100644 --- a/test/runtime/samples/binding-input-number/_config.js +++ b/test/runtime/samples/binding-input-number/_config.js @@ -1,43 +1,48 @@ export default { data: { - count: 42 + count: 42, }, html: ` - +number 42
`, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); - assert.equal( input.value, '42' ); + ssrHtml: ` + +number 42
+ `, - const event = new window.Event( 'input' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); + assert.equal(input.value, '42'); + + const event = new window.Event('input'); input.value = '43'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( component.get().count, 43 ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(component.get().count, 43); + assert.htmlEqual(target.innerHTML, `number 43
- ` ); + `); component.set({ count: 44 }); - assert.equal( input.value, '44' ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(input.value, '44'); + assert.htmlEqual(target.innerHTML, `number 44
- ` ); + `); // empty string should be treated as undefined input.value = ''; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( component.get().count, undefined ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(component.get().count, undefined); + assert.htmlEqual(target.innerHTML, `undefined undefined
- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/binding-input-range-change/_config.js b/test/runtime/samples/binding-input-range-change/_config.js index b76a8cffb4a8..68b304b2ef17 100644 --- a/test/runtime/samples/binding-input-range-change/_config.js +++ b/test/runtime/samples/binding-input-range-change/_config.js @@ -1,33 +1,38 @@ export default { data: { - count: 42 + count: 42, }, html: ` - +number 42
`, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); - assert.equal( input.value, '42' ); + ssrHtml: ` + +number 42
+ `, - const event = new window.Event( 'change' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); + assert.equal(input.value, '42'); + + const event = new window.Event('change'); input.value = '43'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( component.get().count, 43 ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(component.get().count, 43); + assert.htmlEqual(target.innerHTML, `number 43
- ` ); + `); component.set({ count: 44 }); - assert.equal( input.value, '44' ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(input.value, '44'); + assert.htmlEqual(target.innerHTML, `number 44
- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/binding-input-range/_config.js b/test/runtime/samples/binding-input-range/_config.js index 15c602e7f4fe..399ac72aa1df 100644 --- a/test/runtime/samples/binding-input-range/_config.js +++ b/test/runtime/samples/binding-input-range/_config.js @@ -1,33 +1,38 @@ export default { data: { - count: 42 + count: 42, }, html: ` - +number 42
`, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); - assert.equal( input.value, '42' ); + ssrHtml: ` + +number 42
+ `, - const event = new window.Event( 'input' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); + assert.equal(input.value, '42'); + + const event = new window.Event('input'); input.value = '43'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( component.get().count, 43 ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(component.get().count, 43); + assert.htmlEqual(target.innerHTML, `number 43
- ` ); + `); component.set({ count: 44 }); - assert.equal( input.value, '44' ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(input.value, '44'); + assert.htmlEqual(target.innerHTML, `number 44
- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/binding-input-text-contextual/_config.js b/test/runtime/samples/binding-input-text-contextual/_config.js index a8949510d706..77b370324bf3 100644 --- a/test/runtime/samples/binding-input-text-contextual/_config.js +++ b/test/runtime/samples/binding-input-text-contextual/_config.js @@ -1,29 +1,69 @@ export default { data: { - items: [ - 'one', - 'two', - 'three' - ] + items: ['one', 'two', 'three'], }, - html: `one
two
three
one
+two
+three
+one
+two
+three
+one
four
three
one
+four
+three
+one
four
five
one
+four
+five
+{"foo":"a","bar":"b","baz":"c"}`, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); - const event = new window.Event( 'input' ); + ssrHtml: ` + +
{"foo":"a","bar":"b","baz":"c"}+ `, - assert.equal( input.value, 'b' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); + const event = new window.Event('input'); + + assert.equal(input.value, 'b'); // edit bar input.value = 'e'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"a","bar":"e","baz":"c"}- ` ); + `); // edit baz component.set({ prop: 'baz' }); - assert.equal( input.value, 'c' ); + assert.equal(input.value, 'c'); input.value = 'f'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"a","bar":"e","baz":"f"}- ` ); + `); // edit foo component.set({ prop: 'foo' }); - assert.equal( input.value, 'a' ); + assert.equal(input.value, 'a'); input.value = 'd'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"d","bar":"e","baz":"f"}- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/binding-input-text-deep-computed/_config.js b/test/runtime/samples/binding-input-text-deep-computed/_config.js index 33cc605a615e..3f314197b88e 100644 --- a/test/runtime/samples/binding-input-text-deep-computed/_config.js +++ b/test/runtime/samples/binding-input-text-deep-computed/_config.js @@ -2,29 +2,43 @@ export default { data: { prop: 'name', user: { - name: 'alice' - } + name: 'alice', + }, }, - html: `\n
hello alice
`, + html: ` + +hello alice
+ `, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); + ssrHtml: ` + +hello alice
+ `, - assert.equal( input.value, 'alice' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); - const event = new window.Event( 'input' ); + assert.equal(input.value, 'alice'); + + const event = new window.Event('input'); input.value = 'bob'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( target.innerHTML, `\nhello bob
` ); + assert.htmlEqual(target.innerHTML, ` + +hello bob
+ `); const user = component.get().user; user.name = 'carol'; component.set({ user }); - assert.equal( input.value, 'carol' ); - assert.equal( target.innerHTML, `\nhello carol
` ); - } + assert.equal(input.value, 'carol'); + assert.htmlEqual(target.innerHTML, ` + +hello carol
+ `); + }, }; diff --git a/test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js b/test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js index 5a16a691bfbe..f6401134c2cf 100644 --- a/test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js +++ b/test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js @@ -1,11 +1,13 @@ export default { data: { prop: 'bar', - objects: [{ - foo: 'a', - bar: 'b', - baz: 'c' - }] + objects: [ + { + foo: 'a', + bar: 'b', + baz: 'c', + }, + ], }, html: ` @@ -13,43 +15,48 @@ export default {{"foo":"a","bar":"b","baz":"c"}`, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); - const event = new window.Event( 'input' ); + ssrHtml: ` + +
{"foo":"a","bar":"b","baz":"c"}+ `, - assert.equal( input.value, 'b' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); + const event = new window.Event('input'); + + assert.equal(input.value, 'b'); // edit bar input.value = 'e'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"a","bar":"e","baz":"c"}- ` ); + `); // edit baz component.set({ prop: 'baz' }); - assert.equal( input.value, 'c' ); + assert.equal(input.value, 'c'); input.value = 'f'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"a","bar":"e","baz":"f"}- ` ); + `); // edit foo component.set({ prop: 'foo' }); - assert.equal( input.value, 'a' ); + assert.equal(input.value, 'a'); input.value = 'd'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `
{"foo":"d","bar":"e","baz":"f"}- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/binding-input-text-deep-contextual/_config.js b/test/runtime/samples/binding-input-text-deep-contextual/_config.js index 8cf72df95649..0ca5c10e2c29 100644 --- a/test/runtime/samples/binding-input-text-deep-contextual/_config.js +++ b/test/runtime/samples/binding-input-text-deep-contextual/_config.js @@ -3,27 +3,47 @@ export default { items: [ { description: 'one' }, { description: 'two' }, - { description: 'three' } - ] + { description: 'three' }, + ], }, - html: `
one
two
three
one
two
three
one
two
three
one
four
three
one
four
three
one
four
five
one
four
five
hello alice
`, + html: ` + +hello alice
+ `, - test ( assert, component, target, window ) { - const input = target.querySelector( 'input' ); + ssrHtml: ` + +hello alice
+ `, - assert.equal( input.value, 'alice' ); + test(assert, component, target, window) { + const input = target.querySelector('input'); - const event = new window.Event( 'input' ); + assert.equal(input.value, 'alice'); + + const event = new window.Event('input'); input.value = 'bob'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.equal( target.innerHTML, `\nhello bob
` ); + assert.htmlEqual(target.innerHTML, ` + +hello bob
+ `); const user = component.get().user; user.name = 'carol'; component.set({ user }); - assert.equal( input.value, 'carol' ); - assert.equal( target.innerHTML, `\nhello carol
` ); - } + assert.equal(input.value, 'carol'); + assert.htmlEqual(target.innerHTML, ` + +hello carol
+ `); + }, }; diff --git a/test/runtime/samples/binding-input-text/_config.js b/test/runtime/samples/binding-input-text/_config.js index 2c54fc8c32ea..c7c53e3fe9b8 100644 --- a/test/runtime/samples/binding-input-text/_config.js +++ b/test/runtime/samples/binding-input-text/_config.js @@ -8,6 +8,11 @@ export default {hello world
`, + ssrHtml: ` + +hello world
+ `, + test(assert, component, target, window) { const input = target.querySelector('input'); assert.equal(input.value, 'world'); diff --git a/test/runtime/samples/binding-select-implicit-option-value/_config.js b/test/runtime/samples/binding-select-implicit-option-value/_config.js index 1ab8de20aa7f..3a5098b76d02 100644 --- a/test/runtime/samples/binding-select-implicit-option-value/_config.js +++ b/test/runtime/samples/binding-select-implicit-option-value/_config.js @@ -14,6 +14,16 @@ export default {foo: 2
`, + ssrHtml: ` + + +foo: 2
+ `, + test(assert, component, target, window) { const select = target.querySelector('select'); const options = [...target.querySelectorAll('option')]; diff --git a/test/runtime/samples/binding-select-initial-value/_config.js b/test/runtime/samples/binding-select-initial-value/_config.js index 7338af165f8d..4f25aec6e726 100644 --- a/test/runtime/samples/binding-select-initial-value/_config.js +++ b/test/runtime/samples/binding-select-initial-value/_config.js @@ -11,17 +11,29 @@ export default {selected: b
`, + ssrHtml: ` +selected: b
+ + + +selected: b
+ `, + data: { - selected: 'b' + selected: 'b', }, - test ( assert, component, target ) { - const select = target.querySelector( 'select' ); - const options = [ ...target.querySelectorAll( 'option' ) ]; + test(assert, component, target) { + const select = target.querySelector('select'); + const options = [...target.querySelectorAll('option')]; - assert.equal( select.value, 'b' ); - assert.ok( options[1].selected ); + assert.equal(select.value, 'b'); + assert.ok(options[1].selected); component.destroy(); - } + }, }; diff --git a/test/runtime/samples/binding-select/_config.js b/test/runtime/samples/binding-select/_config.js index f40f51a6f0fd..7b81425266bd 100644 --- a/test/runtime/samples/binding-select/_config.js +++ b/test/runtime/samples/binding-select/_config.js @@ -11,24 +11,36 @@ export default {selected: one
`, + ssrHtml: ` +selected: one
+ + + +selected: one
+ `, + data: { - selected: 'one' + selected: 'one', }, - test ( assert, component, target, window ) { - const select = target.querySelector( 'select' ); - const options = [ ...target.querySelectorAll( 'option' ) ]; + test(assert, component, target, window) { + const select = target.querySelector('select'); + const options = [...target.querySelectorAll('option')]; - assert.deepEqual( options, select.options ); - assert.equal( component.get().selected, 'one' ); + assert.deepEqual(options, select.options); + assert.equal(component.get().selected, 'one'); - const change = new window.Event( 'change' ); + const change = new window.Event('change'); options[1].selected = true; - select.dispatchEvent( change ); + select.dispatchEvent(change); - assert.equal( component.get().selected, 'two' ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(component.get().selected, 'two'); + assert.htmlEqual(target.innerHTML, `selected: two
selected: two
- ` ); + `); component.set({ selected: 'three' }); - } + }, }; diff --git a/test/runtime/samples/binding-textarea/_config.js b/test/runtime/samples/binding-textarea/_config.js index 3ba2735c9081..742c05e4f54a 100644 --- a/test/runtime/samples/binding-textarea/_config.js +++ b/test/runtime/samples/binding-textarea/_config.js @@ -1,6 +1,6 @@ export default { data: { - value: 'some text' + value: 'some text', }, html: ` @@ -8,25 +8,30 @@ export default {some text
`, - test ( assert, component, target, window ) { - const textarea = target.querySelector( 'textarea' ); - assert.equal( textarea.value, 'some text' ); + ssrHtml: ` + +some text
+ `, - const event = new window.Event( 'input' ); + test(assert, component, target, window) { + const textarea = target.querySelector('textarea'); + assert.equal(textarea.value, 'some text'); + + const event = new window.Event('input'); textarea.value = 'hello'; - textarea.dispatchEvent( event ); + textarea.dispatchEvent(event); - assert.htmlEqual( target.innerHTML, ` + assert.htmlEqual(target.innerHTML, `hello
- ` ); + `); component.set({ value: 'goodbye' }); - assert.equal( textarea.value, 'goodbye' ); - assert.htmlEqual( target.innerHTML, ` + assert.equal(textarea.value, 'goodbye'); + assert.htmlEqual(target.innerHTML, `goodbye
- ` ); - } + `); + }, }; diff --git a/test/runtime/samples/component-binding-deep/_config.js b/test/runtime/samples/component-binding-deep/_config.js index 65591dc24dcc..4538d8a12629 100644 --- a/test/runtime/samples/component-binding-deep/_config.js +++ b/test/runtime/samples/component-binding-deep/_config.js @@ -4,19 +4,22 @@ export default {foo
`, - test ( assert, component, target, window ) { - const event = new window.MouseEvent( 'input' ); - const input = target.querySelector( 'input' ); + ssrHtml: ` + +foo
+ `, + + test(assert, component, target, window) { + const event = new window.MouseEvent('input'); + const input = target.querySelector('input'); input.value = 'blah'; - input.dispatchEvent( event ); + input.dispatchEvent(event); - assert.deepEqual( component.get().deep, { name: 'blah' } ); - assert.htmlEqual( target.innerHTML, ` + assert.deepEqual(component.get().deep, { name: 'blah' }); + assert.htmlEqual(target.innerHTML, `blah
- ` ); - - component.destroy(); - } + `); + }, }; diff --git a/test/runtime/samples/component-binding-each-nested/_config.js b/test/runtime/samples/component-binding-each-nested/_config.js index 83bd81dbcb4d..d160a03b1d57 100644 --- a/test/runtime/samples/component-binding-each-nested/_config.js +++ b/test/runtime/samples/component-binding-each-nested/_config.js @@ -4,6 +4,13 @@ export default {foo, bar, baz
`, + ssrHtml: ` + + + +foo, bar, baz
+ `, + test ( assert, component, target, window ) { const event = new window.MouseEvent( 'input' ); const inputs = target.querySelectorAll( 'input' ); diff --git a/test/runtime/samples/component-binding-each/_config.js b/test/runtime/samples/component-binding-each/_config.js index 4ab071a28676..cdcd03e75699 100644 --- a/test/runtime/samples/component-binding-each/_config.js +++ b/test/runtime/samples/component-binding-each/_config.js @@ -4,6 +4,13 @@ export default {foo, bar, baz
`, + ssrHtml: ` + + + +foo, bar, baz
+ `, + test ( assert, component, target, window ) { const event = new window.MouseEvent( 'input' ); const inputs = target.querySelectorAll( 'input' ); diff --git a/test/runtime/samples/deconflict-component-refs/_config.js b/test/runtime/samples/deconflict-component-refs/_config.js index 213abd245c75..45f01e43e046 100644 --- a/test/runtime/samples/deconflict-component-refs/_config.js +++ b/test/runtime/samples/deconflict-component-refs/_config.js @@ -7,6 +7,14 @@ export default { `, + ssrHtml: ` +Doctor Who
`, + ssrHtml: ` + + +Doctor Who
+ `, + test(assert, component, target, window) { const inputs = target.querySelectorAll('input'); diff --git a/test/runtime/samples/globals-not-overwritten-by-bindings/_config.js b/test/runtime/samples/globals-not-overwritten-by-bindings/_config.js index cf15f47d9d3d..4965976df016 100644 --- a/test/runtime/samples/globals-not-overwritten-by-bindings/_config.js +++ b/test/runtime/samples/globals-not-overwritten-by-bindings/_config.js @@ -16,6 +16,23 @@ export default { `, + ssrHtml: ` +x
', + html: ` +x
+ + `, + + ssrHtml: ` +x
+ + `, test(assert, component, target) { component.set({ x: 'y' }); - assert.htmlEqual(target.innerHTML, 'y
'); + assert.htmlEqual(target.innerHTML, ` +y
+ + `); }, }; diff --git a/test/runtime/samples/observe-binding-ignores-unchanged/_config.js b/test/runtime/samples/observe-binding-ignores-unchanged/_config.js index 04fee0d94ea6..7163e8e4ae9c 100644 --- a/test/runtime/samples/observe-binding-ignores-unchanged/_config.js +++ b/test/runtime/samples/observe-binding-ignores-unchanged/_config.js @@ -1,6 +1,12 @@ export default { html: ` - + +field1: 1
+field2: 2
+ `, + + ssrHtml: ` +field1: 1
field2: 2
`, diff --git a/test/runtime/samples/spread-component-with-bind/_config.js b/test/runtime/samples/spread-component-with-bind/_config.js index 12a400b755d1..06476712af99 100644 --- a/test/runtime/samples/spread-component-with-bind/_config.js +++ b/test/runtime/samples/spread-component-with-bind/_config.js @@ -4,6 +4,11 @@ export default { `, + ssrHtml: ` +foo
+ + `, + test (assert, component, target, window) { const input = target.querySelector('input'); diff --git a/test/runtime/samples/store-binding/_config.js b/test/runtime/samples/store-binding/_config.js index 7839a9e3ea5f..1b257f47e56b 100644 --- a/test/runtime/samples/store-binding/_config.js +++ b/test/runtime/samples/store-binding/_config.js @@ -12,6 +12,11 @@ export default { `, + ssrHtml: ` +foo, bar, baz
+ `, + + ssrHtml: ` + + +foo, bar, baz
`, @@ -21,7 +30,9 @@ export default { assert.deepEqual(store.get().a, ['blah', 'bar', 'baz']); assert.htmlEqual(target.innerHTML, ` - + + +blah, bar, baz
`); diff --git a/test/runtime/samples/store-component-binding/_config.js b/test/runtime/samples/store-component-binding/_config.js index 12b0fcbfb41d..57ee8a63d102 100644 --- a/test/runtime/samples/store-component-binding/_config.js +++ b/test/runtime/samples/store-component-binding/_config.js @@ -12,6 +12,11 @@ export default { `, + ssrHtml: ` +