| <!DOCTYPE html> | |
| <link rel="help" href="https://drafts.csswg.org/css-values-5/#random"> | |
| <link rel="author" title="sam@webkit.org"> | |
| <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> | |
| <iframe id="iframe" srcdoc="<div id=target>"></iframe> | |
| <style> | |
| @property --x { | |
| syntax: "<number>"; | |
| inherits: true; | |
| initial-value: 3; | |
| } | |
| @property --y { | |
| syntax: "<number>"; | |
| inherits: true; | |
| initial-value: 3; | |
| } | |
| @property --random-length-1 { | |
| syntax: "<length>"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --random-length-2 { | |
| syntax: "<length>"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --random-in-initial { | |
| syntax: "<number>"; | |
| inherits: false; | |
| initial-value: random(1, 30); | |
| } | |
| @property --percent { | |
| syntax: "<percentage>"; | |
| inherits: true; | |
| initial-value: 3%; | |
| } | |
| @property --len-a { | |
| syntax: "<length>"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --len-b { | |
| syntax: "<length>"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --len-list { | |
| syntax: "<length>+"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --len-scoped { | |
| syntax: "<length>"; | |
| inherits: true; | |
| initial-value: 3px; | |
| } | |
| @property --transform-function { | |
| syntax: "<transform-function>"; | |
| inherits: true; | |
| initial-value: translate(3%); | |
| } | |
| #container { | |
| font-size: 30px; | |
| } | |
| .randomNoIdentifier { | |
| width: random(0px, 300000px); | |
| height: random(0px, 300000px); | |
| left: random(0px, 300000px); | |
| right: random(0px, 300000px); | |
| margin: random(0px, 300000px) random(0px, 300000px); | |
| --x: random(0, 300000); | |
| --y: random(0, 300000); | |
| --random-length-1: random(fixed random(0, 1), 0px, 100px); | |
| --random-length-2: random(fixed random(0, 1), 0px, 100px); | |
| } | |
| .randomNoIdentifierPercent { | |
| left: random(0%, 100%); | |
| top: random(0%, 100%); | |
| } | |
| .randomCustomLength { | |
| width: random(0px, 300000px); | |
| --len-a: random(0px, 300000px); | |
| --len-b: random(0px, 300000px); | |
| --len-list: random(0px, 300000px) random(0px, 300000px); | |
| --len-scoped: random(property-scoped, 0px, 300000px); | |
| } | |
| .randomMatchElement { | |
| width: random(property-index-scoped, 0px, 300000px); | |
| height: random(property-index-scoped, 0px, 300000px); | |
| left: random(property-index-scoped, 0px, 300000px); | |
| right: random(property-index-scoped, 0px, 300000px); | |
| margin: random(property-index-scoped, 0px, 300000px) random(property-index-scoped, 0px, 300000px); | |
| translate: random(property-index-scoped, 0%, 300000%); | |
| scale: random(property-index-scoped, 1, 300000) random(property-index-scoped, 1, 300000); | |
| } | |
| .randomIdentifier { | |
| width: random(--identifier element-scoped, 0px, 300000px); | |
| height: random(--identifier element-scoped, 0px, 300000px); | |
| left: random(--identifier element-scoped, 0px, 300000px); | |
| right: random(--identifier element-scoped, 0px, 300000px); | |
| margin: random(--identifier element-scoped, 0px, 300000px) random(--identifier element-scoped, 0px, 300000px); | |
| } | |
| .randomMatchElementAndIdentifier { | |
| width: random(--other-identifier, 0px, 300000px); | |
| height: random(--other-identifier, 0px, 300000px); | |
| left: random(--other-identifier, 0px, 300000px); | |
| right: random(--other-identifier, 0px, 300000px); | |
| margin: random(--other-identifier, 0px, 300000px) random(--other-identifier, 0px, 300000px); | |
| } | |
| .randomFixed { | |
| width: random(fixed 0.5, 0px, 300000px); | |
| height: random(fixed 0.5, 0px, 300000px); | |
| left: random(fixed 0.5, 0px, 300000px); | |
| right: random(fixed 0.5, 0px, 300000px); | |
| margin: random(fixed 0.5, 0px, 300000px) random(fixed 0.5, 0px, 300000px); | |
| } | |
| </style> | |
| <script> | |
| // Run each test a number of times to increase the likelyhood that failure is not the cause of random chance. | |
| // Should only be used if we cannot increase random() range. | |
| const ITERATIONS = 5; | |
| // Since actual and expected values are generated randomly, `assert_equals()` | |
| // does not generate deterministic test failure output. Chrome relies on test | |
| // failure output to be deterministic and stable for failing test expectations. | |
| function test_random_equals(actual, expected, message = "Random values should be equal") { | |
| assert_true(actual == expected, message); | |
| } | |
| function test_random_not_equals(actual, expected, message = "Random values should not be equal") { | |
| assert_false(actual == expected, message); | |
| } | |
| 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'); | |
| if (!property.startsWith('--')) { | |
| 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.setProperty(property, ''); | |
| target.style.setProperty(property, specified); | |
| let readValue = getComputedStyle(target).getPropertyValue(property); | |
| if (options.comparisonFunction) { | |
| options.comparisonFunction(readValue, computed); | |
| } else if (Array.isArray(computed)) { | |
| assert_in_array(readValue, computed); | |
| } else { | |
| test_random_equals(readValue, computed); | |
| } | |
| if (readValue !== specified) { | |
| target.style.setProperty(property, ''); | |
| target.style.setProperty(property, readValue); | |
| test_random_equals(getComputedStyle(target).getPropertyValue(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'); | |
| if (!property.startsWith('--')) { | |
| 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.setProperty(property, ''); | |
| target.style.setProperty(property, specified); | |
| let readValue = getComputedStyle(target).getPropertyValue(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(() => { | |
| 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, expectedFixedValue = undefined, titleExtra = undefined) { | |
| test(() => { | |
| for (i = 0; i < ITERATIONS; ++i) { | |
| const target = document.getElementById('target'); | |
| if (!property.startsWith('--')) { | |
| 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.setProperty(property, ''); | |
| target.style.setProperty(property, specified); | |
| let readValue = getComputedStyle(target).getPropertyValue(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(' '); | |
| // Use assert_true so that error message is deterministic. | |
| assert_true(fixedString == 'fixed', `Computed value for ${specified} should include 'fixed'`); | |
| if (expectedFixedValue) { | |
| test_random_equals(parseFloat(fixedValue), expectedFixedValue, `Random value for ${specified} should be ${expectedFixedValue}`); | |
| } else { | |
| assert_greater_than_equal(parseFloat(fixedValue), 0, specified); | |
| assert_less_than(parseFloat(fixedValue), 1, specified); | |
| } | |
| test_random_equals(minComponent, minPercentage, specified); | |
| test_random_equals(maxComponent, maxPercentage, specified); | |
| } | |
| }, `Property ${property} value '${specified}'${titleExtra ? ' ' + titleExtra : ''}`); | |
| } | |
| function test_random_base_is_not_1(property, specified, max) { | |
| test(() => { | |
| 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; | |
| const computed = target.computedStyleMap().get(property); | |
| assert_true(computed instanceof CSSUnitValue); | |
| assert_false(computed.value == max, "Random base value should not be clamped to 1"); | |
| }, `Property ${property} value '${specified}'`); | |
| } | |
| function test_random_shared_by_property(property, random_value, random_element_shared_value, iterations = 1) { | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| var randomValuesSameOnDifferentElements = true; | |
| try { | |
| for (let i = 0; i < iterations; ++i) { | |
| const t1 = document.createElement('div'); | |
| holder.appendChild(t1); | |
| const t2 = document.createElement('div'); | |
| holder.appendChild(t2); | |
| t1.style[property] = random_value; | |
| t2.style[property] = random_value; | |
| let t1Computed = getComputedStyle(t1)[property]; | |
| let t2Computed = getComputedStyle(t2)[property]; | |
| if (t1Computed != t2Computed) { | |
| randomValuesSameOnDifferentElements = false; | |
| } | |
| t1.style[property] = random_element_shared_value; | |
| t2.style[property] = random_element_shared_value; | |
| let t1ComputedElementShared = getComputedStyle(t1)[property]; | |
| let t2ComputedElementShared = getComputedStyle(t2)[property]; | |
| test_random_equals(t1ComputedElementShared, t2ComputedElementShared, | |
| `${random_element_shared_value} values on different elements should be equal`); | |
| } | |
| assert_false(randomValuesSameOnDifferentElements, | |
| `${random_value} values on different elements should not be equal`); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by property '${property}' with values '${random_value}', '${random_element_shared_value}'`); | |
| } | |
| function test_random_cross_document(property, specified) { | |
| test(() => { | |
| for (let i = 0; i < ITERATIONS; ++i) { | |
| target.style.setProperty(property, ''); | |
| target.style.setProperty(property, specified); | |
| iframe.contentWindow.target.style.setProperty(property, ''); | |
| iframe.contentWindow.target.style.setProperty(property, specified); | |
| let selfComputed = getComputedStyle(target).getPropertyValue(property); | |
| let iframeComputed = iframe.contentWindow.getComputedStyle(iframe.contentWindow.target).getPropertyValue(property); | |
| test_random_not_equals(selfComputed, iframeComputed); | |
| target.style.setProperty(property, ''); | |
| iframe.contentWindow.target.style.setProperty(property, ''); | |
| } | |
| }, `Property ${property} value '${specified}' differs across documents`); | |
| } | |
| const property = 'scale'; | |
| test_random_computed_value_in_range(property, 'random(1, 11)', '1', '11'); | |
| test_random_computed_value_in_range(property, 'random(--foo element-scoped, 2, 12)', '2', '12'); | |
| test_random_computed_value_in_range(property, 'random(--foo, 3, 13)', '3', '13'); | |
| test_random_computed_value_in_range(property, 'random(--foo, 4, 14)', '4', '14'); | |
| test_random_computed_value(property, 'random(0, 10, 5)', ['0', '5', '10']); | |
| test_random_computed_value(property, 'random(--foo element-scoped, 10, 20, 5)', ['10', '15', '20']); | |
| test_random_computed_value(property, 'random(--foo, 20, 30, 5)', ['20', '25', '30']); | |
| test_random_computed_value(property, 'random(--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)', '10'); | |
| test_random_computed_value(property, 'calc(10 + random(10, 100, infinity))', '20'); | |
| // 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(1, 300000)', '1', '300000'); | |
| test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(--bar element-scoped, 1, 300000)', '1', '300000'); | |
| test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(property-index-scoped, 1, 300000)', '1', '300000'); | |
| test_pseudo_element_random_computed_value_in_range(property, '::before', 'random(--foo, 1, 300000)', '1', '300000'); | |
| // Test unresolvable percentage values | |
| test_random_computed_value_has_fixed('translate', 'random(10%, 100%)', '10%', '100%'); | |
| test_random_computed_value_has_fixed('translate', 'random(3 * 10% , 10 * 10%)', '30%', '100%'); | |
| test_random_computed_value_has_fixed('translate', 'random(10%, 1%)', '10%', '1%'); | |
| test_random_computed_value_has_fixed('translate', 'random(--identifier, 10%, 100%)', '10%', '100%'); | |
| test_random_computed_value_has_fixed('text-indent', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('flex-basis', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('offset-distance', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('shape-margin', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('stroke-dasharray', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('stroke-dashoffset', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('stroke-width', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('background-position-x', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('background-position-y', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('border-top-left-radius', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('border-top-right-radius', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('border-bottom-left-radius', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('border-bottom-right-radius', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('scroll-padding-top', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('scroll-padding-bottom', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('scroll-padding-left', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('scroll-padding-right', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('cx', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('cy', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('rx', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('ry', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('x', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('y', 'random(10%, 30%)', '10%', '30%'); | |
| test_random_computed_value_has_fixed('border-image-slice', 'random(10%, 30%)', '10%', '30%'); | |
| // Test resolvable percentage values | |
| test_random_computed_value('background-color', 'rgb(225, 215, 0, random(30%, 10%))', 'rgba(225, 215, 0, 0.3)'); | |
| test_random_computed_value('font-size', 'random(30%, 10%)', '9px'); | |
| test_random_computed_value('font-size', 'random(10px * 10% / 1%, 0%)', '100px'); | |
| test_random_computed_value_in_range('--percent', 'random(10%, 30%)', '10%', '30%'); | |
| // Test out of range math functions for fixed value | |
| test_random_base_is_not_1('width', 'random(fixed random(1, 2), 10px, 100px)', 100); | |
| test_random_computed_value_has_fixed('translate', 'random(fixed random(-2, -1), 10%, 100%)', '10%', '100%', 0); | |
| // Random inside function | |
| test_random_computed_value('color', 'rgb(random(30, 10) random(60, 10) random(90, 10))', 'rgb(30, 60, 90)'); | |
| test_random_computed_value('color', 'rgb(from blue random(51, 10) random(g + 51, g) random(b, b))', 'color(srgb 0.2 0.2 1)'); | |
| test_random_computed_value('color', 'color-mix(in srgb, rgb(random(30, 10) 0 0), rgb(random(21, 10) 0 0))', 'color(srgb 0.1 0 0)'); | |
| test_random_computed_value('math-depth', 'add(random(30, 10))', '30'); | |
| test_random_computed_value('view-transition-name', 'ident("myident" random(30, 10))', 'myident30'); | |
| test_random_computed_value('background-image', 'image-set(url("http://does-not-exist.test/image.png") calc(random(fixed 0.3, 0, 10) * 1x))', 'image-set(url("http://does-not-exist.test/image.png") 3dppx)'); | |
| test_random_computed_value('aspect-ratio', 'random(3, 1) / random(9, 6)', '3 / 9'); | |
| test_random_computed_value('filter', 'drop-shadow(random(3px, 1px) random(6px, 1px) random(9px, 1px) black)', 'drop-shadow(rgb(0, 0, 0) 3px 6px 9px)'); | |
| test_random_computed_value('font-variation-settings', '"wght" random(300, 100)', '"wght" 300'); | |
| test_random_computed_value('font-feature-settings', '"liga" random(3, 1)', '"liga" 3'); | |
| test_random_computed_value('font-style', 'oblique random(90deg, 10deg)', 'oblique 90deg'); | |
| test_random_computed_value('font-palette', 'palette-mix(in lch, --blue calc(90% * random(1, 0)), --yellow 10%)', 'palette-mix(in lch, --blue 90%, --yellow 10%)'); | |
| test_random_computed_value('font-palette', 'palette-mix(in lch, --blue random(90%, 10%), --yellow 10%)', 'palette-mix(in lch, --blue 90%, --yellow 10%)'); | |
| test_random_computed_value('animation-timeline', 'view(random(10px, 10px) random(30px, 10px))', 'view(10px 30px)'); | |
| test_random_computed_value('color', 'light-dark(rgb(random(30, 10) random(60, 10) random(90, 10)), rgb(random(30, 10) random(60, 10) random(90, 10)))', | |
| 'rgb(30, 60, 90)'); | |
| test_random_computed_value('rotate', | |
| 'random(1, 0) random(1, 0) 1 90deg', | |
| '1 1 1 90deg'); | |
| test_random_computed_value('rotate', | |
| 'x random(90deg, 30deg)', | |
| 'x 90deg'); | |
| test_random_computed_value('corner-shape', | |
| 'superellipse(random(3, 1))', | |
| 'superellipse(3)'); | |
| test_random_computed_value('offset-path', | |
| 'ray(random(30deg, 10deg))', | |
| 'ray(30deg)'); | |
| test_random_shared_by_property('color', | |
| 'color-mix(in srgb, rgb(from blue random(10, 30) random(g, g + 30) random(b, b)), rgb(random(10, 90) 0 0))', | |
| 'color-mix(in srgb, rgb(from blue random(property-index-scoped, 10, 30) random(property-index-scoped, g, g + 30) random(property-index-scoped, b, b)), rgb(random(property-index-scoped, 10, 90) 0 0))', | |
| ITERATIONS); | |
| test_random_shared_by_property('math-depth', | |
| 'add(random(1, 100))', | |
| 'add(random(property-index-scoped, 1, 100))', | |
| ITERATIONS); | |
| test_random_shared_by_property('view-transition-name', | |
| 'ident("myident" random(1, 300000))', | |
| 'ident("myident" random(property-index-scoped, 1, 300000))'); | |
| test_random_shared_by_property('aspect-ratio', | |
| 'random(1, 3000000, 1) / random(3000000, 9000000, 1)', | |
| 'random(property-index-scoped, 1, 3000000, 1) / random(property-index-scoped, 3000000, 9000000, 1)'); | |
| test_random_shared_by_property('filter', | |
| 'drop-shadow(random(1px, 300000px) random(1px, 600000px) random(1px, 900000px) black)', | |
| 'drop-shadow(random(property-index-scoped, 1px, 300000px) random(property-index-scoped, 1px, 600000px) random(property-index-scoped, 1px, 900000px) black)'); | |
| test_random_shared_by_property('font-variation-settings', | |
| '"wght" random(100, 900)', | |
| '"wght" random(property-index-scoped, 100, 900)', | |
| ITERATIONS); | |
| test_random_shared_by_property('font-style', | |
| 'oblique random(10deg, 90deg)', | |
| 'oblique random(property-index-scoped, 10deg, 90deg)', | |
| ITERATIONS); | |
| test_random_shared_by_property('font-palette', | |
| 'palette-mix(in lch, --blue calc(90% * random(0, 1)), --yellow)', | |
| 'palette-mix(in lch, --blue calc(90% * random(property-index-scoped, 0, 1)), --yellow)', | |
| ITERATIONS); | |
| test_random_shared_by_property('font-palette', | |
| 'palette-mix(in lch, --blue random(10%, 90%), --yellow)', | |
| 'palette-mix(in lch, --blue random(property-index-scoped, 10%, 90%), --yellow)', | |
| ITERATIONS); | |
| test_random_shared_by_property('animation-timeline', | |
| 'view(random(1px, 300000px) random(300000px, 600000px))', | |
| 'view(random(property-index-scoped, 1px, 300000px) random(property-index-scoped, 300000px, 600000px))'); | |
| test_random_shared_by_property('color', | |
| 'light-dark(rgb(random(10, 30) random(10, 60) random(10, 90)), rgb(random(30, 10) random(60, 10) random(90, 10)))', | |
| `light-dark(rgb(random(property-index-scoped, 10, 30) random(property-index-scoped, 10, 60) random(property-index-scoped, 10, 90)), | |
| rgb(random(property-index-scoped, 30, 10) random(property-index-scoped, 60, 10) random(property-index-scoped, 90, 10)))`, | |
| ITERATIONS); | |
| // 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']; | |
| const other = document.createElement('div'); | |
| other.className = 'randomNoIdentifier'; | |
| holder.appendChild(other); | |
| const otherComputedLeft = getComputedStyle(other)['left']; | |
| test_random_not_equals(elComputedLeft, otherComputedLeft); | |
| const otherComputedRight = getComputedStyle(other)['right']; | |
| test_random_not_equals(elComputedLeft, otherComputedRight); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Maximum random: 'random(a, b)'`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const other = document.createElement('div'); | |
| other.className = 'randomNoIdentifier'; | |
| holder.appendChild(other); | |
| const otherComputedMarginLeft = getComputedStyle(other)['margin-left']; | |
| const otherComputedMarginTop = getComputedStyle(other)['margin-top']; | |
| const otherComputedMarginBottom = getComputedStyle(other)['margin-bottom']; | |
| test_random_not_equals(otherComputedMarginLeft, otherComputedMarginTop); | |
| test_random_equals(otherComputedMarginBottom, otherComputedMarginTop); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Maximum random - shorthand: random(a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const other1 = document.createElement('div'); | |
| other1.style.animationIterationCount = 'random(property-index-scoped, 0, 300000), random(property-index-scoped, 0, 300000)'; | |
| holder.appendChild(other1); | |
| const other2 = document.createElement('div'); | |
| other2.style.animationIterationCount = '300, random(property-index-scoped, 0, 300000)'; | |
| holder.appendChild(other2); | |
| let [computed11, computed12] = getComputedStyle(other1)['animation-iteration-count'].split(', '); | |
| let [computed21, computed22] = getComputedStyle(other2)['animation-iteration-count'].split(', '); | |
| test_random_not_equals(computed11, computed12, | |
| "Random values for same property name but different value indexes should differ"); | |
| test_random_equals(computed11, computed22); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by property name and value index: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomMatchElement'; | |
| holder.appendChild(el); | |
| const other = document.createElement('div'); | |
| other.className = 'randomMatchElement'; | |
| holder.appendChild(other); | |
| const elScale = getComputedStyle(el)['scale']; | |
| const otherScale = getComputedStyle(other)['scale']; | |
| test_random_equals(elScale, otherScale, | |
| "random() values should be equal on same position in the list on same property"); | |
| let [scaleX, scaleY] = otherScale.split(' '); | |
| test_random_not_equals(scaleX, scaleY, | |
| "random() values should not be equal on different positions in the list on same property"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by property and index in list value: random(a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| var allSame = true; | |
| for (i = 0; i < ITERATIONS; ++i) { | |
| const el = document.createElement('div'); | |
| el.className = 'randomNoIdentifier'; | |
| holder.appendChild(el); | |
| const elComputedLength1 = getComputedStyle(el).getPropertyValue('--random-length-1'); | |
| const elComputedLength2 = getComputedStyle(el).getPropertyValue('--random-length-2'); | |
| if (elComputedLength1 != elComputedLength2) { | |
| allSame = false; | |
| } | |
| } | |
| assert_false(allSame, "Different custom properties on the same element should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Nested in fixed value random() function used for custom property: 'random(a, b)'`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomNoIdentifier'; | |
| holder.appendChild(el); | |
| const elComputedX = getComputedStyle(el).getPropertyValue('--x'); | |
| const elComputedY = getComputedStyle(el).getPropertyValue('--y'); | |
| test_random_not_equals(elComputedX, elComputedY, | |
| "Different custom properties on the same element should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() in different custom properties on the same element should not be shared`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomCustomLength'; | |
| holder.appendChild(el); | |
| const computedA = getComputedStyle(el).getPropertyValue('--len-a'); | |
| const computedB = getComputedStyle(el).getPropertyValue('--len-b'); | |
| test_random_not_equals(computedA, computedB, | |
| "Different registered <length> custom properties on the same element should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() in different registered <length> custom properties on the same element should not be shared`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomCustomLength'; | |
| holder.appendChild(el); | |
| const other = document.createElement('div'); | |
| other.className = 'randomCustomLength'; | |
| holder.appendChild(other); | |
| const elComputed = getComputedStyle(el).getPropertyValue('--len-a'); | |
| const otherComputed = getComputedStyle(other).getPropertyValue('--len-a'); | |
| test_random_not_equals(elComputed, otherComputed, | |
| "The same custom property on different elements should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() in a custom property should be element-scoped by default`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomCustomLength'; | |
| holder.appendChild(el); | |
| // Both are the first random() in their own property, so these only differ if the caching key | |
| // distinguishes a custom property from a non-custom one. | |
| const computedWidth = getComputedStyle(el)['width']; | |
| const computedLength = getComputedStyle(el).getPropertyValue('--len-a'); | |
| test_random_not_equals(computedWidth, computedLength, | |
| "A custom property and a non-custom property should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() in a custom property should not be shared with a non-custom property at the same index`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomCustomLength'; | |
| holder.appendChild(el); | |
| const other = document.createElement('div'); | |
| other.className = 'randomCustomLength'; | |
| holder.appendChild(other); | |
| const elComputed = getComputedStyle(el).getPropertyValue('--len-scoped'); | |
| const otherComputed = getComputedStyle(other).getPropertyValue('--len-scoped'); | |
| test_random_equals(elComputed, otherComputed); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random(property-scoped, ...) in a custom property should be equal between elements`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomCustomLength'; | |
| holder.appendChild(el); | |
| const [first, second] = getComputedStyle(el).getPropertyValue('--len-list').split(' '); | |
| test_random_not_equals(first, second, | |
| "Two random() functions in one custom property should not have equal values"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `two random() functions in the same custom property should not be shared`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.style.setProperty('--len-a', 'random(0px, 300000px)'); | |
| // The author-supplied <dashed-ident> happens to name the other property. It is a separate | |
| // namespace from the property a key is implicitly scoped to, so these must not collide. | |
| el.style.setProperty('--len-b', 'random(--len-a, 0px, 300000px)'); | |
| holder.appendChild(el); | |
| const computedA = getComputedStyle(el).getPropertyValue('--len-a'); | |
| const computedB = getComputedStyle(el).getPropertyValue('--len-b'); | |
| test_random_not_equals(computedA, computedB, | |
| "An implicit property scope should not collide with an author <dashed-ident> of the same name"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() keyed on a custom property should not collide with an author <dashed-ident> naming it`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomIdentifier'; | |
| holder.appendChild(el); | |
| let elComputedWidth = getComputedStyle(el)['width']; | |
| let elComputedHeight = getComputedStyle(el)['height']; | |
| test_random_equals(elComputedWidth, elComputedHeight, | |
| "width and height values on same element should be equal"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by name within an element: 'random(--identifier element-scoped, a, b)'`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const other = document.createElement('div'); | |
| other.className = 'randomIdentifier'; | |
| holder.appendChild(other); | |
| const otherComputedMarginLeft = getComputedStyle(other)['margin-left']; | |
| const otherComputedMarginTop = getComputedStyle(other)['margin-top']; | |
| test_random_equals(otherComputedMarginLeft, otherComputedMarginTop); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by name within an element - shorthand: random(--identifier element-scoped, a, b))`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| 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']; | |
| test_random_equals(t1ComputedWidth, t2ComputedWidth, | |
| "width values on different elements should be equal"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared between elements within a property: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| var allSame = true; | |
| try { | |
| for (let i = 0; i < ITERATIONS; ++i) { | |
| const t1 = document.createElement('div'); | |
| t1.style['color'] = 'color-mix(in srgb, rgb(0 random(0, 255) 0) 50%, rgb(random(0, 255) 0 0) 50%)'; | |
| holder.appendChild(t1); | |
| let t1ComputedColor = getComputedStyle(t1)['color']; | |
| let [r, g, b] = t1ComputedColor.replace('color(srgb ', '').split(' '); | |
| if (r != g) { | |
| allSame = false; | |
| } | |
| } | |
| assert_false(allSame, | |
| "random() values on different positions should not be equal"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared between elements within a property, random inside color functions: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| 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)['translate']; | |
| let t2ComputedWidth = getComputedStyle(t2)['translate']; | |
| test_random_equals(t1ComputedWidth, t2ComputedWidth, | |
| "translate values with percentages on different elements should be equal"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared between elements within a property, unresolved percentage values: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const other = document.createElement('div'); | |
| other.className = 'randomMatchElement'; | |
| holder.appendChild(other); | |
| const otherComputedMarginLeft = getComputedStyle(other)['margin-left']; | |
| const otherComputedMarginRight = getComputedStyle(other)['margin-right']; | |
| const otherComputedMarginTop = getComputedStyle(other)['margin-top']; | |
| const otherComputedMarginBottom = getComputedStyle(other)['margin-bottom']; | |
| test_random_equals(otherComputedMarginLeft, otherComputedMarginRight); | |
| test_random_equals(otherComputedMarginTop, otherComputedMarginBottom); | |
| test_random_not_equals(otherComputedMarginLeft, otherComputedMarginTop); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared between elements within a property - shorthand: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| 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']; | |
| test_random_equals(t1ComputedWidth, t2ComputedHeight, | |
| "width and height values on different elements should be equal"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared globally: random(--identifier, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomMatchElementAndIdentifier'; | |
| holder.appendChild(el); | |
| const elComputedMarginLeft = getComputedStyle(el)['margin-left']; | |
| const elComputedMarginTop = getComputedStyle(el)['margin-top']; | |
| test_random_equals(elComputedMarginLeft, elComputedMarginTop); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared globally - shorthand: random(--other-identifier, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomNoIdentifierPercent'; | |
| holder.appendChild(el); | |
| const elComputedLeft = getComputedStyle(el)['left']; | |
| const elComputedTop = getComputedStyle(el)['top']; | |
| test_random_not_equals(elComputedLeft, elComputedTop); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Different between properties with percentage value: random(0%, 100%)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.className = 'randomNoIdentifierPercent'; | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.className = 'randomNoIdentifierPercent'; | |
| holder.appendChild(el2); | |
| const el1ComputedLeft = getComputedStyle(el1)['left']; | |
| const el2ComputedLeft = getComputedStyle(el2)['left']; | |
| test_random_not_equals(el1ComputedLeft, el2ComputedLeft, | |
| "random() with percentages should differ on different elements"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Different between elements with percentage value: random(0%, 100%)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.style['margin'] = 'random(property-index-scoped, 1px, 300000px)'; | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.style['margin-top'] = 'random(property-index-scoped, 1px, 300000px)'; | |
| holder.appendChild(el2); | |
| const el1ComputedMargin = getComputedStyle(el1)['margin']; | |
| const el2ComputedMarginTop = getComputedStyle(el2)['margin-top']; | |
| test_random_not_equals(el1ComputedMargin, el2ComputedMarginTop, | |
| "random() should not be shared between longhand and shorthand"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by property - shorthand and longhand: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.style['margin-block-start'] = 'random(property-index-scoped, 1px, 300000px)'; | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.style['margin-top'] = 'random(property-index-scoped, 1px, 300000px)'; | |
| holder.appendChild(el2); | |
| const el1ComputedMargin = getComputedStyle(el1)['margin-block-start']; | |
| const el2ComputedMarginTop = getComputedStyle(el2)['margin-top']; | |
| test_random_not_equals(el1ComputedMargin, el2ComputedMarginTop, | |
| "random() should not be shared between logical and physical properties"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Shared by property - logical and physical property: random(property-index-scoped, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const t1 = document.createElement('div'); | |
| t1.className = 'randomFixed'; | |
| holder.appendChild(t1); | |
| let t1ComputedWidth = getComputedStyle(t1)['width']; | |
| test_random_equals(t1ComputedWidth, "150000px", "Random value with fixed should be 150000px"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Fixed: random(fixed <number>, a, b)`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.style.setProperty('--transform-function', 'translate(random(30%, 10%))'); | |
| holder.appendChild(el); | |
| let computed = getComputedStyle(el).getPropertyValue('--transform-function'); | |
| test_random_equals(computed, "translate(30%)"); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Custom property with random() inside transform() should not have 'fixed'`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.style.setProperty('background-image', 'radial-gradient(at 30% random(33%, 1%), silver random(30%, 10%, 1%), gold random(70%, 10%, 1%))'); | |
| holder.appendChild(el); | |
| let computed = getComputedStyle(el).getPropertyValue('background-image'); | |
| const re = /radial-gradient\(at 30% random\(fixed 0.\d+, 33%, 1%\), rgb\(192, 192, 192\) 30%, rgb\(255, 215, 0\) 70%\)/; | |
| assert_true(re.test(computed)); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() with percentages inside multiple nested functions should have 'fixed'`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomIdentifier'; | |
| holder.appendChild(el); | |
| const elComputedHeight = getComputedStyle(el)['height']; | |
| const other = document.createElement('div'); | |
| other.className = 'randomIdentifier'; | |
| holder.appendChild(other); | |
| const otherComputedHeight = getComputedStyle(other)['height']; | |
| test_random_not_equals(elComputedHeight, otherComputedHeight); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random(--identifier element-scoped, ...) should be different between elements`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.className = 'randomNoIdentifier'; | |
| holder.appendChild(el); | |
| // The initial-value is invalid, so the @property rule registers nothing and the property is | |
| // left unregistered, which reads back as the empty string. | |
| const computedValue = getComputedStyle(el).getPropertyValue('--random-in-initial'); | |
| test_random_equals(computedValue, ''); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() values should not be allowed as initial values in @property`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.style.setProperty('--unregistered1', 'random(property-index-scoped, 1, 300000)'); | |
| el1.style.setProperty('scale', 'var(--unregistered1)'); | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.style.setProperty('--unregistered2', 'random(property-index-scoped, 1, 300000)'); | |
| el2.style.setProperty('scale', 'var(--unregistered2)'); | |
| holder.appendChild(el2); | |
| const el1ComputedScale = getComputedStyle(el1)['scale']; | |
| const el2ComputedScale = getComputedStyle(el2)['scale']; | |
| test_random_equals(el1ComputedScale, el2ComputedScale); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() shared by property in var()`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| holder.style.setProperty('--unregistered', 'random(property-index-scoped, 1, 300000)'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.style.setProperty('--x', 'var(--unregistered)'); | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.style.setProperty('--x', 'random(property-index-scoped, 1, 300000)'); | |
| holder.appendChild(el2); | |
| const el3 = document.createElement('div'); | |
| el3.style.setProperty('--y', 'var(--unregistered)'); | |
| holder.appendChild(el3); | |
| const el1ComputedX = getComputedStyle(el1).getPropertyValue('--x'); | |
| const el2ComputedX = getComputedStyle(el2).getPropertyValue('--x'); | |
| const el3ComputedY = getComputedStyle(el3).getPropertyValue('--y'); | |
| test_random_equals(el1ComputedX, el2ComputedX); | |
| test_random_not_equals(el1ComputedX, el3ComputedY); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() shared by custom property in var()`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el = document.createElement('div'); | |
| el.style.setProperty('--unregistered', 'random(1px, 300000px)'); | |
| el.style.setProperty('margin', 'var(--unregistered) var(--unregistered)'); | |
| holder.appendChild(el); | |
| const elComputedMarginTop = getComputedStyle(el)['margin-top']; | |
| const elComputedMarginLeft = getComputedStyle(el)['margin-left']; | |
| test_random_not_equals(elComputedMarginTop, elComputedMarginLeft); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() shared by shorthand property in var(), test random() value index`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.setAttribute("data-foo", 'random(property-index-scoped, 1, 300000)'); | |
| el1.style.setProperty('scale', 'attr(data-foo)'); | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.setAttribute("data-foo", 'random(property-index-scoped, 1, 300000)'); | |
| el2.style.setProperty('scale', 'attr(data-foo)'); | |
| holder.appendChild(el2); | |
| const el1ComputedScale = getComputedStyle(el1)['scale']; | |
| const el2ComputedScale = getComputedStyle(el2)['scale']; | |
| test_random_equals(el1ComputedScale, el2ComputedScale); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() shared by property in attr()`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const el1 = document.createElement('div'); | |
| el1.setAttribute("data-foo", 'random(property-index-scoped, 1, 300000)'); | |
| el1.style.setProperty('scale', 'attr(data-foo type(<number>))'); | |
| holder.appendChild(el1); | |
| const el2 = document.createElement('div'); | |
| el2.setAttribute("data-foo", 'random(property-index-scoped, 1, 300000)'); | |
| el2.style.setProperty('scale', 'attr(data-foo type(<number>))'); | |
| holder.appendChild(el2); | |
| const el1ComputedScale = getComputedStyle(el1)['scale']; | |
| const el2ComputedScale = getComputedStyle(el2)['scale']; | |
| test_random_equals(el1ComputedScale, el2ComputedScale); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `random() shared by property in typed attr()`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const t1 = document.createElement('div'); | |
| t1.style.setProperty('width', 'random(--ident property-scoped, 1px, 300000px)'); | |
| holder.appendChild(t1); | |
| const t2 = document.createElement('div'); | |
| t2.style.setProperty('width', 'random(--identwidth, 1px, 300000px)'); | |
| holder.appendChild(t2); | |
| let t1ComputedWidth = getComputedStyle(t1)['width']; | |
| let t2ComputedWidth = getComputedStyle(t2)['width']; | |
| test_random_not_equals(t1ComputedWidth, t2ComputedWidth); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Test collision with property name and identifier`); | |
| test(() => { | |
| const holder = document.createElement('div'); | |
| document.body.appendChild(holder); | |
| try { | |
| const t = document.createElement('div'); | |
| t.style.setProperty('width', 'random(--foo ua-height-1, 1px, 300000px)'); | |
| t.style.setProperty('height', 'random(--foo property-index-scoped, 1px, 300000px)'); | |
| holder.appendChild(t); | |
| let tComputedWidth = getComputedStyle(t)['width']; | |
| let tComputedHeight = getComputedStyle(t)['height']; | |
| test_random_equals(tComputedWidth, tComputedHeight); | |
| } finally { | |
| document.body.removeChild(holder); | |
| } | |
| }, `Test user specified <random-ua-ident>`); | |
| iframe.onload = function run_iframe_tests() { | |
| // Random without element-scoped should still differ across documents | |
| test_random_cross_document(property, 'random(--foo, 0, 1)'); | |
| test_random_cross_document(property, 'random(property-scoped, 0, 1)'); | |
| test_random_cross_document(property, 'random(property-index-scoped, 0, 1)'); | |
| test_random_cross_document(property, 'random(--foo property-scoped, 0, 1)'); | |
| test_random_cross_document(property, 'random(--foo property-index-scoped, 0, 1)'); | |
| test_random_cross_document(property, `random(ua-${property}, 0, 1)`); | |
| test_random_cross_document(property, `random(ua-${property}-1, 0, 1)`); | |
| test_random_cross_document(property, `random(--foo ua-${property}, 0, 1)`); | |
| test_random_cross_document(property, `random(--foo ua-${property}-1, 0, 1)`); | |
| // Random with element-scoped should always differ across documents | |
| test_random_cross_document(property, 'random(0, 1)'); | |
| test_random_cross_document(property, 'random(element-scoped, 0, 1)'); | |
| test_random_cross_document(property, 'random(--foo element-scoped, 0, 1)'); | |
| }; | |
| </script> |