474 lines
20 KiB
HTML
474 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<link rel="help" href="https://drafts.csswg.org/css-values-5/#random">
|
|
<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>
|