Files
polymer/test/unit/styling-cross-scope-var.html
2015-12-28 19:37:13 +01:00

688 lines
18 KiB
HTML

<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
<meta charset="utf-8">
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer.html">
</head>
<body>
<simple-element></simple-element>
<simple-element></simple-element>
<x-scope></x-scope>
<dom-module id="x-grand-child-scope">
<style>
:host {
display: block;
padding: 8px;
}
#scope {
border: var(--scope-var);
}
#child {
border: var(--child-scope-var);
}
#me {
border: var(--grand-child-scope-var);
}
</style>
<template>
<div id="me">x-grand-child-scope</div>
<div id="scope">From x-scope</div>
<div id="child">From x-child-scope</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-grand-child-scope'});
});
</script>
</dom-module>
<dom-module id="x-host-property">
<style>
:host {
display: block;
padding: 8px;
border: var(--scope-var);
}
</style>
<template>
Host property
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-host-property'});
});
</script>
</dom-module>
<dom-module id="x-child-scope">
<style>
:host {
display: block;
padding: 8px;
}
:root {
--gc4-scope: 5px solid green;
}
#me {
border: var(--child-scope-var);
}
#gc2 {
--grand-child-scope-var: 4px solid seagreen;
}
#gc4 {
--grand-child-scope-var:
var(--gc4-scope);
}
</style>
<template>
<div id="me">x-child-scope</div>
<x-grand-child-scope id="gc1"></x-grand-child-scope>
<x-grand-child-scope id="gc2"></x-grand-child-scope>
<x-grand-child-scope id="gc3"></x-grand-child-scope>
<x-grand-child-scope id="gc4"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-child-scope'});
});
</script>
</dom-module>
<dom-module id="x-overrides">
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
--grand-child-scope-var: var(--rename);
}
</style>
<template>
overrides:
<x-grand-child-scope id="gc1"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides'});
});
</script>
</dom-module>
<dom-module id="x-overrides2">
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
}
:root {
--grand-child-scope-var: var(--rename);
}
</style>
<template>
overrides:
<x-grand-child-scope id="gc1"></x-grand-child-scope>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides2'});
});
</script>
</dom-module>
<dom-module id="x-late">
<style>
:host {
border: var(--late);
display: block;
}
</style>
<template>
late
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-late'});
});
</script>
</dom-module>
<dom-module id="x-overrides3">
<style>
:host {
border: 1px dashed gray;
margin: 8px;
padding: 8px;
display: block;
}
:root {
--fillin: 16px;
}
</style>
<template>
overrides:
<x-late id="late"></x-late>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-overrides3'});
});
</script>
</dom-module>
<dom-module id="x-has-def">
<style>
:host {
border: var(--border, --defaultBorder);
margin: 8px;
padding: 8px;
display: block;
}
</style>
<template>
Element with default variable.
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-has-def'});
});
</script>
</dom-module>
<dom-module id="x-has-if">
<style>
.iffy {
border: var(--scope-var);
}
</style>
<template>
<template is="dom-if" if="{{gogo}}">
<div class="iffy">iffy</div>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-has-if',
properties: {
gogo: {value: true}
}
});
});
</script>
</dom-module>
<dom-module id="x-button">
<style>
:host {
display: block;
border: var(--button-border);
}
</style>
<template>
Button!
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-button',
extends: 'button'
});
});
</script>
</dom-module>
<dom-module id="x-dynamic">
<style>
:host {
display: block;
margin: 20px;
border: var(--dynamic);
}
</style>
<template>
Dynamic
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-dynamic'
});
});
</script>
</dom-module>
<dom-module id="x-scope">
<style>
:host {
x--invalid: 15px solid gray;
display: block;
padding: 8px;
--scope-var: 1px solid black;
--fallback: 7px solid orange;
--default1: var(--undefined, 6px solid yellow);
--default2: var(--undefined, --fallback);
--default3: var(--undefined, rgb(128, 200, 250));
--defaultBorder: 22px solid green;
--a: 10px;
--b: 5px;
--primary-color: rgb(128, 128, 128);
--late: var(--fillin);
--button-border: 16px solid tomato;
--after: 17px solid brown;
--end-term: 19px solid blue}
:root{--ws-term: 18px solid orange}
#me {
border: var(--scope-var);
}
x-child-scope {
--child-scope-var: 2px solid orange;
--grand-child-scope-var: 3px solid steelblue;
}
x-child-scope.special {
--child-scope-var: 12px solid orange;
}
#applyDefault1 {
border: var(--undefined, 6px solid yellow);
}
#applyDefault2 {
border: var(--undefined, --fallback);
}
#default1 {
border: var(--default1);
}
#default2 {
border: var(--default2);
}
#default3 {
padding: 8px;
background-color: var(--default3);
}
#defaultElement2 {
--defaultBorder: 23px solid goldenrod;
}
#overrides1a, #overrides1b, #overrides2 {
--rename: 8px solid navy;
}
#overrides1b, #overrides2 {
--grand-child-scope-var: 9px solid orange;
}
#overridesConcrete {
border: var(--scope-var);
border: 4px solid steelblue;
}
#calc {
border: solid red;
border-width: calc(var(--a) + var(--b));
}
#shadow {
box-shadow: 10px 10px 10px var(--primary-color);
-webkit-box-shadow: 10px 10px 10px var(--primary-color);
}
x-host-property {
border: 10px solid purple;
}
#invalid {
border: var(--invalid);
}
#after::after {
content: 'after';
border: var(--after);
}
#wsTerm {
border: var(--ws-term)
}
#endTerm {border: var(--end-term)}
</style>
<template>
<div id="me">x-scope</div>
<x-child-scope id="child"></x-child-scope>
<x-child-scope id="child2"></x-child-scope>
<x-overrides id="overrides1a"></x-overrides>
<x-overrides id="overrides1b"></x-overrides>
<x-overrides2 id="overrides2"></x-overrides2>
<x-overrides3 id="overrides3"></x-overrides3>
<div id="overridesConcrete">override concrete</div>
<button id="button" is="x-button"></button>
<div id="default1">default</div>
<div id="default2">var default</div>
<div id="default3">tricky property rgb(...) default</div>
<x-has-def id="defaultElement1"></x-has-def>
<x-has-def id="defaultElement2"></x-has-def>
<div id="applyDefault1">default</div>
<div id="applyDefault2">var default</div>
<div id="calc">Calc</div>
<div id="shadow">Shadow</div>
<div id="invalid">invalid</div>
<x-host-property id="hostProp"></x-host-property>
<x-has-if id="iffy"></x-has-if>
<div id="after"></div>
<x-dynamic id="dynamic"></x-dynamic>
<div id="wsTerm">new line var</div>
<div id="endTerm">end var</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-scope'
});
});
</script>
</dom-module>
<dom-module id="x-inside">
<style>
:host {
display: inline-block;
border: var(--border) solid orange;
height: 10px;
width: 10px;
background-color: tomato;
}
</style>
<template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-inside'
});
});
</script>
</dom-module>
<dom-module id="simple-element">
<style>
:host {
display: block;
}
x-inside {
color: var(--dne);
--border: 10px;
}
</style>
<template>
<x-inside id="inner"></x-inside>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'simple-element'
});
});
</script>
</dom-module>
<script>
suite('scoped-styling-var', function() {
function assertComputed(element, value, pseudo) {
var name = 'border-top-width';
var computed = element.getComputedStyleValue && !pseudo ?
element.getComputedStyleValue(name) :
getComputedStyle(element, pseudo)[name];
assert.equal(computed, value, 'computed style incorrect');
}
function assertStylePropertyValue(element, name, includeValue) {
var value = element.getComputedStyleValue(name);
assert.include(value, includeValue);
}
var styled = document.querySelector('x-scope');
test('mutiple elements in document', function() {
var e$ = document.querySelectorAll('simple-element');
assertComputed(e$[0].$.inner, '10px');
assertComputed(e$[1].$.inner, '10px');
});
test('simple variables calculated correctly between scopes', function() {
assertStylePropertyValue(styled, '--scope-var', '1px');
//
var child = styled.$.child;
assertStylePropertyValue(child, '--scope-var', '1px');
assertStylePropertyValue(child, '--child-scope-var', '2px');
assertStylePropertyValue(child, '--grand-child-scope-var', '3px');
//
var gc1 = child.$.gc1;
assertStylePropertyValue(gc1, '--scope-var', '1px');
assertStylePropertyValue(gc1, '--child-scope-var', '2px');
assertStylePropertyValue(gc1, '--grand-child-scope-var', '3px');
//
var gc2 = child.$.gc2;
assertStylePropertyValue(gc2, '--scope-var', '1px');
assertStylePropertyValue(gc2, '--child-scope-var', '2px');
assertStylePropertyValue(gc2, '--grand-child-scope-var', '4px');
//
var gc3 = child.$.gc3;
assertStylePropertyValue(gc3, '--scope-var', '1px');
assertStylePropertyValue(gc3, '--child-scope-var', '2px');
assertStylePropertyValue(gc3, '--grand-child-scope-var', '3px');
});
test('invalid variables not parsed', function() {
assert.notProperty(styled._styleProperties, 'x--invalid');
assertComputed(styled.$.invalid, '0px');
});
test('simple variables applied correctly between scopes', function() {
assertComputed(styled.$.me, '1px');
assertComputed(styled.$.child.$.me, '2px');
assertComputed(styled.$.child.$.gc1.$.me, '3px');
assertComputed(styled.$.child.$.gc1.$.scope, '1px');
assertComputed(styled.$.child.$.gc1.$.child, '2px');
assertComputed(styled.$.child.$.gc2.$.me, '4px');
assertComputed(styled.$.child.$.gc2.$.scope, '1px');
assertComputed(styled.$.child.$.gc2.$.child, '2px');
});
test('variable can be set to another variable', function() {
var gc4 = styled.$.child.$.gc4;
assertStylePropertyValue(gc4, '--grand-child-scope-var', '5px');
assertComputed(gc4.$.me, '5px');
});
test('variable default values can be assigned to other variables', function() {
assertStylePropertyValue(styled, '--default1', '6px');
assertStylePropertyValue(styled, '--default2', '7px');
assertComputed(styled.$.default1, '6px');
assertComputed(styled.$.default2, '7px');
assertComputed(styled.$.applyDefault1, '6px');
assertComputed(styled.$.applyDefault2, '7px');
});
test('variable literal defaults can contain one (...)', function() {
var b = getComputedStyle(styled.$.default3).backgroundColor;
assert.match(b, /rgb\(128/, 'literal fallback containin (...) not set');
});
test('variable values can be used with calc', function() {
assertComputed(styled.$.calc, '15px');
});
test('variable values can be used with box-shadow', function() {
var b = getComputedStyle(styled.$.shadow).boxShadow;
assert.match(b, /rgb\(128/, 'box shadow not set correctly');
});
test('host properties can be overridden with outer scope styles', function() {
assertComputed(styled.$.hostProp, '10px');
});
test('updateStyles changes property values and using style cache', function() {
styled.$.child.classList.add('special');
var l = document.querySelectorAll('style').length;
styled.updateStyles();
if (styled.shadyRoot) {
assert.equal(document.querySelectorAll('style').length, l+4);
}
assertComputed(styled.$.child.$.me, '12px');
styled.$.child.classList.remove('special');
styled.updateStyles();
if (styled.shadyRoot) {
assert.equal(document.querySelectorAll('style').length, l);
}
assertComputed(styled.$.child.$.me, '2px');
});
test('updateStyles changes own properties based on customStyle changes', function() {
styled.$.child.customStyle['--child-scope-var'] = '30px solid orange';
styled.$.child.updateStyles();
assertComputed(styled.$.child.$.me, '30px');
styled.$.child.customStyle = {};
styled.$.child.updateStyles();
assertComputed(styled.$.child.$.me, '2px');
});
test('updateStyles with properties argument changes styles', function() {
styled.$.child.updateStyles({'--child-scope-var': '26px solid seagreen'});
assertComputed(styled.$.child.$.me, '26px');
styled.$.child.customStyle = {};
styled.$.child.updateStyles();
assertComputed(styled.$.child.$.me, '2px');
});
test('styles update based on root customStyle changes', function() {
assertComputed(styled.$.dynamic, '0px');
Polymer.StyleDefaults.customStyle['--dynamic'] = '4px solid navy';
Polymer.updateStyles();
assertComputed(styled.$.dynamic, '4px');
Polymer.updateStyles({'--dynamic': '6px solid gray'});
assertComputed(styled.$.dynamic, '6px');
});
test('null customStyles unapply', function() {
styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});
assertComputed(styled.$.dynamic, '8px');
styled.$.dynamic.updateStyles({'--dynamic': null});
assertComputed(styled.$.dynamic, '6px');
styled.$.dynamic.updateStyles({'--dynamic': '8px solid black'});
assertComputed(styled.$.dynamic, '8px');
styled.$.dynamic.updateStyles({'--dynamic': null});
assertComputed(styled.$.dynamic, '6px');
});
test('style properties with dom-if', function() {
var e = styled.$.iffy;
var c = Polymer.dom(e.root).querySelector('.iffy');
assert.ok(c, 'dom-if did not stamp');
assertComputed(c, '1px');
});
test('variable precedence and overrides', function() {
// renamed property applied
var o1a = styled.$.overrides1a;
assertStylePropertyValue(o1a, '--rename', '8px');
assertStylePropertyValue(o1a, '--grand-child-scope-var', '8px');
assertComputed(o1a.$.gc1.$.me, '8px');
// :host property overridden by outer scope
var o1b = styled.$.overrides1b;
assertStylePropertyValue(o1b, '--rename', '8px');
assertStylePropertyValue(o1b, '--grand-child-scope-var', '9px');
assertComputed(o1b.$.gc1.$.me, '9px');
// own scope property overrides outer scope
var o2 = styled.$.overrides2;
assertStylePropertyValue(o2, '--rename', '8px');
assertStylePropertyValue(o2, '--grand-child-scope-var', '8px');
assertComputed(o2.$.gc1.$.me, '8px');
// late bound property does *not* resolve using inherited value
var o3 = styled.$.overrides3;
assert.equal(o3._styleProperties['--late'], '', 'property should not be late bound');
assertStylePropertyValue(o3, '--fillin', '16px');
assertComputed(o3.$.late, '0px');
});
test('type extension elements consume properties in :host rules', function() {
assertComputed(styled.$.button, '16px');
});
test('pseudo-elements can consume custom properties', function() {
assertComputed(styled.$.after, '17px', '::after');
});
test('elements using only variable defaults are styled properly', function() {
assertComputed(styled.$.defaultElement1, '22px');
assertComputed(styled.$.defaultElement2, '23px');
});
test('vars with trailing new line or } apply', function() {
assertComputed(styled.$.wsTerm, '18px');
assertComputed(styled.$.endTerm, '19px');
});
// TODO(sorvell): fix for #1761 was reverted; include test once this issue is addressed
// test('var values can be overridden by subsequent concrete properties', function() {
// assertComputed(styled.$.overridesConcrete, '4px');
// });
});
</script>
</body>
</html>