diff options
Diffstat (limited to 'testing/web-platform/tests/css/support')
63 files changed, 2074 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/support/1x1-green.png b/testing/web-platform/tests/css/support/1x1-green.png Binary files differnew file mode 100644 index 0000000000..b98ca0ba0a --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-green.png diff --git a/testing/web-platform/tests/css/support/1x1-lime.png b/testing/web-platform/tests/css/support/1x1-lime.png Binary files differnew file mode 100644 index 0000000000..cb397fb090 --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-lime.png diff --git a/testing/web-platform/tests/css/support/1x1-maroon.png b/testing/web-platform/tests/css/support/1x1-maroon.png Binary files differnew file mode 100644 index 0000000000..3f86b07219 --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-maroon.png diff --git a/testing/web-platform/tests/css/support/1x1-navy.png b/testing/web-platform/tests/css/support/1x1-navy.png Binary files differnew file mode 100644 index 0000000000..9b9a03955b --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-navy.png diff --git a/testing/web-platform/tests/css/support/1x1-red.png b/testing/web-platform/tests/css/support/1x1-red.png Binary files differnew file mode 100644 index 0000000000..6bd73ac101 --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-red.png diff --git a/testing/web-platform/tests/css/support/1x1-white.png b/testing/web-platform/tests/css/support/1x1-white.png Binary files differnew file mode 100644 index 0000000000..dd43faec54 --- /dev/null +++ b/testing/web-platform/tests/css/support/1x1-white.png diff --git a/testing/web-platform/tests/css/support/60x60-gg-rr.png b/testing/web-platform/tests/css/support/60x60-gg-rr.png Binary files differnew file mode 100644 index 0000000000..84f5b2a4f1 --- /dev/null +++ b/testing/web-platform/tests/css/support/60x60-gg-rr.png diff --git a/testing/web-platform/tests/css/support/60x60-green.png b/testing/web-platform/tests/css/support/60x60-green.png Binary files differnew file mode 100644 index 0000000000..b3c8cf3eb4 --- /dev/null +++ b/testing/web-platform/tests/css/support/60x60-green.png diff --git a/testing/web-platform/tests/css/support/60x60-red.png b/testing/web-platform/tests/css/support/60x60-red.png Binary files differnew file mode 100644 index 0000000000..823f125b8e --- /dev/null +++ b/testing/web-platform/tests/css/support/60x60-red.png diff --git a/testing/web-platform/tests/css/support/META.yml b/testing/web-platform/tests/css/support/META.yml new file mode 100644 index 0000000000..babe8bdaeb --- /dev/null +++ b/testing/web-platform/tests/css/support/META.yml @@ -0,0 +1,2 @@ +suggested_reviewers: + - frivoal diff --git a/testing/web-platform/tests/css/support/README b/testing/web-platform/tests/css/support/README new file mode 100644 index 0000000000..2e5f2ad073 --- /dev/null +++ b/testing/web-platform/tests/css/support/README @@ -0,0 +1,28 @@ +CSS Global Support Directory +============================ + +This directory contains common support files (such as images and external +style sheets). These are sync'ed into the support directories of all our +test suites. If you have test-suite-specific support files, please add +them to the appropriate test-suite-specific support/ directory. + +If you add to a support/ directory, please run the tools/supportprop.py +script from the top of the repository to cascade support files into the +lower-level support directories. + +Description of the Common Support File Collection +------------------------------------------------- + +The 1x1-* images are all exactly one pixel. + +The swatch-* images all use 15x15 cells. + +The square-* images all use 15x15 cells with one pixel borders. + +The pattern-* images use cells of various sizes: + + pattern-grg-rgr-grg.png 20x20 + pattern-rgr-grg-rgr.png 20x20 + pattern-tr.png 15x15 + pattern-grg-rrg-rgg.png 15x15 + diff --git a/testing/web-platform/tests/css/support/a-green.css b/testing/web-platform/tests/css/support/a-green.css new file mode 100644 index 0000000000..b0dbb071d5 --- /dev/null +++ b/testing/web-platform/tests/css/support/a-green.css @@ -0,0 +1 @@ +.a { color: green; } diff --git a/testing/web-platform/tests/css/support/alignment.css b/testing/web-platform/tests/css/support/alignment.css new file mode 100644 index 0000000000..d4c970c52b --- /dev/null +++ b/testing/web-platform/tests/css/support/alignment.css @@ -0,0 +1,367 @@ +/* align-self */ +.alignSelfAuto { align-self: auto; } +.alignSelfNormal { align-self: normal; } +.alignSelfStretch { align-self: stretch; } +.alignSelfStart { align-self: start; } +.alignSelfEnd { align-self: end; } +.alignSelfCenter { align-self: center; } +.alignSelfRight { align-self: right; } +.alignSelfLeft { align-self: left; } + +.alignSelfFlexStart { align-self: flex-start; } +.alignSelfFlexEnd { align-self: flex-end; } + +.alignSelfSelfStart { align-self: self-start; } +.alignSelfSelfEnd { align-self: self-end; } + +.alignSelfSafeCenter { align-self: safe center; } +.alignSelfUnsafeCenter { align-self: unsafe center; } +.alignSelfSafeEnd { align-self: safe end; } +.alignSelfUnsafeEnd { align-self: unsafe end; } +.alignSelfSafeSelfEnd { align-self: safe self-end; } +.alignSelfUnsafeSelfEnd { align-self: unsafe self-end; } +.alignSelfSafeSelfStart { align-self: safe self-start; } +.alignSelfUnsafeSelfStart { align-self: unsafe self-start; } +.alignSelfSafeRight { align-self: safe right; } +.alignSelfUnsafeRight { align-self: unsafe right; } +.alignSelfSafeLeft { align-self: safe left; } +.alignSelfUnsafeLeft { align-self: unsafe left; } +.alignSelfSafeFlexEnd { align-self: safe flex-end; } +.alignSelfUnsafeFlexEnd { align-self: unsafe flex-end; } +.alignSelfSafeFlexStart { align-self: safe flex-start; } +.alignSelfUnsafeFlexStart { align-self: unsafe flex-start; } + +.alignSelfBaseline { align-self: baseline; } +.alignSelfFirstBaseline { align-self: first baseline; } +.alignSelfLastBaseline { align-self: last baseline; } + +/* align-items */ +.alignItemsAuto { align-items: auto; } +.alignItemsNormal { align-items: normal; } +.alignItemsStretch { align-items: stretch; } +.alignItemsStart { align-items: start; } +.alignItemsCenter { align-items: center; } +.alignItemsEnd { align-items: end; } +.alignItemsLeft { align-items: left; } +.alignItemsRight { align-items: right; } + +.alignItemsFlexStart { align-items: flex-start; } +.alignItemsFlexEnd { align-items: flex-end; } + +.alignItemsSelfStart { align-items: self-start; } +.alignItemsSelfEnd { align-items: self-end; } + +.alignItemsSafeCenter { align-items: safe center; } +.alignItemsUnsafeCenter { align-items: unsafe center; } +.alignItemsSafeEnd { align-items: safe end; } +.alignItemsUnsafeEnd { align-items: unsafe end; } +.alignItemsSafeSelfEnd { align-items: safe self-end; } +.alignItemsUnsafeSelfEnd { align-items: unsafe self-end; } +.alignItemsSafeSelfStart { align-items: safe self-start; } +.alignItemsUnsafeSelfStart { align-items: unsafe self-start; } +.alignItemsSafeRight { align-items: safe right; } +.alignItemsUnsafeRight { align-items: unsafe right; } +.alignItemsSafeLeft { align-items: safe left; } +.alignItemsUnsafeLeft { align-items: unsafe left; } +.alignItemsSafeFlexEnd { align-items: safe flex-end; } +.alignItemsUnsafeFlexEnd { align-items: unsafe flex-end; } +.alignItemsSafeFlexStart { align-items: safe flex-start; } +.alignItemsUnsafeFlexStart { align-items: unsafe flex-start; } + +.alignItemsBaseline { align-items: baseline; } +.alignItemsFirstBaseline { align-items: first baseline; } +.alignItemsLastBaseline { align-items: last baseline; } + +/* align-content */ +.alignContentBaseline { align-content: baseline; } +.alignContentLastBaseline { align-content: last-baseline; } +.alignContentStart { align-content: start; } +.alignContentEnd { align-content: end; } +.alignContentCenter { align-content: center; } +.alignContentLeft { align-content: left; } +.alignContentRight { align-content: right; } + +.alignContentFlexStart { align-content: flex-start; } +.alignContentFlexEnd { align-content: flex-end; } + +.alignContentSpaceBetween { align-content: space-between; } +.alignContentSpaceAround { align-content: space-around; } +.alignContentSpaceEvenly { align-content: space-evenly; } +.alignContentStretch { align-content: stretch; } + +.alignContentSafeCenter { align-content: safe center; } +.alignContentUnsafeCenter { align-content: unsafe center; } +.alignContentSafeEnd { align-content: safe end; } +.alignContentUnsafeEnd { align-content: unsafe end; } +.alignContentSafeRight { align-content: safe right; } +.alignContentUnsafeRight { align-content: unsafe right; } +.alignContentSafeLeft { align-content: safe left; } +.alignContentUnsafeLeft { align-content: unsafe left; } +.alignContentSafeFlexEnd { align-content: safe flex-end; } +.alignContentUnsafeFlexEnd { align-content: unsafe flex-end; } +.alignContentSafeFlexStart { align-content: safe flex-start; } +.alignContentUnsafeFlexStart { align-content: unsafe flex-start; } + +.alignContentBaseline { align-content: baseline; } +.alignContentFirstBaseline { align-content: first baseline; } +.alignContentLastBaseline { align-content: last baseline; } + +/* justify-self */ +.justifySelfAuto { justify-self: auto; } +.justifySelfNormal { justify-self: normal; } +.justifySelfStretch { justify-self: stretch; } +.justifySelfStart { justify-self: start; } +.justifySelfCenter { justify-self: center; } +.justifySelfEnd { justify-self: end; } +.justifySelfRight { justify-self: right; } +.justifySelfLeft { justify-self: left; } + +.justifySelfFlexStart { justify-self: flex-start; } +.justifySelfFlexEnd { justify-self: flex-end; } + +.justifySelfSelfStart { justify-self: self-start; } +.justifySelfSelfEnd { justify-self: self-end; } + +.justifySelfSafeCenter { justify-self: safe center; } +.justifySelfUnsafeCenter { justify-self: unsafe center; } +.justifySelfSafeEnd { justify-self: safe end; } +.justifySelfUnsafeEnd { justify-self: unsafe end; } +.justifySelfSafeSelfEnd { justify-self: safe self-end; } +.justifySelfUnsafeSelfEnd { justify-self: unsafe self-end; } +.justifySelfSafeSelfStart { justify-self: safe self-start; } +.justifySelfUnsafeSelfStart { justify-self: unsafe self-start; } +.justifySelfSafeRight { justify-self: safe right; } +.justifySelfUnsafeRight { justify-self: unsafe right; } +.justifySelfSafeLeft { justify-self: safe left; } +.justifySelfUnsafeLeft { justify-self: unsafe left; } +.justifySelfSafeFlexEnd { justify-self: safe flex-end; } +.justifySelfUnsafeFlexEnd { justify-self: unsafe flex-end; } +.justifySelfSafeFlexStart { justify-self: safe flex-start; } +.justifySelfUnsafeFlexStart { justify-self: unsafe flex-start; } + +.justifySelfBaseline { justify-self: baseline; } +.justifySelfFirstBaseline { justify-self: first baseline; } +.justifySelfLastBaseline { justify-self: last baseline; } + +/* justify-items */ +.justifyItemsAuto { justify-items: auto; } +.justifyItemsNormal { justify-items: normal; } +.justifyItemsStretch { justify-items: stretch; } +.justifyItemsStart { justify-items: start; } +.justifyItemsCenter { justify-items: center; } +.justifyItemsEnd { justify-items: end; } +.justifyItemsLeft { justify-items: left; } +.justifyItemsRight { justify-items: right; } + +.justifyItemsFlexStart { justify-items: flex-start; } +.justifyItemsFlexEnd { justify-items: flex-end; } + +.justifyItemsSelfStart { justify-items: self-start; } +.justifyItemsSelfEnd { justify-items: self-end; } + +.justifyItemsLegacy { justify-items: legacy; } +.justifyItemsLegacyLeft { justify-items: legacy left; } +.justifyItemsLegacyCenter { justify-items: legacy center; } +.justifyItemsLegacyRight { justify-items: legacy right; } +.justifyItemsLeftLegacy { justify-items: left legacy; } +.justifyItemsCenterLegacy { justify-items: center legacy; } +.justifyItemsRightLegacy { justify-items: right legacy; } + +.justifyItemsSafeCenter { justify-items: safe center; } +.justifyItemsUnsafeCenter { justify-items: unsafe center; } +.justifyItemsSafeEnd { justify-items: safe end; } +.justifyItemsUnsafeEnd { justify-items: unsafe end; } +.justifyItemsSafeSelfEnd { justify-items: safe self-end; } +.justifyItemsUnsafeSelfEnd { justify-items: unsafe self-end; } +.justifyItemsSafeSelfStart { justify-items: safe self-start; } +.justifyItemsUnsafeSelfStart { justify-items: unsafe self-start; } +.justifyItemsSafeRight { justify-items: safe right; } +.justifyItemsUnsafeRight { justify-items: unsafe right; } +.justifyItemsSafeLeft { justify-items: safe left; } +.justifyItemsUnsafeLeft { justify-items: unsafe left; } +.justifyItemsSafeFlexEnd { justify-items: safe flex-end; } +.justifyItemsUnsafeFlexEnd { justify-items: unsafe flex-end; } +.justifyItemsSafeFlexStart { justify-items: safe flex-start; } +.justifyItemsUnsafeFlexStart { justify-items: unsafe flex-start; } + +.justifyItemsTest { justify-items: safe end; } + +.justifyItemsBaseline { justify-items: baseline; } +.justifyItemsFirstBaseline { justify-items: first baseline; } +.justifyItemsLastBaseline { justify-items: last baseline; } + +/* justify-content */ +.justifyContentBaseline { justify-content: baseline; } +.justifyContentLastBaseline { justify-content: last-baseline; } +.justifyContentStart { justify-content: start; } +.justifyContentEnd { justify-content: end; } +.justifyContentCenter { justify-content: center; } +.justifyContentLeft { justify-content: left; } +.justifyContentRight { justify-content: right; } + +.justifyContentFlexStart { justify-content: flex-start; } +.justifyContentFlexEnd { justify-content: flex-end; } + +.justifyContentSpaceBetween { justify-content: space-between; } +.justifyContentSpaceAround { justify-content: space-around; } +.justifyContentSpaceEvenly { justify-content: space-evenly; } +.justifyContentStretch { justify-content: stretch; } + +.justifyContentSafeCenter { justify-content: safe center; } +.justifyContentUnsafeCenter { justify-content: unsafe center; } +.justifyContentSafeEnd { justify-content: safe end; } +.justifyContentUnsafeEnd { justify-content: unsafe end; } +.justifyContentSafeRight { justify-content: safe right; } +.justifyContentUnsafeRight { justify-content: unsafe right; } +.justifyContentSafeLeft { justify-content: safe left; } +.justifyContentUnsafeLeft { justify-content: unsafe left; } +.justifyContentSafeFlexEnd { justify-content: safe flex-end; } +.justifyContentUnsafeFlexEnd { justify-content: unsafe flex-end; } +.justifyContentSafeFlexStart { justify-content: safe flex-start; } +.justifyContentUnsafeFlexStart { justify-content: unsafe flex-start; } + +.justifyContentBaseline { justify-content: baseline; } +.justifyContentFirstBaseline { justify-content: first baseline; } +.justifyContentLastBaseline { justify-content: last baseline; } + +/* Both align-items and justify-items */ +.itemsNormal { + align-items: normal; + justify-items: normal; +} + +.itemsStretch { + align-items: stretch; + justify-items: stretch; +} + +.itemsStart { + align-items: start; + justify-items: start; +} + +.itemsCenter { + align-items: center; + justify-items: center; +} + +.itemsEnd { + align-items: end; + justify-items: end; +} + +.itemsLeft { + align-items: left; + justify-items: left; +} + +.itemsRight { + align-items: right; + justify-items: right; +} + +.itemsSelfStart { + align-items: self-start; + justify-items: self-start; +} + +.itemsSelfEnd { + align-items: self-end; + justify-items: self-end; +} +.itemsBaseline { + align-items: baseline; + justify-items: baseline; +} + +/* Both align-self and justify-self */ +.selfStretch { + align-self: stretch; + justify-self: stretch; +} +.selfStart { + align-self: start; + justify-self: start; +} +.selfEnd { + align-self: end; + justify-self: end; +} +.selfCenter { + align-self: center; + justify-self: center; +} +.selfRight { + align-self: right; + justify-self: right; +} +.selfLeft { + align-self: left; + justify-self: left; +} +.selfSelfStart { + align-self: self-start; + justify-self: self-start; +} +.selfSelfEnd { + align-self: self-end; + justify-self: self-end; +} +.selfBaseline { + align-self: baseline; + justify-self: baseline; +} + +/* Both align-content and justify-content */ +.contentStart { + align-content: start; + justify-content: start; +} +.contentCenter { + align-content: center; + justify-content: center; +} +.contentEnd { + align-content: end; + justify-content: end; +} + +.contentCenterSafe { + align-content: safe center; + justify-content: safe center; +} + +.contentCenterUnsafe { + align-content: unsafe center; + justify-content: unsafe center; +} + +.contentEndSafe { + align-content: safe end; + justify-content: safe end; +} + +.contentEndUnsafe { + align-content: unsafe end; + justify-content: unsafe end; +} + +.contentSpaceBetween { + justify-content: space-between; + align-content: space-between; +} + +.contentSpaceAround { + justify-content: space-around; + align-content: space-around; +} + +.contentSpaceEvenly { + justify-content: space-evenly; + align-content: space-evenly; +} + +.contentStretch { + justify-content: stretch; + align-content: stretch; +} diff --git a/testing/web-platform/tests/css/support/b-green.css b/testing/web-platform/tests/css/support/b-green.css new file mode 100644 index 0000000000..a0473f5ca2 --- /dev/null +++ b/testing/web-platform/tests/css/support/b-green.css @@ -0,0 +1 @@ +.b { color: green; }
\ No newline at end of file diff --git a/testing/web-platform/tests/css/support/blue-100.png b/testing/web-platform/tests/css/support/blue-100.png Binary files differnew file mode 100644 index 0000000000..f578ae7253 --- /dev/null +++ b/testing/web-platform/tests/css/support/blue-100.png diff --git a/testing/web-platform/tests/css/support/blue32x32.ico b/testing/web-platform/tests/css/support/blue32x32.ico Binary files differnew file mode 100644 index 0000000000..5844dd614c --- /dev/null +++ b/testing/web-platform/tests/css/support/blue32x32.ico diff --git a/testing/web-platform/tests/css/support/c-red.css b/testing/web-platform/tests/css/support/c-red.css new file mode 100644 index 0000000000..d4ba5c64e9 --- /dev/null +++ b/testing/web-platform/tests/css/support/c-red.css @@ -0,0 +1 @@ +.c { color: red; }
\ No newline at end of file diff --git a/testing/web-platform/tests/css/support/cat.png b/testing/web-platform/tests/css/support/cat.png Binary files differnew file mode 100644 index 0000000000..85dd732481 --- /dev/null +++ b/testing/web-platform/tests/css/support/cat.png diff --git a/testing/web-platform/tests/css/support/computed-testcommon.js b/testing/web-platform/tests/css/support/computed-testcommon.js new file mode 100644 index 0000000000..831baf311a --- /dev/null +++ b/testing/web-platform/tests/css/support/computed-testcommon.js @@ -0,0 +1,212 @@ +'use strict'; + +/** + * Create test that a CSS property computes to the expected value. + * The document element #target is used to perform the test. + * + * @param {string} property The name of the CSS property being tested. + * @param {string} specified A specified value for the property. + * @param {string|array} computed The expected computed value, + * or an array of permitted computed value. + * If omitted, defaults to specified. + */ +function test_computed_value(property, specified, computed, titleExtra) { + if (!computed) + computed = specified; + + 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; + + let readValue = getComputedStyle(target)[property]; + if (Array.isArray(computed)) { + assert_in_array(readValue, computed); + } else { + if (property == "color") + colorValuesAlmostEqual(readValue, computed, 0.0001, 1); + 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 colorValuesAlmostEqual(color1, color2, float_epsilon, integer_epsilon) { + // Legacy color formats use integers in [0, 255] and thus will have wider epsilons + const epsilon = getNonNumbers(color1).startsWith("rgb") ? integer_epsilon : float_epsilon; + // Colors can be split by spaces, commas or the '(' character. + const colorElementDividers = /( |\(|,)/; + // Return the string stripped of numbers. + function getNonNumbers(color) { + return color.replace(/[0-9]/g, ''); + } + // Return an array of all numbers in the color. + function getNumbers(color) { + const result = []; + // const entries = color.split(colorElementDividers); + color.split(colorElementDividers).forEach(element => { + const numberElement = parseFloat(element); + if (!isNaN(numberElement)) { + result.push(numberElement); + } + }); + return result; + } + + assert_array_approx_equals(getNumbers(color1), getNumbers(color2), epsilon, "Numeric parameters are approximately equal."); + // Assert that the text of the two colors are equal. i.e. colorSpace, colorFunction and format. + assert_equals(getNonNumbers(color1), getNonNumbers(color2), "Color format is correct."); +} + +function testComputedValueGreaterOrLowerThan(property, specified, expected, titleExtra) { + 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; + 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 testTransformValuesCloseTo(specified, epsilon, expectedValue, description) +{ + if(!description) { + description = `Property ${specified} value expected same with ${expectedValue} in +/-${epsilon}` + } + + test(function() + { + var targetElement = document.getElementById("target"); + targetElement.style.setProperty('transform', "initial"); + + /* + Since we are running many consecutive tests on the same + element, then it is necessary to reset its property + to an initial value before actually re-testing it. + */ + + targetElement.style.setProperty('transform', specified); + + var computedCalcValue = getComputedStyle(targetElement)['transform']; + + /* + We first strip out the word "matrix" with the + opening parenthesis "(" and the closing + parenthesis ")" + */ + + computedCalcValue = computedCalcValue.replace("matrix(", "").replace(")", ""); + + /* + Then, we split the string at each comma "," + and store the resulting 6 sub-strings into + tableSplitComputedCalcValue + */ + + var tableSplitCalcValue = computedCalcValue.split(","); + + /* + We convert the 6 sub-strings into numerical floating values + so that mathematical operations (subtraction, absolute value, + comparison) can be performed. + */ + + tableSplitCalcValue[0] = parseFloat(tableSplitCalcValue[0]); + tableSplitCalcValue[1] = parseFloat(tableSplitCalcValue[1]); + tableSplitCalcValue[2] = parseFloat(tableSplitCalcValue[2]); + tableSplitCalcValue[3] = parseFloat(tableSplitCalcValue[3]); + tableSplitCalcValue[4] = parseFloat(tableSplitCalcValue[4]); + tableSplitCalcValue[5] = parseFloat(tableSplitCalcValue[5]); + + /* + Now, we execute the same steps with the expectedValue + */ + + targetElement.style.setProperty('transform', expectedValue); + + var computedExpectedValue = getComputedStyle(targetElement)['transform']; + + /* + We first strip out the word "matrix" with the + opening parenthesis "(" and the closing + parenthesis ")" + */ + + computedExpectedValue = computedExpectedValue.replace("matrix(", "").replace(")", ""); + + /* + Then, we split the string at each comma "," + and store the resulting 6 sub-strings into + tableSplitComputedCalcValue + */ + + var tableSplitExpectedValue = computedExpectedValue.split(","); + + /* + We convert the 6 sub-strings into numerical floating values + so that mathematical operations (subtraction, absolute value, + comparison) can be performed. + */ + + tableSplitExpectedValue[0] = parseFloat(tableSplitExpectedValue[0]); + tableSplitExpectedValue[1] = parseFloat(tableSplitExpectedValue[1]); + tableSplitExpectedValue[2] = parseFloat(tableSplitExpectedValue[2]); + tableSplitExpectedValue[3] = parseFloat(tableSplitExpectedValue[3]); + tableSplitExpectedValue[4] = parseFloat(tableSplitExpectedValue[4]); + tableSplitExpectedValue[5] = parseFloat(tableSplitExpectedValue[5]); + + assert_array_approx_equals(tableSplitCalcValue, tableSplitExpectedValue, epsilon); + } , description); + +} + +function test_pseudo_computed_value(pseudo, property, specified, computed, titleExtra) { + if (!computed) + computed = specified; + + test(() => { + assert_true(/^::\w+$/.test(pseudo), pseudo + " doesn't seem to be a pseudo-element"); + const styleElement = document.createElement("style"); + document.documentElement.appendChild(styleElement); + try { + const {sheet} = styleElement; + sheet.insertRule("#target" + pseudo + "{}"); + const {style} = sheet.cssRules[0]; + const target = document.getElementById('target'); + + assert_true(property in getComputedStyle(target, pseudo), property + " doesn't seem to be supported in the computed style"); + assert_true(CSS.supports(property, specified), "'" + specified + "' is a supported value for " + property + "."); + style[property] = specified; + + let readValue = getComputedStyle(target, pseudo)[property]; + if (Array.isArray(computed)) { + assert_in_array(readValue, computed); + } else { + assert_equals(readValue, computed); + } + if (readValue !== specified) { + style[property] = ''; + style[property] = readValue; + assert_equals(getComputedStyle(target, pseudo)[property], readValue, + 'computed value should round-trip'); + } + } finally { + document.documentElement.removeChild(styleElement); + } + }, `Property ${property} value '${specified}' in ${pseudo}${titleExtra ? ' ' + titleExtra : ''}`); +} diff --git a/testing/web-platform/tests/css/support/delete-other-rule-crash.css b/testing/web-platform/tests/css/support/delete-other-rule-crash.css new file mode 100644 index 0000000000..13f5d6acf0 --- /dev/null +++ b/testing/web-platform/tests/css/support/delete-other-rule-crash.css @@ -0,0 +1,2 @@ +.a {} +.b { .c {} } diff --git a/testing/web-platform/tests/css/support/green.ico b/testing/web-platform/tests/css/support/green.ico Binary files differnew file mode 100644 index 0000000000..691f61166f --- /dev/null +++ b/testing/web-platform/tests/css/support/green.ico diff --git a/testing/web-platform/tests/css/support/grid.css b/testing/web-platform/tests/css/support/grid.css new file mode 100644 index 0000000000..4007ebba43 --- /dev/null +++ b/testing/web-platform/tests/css/support/grid.css @@ -0,0 +1,289 @@ +.grid { + display: grid; + background-color: grey; +} + +.inline-grid { + display: inline-grid; + background-color: grey; +} + +.firstRowFirstColumn { + background-color: blue; + grid-column: 1; + grid-row: 1; +} + +.onlyFirstRowOnlyFirstColumn { + background-color: blue; + grid-column: 1 / 2; + grid-row: 1 / 2; +} + +.firstRowSecondColumn { + background-color: lime; + grid-column: 2; + grid-row: 1; +} + +.onlyFirstRowOnlySecondColumn { + background-color: lime; + grid-column: 2 / 3; + grid-row: 1 / 2; +} + +.firstRowThirdColumn { + background-color: magenta; + grid-column: 3; + grid-row: 1; +} + +.firstRowFourthColumn { + background-color: green; + grid-column: 4; + grid-row: 1; +} + +.secondRowFirstColumn { + background-color: purple; + grid-column: 1; + grid-row: 2; +} + +.onlySecondRowOnlyFirstColumn { + background-color: purple; + grid-column: 1 / 2; + grid-row: 2 / 3; +} + +.secondRowSecondColumn { + background-color: orange; + grid-column: 2; + grid-row: 2; +} + +.onlySecondRowOnlySecondColumn { + background-color: orange; + grid-column: 2 / 3; + grid-row: 2 / 3; +} + +.endSecondRowEndSecondColumn { + background-color: orange; + grid-column-end: 3; + grid-row-end: 3; +} + +.secondRowThirdColumn { + background-color: navy; + grid-column: 3; + grid-row: 2; +} + +.secondRowFourthColumn { + background-color: pink; + grid-column: 4; + grid-row: 2; +} + +.thirdRowFirstColumn { + background-color: green; + grid-column: 1; + grid-row: 3; +} + +.thirdRowSecondColumn { + background-color: red; + grid-column: 2; + grid-row: 3; +} + +.thirdRowThirdColumn { + background-color: salmon; + grid-column: 3; + grid-row: 3; +} + +.firstAutoRowSecondAutoColumn { + grid-row: 1 / auto; + grid-column: 2 / auto; +} + +.autoLastRowAutoLastColumn { + grid-row: auto / -1; + grid-column: auto / -1; +} + +.autoSecondRowAutoFirstColumn { + grid-row: auto / 2; + grid-column: auto / 1; +} + +.firstRowBothColumn { + grid-row: 1; + grid-column: 1 / -1; +} + +.secondRowBothColumn { + grid-row: 2; + grid-column: 1 / -1; +} + +.bothRowFirstColumn { + grid-row: 1 / -1; + grid-column: 1; +} + +.bothRowSecondColumn { + grid-row: 1 / -1; + grid-column: 2; +} + +.bothRowBothColumn { + grid-row: 1 / -1; + grid-column: 1 / -1; +} + +/* Auto column / row. */ +.autoRowAutoColumn { + background-color: pink; + grid-column: auto; + grid-row: auto; +} + +.firstRowAutoColumn { + background-color: blue; + grid-column: auto; + grid-row: 1; +} + +.secondRowAutoColumn { + background-color: purple; + grid-column: auto; + grid-row: 2; +} + +.thirdRowAutoColumn { + background-color: navy; + grid-column: auto; + grid-row: 3; +} + +.autoRowFirstColumn { + background-color: lime; + grid-column: 1; + grid-row: auto; +} + +.autoRowSecondColumn { + background-color: orange; + grid-column: 2; + grid-row: auto; +} + +.autoRowThirdColumn { + background-color: magenta; + grid-column: 3; + grid-row: auto; +} + +.autoRowAutoColumnSpanning2 { + background-color: maroon; + grid-column: span 2; + grid-row: auto; +} + +.autoRowSpanning2AutoColumn { + background-color: aqua; + grid-column: auto; + grid-row: span 2; +} + +.autoRowSpanning2AutoColumnSpanning3 { + background-color: olive; + grid-column: span 3; + grid-row: span 2; +} + +.autoRowSpanning3AutoColumnSpanning2 { + background-color: indigo; + grid-column: span 2; + grid-row: span 3; +} + +.autoRowFirstColumnSpanning2 { + background-color: maroon; + grid-column: 1 / span 2; + grid-row: auto; +} + +.autoRowSecondColumnSpanning2 { + background-color: olive; + grid-column: 2 / span 2; + grid-row: auto; +} + +.firstRowSpanning2AutoColumn { + background-color: maroon; + grid-column: auto; + grid-row: 1 / span 2; + height: 100%; +} + +.secondRowSpanning2AutoColumn { + background-color: olive; + grid-column: auto; + grid-row: 2 / span 2; + height: 100%; +} + +/* Grid element flow. */ +.gridAutoFlowColumnSparse { + grid-auto-flow: column; +} + +.gridAutoFlowColumnDense { + grid-auto-flow: column dense; +} + +.gridAutoFlowRowSparse { + grid-auto-flow: row; +} + +.gridAutoFlowRowDense { + grid-auto-flow: row dense; +} + +/* This rule makes sure the container is smaller than any grid items to avoid distributing any extra logical space to them. */ +.constrainedContainer { + width: 10px; + height: 10px; +} + +.unconstrainedContainer { + width: 1000px; + height: 1000px; +} + +.sizedToGridArea { + font: 10px/1 Ahem; + /* Make us fit our grid area. */ + width: 100%; + height: 100%; +} + +.verticalRL { + writing-mode: vertical-rl; +} +.verticalLR { + writing-mode: vertical-lr; +} +.horizontalTB { + writing-mode: horizontal-tb; +} +.directionRTL { + direction: rtl; +} +.directionLTR { + direction: ltr; +} diff --git a/testing/web-platform/tests/css/support/height-keyword-classes.css b/testing/web-platform/tests/css/support/height-keyword-classes.css new file mode 100644 index 0000000000..d26f564442 --- /dev/null +++ b/testing/web-platform/tests/css/support/height-keyword-classes.css @@ -0,0 +1,39 @@ +/* In the current spec for heights, min-content, max-content and fit-content are + * equivalent. + */ + +.min-content { + height: min-content; +} + +.max-content { + height: max-content; +} + +.fit-content { + height: fit-content; +} + +.max-height-min-content { + max-height: min-content; +} + +.max-height-max-content { + max-height: max-content; +} + +.max-height-fit-content { + max-height: fit-content; +} + +.min-height-min-content { + min-height: min-content; +} + +.min-height-max-content { + min-height: max-content; +} + +.min-height-fit-content { + min-height: fit-content; +} diff --git a/testing/web-platform/tests/css/support/import-green.css b/testing/web-platform/tests/css/support/import-green.css new file mode 100644 index 0000000000..537104e663 --- /dev/null +++ b/testing/web-platform/tests/css/support/import-green.css @@ -0,0 +1 @@ +.import { color: green; } diff --git a/testing/web-platform/tests/css/support/import-red.css b/testing/web-platform/tests/css/support/import-red.css new file mode 100644 index 0000000000..9945ef4711 --- /dev/null +++ b/testing/web-platform/tests/css/support/import-red.css @@ -0,0 +1 @@ +.import { color: red; } diff --git a/testing/web-platform/tests/css/support/inheritance-testcommon.js b/testing/web-platform/tests/css/support/inheritance-testcommon.js new file mode 100644 index 0000000000..38ac94eb12 --- /dev/null +++ b/testing/web-platform/tests/css/support/inheritance-testcommon.js @@ -0,0 +1,96 @@ +'use strict'; + +(function() { + +function assert_initial(property, initial) { + let initialDesc = initial; + if (Array.isArray(initial)) + initialDesc = '[' + initial.map(e => "'" + e + "'").join(' or ') + ']'; + + test(() => { + const target = document.getElementById('target'); + assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style"); + target.style[property] = 'initial'; + if (Array.isArray(initial)) { + assert_in_array(getComputedStyle(target)[property], initial); + } else { + assert_equals(getComputedStyle(target)[property], initial); + } + target.style[property] = ''; + }, 'Property ' + property + ' has initial value ' + initialDesc); +} + +/** + * Create tests that a CSS property inherits and has the given initial value. + * + * The current document must have an element #target within element #container. + * + * @param {string} property The name of the CSS property being tested. + * @param {string|array} initial The computed value for 'initial' or a list + * of acceptable computed value serializations. + * @param {string} other An arbitrary value for the property that + * round trips and is distinct from the initial + * value. + */ +function assert_inherited(property, initial, other) { + if (initial) + assert_initial(property, initial); + + test(() => { + const container = document.getElementById('container'); + const target = document.getElementById('target'); + assert_true(property in getComputedStyle(target), property + " doesn't seem to be supported in the computed style"); + container.style[property] = 'initial'; + target.style[property] = 'unset'; + assert_not_equals(getComputedStyle(container)[property], other); + assert_not_equals(getComputedStyle(target)[property], other); + container.style[property] = other; + assert_equals(getComputedStyle(container)[property], other); + assert_equals(getComputedStyle(target)[property], other); + target.style[property] = 'initial'; + assert_equals(getComputedStyle(container)[property], other); + assert_not_equals(getComputedStyle(target)[property], other); + target.style[property] = 'inherit'; + assert_equals(getComputedStyle(target)[property], other); + container.style[property] = ''; + target.style[property] = ''; + }, 'Property ' + property + ' inherits'); +} + +/** + * Create tests that a CSS property does not inherit, and that it has the + * given initial value. + * + * The current document must have an element #target within element #container. + * + * @param {string} property The name of the CSS property being tested. + * @param {string|array} initial The computed value for 'initial' or a list + * of acceptable computed value serializations. + * @param {string} other An arbitrary value for the property that + * round trips and is distinct from the initial + * value. + */ +function assert_not_inherited(property, initial, other) { + assert_initial(property, initial); + + test(() => { + const container = document.getElementById('container'); + const target = document.getElementById('target'); + assert_true(property in getComputedStyle(target)); + container.style[property] = 'initial'; + target.style[property] = 'unset'; + assert_not_equals(getComputedStyle(container)[property], other); + assert_not_equals(getComputedStyle(target)[property], other); + container.style[property] = other; + assert_equals(getComputedStyle(container)[property], other); + assert_not_equals(getComputedStyle(target)[property], other); + target.style[property] = 'inherit'; + assert_equals(getComputedStyle(target)[property], other); + container.style[property] = ''; + target.style[property] = ''; + }, 'Property ' + property + ' does not inherit'); +} + +window.assert_inherited = assert_inherited; +window.assert_not_inherited = assert_not_inherited; +})(); diff --git a/testing/web-platform/tests/css/support/interpolation-testcommon.js b/testing/web-platform/tests/css/support/interpolation-testcommon.js new file mode 100644 index 0000000000..2ee00e457a --- /dev/null +++ b/testing/web-platform/tests/css/support/interpolation-testcommon.js @@ -0,0 +1,467 @@ +'use strict'; +(function() { + var interpolationTests = []; + var compositionTests = []; + var cssAnimationsData = { + sharedStyle: null, + nextID: 0, + }; + var expectNoInterpolation = {}; + var expectNotAnimatable = {}; + var neutralKeyframe = {}; + function isNeutralKeyframe(keyframe) { + return keyframe === neutralKeyframe; + } + + // For the CSS interpolation methods set the delay to be negative half the + // duration, so we are immediately at the halfway point of the animation. + // We then use an easing function that maps halfway to whatever progress + // we actually want. + + var cssAnimationsInterpolation = { + name: 'CSS Animations', + isSupported: function() {return true;}, + supportsProperty: function() {return true;}, + supportsValue: function() {return true;}, + setup: function() {}, + nonInterpolationExpectations: function(from, to) { + return expectFlip(from, to, 0.5); + }, + notAnimatableExpectations: function(from, to, underlying) { + return expectFlip(underlying, underlying, -Infinity); + }, + interpolate: function(property, from, to, at, target) { + var id = cssAnimationsData.nextID++; + if (!cssAnimationsData.sharedStyle) { + cssAnimationsData.sharedStyle = createElement(document.body, 'style'); + } + cssAnimationsData.sharedStyle.textContent += '' + + '@keyframes animation' + id + ' {' + + (isNeutralKeyframe(from) ? '' : `from {${property}:${from};}`) + + (isNeutralKeyframe(to) ? '' : `to {${property}:${to};}`) + + '}'; + target.style.animationName = 'animation' + id; + target.style.animationDuration = '100s'; + target.style.animationDelay = '-50s'; + target.style.animationTimingFunction = createEasing(at); + }, + }; + + var cssTransitionsInterpolation = { + name: 'CSS Transitions', + isSupported: function() {return true;}, + supportsProperty: function() {return true;}, + supportsValue: function() {return true;}, + setup: function(property, from, target) { + target.style.setProperty(property, isNeutralKeyframe(from) ? '' : from); + }, + nonInterpolationExpectations: function(from, to) { + return expectFlip(from, to, 0.5); + }, + notAnimatableExpectations: function(from, to, underlying) { + return expectFlip(from, to, -Infinity); + }, + interpolate: function(property, from, to, at, target) { + // Force a style recalc on target to set the 'from' value. + getComputedStyle(target).getPropertyValue(property); + target.style.transitionDuration = '100s'; + target.style.transitionDelay = '-50s'; + target.style.transitionTimingFunction = createEasing(at); + target.style.transitionProperty = property; + target.style.setProperty(property, isNeutralKeyframe(to) ? '' : to); + }, + }; + + var cssTransitionAllInterpolation = { + name: 'CSS Transitions with transition: all', + isSupported: function() {return true;}, + // The 'all' value doesn't cover custom properties. + supportsProperty: function(property) {return property.indexOf('--') !== 0;}, + supportsValue: function() {return true;}, + setup: function(property, from, target) { + target.style.setProperty(property, isNeutralKeyframe(from) ? '' : from); + }, + nonInterpolationExpectations: function(from, to) { + return expectFlip(from, to, -Infinity); + }, + notAnimatableExpectations: function(from, to, underlying) { + return expectFlip(from, to, -Infinity); + }, + interpolate: function(property, from, to, at, target) { + // Force a style recalc on target to set the 'from' value. + getComputedStyle(target).getPropertyValue(property); + target.style.transitionDuration = '100s'; + target.style.transitionDelay = '-50s'; + target.style.transitionTimingFunction = createEasing(at); + target.style.transitionProperty = 'all'; + target.style.setProperty(property, isNeutralKeyframe(to) ? '' : to); + }, + }; + + var webAnimationsInterpolation = { + name: 'Web Animations', + isSupported: function() {return 'animate' in Element.prototype;}, + supportsProperty: function(property) {return true;}, + supportsValue: function(value) {return value !== '';}, + setup: function() {}, + nonInterpolationExpectations: function(from, to) { + return expectFlip(from, to, 0.5); + }, + notAnimatableExpectations: function(from, to, underlying) { + return expectFlip(underlying, underlying, -Infinity); + }, + interpolate: function(property, from, to, at, target) { + this.interpolateComposite(property, from, 'replace', to, 'replace', at, target); + }, + interpolateComposite: function(property, from, fromComposite, to, toComposite, at, target) { + // This case turns into a test error later on. + if (!this.isSupported()) + return; + + // Convert standard properties to camelCase. + if (!property.startsWith('--')) { + for (var i = property.length - 2; i > 0; --i) { + if (property[i] === '-') { + property = property.substring(0, i) + property[i + 1].toUpperCase() + property.substring(i + 2); + } + } + if (property === 'offset') { + property = 'cssOffset'; + } else if (property === 'float') { + property = 'cssFloat'; + } + } + var keyframes = []; + if (!isNeutralKeyframe(from)) { + keyframes.push({ + offset: 0, + composite: fromComposite, + [property]: from, + }); + } + if (!isNeutralKeyframe(to)) { + keyframes.push({ + offset: 1, + composite: toComposite, + [property]: to, + }); + } + var animation = target.animate(keyframes, { + fill: 'forwards', + duration: 100 * 1000, + easing: createEasing(at), + }); + animation.pause(); + animation.currentTime = 50 * 1000; + }, + }; + + function expectFlip(from, to, flipAt) { + return [-0.3, 0, 0.3, 0.5, 0.6, 1, 1.5].map(function(at) { + return { + at: at, + expect: at < flipAt ? from : to + }; + }); + } + + // Constructs a timing function which produces 'y' at x = 0.5 + function createEasing(y) { + if (y == 0) { + return 'steps(1, end)'; + } + if (y == 1) { + return 'steps(1, start)'; + } + if (y == 0.5) { + return 'linear'; + } + // Approximate using a bezier. + var b = (8 * y - 1) / 6; + return 'cubic-bezier(0, ' + b + ', 1, ' + b + ')'; + } + + function createElement(parent, tag, text) { + var element = document.createElement(tag || 'div'); + element.textContent = text || ''; + parent.appendChild(element); + return element; + } + + function createTargetContainer(parent, className) { + var targetContainer = createElement(parent); + targetContainer.classList.add('container'); + var template = document.querySelector('#target-template'); + if (template) { + targetContainer.appendChild(template.content.cloneNode(true)); + } + var target = targetContainer.querySelector('.target') || targetContainer; + target.classList.add('target', className); + target.parentElement.classList.add('parent'); + targetContainer.target = target; + return targetContainer; + } + + function roundNumbers(value) { + return value. + // Round numbers to two decimal places. + replace(/-?\d*\.\d+(e-?\d+)?/g, function(n) { + return (parseFloat(n).toFixed(2)). + replace(/\.\d+/, function(m) { + return m.replace(/0+$/, ''); + }). + replace(/\.$/, ''). + replace(/^-0$/, '0'); + }); + } + + var anchor = document.createElement('a'); + function sanitizeUrls(value) { + var matches = value.match(/url\("([^#][^\)]*)"\)/g); + if (matches !== null) { + for (var i = 0; i < matches.length; ++i) { + var url = /url\("([^#][^\)]*)"\)/g.exec(matches[i])[1]; + anchor.href = url; + anchor.pathname = '...' + anchor.pathname.substring(anchor.pathname.lastIndexOf('/')); + value = value.replace(matches[i], 'url(' + anchor.href + ')'); + } + } + return value; + } + + function normalizeValue(value) { + return roundNumbers(sanitizeUrls(value)). + // Place whitespace between tokens. + replace(/([\w\d.]+|[^\s])/g, '$1 '). + replace(/\s+/g, ' '); + } + + function stringify(text) { + if (!text.includes("'")) { + return `'${text}'`; + } + return `"${text.replace('"', '\\"')}"`; + } + + function keyframeText(keyframe) { + return isNeutralKeyframe(keyframe) ? 'neutral' : `[${keyframe}]`; + } + + function keyframeCode(keyframe) { + return isNeutralKeyframe(keyframe) ? 'neutralKeyframe' : `${stringify(keyframe)}`; + } + + function createInterpolationTestTargets(interpolationMethod, interpolationMethodContainer, interpolationTest) { + var property = interpolationTest.options.property; + var from = interpolationTest.options.from; + var to = interpolationTest.options.to; + var comparisonFunction = interpolationTest.options.comparisonFunction; + + if ((interpolationTest.options.method && interpolationTest.options.method != interpolationMethod.name) + || !interpolationMethod.supportsProperty(property) + || !interpolationMethod.supportsValue(from) + || !interpolationMethod.supportsValue(to)) { + return; + } + + var testText = `${interpolationMethod.name}: property <${property}> from ${keyframeText(from)} to ${keyframeText(to)}`; + var testContainer = createElement(interpolationMethodContainer, 'div'); + createElement(testContainer); + var expectations = interpolationTest.expectations; + var applyUnderlying = false; + if (expectations === expectNoInterpolation) { + expectations = interpolationMethod.nonInterpolationExpectations(from, to); + } else if (expectations === expectNotAnimatable) { + expectations = interpolationMethod.notAnimatableExpectations(from, to, interpolationTest.options.underlying); + applyUnderlying = true; + } else if (interpolationTest.options[interpolationMethod.name]) { + expectations = interpolationTest.options[interpolationMethod.name]; + } + + // Setup a standard equality function if an override is not provided. + if (!comparisonFunction) { + comparisonFunction = (actual, expected) => { + assert_equals(normalizeValue(actual), normalizeValue(expected)); + }; + } + + return expectations.map(function(expectation) { + var actualTargetContainer = createTargetContainer(testContainer, 'actual'); + var expectedTargetContainer = createTargetContainer(testContainer, 'expected'); + var expectedProperties = expectation.option || expectation.expect; + if (typeof expectedProperties !== "object") { + expectedProperties = {[property]: expectedProperties}; + } + var target = actualTargetContainer.target; + if (applyUnderlying) { + let underlying = interpolationTest.options.underlying; + assert_true(typeof underlying !== 'undefined', '\'underlying\' value must be provided'); + assert_true(CSS.supports(property, underlying), '\'underlying\' value must be supported'); + target.style.setProperty(property, underlying); + } + interpolationMethod.setup(property, from, target); + target.interpolate = function() { + interpolationMethod.interpolate(property, from, to, expectation.at, target); + }; + target.measure = function() { + for (var [expectedProp, expectedStr] of Object.entries(expectedProperties)) { + if (!isNeutralKeyframe(expectedStr)) { + expectedTargetContainer.target.style.setProperty(expectedProp, expectedStr); + } + var expectedValue = getComputedStyle(expectedTargetContainer.target).getPropertyValue(expectedProp); + let testName = `${testText} at (${expectation.at}) should be [${sanitizeUrls(expectedStr)}]`; + if (property !== expectedProp) { + testName += ` for <${expectedProp}>`; + } + test(function() { + assert_true(interpolationMethod.isSupported(), `${interpolationMethod.name} should be supported`); + + if (from && from !== neutralKeyframe) { + assert_true(CSS.supports(property, from), '\'from\' value should be supported'); + } + if (to && to !== neutralKeyframe) { + assert_true(CSS.supports(property, to), '\'to\' value should be supported'); + } + if (typeof underlying !== 'undefined') { + assert_true(CSS.supports(property, underlying), '\'underlying\' value should be supported'); + } + + comparisonFunction( + getComputedStyle(target).getPropertyValue(expectedProp), + expectedValue); + }, testName); + } + }; + return target; + }); + } + + function createCompositionTestTargets(compositionContainer, compositionTest) { + var options = compositionTest.options; + var property = options.property; + var underlying = options.underlying; + var comparisonFunction = options.comparisonFunction; + var from = options.accumulateFrom || options.addFrom || options.replaceFrom; + var to = options.accumulateTo || options.addTo || options.replaceTo; + var fromComposite = 'accumulateFrom' in options ? 'accumulate' : 'addFrom' in options ? 'add' : 'replace'; + var toComposite = 'accumulateTo' in options ? 'accumulate' : 'addTo' in options ? 'add' : 'replace'; + const invalidFrom = 'addFrom' in options === 'replaceFrom' in options + && 'addFrom' in options === 'accumulateFrom' in options; + const invalidTo = 'addTo' in options === 'replaceTo' in options + && 'addTo' in options === 'accumulateTo' in options; + if (invalidFrom || invalidTo) { + test(function() { + assert_false(invalidFrom, 'Exactly one of accumulateFrom, addFrom, or replaceFrom must be specified'); + assert_false(invalidTo, 'Exactly one of accumulateTo, addTo, or replaceTo must be specified'); + }, `Composition tests must have valid setup`); + } + + var testText = `Compositing: property <${property}> underlying [${underlying}] from ${fromComposite} [${from}] to ${toComposite} [${to}]`; + var testContainer = createElement(compositionContainer, 'div'); + createElement(testContainer); + + // Setup a standard equality function if an override is not provided. + if (!comparisonFunction) { + comparisonFunction = (actual, expected) => { + assert_equals(normalizeValue(actual), normalizeValue(expected)); + }; + } + + return compositionTest.expectations.map(function(expectation) { + var actualTargetContainer = createTargetContainer(testContainer, 'actual'); + var expectedTargetContainer = createTargetContainer(testContainer, 'expected'); + var expectedStr = expectation.option || expectation.expect; + if (!isNeutralKeyframe(expectedStr)) { + expectedTargetContainer.target.style.setProperty(property, expectedStr); + } + var target = actualTargetContainer.target; + target.style.setProperty(property, underlying); + target.interpolate = function() { + webAnimationsInterpolation.interpolateComposite(property, from, fromComposite, to, toComposite, expectation.at, target); + }; + target.measure = function() { + var expectedValue = getComputedStyle(expectedTargetContainer.target).getPropertyValue(property); + test(function() { + + if (from && from !== neutralKeyframe) { + assert_true(CSS.supports(property, from), '\'from\' value should be supported'); + } + if (to && to !== neutralKeyframe) { + assert_true(CSS.supports(property, to), '\'to\' value should be supported'); + } + if (typeof underlying !== 'undefined') { + assert_true(CSS.supports(property, underlying), '\'underlying\' value should be supported'); + } + + comparisonFunction( + getComputedStyle(target).getPropertyValue(property), + expectedValue); + }, `${testText} at (${expectation.at}) should be [${sanitizeUrls(expectedStr)}]`); + }; + return target; + }); + } + + + + function createTestTargets(interpolationMethods, interpolationTests, compositionTests, container) { + var targets = []; + for (var interpolationMethod of interpolationMethods) { + var interpolationMethodContainer = createElement(container); + for (var interpolationTest of interpolationTests) { + if(!interpolationTest.options.target_names || + interpolationTest.options.target_names.includes(interpolationMethod.name)) { + [].push.apply(targets, createInterpolationTestTargets(interpolationMethod, interpolationMethodContainer, interpolationTest)); + } + } + } + var compositionContainer = createElement(container); + for (var compositionTest of compositionTests) { + [].push.apply(targets, createCompositionTestTargets(compositionContainer, compositionTest)); + } + return targets; + } + + function test_no_interpolation(options) { + test_interpolation(options, expectNoInterpolation); + } + function test_not_animatable(options) { + test_interpolation(options, expectNotAnimatable); + } + function create_tests() { + var interpolationMethods = [ + cssTransitionsInterpolation, + cssTransitionAllInterpolation, + cssAnimationsInterpolation, + webAnimationsInterpolation, + ]; + var container = createElement(document.body); + var targets = createTestTargets(interpolationMethods, interpolationTests, compositionTests, container); + // Separate interpolation and measurement into different phases to avoid O(n^2) of the number of targets. + for (var target of targets) { + target.interpolate(); + } + for (var target of targets) { + target.measure(); + } + container.remove(); + } + + function test_interpolation(options, expectations) { + interpolationTests.push({options, expectations}); + create_tests(); + interpolationTests = []; + } + function test_composition(options, expectations) { + compositionTests.push({options, expectations}); + create_tests(); + compositionTests = []; + } + window.test_interpolation = test_interpolation; + window.test_no_interpolation = test_no_interpolation; + window.test_not_animatable = test_not_animatable; + window.test_composition = test_composition; + window.neutralKeyframe = neutralKeyframe; + window.roundNumbers = roundNumbers; + window.normalizeValue = normalizeValue; +})(); diff --git a/testing/web-platform/tests/css/support/numeric-testcommon.js b/testing/web-platform/tests/css/support/numeric-testcommon.js new file mode 100644 index 0000000000..3a39e2a973 --- /dev/null +++ b/testing/web-platform/tests/css/support/numeric-testcommon.js @@ -0,0 +1,196 @@ +'use strict'; + +/* +Provides functions to help test that two numeric values are equivalent. +These *do not* rely on you predicting what one value will serialize to; +instead, they set and serialize *both* values, +and just ensure that they serialize to the same thing. + +They rely on a #target element existing in the document, +as this might rely on layout to resolve styles, +and so it needs to be in the document. + +Three main functions are defined, with the same signatures: +test_math_used() (for testing used values), +test_math_computed() (for testing computed values), +and test_math_specified() (for testing specified values). +Signature for all is: + +test_math_X( + testString, // A numeric value; required. + expectedString, // A hopefully-equivalent numeric value; required. + { // all of these are optional + type, // "number", "length", etc. See impl for full list. Defaults to "length". + msg, // The message to display for the test; autogenned if not provided. + msgExtra, // Extra info to put after the auto-genned message. + prop, // If you want to override the automatic choice of tested property. + extraStyle, // Styles that need to be set at the same time to properly test the value. + } +); + + +Additionally, five specialized functions are provided +to test that a given value is ±∞, ±0, or NaN: + +* test_plus_infinity(testString) +* test_minus_infinity(testString) +* test_plus_zero(testString) +* test_minus_zero(testString) +* test_nan(testString) + +*/ + + + +function test_math_used(testString, expectedString, {approx, msg, msgExtra, type, prop, prefix, suffix, extraStyle={}}={}) { + if(type === undefined) type = "length"; + if(!prop) { + switch(type) { + case "number": prop = "transform"; prefix="scale("; suffix=")"; break; + case "integer": prop = "z-index"; extraStyle.position="absolute"; break; + case "length": prop = "margin-left"; break; + case "angle": prop = "transform"; prefix="rotate("; suffix=")"; break; + case "time": prop = "transition-delay"; break; + case "resolution": prop = "image-resolution"; break; + case "flex": prop = "grid-template-rows"; break; + default: throw Exception(`Value type '${type}' isn't capable of math.`); + } + + } + _test_math({stage:'used', testString, expectedString, type, approx, msg, msgExtra, prop, prefix, suffix, extraStyle}); +} + +function test_math_computed(testString, expectedString, {approx, msg, msgExtra, type, prop, prefix, suffix, extraStyle={}}={}) { + if(type === undefined) type = "length"; + if(!prop) { + switch(type) { + case "number": prop = "transform"; prefix="scale("; suffix=")"; break; + case "integer": prop = "z-index"; extraStyle.position="absolute"; break; + case "length": prop = "flex-basis"; break; + case "angle": prop = "transform"; prefix="rotate("; suffix=")"; break; + case "time": prop = "transition-delay"; break; + case "resolution": prop = "image-resolution"; break; + case "flex": prop = "grid-template-rows"; break; + default: throw Exception(`Value type '${type}' isn't capable of math.`); + } + + } + _test_math({stage:'computed', testString, expectedString, type, approx, msg, msgExtra, prop, prefix, suffix, extraStyle}); +} + +function test_math_specified(testString, expectedString, {approx, msg, msgExtra, type, prop, prefix, suffix, extraStyle={}}={}) { + if(type === undefined) type = "length"; + const stage = "specified"; + if(!prop) { + switch(type) { + case "number": prop = "transform"; prefix="scale("; suffix=")"; break; + case "integer": prop = "z-index"; extraStyle.position="absolute"; break; + case "length": prop = "flex-basis"; break; + case "angle": prop = "transform"; prefix="rotate("; suffix=")"; break; + case "time": prop = "transition-delay"; break; + case "resolution": prop = "image-resolution"; break; + case "flex": prop = "grid-template-rows"; break; + default: throw Exception(`Value type '${type}' isn't capable of math.`); + } + + } + // Find the test element + const testEl = document.getElementById('target'); + if(testEl == null) throw "Couldn't find #target element to run tests on."; + // Then reset its styles + testEl.style = ""; + for(const p in extraStyle) { + testEl.style[p] = extraStyle[p]; + } + if(!msg) { + msg = `${testString} should be ${stage}-value-equivalent to ${expectedString}`; + if(msgExtra) msg += "; " + msgExtra; + } + let t = testString; + let e = expectedString; + if(prefix) { + t = prefix + t; + e = prefix + e; + } + if(suffix) { + t += suffix; + e += suffix; + } + test(()=>{ + testEl.style[prop] = ''; + testEl.style[prop] = t; + const usedValue = testEl.style[prop]; + assert_not_equals(usedValue, '', `${testString} isn't valid in '${prop}'; got the default value instead.`); + testEl.style[prop] = ''; + testEl.style[prop] = e; + const expectedValue = testEl.style[prop]; + assert_not_equals(expectedValue, '', `${expectedString} isn't valid in '${prop}'; got the default value instead.`) + assert_equals(usedValue, expectedValue, `${testString} and ${expectedString} serialize to the same thing in ${stage} values.`); + }, msg); +} + +/* +All of these expect the testString to evaluate to a <number>. +*/ +function test_plus_infinity(testString) { + test_math_used(testString, "calc(infinity)", {type:"number"}); +} +function test_minus_infinity(testString) { + test_math_used(testString, "calc(-infinity)", {type:"number"}); +} +function test_plus_zero(testString) { + test_math_used(`calc(1 / ${testString})`, "calc(infinity)", {type:"number"}); +} +function test_minus_zero(testString) { + test_math_used(`calc(1 / ${testString})`, "calc(-infinity)", {type:"number"}); +} +function test_nan(testString) { + // Make sure that it's NaN, not an infinity, + // by making sure that it's the same value both pos and neg. + test_math_used(testString, "calc(NaN)", {type:"number"}); + test_math_used(`calc(-1 * ${testString})`, "calc(NaN)", {type:"number"}); +} + + +function _test_math({stage, testEl, testString, expectedString, type, approx, msg, msgExtra, prop, prefix, suffix, extraStyle}={}) { + // Find the test element + if(!testEl) testEl = document.getElementById('target'); + if(testEl == null) throw "Couldn't find #target element to run tests on."; + // Then reset its styles + testEl.style = ""; + for(const p in extraStyle) { + testEl.style[p] = extraStyle[p]; + } + if(!msg) { + msg = `${testString} should be ${stage}-value-equivalent to ${expectedString}`; + if(msgExtra) msg += "; " + msgExtra; + } + let t = testString; + let e = expectedString; + if(prefix) { + t = prefix + t; + e = prefix + e; + } + if(suffix) { + t += suffix; + e += suffix; + } + test(()=>{ + testEl.style[prop] = ''; + const defaultValue = getComputedStyle(testEl)[prop]; + testEl.style[prop] = t; + const usedValue = getComputedStyle(testEl)[prop]; + assert_not_equals(usedValue, defaultValue, `${testString} isn't valid in '${prop}'; got the default value instead.`); + testEl.style[prop] = ''; + testEl.style[prop] = e; + const expectedValue = getComputedStyle(testEl)[prop]; + assert_not_equals(expectedValue, defaultValue, `${expectedString} isn't valid in '${prop}'; got the default value instead.`) + if(approx && (type == "number" || type == "angle")){ + let parsedUsed = usedValue.split('(')[1].split(')')[0].split(',').map(parseFloat); + let parsedExpected = expectedValue.split('(')[1].split(')')[0].split(',').map(parseFloat); + assert_array_approx_equals(parsedUsed, parsedExpected, approx, `${testString} and ${expectedString} ${approx} serialize to the same thing in ${stage} values.`); + } else { + assert_equals(usedValue, expectedValue, `${testString} and ${expectedString} serialize to the same thing in ${stage} values.`); + } + }, msg); +} diff --git a/testing/web-platform/tests/css/support/parsing-testcommon.js b/testing/web-platform/tests/css/support/parsing-testcommon.js new file mode 100644 index 0000000000..cc040be511 --- /dev/null +++ b/testing/web-platform/tests/css/support/parsing-testcommon.js @@ -0,0 +1,166 @@ +'use strict'; + +// serializedValue can be the expected serialization of value, +// or an array of permitted serializations, +// or omitted if value should serialize as value. +function test_valid_value(property, value, serializedValue) { + if (arguments.length < 3) + serializedValue = value; + + var stringifiedValue = JSON.stringify(value); + + test(function(){ + var div = document.getElementById('target') || document.createElement('div'); + div.style[property] = ""; + div.style[property] = value; + var readValue = div.style.getPropertyValue(property); + assert_not_equals(readValue, "", "property should be set"); + if (Array.isArray(serializedValue)) + assert_in_array(readValue, serializedValue, "serialization should be sound"); + else + assert_equals(readValue, serializedValue, "serialization should be canonical"); + + div.style[property] = readValue; + assert_equals(div.style.getPropertyValue(property), readValue, "serialization should round-trip"); + + }, "e.style['" + property + "'] = " + stringifiedValue + " should set the property value"); +} + +function test_invalid_value(property, value) { + var stringifiedValue = JSON.stringify(value); + + test(function(){ + var div = document.getElementById('target') || document.createElement('div'); + div.style[property] = ""; + div.style[property] = value; + assert_equals(div.style.getPropertyValue(property), ""); + }, "e.style['" + property + "'] = " + stringifiedValue + " should not set the property value"); +} + +// serializedSelector can be the expected serialization of selector, +// or an array of permitted serializations, +// or omitted if value should serialize as selector. +function test_valid_selector(selector, serializedSelector) { + if (arguments.length < 2) + serializedSelector = selector; + + const stringifiedSelector = JSON.stringify(selector); + + test(function(){ + document.querySelector(selector); + assert_true(true, stringifiedSelector + " should not throw in querySelector"); + + const style = document.createElement("style"); + document.head.append(style); + const {sheet} = style; + document.head.removeChild(style); + const {cssRules} = sheet; + + assert_equals(cssRules.length, 0, "Sheet should have no rule"); + sheet.insertRule(selector + "{}"); + assert_equals(cssRules.length, 1, "Sheet should have 1 rule"); + + const readSelector = cssRules[0].selectorText; + if (Array.isArray(serializedSelector)) + assert_in_array(readSelector, serializedSelector, "serialization should be sound"); + else + assert_equals(readSelector, serializedSelector, "serialization should be canonical"); + + sheet.deleteRule(0); + assert_equals(cssRules.length, 0, "Sheet should have no rule"); + sheet.insertRule(readSelector + "{}"); + assert_equals(cssRules.length, 1, "Sheet should have 1 rule"); + + assert_equals(cssRules[0].selectorText, readSelector, "serialization should round-trip"); + }, stringifiedSelector + " should be a valid selector"); +} + +function test_invalid_selector(selector) { + const stringifiedSelector = JSON.stringify(selector); + + test(function(){ + assert_throws_dom( + DOMException.SYNTAX_ERR, + () => document.querySelector(selector), + stringifiedSelector + " should throw in querySelector"); + + const style = document.createElement("style"); + document.head.append(style); + const {sheet} = style; + document.head.removeChild(style); + + assert_throws_dom( + DOMException.SYNTAX_ERR, + () => sheet.insertRule(selector + "{}"), + stringifiedSelector + " should throw in insertRule"); + }, stringifiedSelector + " should be an invalid selector"); +} + +// serialized can be the expected serialization of rule, or an array of +// permitted serializations, or omitted if value should serialize as rule. +function test_valid_rule(rule, serialized) { + if (serialized === undefined) + serialized = rule; + + test(function(){ + const style = document.createElement("style"); + document.head.append(style); + const {sheet} = style; + document.head.removeChild(style); + const {cssRules} = sheet; + + assert_equals(cssRules.length, 0, "Sheet should have no rules"); + sheet.insertRule(rule); + assert_equals(cssRules.length, 1, "Sheet should have 1 rule"); + + const serialization = cssRules[0].cssText; + if (Array.isArray(serialized)) + assert_in_array(serialization, serialized, "serialization should be sound"); + else + assert_equals(serialization, serialized, "serialization should be canonical"); + + sheet.deleteRule(0); + assert_equals(cssRules.length, 0, "Sheet should have no rule"); + sheet.insertRule(serialization); + assert_equals(cssRules.length, 1, "Sheet should have 1 rule"); + + assert_equals(cssRules[0].cssText, serialization, "serialization should round-trip"); + }, rule + " should be a valid rule"); +} + +function test_invalid_rule(rule) { + test(function(){ + const style = document.createElement("style"); + document.head.append(style); + const {sheet} = style; + document.head.removeChild(style); + + assert_throws_dom( + DOMException.SYNTAX_ERR, + () => sheet.insertRule(rule), + rule + " should throw in insertRule"); + }, rule + " should be an invalid rule"); +} + +function _set_style(rule) { + const style = document.createElement('style'); + style.innerText = rule; + document.head.append(style); + const { sheet } = style; + document.head.removeChild(style); + return sheet; +} + +function test_keyframes_name_valid(keyframes_name) { + test(t => { + const sheet = _set_style(`@keyframes ${keyframes_name} {}`); + assert_equals(sheet.cssRules.length, 1); + }, `valid: @keyframes ${keyframes_name} { }`); +} + +function test_keyframes_name_invalid(keyframes_name) { + test(t => { + const sheet = _set_style(`@keyframes ${keyframes_name} {}`); + assert_equals(sheet.cssRules.length, 0); + }, `invalid: @keyframes ${keyframes_name} { }`); +}
\ No newline at end of file diff --git a/testing/web-platform/tests/css/support/pattern-grg-rgr-grg.png b/testing/web-platform/tests/css/support/pattern-grg-rgr-grg.png Binary files differnew file mode 100644 index 0000000000..9b88fbd811 --- /dev/null +++ b/testing/web-platform/tests/css/support/pattern-grg-rgr-grg.png diff --git a/testing/web-platform/tests/css/support/pattern-grg-rrg-rgg.png b/testing/web-platform/tests/css/support/pattern-grg-rrg-rgg.png Binary files differnew file mode 100644 index 0000000000..fcf4f3fd7d --- /dev/null +++ b/testing/web-platform/tests/css/support/pattern-grg-rrg-rgg.png diff --git a/testing/web-platform/tests/css/support/pattern-rgr-grg-rgr.png b/testing/web-platform/tests/css/support/pattern-rgr-grg-rgr.png Binary files differnew file mode 100644 index 0000000000..d454e3a630 --- /dev/null +++ b/testing/web-platform/tests/css/support/pattern-rgr-grg-rgr.png diff --git a/testing/web-platform/tests/css/support/pattern-tr.png b/testing/web-platform/tests/css/support/pattern-tr.png Binary files differnew file mode 100644 index 0000000000..8b4b25364e --- /dev/null +++ b/testing/web-platform/tests/css/support/pattern-tr.png diff --git a/testing/web-platform/tests/css/support/query-testcommon.js b/testing/web-platform/tests/css/support/query-testcommon.js new file mode 100644 index 0000000000..73246e17e8 --- /dev/null +++ b/testing/web-platform/tests/css/support/query-testcommon.js @@ -0,0 +1,18 @@ +'use strict'; + +function test_query_selector(parentNode, selector, expected) { + if (!Array.isArray(expected)) + expected = [ expected ]; + + test(function(){ + const elementList = parentNode.querySelectorAll(selector); + assert_equals(elementList.length, expected.length); + + for (let i = 0; i < elementList.length; ++i) { + if (typeof expected[i] === 'string') + assert_equals(elementList[i].id, expected[i]); + else + assert_equals(elementList[i], expected[i]); + } + }, "Selector '" + selector + '" should find the expected elements'); +} diff --git a/testing/web-platform/tests/css/support/red-rect.svg b/testing/web-platform/tests/css/support/red-rect.svg new file mode 100644 index 0000000000..3fe10a2b6f --- /dev/null +++ b/testing/web-platform/tests/css/support/red-rect.svg @@ -0,0 +1,6 @@ +<?xml version="1.0"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100"> + <rect width="200" height="100" style="fill:red;" /> +</svg> diff --git a/testing/web-platform/tests/css/support/red.ico b/testing/web-platform/tests/css/support/red.ico Binary files differnew file mode 100644 index 0000000000..22a7b36fe3 --- /dev/null +++ b/testing/web-platform/tests/css/support/red.ico diff --git a/testing/web-platform/tests/css/support/ruler-h-50%.png b/testing/web-platform/tests/css/support/ruler-h-50%.png Binary files differnew file mode 100644 index 0000000000..cf2eea6b43 --- /dev/null +++ b/testing/web-platform/tests/css/support/ruler-h-50%.png diff --git a/testing/web-platform/tests/css/support/ruler-h-50px.png b/testing/web-platform/tests/css/support/ruler-h-50px.png Binary files differnew file mode 100644 index 0000000000..9f46583665 --- /dev/null +++ b/testing/web-platform/tests/css/support/ruler-h-50px.png diff --git a/testing/web-platform/tests/css/support/ruler-v-100px.png b/testing/web-platform/tests/css/support/ruler-v-100px.png Binary files differnew file mode 100644 index 0000000000..a837eca222 --- /dev/null +++ b/testing/web-platform/tests/css/support/ruler-v-100px.png diff --git a/testing/web-platform/tests/css/support/ruler-v-50px.png b/testing/web-platform/tests/css/support/ruler-v-50px.png Binary files differnew file mode 100644 index 0000000000..8414102802 --- /dev/null +++ b/testing/web-platform/tests/css/support/ruler-v-50px.png diff --git a/testing/web-platform/tests/css/support/serialize-testcommon.js b/testing/web-platform/tests/css/support/serialize-testcommon.js new file mode 100644 index 0000000000..18cebf538e --- /dev/null +++ b/testing/web-platform/tests/css/support/serialize-testcommon.js @@ -0,0 +1,94 @@ +"use strict"; + + +/* Functions to test serialization of properties. + +Each takes (property, testString, expectedSerialization) arguments. + +These functions depend on a #target element existing in the page, +and will error if they don't find one. + +Note that test_computed_serialization and test_used_serialization +are identical except for assertion messages; +you need to choose properties with the correct resolved values +to test the value stage that you want. + + +For ease of use, it's recommended that you define and use +the following function in your test page: + +function test_serialization(t,s,c,u, {prop}={}) { + test_specified_serialization(prop || 'text-indent', t, s); + test_computed_serialization(prop || 'text-indent', t, c); + if(u) test_used_serialization(prop || 'margin-left', t, u); +} + +(swapping the property names for what you're expecting to test) + +Then you can write tests easily as: + +test_serialization( + 'calc(min(1%, 2%) + max(3%, 4%) + 10%)', // test string + 'calc(15%)', // expected specified value + '15%', // expected computed value + '15px'); // expected used value + +*/ + + + + +function test_specified_serialization(prop, t, e) { + const el = document.querySelector("#target"); + if(!el) throw new Exception("Couldn't find #target element to run tests on."); + test(()=>{ + el.style[prop] = ''; + el.style[prop] = t; + const tValue = el.style[prop]; + assert_not_equals(tValue, '', `'${t}' should be valid in ${prop}.`); + + el.style[prop] = ''; + el.style[prop] = e; + const eValue = el.style[prop]; + assert_not_equals(eValue, '', `'${e}' should be valid in ${prop}.`); + assert_equals(eValue, e, `'${e}' should round-trip exactly in specified values.`); + + assert_equals(tValue, e, `'${t}' and '${e}' should serialize the same in specified values.`); + }, `'${t}' as a specified value should serialize as '${e}'.`); +} +function test_computed_serialization(prop, t, e) { + const el = document.querySelector("#target"); + if(!el) throw new Exception("Couldn't find #target element to run tests on."); + test(()=>{ + el.style[prop] = ''; + el.style[prop] = t; + const tValue = getComputedStyle(el)[prop]; + assert_not_equals(tValue, '', `'${t}' should be valid in ${prop}.`); + + el.style[prop] = ''; + el.style[prop] = e; + const eValue = getComputedStyle(el)[prop]; + assert_not_equals(eValue, '', `'${e}' should be valid in ${prop}.`); + assert_equals(eValue, e, `'${e}' should round-trip exactly in computed values.`); + + assert_equals(tValue, e, `'${t}' and '${e}' should serialize the same in computed values.`); + }, `'${t}' as a computed value should serialize as '${e}'.`); +} +function test_used_serialization(prop, t, e) { + const el = document.querySelector("#target"); + if(!el) throw new Exception("Couldn't find #target element to run tests on."); + test(()=>{ + el.style[prop] = ''; + el.style[prop] = t; + const tValue = getComputedStyle(el)[prop]; + assert_not_equals(tValue, '', `'${t}' should be valid in ${prop}.`); + + el.style[prop] = ''; + el.style[prop] = e; + const eValue = getComputedStyle(el)[prop]; + assert_not_equals(eValue, '', `'${e}' should be valid in ${prop}.`); + assert_equals(eValue, e, `'${e}' should round-trip exactly in used values.`); + + assert_equals(tValue, e, `'${t}' and '${e}' should serialize the same in used values.`); + }, `'${t}' as a used value should serialize as '${e}'.`); +}
\ No newline at end of file diff --git a/testing/web-platform/tests/css/support/shorthand-testcommon.js b/testing/web-platform/tests/css/support/shorthand-testcommon.js new file mode 100644 index 0000000000..ab1f3794c8 --- /dev/null +++ b/testing/web-platform/tests/css/support/shorthand-testcommon.js @@ -0,0 +1,40 @@ +'use strict'; + +function test_shorthand_value(property, value, longhands) { + const stringifiedValue = JSON.stringify(value); + + for (let longhand of Object.keys(longhands).sort()) { + test(function(){ + var div = document.getElementById('target') || document.createElement('div'); + div.style[property] = ""; + try { + div.style[property] = value; + + const readValue = div.style[longhand]; + assert_equals(readValue, longhands[longhand], longhand + " should be canonical"); + + div.style[longhand] = ""; + div.style[longhand] = readValue; + assert_equals(div.style[longhand], readValue, "serialization should round-trip"); + } finally { + div.style[property] = ""; + } + }, "e.style['" + property + "'] = " + stringifiedValue + " should set " + longhand); + } + + test(function(){ + var div = document.getElementById('target') || document.createElement('div'); + div.style[property] = ""; + try { + const expectedLength = div.style.length; + div.style[property] = value; + assert_true(CSS.supports(property, value)); + for (let longhand of Object.keys(longhands).sort()) { + div.style[longhand] = ""; + } + assert_equals(div.style.length, expectedLength); + } finally { + div.style[property] = ""; + } + }, "e.style['" + property + "'] = " + stringifiedValue + " should not set unrelated longhands"); +} diff --git a/testing/web-platform/tests/css/support/square-purple.png b/testing/web-platform/tests/css/support/square-purple.png Binary files differnew file mode 100644 index 0000000000..0f522d7872 --- /dev/null +++ b/testing/web-platform/tests/css/support/square-purple.png diff --git a/testing/web-platform/tests/css/support/square-teal.png b/testing/web-platform/tests/css/support/square-teal.png Binary files differnew file mode 100644 index 0000000000..e567f51b91 --- /dev/null +++ b/testing/web-platform/tests/css/support/square-teal.png diff --git a/testing/web-platform/tests/css/support/square-white.png b/testing/web-platform/tests/css/support/square-white.png Binary files differnew file mode 100644 index 0000000000..5853cbb238 --- /dev/null +++ b/testing/web-platform/tests/css/support/square-white.png diff --git a/testing/web-platform/tests/css/support/support/README b/testing/web-platform/tests/css/support/support/README new file mode 100644 index 0000000000..ea8cb9ef35 --- /dev/null +++ b/testing/web-platform/tests/css/support/support/README @@ -0,0 +1,4 @@ +The swatch-green.png file in this directory is really a RED swatch, +and the swatch-red.png file is really a green swatch. + +This directory is used to test relative URIs.
\ No newline at end of file diff --git a/testing/web-platform/tests/css/support/support/swatch-green.png b/testing/web-platform/tests/css/support/support/swatch-green.png Binary files differnew file mode 100644 index 0000000000..1caf25c992 --- /dev/null +++ b/testing/web-platform/tests/css/support/support/swatch-green.png diff --git a/testing/web-platform/tests/css/support/support/swatch-red.png b/testing/web-platform/tests/css/support/support/swatch-red.png Binary files differnew file mode 100644 index 0000000000..0aa79b0c86 --- /dev/null +++ b/testing/web-platform/tests/css/support/support/swatch-red.png diff --git a/testing/web-platform/tests/css/support/swatch-blue.png b/testing/web-platform/tests/css/support/swatch-blue.png Binary files differnew file mode 100644 index 0000000000..bf2759634d --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-blue.png diff --git a/testing/web-platform/tests/css/support/swatch-green.png b/testing/web-platform/tests/css/support/swatch-green.png Binary files differnew file mode 100644 index 0000000000..0aa79b0c86 --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-green.png diff --git a/testing/web-platform/tests/css/support/swatch-lime.png b/testing/web-platform/tests/css/support/swatch-lime.png Binary files differnew file mode 100644 index 0000000000..55fd7fdaed --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-lime.png diff --git a/testing/web-platform/tests/css/support/swatch-orange.png b/testing/web-platform/tests/css/support/swatch-orange.png Binary files differnew file mode 100644 index 0000000000..d3cd498b52 --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-orange.png diff --git a/testing/web-platform/tests/css/support/swatch-red.png b/testing/web-platform/tests/css/support/swatch-red.png Binary files differnew file mode 100644 index 0000000000..1caf25c992 --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-red.png diff --git a/testing/web-platform/tests/css/support/swatch-teal.png b/testing/web-platform/tests/css/support/swatch-teal.png Binary files differnew file mode 100644 index 0000000000..0293ce89de --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-teal.png diff --git a/testing/web-platform/tests/css/support/swatch-white.png b/testing/web-platform/tests/css/support/swatch-white.png Binary files differnew file mode 100644 index 0000000000..1a7d4323d7 --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-white.png diff --git a/testing/web-platform/tests/css/support/swatch-yellow.png b/testing/web-platform/tests/css/support/swatch-yellow.png Binary files differnew file mode 100644 index 0000000000..1591aa0e2e --- /dev/null +++ b/testing/web-platform/tests/css/support/swatch-yellow.png diff --git a/testing/web-platform/tests/css/support/test-bl.png b/testing/web-platform/tests/css/support/test-bl.png Binary files differnew file mode 100644 index 0000000000..904e24e996 --- /dev/null +++ b/testing/web-platform/tests/css/support/test-bl.png diff --git a/testing/web-platform/tests/css/support/test-br.png b/testing/web-platform/tests/css/support/test-br.png Binary files differnew file mode 100644 index 0000000000..f413ff5c1a --- /dev/null +++ b/testing/web-platform/tests/css/support/test-br.png diff --git a/testing/web-platform/tests/css/support/test-inner-half-size.png b/testing/web-platform/tests/css/support/test-inner-half-size.png Binary files differnew file mode 100644 index 0000000000..e473bf80ef --- /dev/null +++ b/testing/web-platform/tests/css/support/test-inner-half-size.png diff --git a/testing/web-platform/tests/css/support/test-outer.png b/testing/web-platform/tests/css/support/test-outer.png Binary files differnew file mode 100644 index 0000000000..82eeace7fc --- /dev/null +++ b/testing/web-platform/tests/css/support/test-outer.png diff --git a/testing/web-platform/tests/css/support/test-tl.png b/testing/web-platform/tests/css/support/test-tl.png Binary files differnew file mode 100644 index 0000000000..f6ac0ef7e8 --- /dev/null +++ b/testing/web-platform/tests/css/support/test-tl.png diff --git a/testing/web-platform/tests/css/support/test-tr.png b/testing/web-platform/tests/css/support/test-tr.png Binary files differnew file mode 100644 index 0000000000..59843ae54b --- /dev/null +++ b/testing/web-platform/tests/css/support/test-tr.png diff --git a/testing/web-platform/tests/css/support/width-keyword-classes.css b/testing/web-platform/tests/css/support/width-keyword-classes.css new file mode 100644 index 0000000000..e777527603 --- /dev/null +++ b/testing/web-platform/tests/css/support/width-keyword-classes.css @@ -0,0 +1,43 @@ +/* + Take every possible line break so the box width is the width of largest + unbreakable line box. +*/ +.min-content { + width: min-content; +} + +.max-content { + width: max-content; +} + +/* + Shrink wrap just like floating. + max(min-content, min(max-content, fill-available)) +*/ +.fit-content { + width: fit-content; +} + +.max-width-min-content { + max-width: min-content; +} + +.max-width-max-content { + max-width: max-content; +} + +.max-width-fit-content { + max-width: fit-content; +} + +.min-width-min-content { + min-width: min-content; +} + +.min-width-max-content { + min-width: max-content; +} + +.min-width-fit-content { + min-width: fit-content; +} |