Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<link rel="author" title="sam@webkit.org">
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../support/computed-testcommon.js"></script>
<div id="container">
<div id="target"></div>
</div>
<style>
.randomNoIdentifier {
width: random(0px, 100px);
height: random(0px, 100px);
left: random(0px, 100000px);
right: random(0px, 100000px);
margin: random(0px, 100000px) random(0px, 100000px);
}
.randomMatchElement {
width: random(element-shared, 0px, 100px);
height: random(element-shared, 0px, 100px);
left: random(element-shared, 0px, 100000px);
right: random(element-shared, 0px, 100000px);
margin: random(element-shared 0px, 100000px) random(element-shared 0px, 100000px);
}
.randomIdentifier {
width: random(--identifier, 0px, 100px);
height: random(--identifier, 0px, 100px);
left: random(--identifier, 0px, 100000px);
right: random(--identifier, 0px, 100000px);
margin: random(--identifier 0px, 100000px) random(--identifier 0px, 100000px);
}
.randomMatchElementAndIdentifier {
width: random(element-shared --other-identifier, 0px, 100px);
height: random(element-shared --other-identifier, 0px, 100px);
left: random(element-shared --other-identifier, 0px, 100000px);
right: random(element-shared --other-identifier, 0px, 100000px);
margin: random(element-shared --other-identifier 0px, 100000px) random(element-shared --other-identifier 0px, 100000px);
}
.randomFixed {
width: random(fixed 0.5, 10px, 100px);
height: random(fixed 0.5, 10px, 100px);
left: random(fixed 0.5, 0px, 100000px);
right: random(fixed 0.5, 0px, 100000px);
margin: random(fixed 0.5 0px, 100000px) random(fixed 0.5 0px, 100000px);
}
</style>
<script>
// Run each test a number of times to increase the likelyhood that failure is not the cause of random chance.
const iterations = 5;
function test_random_computed_value(property, specified, computed, titleExtra, options = {}) {
if (!computed)
computed = specified;
test(() => {
for (i = 0; i < iterations; ++i) {
const target = document.getElementById('target');
assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style");
assert_true(CSS.supports(property, specified), "'" + specified + "' is a supported value for " + property + ".");
target.style[property] = '';
target.style[property] = specified;
let readValue = getComputedStyle(target)[property];
if (options.comparisonFunction) {
options.comparisonFunction(readValue, computed);
} else if (Array.isArray(computed)) {
assert_in_array(readValue, computed);
} else {
assert_equals(readValue, computed);
}
if (readValue !== specified) {
target.style[property] = '';
target.style[property] = readValue;
assert_equals(getComputedStyle(target)[property], readValue,
'computed value should round-trip');
}
}
}, `Property ${property} value '${specified}'${titleExtra ? ' ' + titleExtra : ''}`);
}
function test_random_computed_value_greater_or_lower_than(property, specified, expected, titleExtra) {
test(() => {
for (i = 0; i < iterations; ++i) {
const target = document.getElementById('target');
assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style");
assert_true(CSS.supports(property, specified), "'" + specified + "' is a supported value for " + property + ".");
target.style[property] = '';
target.style[property] = specified;
let readValue = parseFloat(getComputedStyle(target)[property]);
assert_true(isFinite(readValue), specified + " expected finite value but got " + readValue)
assert_false(isNaN(readValue), specified + " expected finite value but got " + readValue)
if (expected > 0)
assert_greater_than_equal(readValue, expected, specified);
else
assert_less_than_equal(readValue, expected, specified);
}
}, `Property ${property} value '${specified}'${titleExtra ? ' ' + titleExtra : ''}`);
}
function test_random_computed_value_in_range(property, specified, computedMin, computedMax, titleExtra) {
test(() => {
for (i = 0; i < iterations; ++i) {
const target = document.getElementById('target');
assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style");
assert_true(CSS.supports(property, specified), "'" + specified + "' is a supported value for " + property + ".");
target.style[property] = '';
target.style[property] = specified;
let readValue = getComputedStyle(target)[property];
let readValueNumber = parseFloat(readValue);
let computedMinNumber = parseFloat(computedMin);
let computedMaxNumber = parseFloat(computedMax);
assert_greater_than_equal(readValueNumber, computedMinNumber, specified);
assert_less_than_equal(readValueNumber, computedMaxNumber, specified);
}
}, `Property ${property} value '${specified}'${titleExtra ? ' ' + titleExtra : ''}`);
}
function test_pseudo_element_random_computed_value_in_range(property, pseudo_element, specified, computedMin, computedMax, titleExtra) {
test(() => {
for (i = 0; i < iterations; ++i) {
const styleEl = document.head.appendChild(document.createElement("style"));
styleEl.innerHTML = `#target${pseudo_element} \{ ${property}: ${specified}; \}`;
try {
const target = document.getElementById("target");
let readValue = getComputedStyle(target, pseudo_element)[property];
let readValueNumber = parseFloat(readValue);
let computedMinNumber = parseFloat(computedMin);
let computedMaxNumber = parseFloat(computedMax);
assert_greater_than_equal(readValueNumber, computedMinNumber, specified);
assert_less_than_equal(readValueNumber, computedMaxNumber, specified);
} finally {
document.head.removeChild(styleEl);
}
}
}, `Property ${property} value on pseudo element '${pseudo_element}' '${specified}'${titleExtra ? ' ' + titleExtra : ''}`);
}
function test_random_computed_value_has_fixed(property, specified, minPercentage, maxPercentage, titleExtra) {
test(() => {
for (i = 0; i < iterations; ++i) {
const target = document.getElementById('target');
assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style");
assert_true(CSS.supports(property, specified), "'" + specified + "' is a supported value for " + property + ".");
target.style[property] = '';
target.style[property] = specified;
let readValue = getComputedStyle(target)[property];
// strip 'random(' and ')'.
let stippedReadValue = readValue.replace('random(', '').replace(')', '');
// split into the three main components
let [fixedComponent, minComponent, maxComponent] = stippedReadValue.split(', ');
// split fixed component into its two components
let [fixedString, fixedValue] = fixedComponent.split(' ');
assert_equals(fixedString, 'fixed', specified);
assert_greater_than_equal(parseFloat(fixedValue), '0', specified);
assert_less_than_equal(parseFloat(fixedValue), '1', specified);
assert_equals(minComponent, minPercentage, specified);
assert_equals(maxComponent, maxPercentage, specified);
}
}, `Property ${property} value '${specified}'${titleExtra ? ' ' + titleExtra : ''}`);
}
const property = 'scale';
test_random_computed_value_in_range(property, 'random(1, 11)', '1', '11');
test_random_computed_value_in_range(property, 'random(--foo, 2, 12)', '2', '12');
test_random_computed_value_in_range(property, 'random(--foo element-shared, 3, 13)', '3', '13');
test_random_computed_value_in_range(property, 'random(element-shared --foo, 4, 14)', '4', '14');
test_random_computed_value(property, 'random(0, 10, 5)', ['0', '5', '10']);
test_random_computed_value(property, 'random(--foo, 10, 20, 5)', ['10', '15', '20']);
test_random_computed_value(property, 'random(--foo element-shared, 20, 30, 5)', ['20', '25', '30']);
test_random_computed_value(property, 'random(element-shared --foo, 30, 40, 5)', ['30', '35', '40']);
// Test out of order.
test_random_computed_value(property, 'random(100, 10)', '100');
test_random_computed_value(property, 'random(-10, -100)', '-10');
// Test negative range values
test_random_computed_value_in_range(property, 'random(-100, -10)', '-100', '-10');
// Test negative step values (treated as if step is not there)
test_random_computed_value_in_range(property, 'random(40, 50, -5)', '40', '50');
// Test nested expressions
test_random_computed_value_in_range(property, 'random(5 * 1, 30 / 2)', '5', '15');
// Test nested in expressions
test_random_computed_value_in_range(property, 'calc(2 * random(6, 16))', '12', '32');
// Test NaN
test_random_computed_value(property, 'random(NaN, 100)', '0');
test_random_computed_value(property, 'random(10, NaN)', '0');
test_random_computed_value(property, 'random(NaN, NaN)', '0');
test_random_computed_value(property, 'random(NaN, 100, 10)', '0');
test_random_computed_value(property, 'random(10, NaN, 10)', '0');
test_random_computed_value(property, 'random(NaN, NaN, 10)', '0');
test_random_computed_value(property, 'random(NaN, 100, NaN)', '0');
test_random_computed_value(property, 'random(10, NaN, NaN)', '0');
test_random_computed_value(property, 'random(NaN, NaN, NaN)', '0');
test_random_computed_value(property, 'random(10, 100, NaN)', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, 100))', '0');
test_random_computed_value(property, 'calc(10 + random(10, NaN))', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, NaN))', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, 100, 10))', '0');
test_random_computed_value(property, 'calc(10 + random(10, NaN, 10))', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, NaN, 10))', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, 100, NaN))', '0');
test_random_computed_value(property, 'calc(10 + random(10, NaN, NaN))', '0');
test_random_computed_value(property, 'calc(10 + random(NaN, NaN, NaN))', '0');
test_random_computed_value(property, 'calc(10 + random(10, 100, NaN))', '0');
// Test infinity
const REALLY_LARGE = 1e6;
const REALLY_LARGE_NEGATIVE = -REALLY_LARGE;
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, 100)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, infinity)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, 100, 10)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, infinity, 10)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, 100, infinity)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'random(infinity, infinity, infinity)', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, 100))', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, infinity))', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, infinity, 10))', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, 100, infinity))', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, infinity, infinity))', REALLY_LARGE);
test_random_computed_value_greater_or_lower_than(property, 'calc(10 + random(infinity, 100, 10))', REALLY_LARGE);
test_random_computed_value(property, 'random(10, infinity)', '0');
test_random_computed_value(property, 'random(10, infinity, 10)', '0');
test_random_computed_value(property, 'random(10, infinity, infinity)', '0');
test_random_computed_value(property, 'calc(10 + random(10, infinity))', '0');
test_random_computed_value(property, 'calc(10 + random(10, infinity, 10))', '0');
test_random_computed_value(property, 'calc(10 + random(10, infinity, infinity))', '0');
test_random_computed_value(property, 'random(10, 100, infinity)', '0');
test_random_computed_value(property, 'calc(10 + random(10, 100, infinity))', '0');
// Negative steps, even infinitely negative steps, are ignored.
test_random_computed_value_in_range(property, 'random(10, 100, -infinity)', '10', '100');
test_random_computed_value_in_range(property, 'calc(10 + random(10, 100, -infinity))', '20', '110');
// Test pseudo on psuedo elements
test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(7, 17)', '7', '17');
test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(--bar, 8, 18)', '8', '18');
test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(element-shared, 9, 19)', '9', '19');
test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(element-shared --foo, 10, 20)', '10', '20');
// Test unresolvable percentage values
test_random_computed_value_has_fixed('translate', 'random(10%, 100%)', '10%', '100%');
// Test random value sharing
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
const el = document.createElement('div');
el.className = 'randomNoIdentifier';
holder.appendChild(el);
const elComputedLeft = getComputedStyle(el)['left'];
var allSame = true;
var allHaveSameLeftAndRight = true;
for (i = 0; i < iterations; ++i) {
const other = document.createElement('div');
other.className = 'randomNoIdentifier';
holder.appendChild(other);
const otherComputedLeft = getComputedStyle(other)['left'];
if (elComputedLeft != otherComputedLeft) {
allSame = false;
}
const otherComputedRight = getComputedStyle(other)['right'];
if (elComputedLeft != otherComputedRight) {
allHaveSameLeftAndRight = false;
}
}
assert_false(allSame);
assert_false(allHaveSameLeftAndRight);
} finally {
document.body.removeChild(holder);
}
}, `Maximum random: 'random(a, b)'`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
var allHaveSameMarginTopAndMarginLeft = true;
for (i = 0; i < iterations; ++i) {
const other = document.createElement('div');
other.className = 'randomNoIdentifier';
holder.appendChild(other);
const otherComputedMarginLeft = getComputedStyle(other)['margin-left'];
const otherComputedMarginTop = getComputedStyle(other)['margin-top'];
if (otherComputedMarginLeft != otherComputedMarginTop) {
allHaveSameMarginTopAndMarginLeft = false;
}
}
assert_false(allHaveSameMarginTopAndMarginLeft);
} finally {
document.body.removeChild(holder);
}
}, `Maximum random - shorthand: random(a, b))`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
for (i = 0; i < iterations; ++i) {
const el = document.createElement('div');
el.className = 'randomIdentifier';
holder.appendChild(el);
let elComputedWidth = getComputedStyle(el)['width'];
let elComputedHeight = getComputedStyle(el)['height'];
assert_equals(elComputedWidth, elComputedHeight);
}
} finally {
document.body.removeChild(holder);
}
}, `Shared by name within an element: 'random(--identifier, a, b)'`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
var allHaveSameMarginTopAndMarginLeft = true;
for (i = 0; i < iterations; ++i) {
const other = document.createElement('div');
other.className = 'randomIdentifier';
holder.appendChild(other);
const otherComputedMarginLeft = getComputedStyle(other)['margin-left'];
const otherComputedMarginTop = getComputedStyle(other)['margin-top'];
if (otherComputedMarginLeft != otherComputedMarginTop) {
allHaveSameMarginTopAndMarginLeft = false;
}
}
assert_true(allHaveSameMarginTopAndMarginLeft);
} finally {
document.body.removeChild(holder);
}
}, `Shared by name within an element - shorthand: random(--identifier, a, b))`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
for (i = 0; i < iterations; ++i) {
const t1 = document.createElement('div');
t1.className = 'randomMatchElement';
holder.appendChild(t1);
const t2 = document.createElement('div');
t2.className = 'randomMatchElement';
holder.appendChild(t2);
let t1ComputedWidth = getComputedStyle(t1)['width'];
let t2ComputedWidth = getComputedStyle(t2)['width'];
assert_equals(t1ComputedWidth, t2ComputedWidth);
}
} finally {
document.body.removeChild(holder);
}
}, `Shared between elements within a property: random(element-shared, a, b)`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
var allHaveSameMarginTopAndMarginLeft = true;
for (i = 0; i < iterations; ++i) {
const other = document.createElement('div');
other.className = 'randomMatchElement';
holder.appendChild(other);
const otherComputedMarginLeft = getComputedStyle(other)['margin-left'];
const otherComputedMarginTop = getComputedStyle(other)['margin-top'];
if (otherComputedMarginLeft != otherComputedMarginTop) {
allHaveSameMarginTopAndMarginLeft = false;
}
}
assert_true(allHaveSameMarginTopAndMarginLeft);
} finally {
document.body.removeChild(holder);
}
}, `Shared between elements within a property - shorthand: random(element-shared, a, b))`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
for (i = 0; i < iterations; ++i) {
const t1 = document.createElement('div');
t1.className = 'randomMatchElementAndIdentifier';
holder.appendChild(t1);
const t2 = document.createElement('div');
t2.className = 'randomMatchElementAndIdentifier';
holder.appendChild(t2);
let t1ComputedWidth = getComputedStyle(t1)['width'];
let t2ComputedHeight = getComputedStyle(t2)['height'];
assert_equals(t1ComputedWidth, t2ComputedHeight);
}
} finally {
document.body.removeChild(holder);
}
}, `Shared globally: random(--identifier element-shared, a, b)`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
var allHaveSameMarginTopAndMarginLeft = true;
for (i = 0; i < iterations; ++i) {
const other = document.createElement('div');
other.className = 'randomMatchElementAndIdentifier';
holder.appendChild(other);
const otherComputedMarginLeft = getComputedStyle(other)['margin-left'];
const otherComputedMarginTop = getComputedStyle(other)['margin-top'];
if (otherComputedMarginLeft != otherComputedMarginTop) {
allHaveSameMarginTopAndMarginLeft = false;
}
}
assert_true(allHaveSameMarginTopAndMarginLeft);
} finally {
document.body.removeChild(holder);
}
}, `Shared globally - shorthand: random(element-shared, a, b))`);
test(() => {
const holder = document.createElement('div');
document.body.appendChild(holder);
try {
for (i = 0; i < iterations; ++i) {
const t1 = document.createElement('div');
t1.className = 'randomFixed';
holder.appendChild(t1);
let t1ComputedWidth = getComputedStyle(t1)['width'];
assert_equals(t1ComputedWidth, "55px");
}
} finally {
document.body.removeChild(holder);
}
}, `Fixed: random(fixed <number>, a, b)`);
</script>