summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-typed-om
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/css/css-typed-om')
-rw-r--r--testing/web-platform/tests/css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html16
-rw-r--r--testing/web-platform/tests/css/css-typed-om/META.yml3
-rw-r--r--testing/web-platform/tests/css/css-typed-om/declared-styleMap-accepts-inherit.html15
-rw-r--r--testing/web-platform/tests/css/css-typed-om/factory-absolute-length.html64
-rw-r--r--testing/web-platform/tests/css/css-typed-om/factory-duration.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/factory-font-relative-length.html41
-rw-r--r--testing/web-platform/tests/css/css-typed-om/factory-frequency.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/historical.html13
-rw-r--r--testing/web-platform/tests/css/css-typed-om/idlharness.html78
-rw-r--r--testing/web-platform/tests/css/css-typed-om/perspective-typed-arithmetic-crash.html11
-rw-r--r--testing/web-platform/tests/css/css-typed-om/resources/testhelper.js217
-rw-r--r--testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle-ref.html17
-rw-r--r--testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/set-css-wide-in-custom-property-crash.html15
-rw-r--r--testing/web-platform/tests/css/css-typed-om/set-var-reference-thcrash.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-image.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-numeric.tentative.html49
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html71
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html187
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse-invalid.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse.html43
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll-invalid.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-convert-crash.html13
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-zero.html11
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssTransform-Internal-value.html12
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssImageValue.html19
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.html145
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-cssom.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html167
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnitValue.tentative.html43
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html44
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssColorValue.html199
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHSL.html85
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHWB.html91
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-invalid.html17
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLCH.html81
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLab.html79
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html61
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLCH.html81
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLab.html79
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRGB.html116
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRotate.tentative.html126
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html89
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html70
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html62
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html62
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-2d-flattening.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html86
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html52
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html97
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTranslate.tentative.html110
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-empty.html15
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-indexed-getter-setter.html54
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-iterable.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-length.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-invalid.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-variable.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/add-two-types.tentative.html60
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html160
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/create-a-type.tentative.html51
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathInvert-type.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathNegate-type.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html80
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-value.html19
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.html32
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssnumericvalue-multiply-two-types.tentative.html61
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html74
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html58
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/resources/testhelper.js9
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html111
-rw-r--r--testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html71
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html68
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html57
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-position.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-shorthand.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get.html51
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-disconnected-element-crash.html7
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-shorthand.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/has.tentative.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html58
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/append.tentative.html74
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/clear.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html76
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-shorthand.html55
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete.html56
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-shorthand.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get.html56
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll-shorthand.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/has.tentative.html36
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set-shorthand.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html98
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/append.tentative.html65
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/clear.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-shorthand.html55
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete.html56
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-invalid.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-shorthand.html36
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get.html56
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll-shorthand.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/has.tentative.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set-shorthand.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html98
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/accent-color.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/alignment-baseline.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/all.html18
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html19
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html19
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-duration.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-fill-mode.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-iteration-count.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-name.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-play-state.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backdrop-filter.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backface-visibility.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-attachment.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-blend-mode.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-clip.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-image.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-origin.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-position.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-repeat.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-size.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/baseline-shift.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/block-size.html63
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-collapse.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-color.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-outset.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-repeat.html41
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-slice.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-source.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-width.html44
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-radius.html38
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-style.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-width.html44
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/bottom.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-shadow.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-sizing.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/break.html41
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caption-side.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caret-color.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/center-coordinate.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clear.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-path.html32
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-rule.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color-interpolation.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-count.html41
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-span.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-width.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/contain.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-name.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-type.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/coordinate.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-increment.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-reset.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-set.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/cursor.html59
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/d.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/direction.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/display.html59
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/dominant-baseline.html28
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/empty-cells.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-opacity.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-rule.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/filter.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-basis.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-direction.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-flow.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-grow.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/float.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-opacity.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-family.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-feature-settings.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-kerning.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-language-override.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-optical-sizing.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-palette.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-presentation.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size-adjust.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size.html72
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-stretch.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-style.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-synthesis.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-alternates.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-caps.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-east-asian.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-emoji.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-ligatures.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-numeric.html32
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variation-settings.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-weight.html50
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/gap.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-area.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-columns-rows.html49
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-flow.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-gap.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-start-end.html28
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-areas.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-columns-rows.html49
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/height.html63
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/hyphens.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/image-rendering.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/inline-size.html63
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/isolation.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/left.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/letter-spacing.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/lighting-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-break.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-height.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-image.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-position.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-type.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/logical.html105
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/margin.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/marker.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-image.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-type.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mix-blend-mode.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-fit.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-position.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-anchor.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-distance.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-path.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-position.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-rotate.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/opacity.html48
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/order.html35
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/orphans.html37
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-color.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-offset.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-style.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-width.html41
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-anchor.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-clip-margin.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-wrap.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overscroll-behavior.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/padding.html39
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/page.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/paint-order.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective-origin.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/pointer-events.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/position.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/quotes.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/radius.html63
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resize.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js485
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/right.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-behavior.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-margin.html32
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-padding.html57
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-align.html39
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-stop.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-gutter.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-width.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-image-threshold.html34
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-margin.html37
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-outside.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-rendering.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/speak.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-opacity.html49
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dasharray.html47
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dashoffset.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linecap.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linejoin.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-miterlimit.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-opacity.html48
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-width.html39
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/tab-size.html42
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/table-layout.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align-last.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-anchor.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-combine-upright.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-line.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip-ink.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip.html29
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-emphasis-color.html30
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-indent.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-justify.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-orientation.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-rendering.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-shadow.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-size-adjust.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-transform.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-offset.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-position.html27
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/top.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/touch-action.html33
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-box.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-interpolated.html31
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-style.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-delay.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html19
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-property.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html40
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition.html20
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/unicode-bidi.html25
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/user-select.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vector-effect.html21
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vertical-align.html23
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/visibility.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/white-space.html51
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/widows.html37
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/width.html63
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/will-change.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-break.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-spacing.html22
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-wrap.html26
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/writing-mode.html24
-rw-r--r--testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/z-index.html37
-rw-r--r--testing/web-platform/tests/css/css-typed-om/width-by-clamp-px-em.html15
-rw-r--r--testing/web-platform/tests/css/css-typed-om/width-by-max-px-em.html15
-rw-r--r--testing/web-platform/tests/css/css-typed-om/width-by-min-px-em.html15
366 files changed, 13987 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html b/testing/web-platform/tests/css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html
new file mode 100644
index 0000000000..f90526ae69
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSSMatrixComponent's matrix attribute is mutable</title>
+<meta name="author" title="Shane Stephens">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+ <div id="log"></div>
+ <script>
+ test(function() {
+ var component = new CSSMatrixComponent(new DOMMatrix());
+ assert_equals(component.matrix.m11, 1, 'DOMMatrix expected to be initialized to identity');
+ component.matrix.m11 = 2;
+ assert_equals(component.matrix.m11, 2, 'modification of m11 component of DOMMatrix expected to succeed');
+ });
+ </script>
diff --git a/testing/web-platform/tests/css/css-typed-om/META.yml b/testing/web-platform/tests/css/css-typed-om/META.yml
new file mode 100644
index 0000000000..a448fc800d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/META.yml
@@ -0,0 +1,3 @@
+spec: https://drafts.css-houdini.org/css-typed-om/
+suggested_reviewers:
+ - darrnshn
diff --git a/testing/web-platform/tests/css/css-typed-om/declared-styleMap-accepts-inherit.html b/testing/web-platform/tests/css/css-typed-om/declared-styleMap-accepts-inherit.html
new file mode 100644
index 0000000000..f02cf98ef5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/declared-styleMap-accepts-inherit.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Declared styleMap objects accept 'inherit' as a value</title>
+<meta name="author" title="Shane Stephens">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+ <div id='element'></div>
+ <div id="log"></div>
+ <script>
+ test(function() {
+ element.attributeStyleMap.set('width', new CSSKeywordValue('inherit'));
+ assert_equals(element.attributeStyleMap.get('width').value, 'inherit', 'inherit should be a valid value for styleMap properties');
+ });
+ </script>
diff --git a/testing/web-platform/tests/css/css-typed-om/factory-absolute-length.html b/testing/web-platform/tests/css/css-typed-om/factory-absolute-length.html
new file mode 100644
index 0000000000..5712ca99f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/factory-absolute-length.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSSOM Test: Numeric Factory Functions for absolute length</title>
+ <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+ <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory">
+ <meta name="assert" content="CSS factory functions produce expected CSSUnitValue">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ test(function(){
+ var length = CSS.cm(10);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 10);
+ assert_equals(length.unit, 'cm');
+ }, 'CSS.cm() produces cm length');
+
+ test(function(){
+ var length = CSS.mm(20);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 20);
+ assert_equals(length.unit, 'mm');
+ }, 'CSS.mm() produces mm length');
+
+ test(function(){
+ var length = CSS.Q(30);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 30);
+ assert_equals(length.unit, 'q');
+ }, 'CSS.Q() produces q length');
+
+ test(function(){
+ var length = CSS.in(40);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 40);
+ assert_equals(length.unit, 'in');
+ }, 'CSS.in() produces in length');
+
+ test(function(){
+ var length = CSS.pt(50);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 50);
+ assert_equals(length.unit, 'pt');
+ }, 'CSS.pt() produces pt length');
+
+ test(function(){
+ var length = CSS.pc(60);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 60);
+ assert_equals(length.unit, 'pc');
+ }, 'CSS.pc() produces pc length');
+
+ test(function(){
+ var length = CSS.px(70);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, 70);
+ assert_equals(length.unit, 'px');
+ }, 'CSS.px() produces px length');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-typed-om/factory-duration.html b/testing/web-platform/tests/css/css-typed-om/factory-duration.html
new file mode 100644
index 0000000000..ac4971393a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/factory-duration.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSSOM Test: Numeric Factory Functions for duration</title>
+ <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+ <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory">
+ <meta name="assert" content="CSS factory functions produce expected CSSUnitValue">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ test(function(){
+ var duration = CSS.s(10);
+ assert_true(duration instanceof CSSUnitValue);
+ assert_equals(duration.value, 10);
+ assert_equals(duration.unit, 's');
+ }, 'CSS.s() produces s duration');
+
+ test(function(){
+ var duration = CSS.ms(20);
+ assert_true(duration instanceof CSSUnitValue);
+ assert_equals(duration.value, 20);
+ assert_equals(duration.unit, 'ms');
+ }, 'CSS.ms() produces ms duration');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-typed-om/factory-font-relative-length.html b/testing/web-platform/tests/css/css-typed-om/factory-font-relative-length.html
new file mode 100644
index 0000000000..f7e41ee297
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/factory-font-relative-length.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>CSSOM Test: Numeric Factory Functions for font relative length</title>
+ <link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
+ <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory">
+ <meta name="assert" content="CSS factory functions produce expected CSSUnitValue">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script>
+ "use strict";
+
+ let units = [
+ "cap",
+ "ch",
+ "em",
+ "ex",
+ "ic",
+ "lh",
+ "rcap",
+ "rch",
+ "rem",
+ "rex",
+ "ric",
+ "rlh"
+ ];
+ let counter = 1;
+ for (let unit of units) {
+ test(function(){
+ let length = CSS[unit](counter);
+ assert_true(length instanceof CSSUnitValue);
+ assert_equals(length.value, counter);
+ assert_equals(length.unit, unit);
+ counter++;
+ }, `CSS.${unit}() produces ${unit} length`);
+ }
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-typed-om/factory-frequency.html b/testing/web-platform/tests/css/css-typed-om/factory-frequency.html
new file mode 100644
index 0000000000..56a544b32f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/factory-frequency.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSSOM Test: Numeric Factory Functions for frequency</title>
+ <link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org">
+ <link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory">
+ <meta name="assert" content="CSS factory functions produce expected CSSUnitValue">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ test(function(){
+ var frequency = CSS.Hz(10);
+ assert_true(frequency instanceof CSSUnitValue);
+ assert_equals(frequency.value, 10);
+ assert_equals(frequency.unit, 'hz');
+ }, 'CSS.Hz() produces hz frequency');
+
+ test(function(){
+ var frequency = CSS.kHz(20);
+ assert_true(frequency instanceof CSSUnitValue);
+ assert_equals(frequency.value, 20);
+ assert_equals(frequency.unit, 'khz');
+ }, 'CSS.kHz() produces khz frequency');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-typed-om/historical.html b/testing/web-platform/tests/css/css-typed-om/historical.html
new file mode 100644
index 0000000000..ceb4dfe567
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/historical.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Historical features</title>
+<link rel=help href="https://drafts.css-houdini.org/css-typed-om/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ // https://github.com/w3c/css-houdini-drafts/commit/5261c1a323ea062d69cb5a3f1e69734fd176948a
+ assert_false("CSSPositionValue" in self);
+}, "Support for CSSPositionValue");
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/idlharness.html b/testing/web-platform/tests/css/css-typed-om/idlharness.html
new file mode 100644
index 0000000000..aaff3a1392
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/idlharness.html
@@ -0,0 +1,78 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS Typed OM IDL</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#idl-index">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+
+<style>
+ body {
+ font-size: normal;
+ }
+</style>
+
+<script>
+'use strict';
+
+idl_test(
+ ['css-typed-om'],
+ ['cssom', 'SVG', 'geometry', 'html', 'dom', 'mathml-core'],
+ idl_array => {
+ try {
+ self.styleMap = document.styleSheets[0].rules[0].styleMap;
+ } catch (e) {}
+
+ try {
+ self.unitValue = CSSStyleValue.parse('height', '10px');
+ } catch (e) {}
+
+ try {
+ self.mathSum = CSSStyleValue.parse('width', 'calc(100% - 32px)');
+ } catch (e) {}
+
+ try {
+ self.transformValue = CSSStyleValue.parse('transform', 'translateX(0)');
+ } catch (e) {}
+
+ try {
+ self.rotate = CSSStyleValue.parse('transform', 'rotateX(0)')[0];
+ } catch (e) {}
+
+ try {
+ self.scale = CSSStyleValue.parse('transform', 'scale(1)')[0];
+ } catch (e) {}
+
+ try {
+ self.skew = CSSStyleValue.parse('transform', 'skew(0,0)')[0];
+ self.skewX = CSSStyleValue.parse('transform', 'skewX(0)')[0];
+ self.skewY = CSSStyleValue.parse('transform', 'skewY(0)')[0];
+ } catch (e) {}
+
+ try {
+ self.perspective = CSSStyleValue.parse('transform', 'perspective(0)')[0];
+ } catch (e) {}
+
+ try {
+ self.matrix = CSSStyleValue.parse('transform', 'matrix(0, 0, 0, 0, 0, 0)')[0];
+ } catch (e) {}
+
+ idl_array.add_objects({
+ StylePropertyMap: ['styleMap'],
+ CSSUnitValue: ['unitValue'],
+ CSSMathSum: ['mathSum'],
+ CSSTransformValue: ['transformValue'],
+ CSSTranslate: ['transformValue[0]'],
+ CSSRotate: ['rotate'],
+ CSSScale: ['scale'],
+ CSSSkew: ['skew'],
+ CSSSkewX: ['skewX'],
+ CSSSkewY: ['skewY'],
+ CSSPerspective: ['perspective'],
+ CSSMatrixComponent: ['matrix'],
+ });
+ }
+);
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/perspective-typed-arithmetic-crash.html b/testing/web-platform/tests/css/css-typed-om/perspective-typed-arithmetic-crash.html
new file mode 100644
index 0000000000..b65625b286
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/perspective-typed-arithmetic-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Don't crash when setting a CSS-wide keyword on a custom property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssperspective">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-create-a-type">
+<link rel="help" href="https://crbug.com/1240638<">
+<div id="target">
+ Don't crash
+</div>
+<script>
+ String(new CSSPerspective(CSS.px(1).mul(CSS.px(1)).div(CSS.px(1))));
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/resources/testhelper.js b/testing/web-platform/tests/css/css-typed-om/resources/testhelper.js
new file mode 100644
index 0000000000..4c9ed78c78
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/resources/testhelper.js
@@ -0,0 +1,217 @@
+function assert_color_channel_approx_equals(a, b) {
+ // Color is is limited to 32bit RGBA, thus channels are values within 0-255.
+ // Our epsilon needs to reflect this relatively limited precision.
+ const EPSILON = 1/255;
+
+ function epsilonForUnitType(unitType) {
+ switch(unitType) {
+ case 'deg':
+ return EPSILON * 360;
+ case 'rad':
+ return EPSILON * 2 * Math.PI;
+ case 'grad':
+ return EPSILON * 400;
+ case 'percent':
+ return EPSILON * 100;
+ default:
+ return EPSILON;
+ }
+ }
+
+ assert_equals(a.constructor.name, b.constructor.name);
+ const className = a.constructor.name;
+ switch (className) {
+ case 'CSSMathSum':
+ case 'CSSMathProduct':
+ case 'CSSMathMin':
+ case 'CSSMathMax':
+ assert_equals(a.values.length, b.values.length);
+ for (let i = 0; i < a.length; i++) {
+ assert_equals(a.unit, b.unit);
+ assert_approx_equals(a[i].value, b[i].value, epsilonForUnitType(a.unit));
+ }
+ break;
+ case 'CSSKeywordValue':
+ assert_equals(a.value, b.value);
+ break;
+ default:
+ assert_equals(a.unit, b.unit);
+ assert_approx_equals(a.value, b.value, epsilonForUnitType(a.unit));
+ }
+}
+
+// Compares two CSSStyleValues to check if they're the same type
+// and have the same attributes.
+function assert_style_value_equals(a, b) {
+ if (a == null || b == null) {
+ assert_equals(a, b);
+ return;
+ }
+
+ assert_equals(a.constructor.name, b.constructor.name);
+ const className = a.constructor.name;
+ switch (className) {
+ case 'CSSStyleValue':
+ assert_equals(a.toString(), b.toString());
+ break;
+ case 'CSSKeywordValue':
+ assert_equals(a.value, b.value);
+ break;
+ case 'CSSUnitValue':
+ assert_approx_equals(a.value, b.value, 1e-6);
+ assert_equals(a.unit, b.unit);
+ break;
+ case 'CSSMathSum':
+ case 'CSSMathProduct':
+ case 'CSSMathMin':
+ case 'CSSMathMax':
+ assert_style_value_array_equals(a.values, b.values);
+ break;
+ case 'CSSMathClamp':
+ assert_style_value_equals(a.lower, b.lower);
+ assert_style_value_equals(a.value, b.value);
+ assert_style_value_equals(a.upper, b.upper);
+ break;
+ case 'CSSMathInvert':
+ case 'CSSMathNegate':
+ assert_style_value_equals(a.value, b.value);
+ break;
+ case 'CSSUnparsedValue':
+ assert_style_value_array_equals(a, b);
+ break;
+ case 'CSSVariableReferenceValue':
+ assert_equals(a.variable, b.variable);
+ assert_style_value_equals(a.fallback, b.fallback);
+ break;
+ case 'CSSTransformValue':
+ assert_style_value_array_equals(a, b);
+ break;
+ case 'CSSRotate':
+ assert_style_value_equals(a.angle, b.angle);
+ // fallthrough
+ case 'CSSTranslate':
+ case 'CSSScale':
+ assert_style_value_equals(a.x, b.x);
+ assert_style_value_equals(a.y, b.y);
+ assert_style_value_equals(a.z, b.z);
+ assert_style_value_equals(a.is2D, b.is2D);
+ break;
+ case 'CSSSkew':
+ assert_style_value_equals(a.ax, b.ax);
+ assert_style_value_equals(a.ay, b.ay);
+ break;
+ case 'CSSSkewX':
+ assert_style_value_equals(a.ax, b.ax);
+ break;
+ case 'CSSSkewY':
+ assert_style_value_equals(a.ay, b.ay);
+ break;
+ case 'CSSPerspective':
+ assert_style_value_equals(a.length, b.length);
+ break;
+ case 'CSSMatrixComponent':
+ assert_matrix_approx_equals(a.matrix, b.matrix, 1e-6);
+ break;
+ default:
+ assert_equals(a, b);
+ break;
+ }
+}
+
+// Compares two arrays of CSSStyleValues to check if every element is equal
+function assert_style_value_array_equals(a, b) {
+ assert_equals(a.length, b.length);
+ for (let i = 0; i < a.length; i++) {
+ assert_style_value_equals(a[i], b[i]);
+ }
+}
+
+const gValidUnits = [
+ 'number', 'percent', 'em', 'ex', 'ch',
+ 'ic', 'rem', 'lh', 'rlh', 'vw',
+ 'vh', 'vi', 'vb', 'vmin', 'vmax',
+ 'cm', 'mm', 'Q', 'in', 'pt',
+ 'pc', 'px', 'deg', 'grad', 'rad',
+ 'turn', 's', 'ms', 'Hz', 'kHz',
+ 'dpi', 'dpcm', 'dppx', 'fr',
+];
+
+// Creates a new div element with specified inline style |cssText|.
+// The created element is deleted during test cleanup.
+function createDivWithStyle(test, cssText) {
+ let element = document.createElement('div');
+ element.style = cssText || '';
+ document.body.appendChild(element);
+ test.add_cleanup(() => {
+ element.remove();
+ });
+ return element;
+}
+
+// Creates a new div element without inline style.
+// The created element is deleted during test cleanup.
+function createDivWithoutStyle(test) {
+ let element = document.createElement('div');
+ document.body.appendChild(element);
+ test.add_cleanup(() => {
+ element.remove();
+ });
+ return element;
+}
+
+// Creates a new div element with inline style |cssText| and returns
+// its inline style property map.
+function createInlineStyleMap(test, cssText) {
+ return createElementWithInlineStyleMap(test, cssText)[1]
+}
+// Same as createInlineStyleMap but also returns the element itself.
+function createElementWithInlineStyleMap(test, cssText) {
+ let elem = createDivWithStyle(test, cssText);
+ return [elem, elem.attributeStyleMap];
+}
+
+// Creates a new div element with inline style |cssText| and returns
+// its computed style property map.
+function createComputedStyleMap(test, cssText) {
+ return createElementWithComputedStyleMap(test, cssText)[1];
+}
+// Same as createComputedStyleMap but also returns the element itself.
+function createElementWithComputedStyleMap(test, cssText) {
+ let elem = createDivWithStyle(test, cssText);
+ return [elem, elem.computedStyleMap()];
+}
+
+// Creates a new style element with a rule |cssText| and returns
+// its declared style property map.
+function createDeclaredStyleMap(test, cssText) {
+ return createRuleWithDeclaredStyleMap(test, cssText)[1];
+}
+// Same as createDeclaredStyleMap but also returns the rule itself.
+function createRuleWithDeclaredStyleMap(test, cssText) {
+ const style = document.createElement('style');
+ document.head.appendChild(style);
+ const rule = style.sheet.cssRules[style.sheet.insertRule('#test { ' + cssText + '}')];
+ test.add_cleanup(() => {
+ style.remove();
+ });
+ return [rule, rule.styleMap];
+}
+
+// Creates a new element with background image set to |imageValue|
+// and returns a new Image element that can be used to attach
+// event listeners regarding the image.
+function loadImageResource(test, imageValue) {
+ // Set a CSSURLImageValue on an element so it can be loaded.
+ let styleMap = createInlineStyleMap(test, '');
+ styleMap.set('background-image', imageValue);
+
+ // add a new Image element to know if the image resource has been loaded
+ let image = new Image();
+ image.src = imageValue.url;
+ return image;
+}
+
+function assert_matrix_approx_equals(actual, expected, epsilon) {
+ assert_array_approx_equals(
+ actual.toFloat64Array(), expected.toFloat64Array(), epsilon);
+}
diff --git a/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle-ref.html b/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle-ref.html
new file mode 100644
index 0000000000..36c18d8429
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
+<meta name="assert" content="CSSUnitValue of different angle units can be added correctly.">
+<style>
+.ref {
+ width: 200px;
+ height: 100px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+ transform: rotate(90deg);
+ background-color: green;
+}
+</style>
+<p>Test passes if there is a filled green rectangle with <strong>no red</strong>.</p>
+<div class="ref"></div>
diff --git a/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle.html b/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle.html
new file mode 100644
index 0000000000..bb79a7df8d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/rotate-by-added-angle.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
+<link rel="match" href="rotate-by-added-angle-ref.html">
+<meta name="assert" content="CSSUnitValue of different angle units can be added correctly.">
+<style>
+.common {
+ width: 200px;
+ height: 100px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+}
+.ref {
+ transform: rotate(90deg);
+ background-color: red;
+}
+.test {
+ background-color: green;
+ z-index: 1;
+}
+</style>
+<p>Test passes if there is a filled green rectangle with <strong>no red</strong>.</p>
+<div class="common ref"></div>
+<div class="common test"></div>
+<script>
+const angle = new CSSMathSum(CSS.deg(45), CSS.turn(0.125)); // 90 degrees
+const transform = new CSSTransformValue([new CSSRotate(angle)]);
+const target = document.querySelector('.test');
+target.attributeStyleMap.set('transform', transform);
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/set-css-wide-in-custom-property-crash.html b/testing/web-platform/tests/css/css-typed-om/set-css-wide-in-custom-property-crash.html
new file mode 100644
index 0000000000..bc977c9889
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/set-css-wide-in-custom-property-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Don't crash when setting a CSS-wide keyword on a custom property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://crbug.com/1310761<">
+<div id="target">
+ Don't crash
+</div>
+<script>
+ for (let keyword of ['initial', 'inherit', 'unset', 'revert', 'revert-layer']) {
+ try {
+ target.attributeStyleMap.set('--x', new CSSKeywordValue(keyword));
+ } catch (e) {
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/set-var-reference-thcrash.html b/testing/web-platform/tests/css/css-typed-om/set-var-reference-thcrash.html
new file mode 100644
index 0000000000..c6bc3cc2a3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/set-var-reference-thcrash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>Don't crash when setting a CSSVariableReferenceValue</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssvariablereferencevalue">
+<link rel="help" href="https://crbug.com/986710<">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ :root { --x: green; }
+</style>
+<div id="target"></div>
+<script>
+ test(function(){
+ let ref = new CSSVariableReferenceValue('--x')
+ let unparsed = new CSSUnparsedValue([' ', ref]);
+ target.attributeStyleMap.set('color', unparsed);
+ assert_equals('rgb(0, 128, 0)', target.computedStyleMap().get('color').toString());
+ }, 'Do not crash when referencing a variable with CSSVariableReferenceValue');
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.html
new file mode 100644
index 0000000000..d118dda4a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-ident.tentative.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Identifier normalization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#normalize-ident">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(() => {
+ assert_style_value_equals(CSSStyleValue.parse('width', 'auto'),
+ new CSSKeywordValue('auto'));
+}, 'CSS identifiers are normalized from String to CSSKeywordValues');
+
+test(t => {
+ assert_style_value_equals(
+ createDivWithStyle(t, 'width: auto').attributeStyleMap.get('width'),
+ new CSSKeywordValue('auto'));
+}, 'CSS identifiers are normalized from CSSOM to CSSKeywordValues');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-image.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-image.html
new file mode 100644
index 0000000000..0b60ec4442
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-image.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSImageValue normalization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#resourcevalue-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gTestUrl = '/media/1x1-green.png';
+const gBadTestUrl = document.location.href;
+
+test(t => {
+ const result = CSSStyleValue.parse('background-image', 'url("' + gTestUrl + '")');
+ assert_class_string(result, 'CSSImageValue');
+}, 'Normalizing a valid <url> returns a CSSImageValue');
+
+test(t => {
+ const result = CSSStyleValue.parse('background-image', 'url("' + gBadTestUrl + '")');
+ assert_class_string(result, 'CSSImageValue');
+}, 'Normalizing a bad <url> returns a CSSImageValue');
+
+test(t => {
+ const result = CSSStyleValue.parse('background-image', 'linear-gradient(red, orange)');
+ assert_equals(result.constructor.name, 'CSSImageValue');
+}, 'Normalizing a <gradient> returns a CSSImageValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-numeric.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-numeric.tentative.html
new file mode 100644
index 0000000000..6d1ae399d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-numeric.tentative.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Numeric normalization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#normalize-numeric">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+function test_numeric_normalization(test, property, cssText, expected) {
+ assert_style_value_equals(CSSNumericValue.parse(cssText), expected);
+ assert_style_value_equals(CSSStyleValue.parse(property, cssText), expected);
+ assert_style_value_equals(
+ createInlineStyleMap(test, property + ': ' + cssText).get(property),
+ expected);
+}
+
+test(t => {
+ test_numeric_normalization(t, 'line-height', '3.14', CSS.number(3.14));
+}, 'Normalizing a <number> returns a number CSSUnitValue');
+
+test(t => {
+ test_numeric_normalization(t, 'width', '3.14%', CSS.percent(3.14));
+}, 'Normalizing a <percentage> returns a percent CSSUnitValue');
+
+test(t => {
+ test_numeric_normalization(t, 'width', '3.14px', CSS.px(3.14));
+}, 'Normalizing a <dimension> returns a CSSUnitValue with the correct unit');
+
+test(t => {
+ test_numeric_normalization(t, 'opacity', '0', CSS.number(0));
+}, 'Normalizing a <number> with a unitless zero returns 0');
+
+test(t => {
+ test_numeric_normalization(t, 'width',
+ 'calc(1px + calc(1px) + calc(1px * 2) + 1%)',
+ new CSSMathSum(CSS.px(4), CSS.percent(1)));
+}, 'Normalizing a <calc> returns simplified expression');
+
+test(t => {
+ assert_style_value_equals(CSSStyleValue.parse('width', '0px'), CSS.px(0));
+ assert_style_value_equals(
+ createInlineStyleMap(t, 'width: 0').get('width'),
+ CSS.px(0));
+}, 'Normalizing a <dimension> with a unitless zero returns 0px');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
new file mode 100644
index 0000000000..c83e093e62
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/normalize-tokens.tentative.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Normalization of raw CSS tokens tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#normalize-tokens">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+function assert_string_normalizes_to(test, property, str, expected) {
+ // From string
+ assert_style_value_equals(CSSStyleValue.parse(property, str), expected);
+ // From CSSOM
+ assert_style_value_equals(
+ createInlineStyleMap(test, property + ':' + str).get(property),
+ expected
+ );
+}
+
+const gTestCases = [
+ {
+ value: 'var(--A)',
+ expectedResult: [
+ new CSSVariableReferenceValue('--A'),
+ ]
+ },
+ {
+ value: 'var(--A, 1em)',
+ expectedResult: [
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' 1em'])),
+ ]
+ },
+ {
+ value: 'var(--A, var(--B))',
+ expectedResult: [
+ new CSSVariableReferenceValue('--A', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--B')])),
+ ]
+ },
+ {
+ value: 'calc(42px + var(--foo, 15em) + var(--bar, var(--far) + 15px))',
+ expectedResult: [
+ 'calc(42px + ',
+ new CSSVariableReferenceValue('--foo', new CSSUnparsedValue([' 15em'])),
+ ' + ',
+ new CSSVariableReferenceValue('--bar', new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--far'), ' + 15px'])),
+ ')',
+ ]
+ },
+];
+
+for (const {value, expectedResult} of gTestCases) {
+ test(t => {
+ assert_string_normalizes_to(t, 'color', value, new CSSUnparsedValue(expectedResult));
+ }, 'Normalizing "' + value + '" on a CSS property returns correct CSSUnparsedValue');
+
+ test(t => {
+ assert_string_normalizes_to(t, 'margin', value, new CSSUnparsedValue(expectedResult));
+ }, 'Normalizing "' + value + '" on a shorthand returns correct CSSUnparsedValue');
+
+ test(t => {
+ assert_string_normalizes_to(t, 'transition-duration', value, new CSSUnparsedValue(expectedResult));
+ }, 'Normalizing "' + value + '" on a list-valued property returns correct CSSUnparsedValue');
+
+ test(t => {
+ assert_string_normalizes_to(t, '--X', value, new CSSUnparsedValue(expectedResult));
+ }, 'Normalizing "' + value + '" on a custom property returns correct CSSUnparsedValue');
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
new file mode 100644
index 0000000000..3154dcf2c4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-normalization/transformvalue-normalization.tentative.html
@@ -0,0 +1,187 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Transform normalization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#transformvalue-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/comparisons.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+function test_transform_normalization(test, cssText, expected) {
+ assert_style_value_equals(CSSStyleValue.parse('transform', cssText), expected);
+ assert_style_value_equals(
+ createInlineStyleMap(test, 'transform: ' + cssText).get('transform'),
+ expected);
+}
+
+test(t => {
+ test_transform_normalization(t, 'matrix(1, 2, 3, 4, 5, 6)',
+ new CSSTransformValue([
+ new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6]))
+ ]));
+}, 'Normalizing a matrix() returns a CSSMatrixComponent');
+
+test(t => {
+ test_transform_normalization(t,
+ 'matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)',
+ new CSSTransformValue([
+ new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]))
+ ]));
+}, 'Normalizing a matrix3d() returns a CSSMatrixComponent');
+
+const gTestCases = [
+ {
+ cssText: 'translate(1px)',
+ expected: new CSSTranslate(CSS.px(1), CSS.px(0)),
+ desc: 'translate() with X'
+ },
+ {
+ cssText: 'translate(1%, 1px)',
+ expected: new CSSTranslate(CSS.percent(1), CSS.px(1)),
+ desc: 'translate() with X and Y'
+ },
+ {
+ cssText: 'translateX(1%)',
+ expected: new CSSTranslate(CSS.percent(1), CSS.px(0)),
+ desc: 'translateX()'
+ },
+ {
+ cssText: 'translateY(1px)',
+ expected: new CSSTranslate(CSS.px(0), CSS.px(1)),
+ desc: 'translateY()'
+ },
+ {
+ cssText: 'translate3d(1px, 2%, 3px)',
+ expected: new CSSTranslate(CSS.px(1), CSS.percent(2), CSS.px(3)),
+ desc: 'translate3d()'
+ },
+ {
+ cssText: 'translateZ(1px)',
+ expected: new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(1)),
+ desc: 'translateZ()'
+ },
+ {
+ cssText: 'scale(2)',
+ expected: new CSSScale(CSS.number(2), CSS.number(2)),
+ desc: 'scale() with one argument'
+ },
+ {
+ cssText: 'scale(2, 3)',
+ expected: new CSSScale(CSS.number(2), CSS.number(3)),
+ desc: 'scale() with two arguments'
+ },
+ {
+ cssText: 'scaleX(2)',
+ expected: new CSSScale(CSS.number(2), CSS.number(1)),
+ desc: 'scaleX()'
+ },
+ {
+ cssText: 'scaleY(2)',
+ expected: new CSSScale(CSS.number(1), CSS.number(2)),
+ desc: 'scaleY()'
+ },
+ {
+ cssText: 'scale3d(1, 2, 3)',
+ expected: new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
+ desc: 'scale3d()'
+ },
+ {
+ cssText: 'scaleZ(2)',
+ expected: new CSSScale(CSS.number(1), CSS.number(1), CSS.number(2)),
+ desc: 'scaleZ()'
+ },
+ {
+ cssText: 'rotate(90deg)',
+ expected: new CSSRotate(CSS.deg(90)),
+ desc: 'rotate()'
+ },
+ {
+ cssText: 'rotate3d(1, 2, 3, 90deg)',
+ expected: new CSSRotate(CSS.number(1), CSS.number(2), CSS.number(3), CSS.deg(90)),
+ desc: 'rotate3d()'
+ },
+ {
+ cssText: 'rotateX(90deg)',
+ expected: new CSSRotate(CSS.number(1), CSS.number(0), CSS.number(0), CSS.deg(90)),
+ desc: 'rotateX()'
+ },
+ {
+ cssText: 'rotateY(90deg)',
+ expected: new CSSRotate(CSS.number(0), CSS.number(1), CSS.number(0), CSS.deg(90)),
+ desc: 'rotateY()'
+ },
+ {
+ cssText: 'rotateZ(90deg)',
+ expected: new CSSRotate(CSS.number(0), CSS.number(0), CSS.number(1), CSS.deg(90)),
+ desc: 'rotateZ()'
+ },
+ {
+ cssText: 'skew(90deg)',
+ expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ desc: 'skew() with only X'
+ },
+ {
+ cssText: 'skew(90deg, 0deg)',
+ expected: new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ desc: 'skew() with X and Y which is 0 value'
+ },
+ {
+ cssText: 'skew(90deg, 45deg)',
+ expected: new CSSSkew(CSS.deg(90), CSS.deg(45)),
+ desc: 'skew() with X and Y'
+ },
+ {
+ cssText: 'skewX(90deg)',
+ expected: new CSSSkewX(CSS.deg(90)),
+ desc: 'skewX()'
+ },
+ {
+ cssText: 'skewY(90deg)',
+ expected: new CSSSkewY(CSS.deg(90)),
+ desc: 'skewY()'
+ },
+ {
+ cssText: 'perspective(1px)',
+ expected: new CSSPerspective(CSS.px(1)),
+ desc: 'perspective()'
+ },
+ {
+ cssText: 'perspective(none)',
+ expected: new CSSPerspective(new CSSKeywordValue('none')),
+ desc: 'perspective(none)'
+ },
+];
+
+for (const {cssText, expected, desc} of gTestCases) {
+ test(t => {
+ test_transform_normalization(t, cssText, new CSSTransformValue([expected]));
+ }, 'Normalizing a ' + desc + ' returns a ' + expected.constructor.name);
+}
+
+test(t => {
+ test_transform_normalization(t,
+ 'translate(1px) rotateX(90deg) perspective(1px) skew(90deg) skewX(20deg) skewY(30deg) scale3d(1, 2, 3)',
+ new CSSTransformValue([
+ new CSSTranslate(CSS.px(1), CSS.px(0)),
+ new CSSRotate(CSS.number(1), CSS.number(0), CSS.number(0), CSS.deg(90)),
+ new CSSPerspective(CSS.px(1)),
+ new CSSSkew(CSS.deg(90), CSS.deg(0)),
+ new CSSSkewX(CSS.deg(20)),
+ new CSSSkewY(CSS.deg(30)),
+ new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
+ ]));
+}, 'Normalizing a <transform-list> returns a CSSTransformValue containing all the transforms');
+
+test(t => {
+ test_transform_normalization(t,
+ 'translate(calc(1px + 1em)) perspective(calc(1px + 1em))',
+ new CSSTransformValue([
+ new CSSTranslate(new CSSMathSum(CSS.px(1), CSS.em(1)), CSS.px(0)),
+ new CSSPerspective(new CSSMathSum(CSS.px(1), CSS.em(1))),
+ ]));
+}, 'Normalizing transforms with calc values contains CSSMathValues');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse-invalid.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse-invalid.html
new file mode 100644
index 0000000000..13ee2df1a6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse-invalid.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue.parse Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parse">
+<meta name="assert" content="Test CSSStyleValue.parse error handling" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parse('', 'auto'));
+}, 'CSSStyleValue.parse() with empty property name throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parse('lemon', 'auto'));
+}, 'CSSStyleValue.parse() with unsupported property name throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parse('width', '10deg'));
+}, 'CSSStyleValue.parse() with invalid value for valid property throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parse('margin', '10deg'));
+}, 'CSSStyleValue.parse() with invalid value for shorthand property throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parse('--foo', ''));
+}, 'CSSStyleValue.parse() with invalid value for custom property throws TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse.html
new file mode 100644
index 0000000000..65e46f2da7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parse.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue.parse</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parse">
+<meta name="assert" content="Test CSSStyleValue.parse returns CSSStyleValues" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = CSSStyleValue.parse('width', '10px');
+ assert_true(result instanceof CSSStyleValue,
+ 'Result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parse() with a valid property returns a CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parse('WiDtH', '10px');
+ assert_true(result instanceof CSSStyleValue,
+ 'Result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parse() is not case sensitive');
+
+test(() => {
+ const result = CSSStyleValue.parse('transition-duration', '1s, 2s, 3s');
+ assert_true(result instanceof CSSStyleValue,
+ 'Result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parse() with a valid list-valued property returns a CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parse('margin', '1px 2px 3px 4px');
+ assert_true(result instanceof CSSStyleValue,
+ 'Result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parse() with a valid shorthand property returns a CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parse('--foo', 'auto');
+ assert_true(result instanceof CSSStyleValue,
+ 'Result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parse() with a valid custom property returns a CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll-invalid.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll-invalid.html
new file mode 100644
index 0000000000..45fad409bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll-invalid.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue.parseAll Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parseall">
+<meta name="assert" content="Test CSSStyleValue.parseAll error handling" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parseAll('', 'auto'));
+}, 'CSSStyleValue.parseAll() with empty property name throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parseAll('lemon', 'auto'));
+}, 'CSSStyleValue.parseAll() with unsupported property name throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parseAll('width', '10deg'));
+}, 'CSSStyleValue.parseAll() with invalid value for valid property throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parseAll('margin', '10deg'));
+}, 'CSSStyleValue.parseAll() with invalid value for shorthand property throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSSStyleValue.parseAll('--foo', ''));
+}, 'CSSStyleValue.parseAll() with invalid value for custom property throws TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll.html
new file mode 100644
index 0000000000..cee450359e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-objects/parseAll.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue.parseAll</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssstylevalue-parseall">
+<meta name="assert" content="Test CSSStyleValue.parseAll returns CSSStyleValues" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = CSSStyleValue.parseAll('width', '10px');
+ assert_equals(result.length, 1, 'Result must be a list with one element');
+ assert_true(result[0] instanceof CSSStyleValue,
+ 'Only element in result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parseAll() with a valid property returns a list with a single CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parseAll('WiDtH', '10px');
+ assert_equals(result.length, 1, 'Result must be a list with one element');
+ assert_true(result[0] instanceof CSSStyleValue,
+ 'Only element in result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parseAll() is not case sensitive');
+
+test(() => {
+ const result = CSSStyleValue.parseAll('transition-duration', '1s, 2s, 3s');
+ assert_equals(result.length, 3, 'Result must be a list with three elements');
+ for (const item of result) {
+ assert_true(item instanceof CSSStyleValue,
+ 'All elements in result must be a subclass of CSSStyleValue');
+ }
+}, 'CSSStyleValue.parseAll() with a valid list-valued property returns a list with a single CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parseAll('margin', '1px 2px 3px 4px');
+ assert_equals(result.length, 1, 'Result must be a list with one element');
+ assert_true(result[0] instanceof CSSStyleValue,
+ 'Only element in result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parseAll() with a valid shorthand property returns a CSSStyleValue');
+
+test(() => {
+ const result = CSSStyleValue.parseAll('--foo', 'auto');
+ assert_equals(result.length, 1, 'Result must be a list with one element');
+ assert_true(result[0] instanceof CSSStyleValue,
+ 'Only element in result must be a subclass of CSSStyleValue');
+}, 'CSSStyleValue.parseAll() with a valid custom property returns a list with a single CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-convert-crash.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-convert-crash.html
new file mode 100644
index 0000000000..8ca27efc3a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-convert-crash.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" href="mailto:0xdevssh@gmail.com">
+<link rel="help" href="https://crbug.com/1238543">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/">
+<meta name="assert" content="The renderer should not crash.">
+
+<p>This test passes if it does not crash.</p>
+<script>
+ var inverted = new CSSMathInvert(CSS.number(0));
+ var converted = inverted.to('number');
+ converted.toString()
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-zero.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-zero.html
new file mode 100644
index 0000000000..b767cf69c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssInvertValue-zero.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="help" href="https://crbug.com/1232775">
+<title>Do not crash when serializing inverted zero via CSSTransformValue</title>
+<script>
+ const inverted = new CSSMathInvert(new CSSUnitValue(0, 'number'));
+ const rotate = new CSSRotate(inverted, 0, 0, CSS.deg(0));
+ const transform = new CSSTransformValue([rotate]);
+ inverted.toString();
+ rotate.toString();
+ transform.toString();
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssTransform-Internal-value.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssTransform-Internal-value.html
new file mode 100644
index 0000000000..96097e4f94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/crashtests/cssTransform-Internal-value.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://crbug.com/1204782">
+<title>Serialize transform components must not crash when the internal CSS value is null</title>
+
+<script>
+ var v98 = new CSSUnitValue(1, "px");
+ var v100 = v98.div(CSS.px(1));
+ var v106 = v98.mul(v100);
+ var v201 = new CSSTranslate(v106, v98, v98);
+ v201.toString()
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssImageValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssImageValue.html
new file mode 100644
index 0000000000..92256e5967
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssImageValue.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSURLImageValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#urlimagevalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<div id="testUrl" style="background-image: url('/media/1x1-green.png')"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = document.getElementById('testUrl').attributeStyleMap.get('background-image');
+ assert_equals(result.toString(), 'url("/media/1x1-green.png")');
+}, 'CSSUrlImageValue serializes correctly');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.html
new file mode 100644
index 0000000000..1e2041d80d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssKeywordValue.tentative.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>IDL-constructed CSSKeywordValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#unparsedvalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(() => {
+ assert_equals(new CSSKeywordValue('auto').toString(), 'auto');
+ assert_equals(new CSSKeywordValue('inherit').toString(), 'inherit');
+ assert_equals(new CSSKeywordValue('lemon').toString(), 'lemon');
+}, 'CSSKeywordValue constructed from IDL serializes correctly');
+
+test(() => {
+ assert_equals(new CSSKeywordValue(' Hello World').toString(), CSS.escape(' Hello World'));
+ assert_equals(new CSSKeywordValue('3').toString(), CSS.escape('3'));
+}, 'CSSKeywordValue constructed from IDL serializes to escaped strings');
+
+test(() => {
+ let result = CSSStyleValue.parse('width', 'auto');
+ result.value = 'lemon';
+ assert_equals(result.toString(), 'lemon');
+}, 'CSSKeywordValue from DOMString modified through "value" setter serializes correctly');
+
+test(t => {
+ let result = createInlineStyleMap(t, 'width: auto').get('width');
+ result.value = 'lemon';
+ assert_equals(result.toString(), 'lemon');
+}, 'CSSKeywordValue from CSSOM modified through "value" setter serializes correctly');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.html
new file mode 100644
index 0000000000..7ee4e8137e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssMathValue.tentative.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>IDL-constructed CSSMathValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#calc-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gTestCases = [
+ {
+ description: 'CSSMathMax with one argument',
+ value: new CSSMathMax(1),
+ cssText: 'max(1)',
+ },
+ {
+ description: 'CSSMathMax with more than one argument',
+ value: new CSSMathMax(1, 2, 3),
+ cssText: 'max(1, 2, 3)',
+ },
+ {
+ description: 'CSSMathMax with pixel arguments',
+ value: new CSSMathMin(CSS.px(100), CSS.px(110)),
+ cssText: 'min(100px, 110px)',
+ },
+ {
+ description: 'CSSMathMax containing nested CSSMathValues',
+ value: new CSSMathMax(new CSSMathSum(1, 2), 3),
+ cssText: 'max(1 + 2, 3)',
+ },
+ {
+ description: 'CSSMathMin with one argument',
+ value: new CSSMathMin(1),
+ cssText: 'min(1)',
+ },
+ {
+ description: 'CSSMathMin with more than one argument',
+ value: new CSSMathMin(1, 2, 3),
+ cssText: 'min(1, 2, 3)',
+ },
+ {
+ description: 'CSSMathMin with pixel arguments',
+ value: new CSSMathMin(CSS.px(90), CSS.px(100)),
+ cssText: 'min(90px, 100px)',
+ },
+ {
+ description: 'CSSMathMin containing nested CSSMathValues',
+ value: new CSSMathMin(new CSSMathSum(1, 2), 3),
+ cssText: 'min(1 + 2, 3)',
+ },
+ {
+ description: 'CSSMathClamp with lower, value and upper arguments',
+ value: new CSSMathClamp(1, 2, 3),
+ cssText: 'clamp(1, 2, 3)',
+ },
+ {
+ description: 'CSSMathClamp with pixel arguments',
+ value: new CSSMathClamp(CSS.px(90), CSS.px(100), CSS.px(110)),
+ cssText: 'clamp(90px, 100px, 110px)',
+ },
+ {
+ description: 'CSSMathClamp containing nested CSSMathValues',
+ value: new CSSMathClamp(new CSSMathSum(1, 2), 3, 4),
+ cssText: 'clamp(1 + 2, 3, 4)',
+ },
+ {
+ description: 'CSSMathSum with one argument',
+ value: new CSSMathSum(1),
+ cssText: 'calc(1)',
+ },
+ {
+ description: 'CSSMathSum with more than one argument',
+ value: new CSSMathSum(1, 2, 3),
+ cssText: 'calc(1 + 2 + 3)',
+ },
+ {
+ description: 'CSSMathSum with a CSSMathNegate as first value',
+ value: new CSSMathSum(new CSSMathNegate(1), 2, 3),
+ cssText: 'calc((-1) + 2 + 3)',
+ },
+ {
+ description: 'CSSMathSum containing a CSSMathNegate after first value',
+ value: new CSSMathSum(1, new CSSMathNegate(2), 3),
+ cssText: 'calc(1 - 2 + 3)',
+ },
+ {
+ description: 'CSSMathSum nested inside a CSSMathValue',
+ value: new CSSMathSum(new CSSMathSum(1, 2), 3),
+ cssText: 'calc((1 + 2) + 3)',
+ },
+ {
+ description: 'CSSMathNegate',
+ value: new CSSMathNegate(1),
+ cssText: 'calc(-1)',
+ },
+ {
+ description: 'CSSMathNegate nested inside a CSSMathValue',
+ value: new CSSMathProduct(new CSSMathNegate(1)),
+ cssText: 'calc((-1))',
+ },
+ {
+ description: 'CSSMathProduct with one argument',
+ value: new CSSMathProduct(1),
+ cssText: 'calc(1)',
+ },
+ {
+ description: 'CSSMathProduct with more than one argument',
+ value: new CSSMathProduct(1, 2, 3),
+ cssText: 'calc(1 * 2 * 3)',
+ },
+ {
+ description: 'CSSMathProduct with a CSSMathInvert as first value',
+ value: new CSSMathProduct(new CSSMathInvert(1), 2, 3),
+ cssText: 'calc((1 / 1) * 2 * 3)',
+ },
+ {
+ description: 'CSSMathProduct containing a CSSMathInvert after first value',
+ value: new CSSMathProduct(1, new CSSMathInvert(2), 3),
+ cssText: 'calc(1 / 2 * 3)',
+ },
+ {
+ description: 'CSSMathProduct nested inside a CSSMathValue',
+ value: new CSSMathProduct(new CSSMathProduct(1, 2), 3),
+ cssText: 'calc((1 * 2) * 3)',
+ },
+ {
+ description: 'CSSMathInvert',
+ value: new CSSMathInvert(1),
+ cssText: 'calc(1 / 1)',
+ },
+ {
+ description: 'CSSMathInvert nested inside a CSSMathValue',
+ value: new CSSMathSum(new CSSMathInvert(1)),
+ cssText: 'calc((1 / 1))',
+ },
+];
+
+for (const {value, cssText, description} of gTestCases) {
+ test(() => {
+ assert_equals(value.toString(), cssText);
+ }, description + ' serializes correctly');
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-cssom.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-cssom.html
new file mode 100644
index 0000000000..5f21bfaa61
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-cssom.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue serialization from CSSOM</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylevalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ const result = createInlineStyleMap(t, 'color: red').get('color');
+ assert_equals(result.toString(), 'red');
+}, 'CSSStyleValue from specified CSSOM serializes correctly');
+
+test(t => {
+ const result = createComputedStyleMap(t, 'color: red').get('color');
+ assert_equals(result.toString(), 'rgb(255, 0, 0)');
+}, 'CSSStyleValue from computed CSSOM serializes correctly');
+
+test(t => {
+ const result = createInlineStyleMap(t, 'background: blue').get('background');
+ assert_equals(result.toString(), 'blue');
+}, 'Shorthand CSSStyleValue from inline CSSOM serializes correctly');
+
+test(t => {
+ const result = createComputedStyleMap(t, 'background: blue').get('background');
+ assert_equals(result.toString(), 'rgb(0, 0, 255) none repeat scroll 0% 0% / auto padding-box border-box');
+}, 'Shorthand CSSStyleValue from computed CSSOM serializes correctly');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.html
new file mode 100644
index 0000000000..747635d319
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssStyleValue-string.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSStyleValue serialization from parsing</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylevalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = CSSStyleValue.parse('color', 'red');
+ assert_equals(result.toString(), 'red');
+}, 'CSSStyleValue parsed from string serializes to given string');
+
+test(() => {
+ const result = CSSStyleValue.parse('background', 'blue');
+ assert_equals(result.toString(), 'blue');
+}, 'Shorthand CSSStyleValue parsed from string serializes to given string');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
new file mode 100644
index 0000000000..89330b8e1c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssTransformValue.tentative.html
@@ -0,0 +1,167 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>IDL-constructed CSSTransformValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#positionvalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gTestCases = [
+ {
+ value: new CSSTranslate(CSS.percent(1), CSS.px(1)),
+ cssText: 'translate(1%, 1px)',
+ desc: 'CSSTranslate with 2 arguments'
+ },
+ {
+ value: new CSSTranslate(CSS.px(1), CSS.percent(2), CSS.px(3)),
+ cssText: 'translate3d(1px, 2%, 3px)',
+ desc: 'CSSTranslate with 3 arguments'
+ },
+ {
+ value: new CSSScale(CSS.number(2), CSS.number(3)),
+ cssText: 'scale(2, 3)',
+ desc: 'CSSScale with 2 arguments'
+ },
+ {
+ value: new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
+ cssText: 'scale3d(1, 2, 3)',
+ desc: 'CSSScale with 3 arguments'
+ },
+ {
+ value: new CSSRotate(CSS.deg(90)),
+ cssText: 'rotate(90deg)',
+ desc: 'CSSRotate with 1 argument'
+ },
+ {
+ value: new CSSRotate(CSS.number(1), CSS.number(2), CSS.number(3), CSS.deg(90)),
+ cssText: 'rotate3d(1, 2, 3, 90deg)',
+ desc: 'CSSRotate with 4 arguments'
+ },
+ {
+ value: new CSSSkew(CSS.deg(90), CSS.deg(45)),
+ cssText: 'skew(90deg, 45deg)',
+ desc: 'CSSSkew'
+ },
+ {
+ value: new CSSSkew(CSS.deg(90), CSS.turn(0)),
+ cssText: 'skew(90deg)',
+ desc: 'CSSSkew with Y which is 0 value'
+ },
+ {
+ value: new CSSSkewX(CSS.deg(90)),
+ cssText: 'skewX(90deg)',
+ desc: 'CSSSkewX'
+ },
+ {
+ value: new CSSSkewY(CSS.deg(90)),
+ cssText: 'skewY(90deg)',
+ desc: 'CSSSkewY'
+ },
+ {
+ value: new CSSPerspective(CSS.px(1)),
+ cssText: 'perspective(1px)',
+ desc: 'CSSPerspective'
+ },
+ {
+ value: new CSSPerspective(CSS.px(-1)),
+ cssText: 'perspective(calc(-1px))',
+ desc: 'CSSPerspective with negative length'
+ },
+ {
+ value: new CSSPerspective("none"),
+ cssText: 'perspective(none)',
+ desc: 'CSSPerspective with none as string'
+ },
+ {
+ value: new CSSPerspective(new CSSKeywordValue("none")),
+ cssText: 'perspective(none)',
+ desc: 'CSSPerspective with none as CSSKeyword'
+ },
+ {
+ value: new CSSTransformValue([new CSSPerspective(CSS.px(1))]),
+ cssText: 'perspective(1px)',
+ desc: 'CSSTransformValue with a single transform'
+ },
+ {
+ value: new CSSTransformValue([
+ new CSSTranslate(CSS.px(1), CSS.px(0)),
+ new CSSRotate(CSS.deg(90)),
+ new CSSPerspective(CSS.px(1)),
+ new CSSSkew(CSS.deg(90), CSS.deg(45)),
+ new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)),
+ ]),
+ cssText: 'translate(1px, 0px) rotate(90deg) perspective(1px) skew(90deg, 45deg) scale3d(1, 2, 3)',
+ desc: 'CSSTransformValue with multiple transforms'
+ },
+ {
+ value: new CSSTransformValue([
+ new CSSTranslate(new CSSMathSum(CSS.px(1), CSS.em(1)), CSS.px(0)),
+ new CSSRotate(new CSSMathSum(CSS.deg(90), CSS.turn(1))),
+ new CSSPerspective(new CSSMathSum(CSS.px(1), CSS.em(1))),
+ new CSSSkew(new CSSMathProduct(CSS.deg(90), 2), new CSSMathProduct(CSS.turn(1), 2)),
+ new CSSScale(
+ new CSSMathProduct(CSS.number(1), CSS.number(2)),
+ new CSSMathSum(CSS.number(1), CSS.number(1)),
+ new CSSMathProduct(CSS.number(3))
+ ),
+ ]),
+ cssText: 'translate(calc(1em + 1px), 0px) rotate(calc(90deg + 360deg)) perspective(calc(1em + 1px)) skew(calc(90deg * 2), calc(360deg * 2)) scale3d(calc(1 * 2), calc(1 + 1), calc(3))',
+ desc: 'CSSTransformValue containing CSSMathValues'
+ },
+ {
+ value: new CSSTransformValue([
+ new CSSRotate(
+ new CSSMathInvert(
+ new CSSUnitValue(0, 'number')),
+ 0, 0, CSS.deg(0))
+ ]),
+ cssText:'rotate3d(calc(1 / 0), 0, 0, 0deg)',
+ desc: 'CSSMathInvert with 0 parameter'
+ },
+ {
+ value: new CSSTransformValue([
+ new CSSRotate(
+ 0, 0, 0,
+ new CSSMathProduct(CSS.deg(1),
+ new CSSMathInvert(
+ new CSSUnitValue(0, 'number')))
+ )
+ ]),
+ cssText:'rotate3d(0, 0, 0, calc(1deg / 0))',
+ desc: 'CSSMathInvert with 0 parameter and nested'
+ },
+ {
+ value: new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6])),
+ cssText: 'matrix(1, 2, 3, 4, 5, 6)',
+ desc: 'CSSMatrixComponent with 6 elements'
+ },
+ {
+ value: new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])),
+ cssText: 'matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)',
+ desc: 'CSSMatrixComponent with 16 elements'
+ },
+];
+
+for (const {value, cssText, desc} of gTestCases) {
+ test(() => {
+ assert_equals(value.toString(), cssText);
+ }, desc + ' serializes correctly');
+}
+
+test(() => {
+ let result = new CSSTransformValue([
+ new CSSTranslate(CSS.px(1), CSS.px(2), CSS.px(3)),
+ new CSSRotate(1, 2, 3, CSS.deg(90)),
+ new CSSScale(1, 2, 3),
+ ]);
+
+ for (const transform of result) {
+ transform.is2D = true;
+ }
+
+ assert_equals(result.toString(), 'translate(1px, 2px) rotate(90deg) scale(1, 2)');
+}, 'CSSTransformValue with updated is2D serializes as 2D transforms');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnitValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnitValue.tentative.html
new file mode 100644
index 0000000000..fc798ddbbf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnitValue.tentative.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>IDL-constructed CSSUnitValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numericvalue-serialization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(() => {
+ assert_equals(new CSSUnitValue(3.14, 'px').toString(), '3.14px');
+ assert_equals(CSS.px(3.14).toString(), '3.14px');
+}, 'CSSUnitValue with length unit constructed from IDL serializes correctly');
+
+test(() => {
+ assert_equals(new CSSUnitValue(3.14, 'percent').toString(), '3.14%');
+ assert_equals(CSS.percent(3.14).toString(), '3.14%');
+}, 'CSSUnitValue with unit "percent" constructed from IDL serializes correctly');
+
+test(() => {
+ assert_equals(new CSSUnitValue(3.14, 'number').toString(), '3.14');
+ assert_equals(CSS.number(3.14).toString(), '3.14');
+}, 'CSSUnitValue with unit "number" constructed from IDL serializes correctly');
+
+test(() => {
+ assert_equals(new CSSUnitValue(3, 'number').toString(), '3');
+}, 'CSSUnitValue with integer values constructed from IDL serializes correctly');
+
+test(() => {
+ let result = CSSStyleValue.parse('width', '1px');
+ result.value = 3.14;
+ assert_equals(result.toString(), '3.14px');
+}, 'CSSKeywordValue from DOMString modified by "value" setter serializes correctly');
+
+test(t => {
+ let result = createInlineStyleMap(t, 'width: 1px').get('width');
+ result.value = 3.14;
+ assert_equals(result.toString(), '3.14px');
+}, 'CSSKeywordValue from CSSOM modified by "value" setter serializes correctly');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
new file mode 100644
index 0000000000..c87553dd91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-serialization/cssUnparsedValue.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>IDL-constructed CSSUnparsedValue serialization tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#unparsedvalue-serialization">
+<meta name="assert" content="Test CSSUnparsedValue are serialized similar to getComputedStyle()" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="tag"></div>
+<div id="elem" style="color-scheme: bar/*comment*/var(--foo)"></div>
+<script>
+'use strict';
+
+test(() => {
+ assert_equals(new CSSUnparsedValue(['lem', 'on', 'ade']).toString(), 'lem/**/on/**/ade');
+}, 'CSSUnparsedValue containing strings serializes to its tokenized contents');
+
+test(() => {
+ assert_equals(new CSSUnparsedValue([
+ new CSSVariableReferenceValue('--A',
+ new CSSUnparsedValue([new CSSVariableReferenceValue('--B')])),
+ new CSSVariableReferenceValue('--C')]).toString(),
+ 'var(--A,var(--B))var(--C)');
+}, 'CSSUnparsedValue containing variable references serializes its ' +
+ 'tokenized contents');
+
+test(() => {
+ assert_equals(new CSSUnparsedValue(['foo', 'bar ',
+ new CSSVariableReferenceValue('--A',
+ new CSSUnparsedValue(['baz ',
+ new CSSVariableReferenceValue('--B'), 'lemon'])),
+ new CSSVariableReferenceValue('--C',
+ new CSSUnparsedValue(['ade']))]).toString(),
+ 'foo/**/bar var(--A,baz var(--B)lemon)var(--C,ade)');
+}, 'CSSUnparsedValue containing mix of strings and variable references ' +
+ 'serializes to its tokenized contents');
+
+test(() => {
+ assert_equals(
+ elem.attributeStyleMap.get("color-scheme").toString(),
+ 'bar/**/var(--foo)');
+}, 'attributeStyleMap round-trips correctly, though the comment is gone');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssColorValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssColorValue.html
new file mode 100644
index 0000000000..59a03c138d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssColorValue.html
@@ -0,0 +1,199 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSColorValue Tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csscolorvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const TEST_COLORS = [
+ {name: "magenta", rgb: [1, 0, 1], hsl: [300, 1, 0.5], hwb: [300, 0, 0]},
+ {name: "dark cyan", rgb: [0, 0.545, 0.545], hsl: [180, 1, 0.2725], hwb: [180, 0, 0.455]},
+ {name: "light goldenrod yellow", rgb: [1, 1, 0.82], hsl: [60, 1, 0.91], hwb: [60, 0.82, 0]},
+ {name: "medium purple", rgb: [0.58, 0.44, 0.86], hsl: [260, 0.5977, 0.649], hwb: [260, 0.44, 0.14]},
+]
+const rgb_attributes = ['r', 'g', 'b', 'alpha']
+const hsl_attributes = ['h', 's', 'l', 'alpha']
+const hwb_attributes = ['h', 'w', 'b', 'alpha']
+
+for (const color of TEST_COLORS) {
+ const hsl_color_degrees = new CSSHSL(CSS.deg(color.hsl[0]), color.hsl[1], color.hsl[2])
+ const hsl_color_radians = new CSSHSL(CSS.rad(color.hsl[0]/360 * 2 * Math.PI), color.hsl[1], color.hsl[2])
+ const hsl_color_gradians = new CSSHSL(CSS.grad(color.hsl[0]/360 * 400), color.hsl[1], color.hsl[2])
+
+ const hwb_color_degrees = new CSSHWB(CSS.deg(color.hwb[0]), color.hwb[1], color.hwb[2])
+ const hwb_color_radians = new CSSHWB(CSS.rad(color.hwb[0]/360 * 2 * Math.PI), color.hwb[1], color.hwb[2])
+ const hwb_color_gradians = new CSSHWB(CSS.grad(color.hwb[0]/360 * 400), color.hwb[1], color.hwb[2])
+
+ const rgb_color = new CSSRGB(color.rgb[0], color.rgb[1], color.rgb[2])
+
+ // Test conversion from CSSHSL to others.
+ test(() => {
+ const hsl_to_rgb = hsl_color_degrees.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hsl_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HSL using degrees to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hsl_to_rgb = hsl_color_radians.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hsl_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HSL using radians to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hsl_to_rgb = hsl_color_gradians.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hsl_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HSL using gradians to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hsl_to_hwb = hsl_color_degrees.toHWB();
+ for (const attr of hwb_attributes) {
+ assert_color_channel_approx_equals(hwb_color_degrees[attr], hsl_to_hwb[attr]);
+ }
+ }, `Converting HSL to HWB works for ${color.name}.`);
+
+ // Test conversion from CSSHWB to others.
+ test(() => {
+ const hwb_to_rgb = hwb_color_degrees.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hwb_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HWB using degrees to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hwb_to_rgb = hwb_color_radians.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hwb_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HWB using radians to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hwb_to_rgb = hwb_color_gradians.toRGB();
+ for (const attr of rgb_attributes) {
+ assert_color_channel_approx_equals(hwb_to_rgb[attr], rgb_color[attr]);
+ }
+ }, `Converting HWB using gradians to RGB works for ${color.name}.`);
+
+ test(() => {
+ const hwb_to_hsl = hwb_color_degrees.toHSL();
+ for (const attr of hsl_attributes) {
+ assert_color_channel_approx_equals(hsl_color_degrees[attr], hwb_to_hsl[attr]);
+ }
+ }, `Converting HWB to HSL works for ${color.name}.`);
+
+ // Test conversion from CSSRGB to others
+ test(() => {
+ const rgb_to_hsl = rgb_color.toHSL();
+ for (const attr of hsl_attributes) {
+ assert_color_channel_approx_equals(hsl_color_degrees[attr], rgb_to_hsl[attr]);
+ }
+ }, `Converting RGB to HSL works for ${color.name}.`);
+
+ test(() => {
+
+ const rgb_to_hwb = rgb_color.toHWB();
+ for (const attr of hwb_attributes) {
+ assert_color_channel_approx_equals(hwb_color_degrees[attr], rgb_to_hwb[attr]);
+ }
+ }, `Converting RGB to HWB works for ${color.name}.`);
+}
+
+const PARSING_COLOR_TEST_CASES = [
+ {
+ value: 'rgb(255,255,255)',
+ expected: new CSSRGB(CSS.number(255), CSS.number(255), CSS.number(255)),
+ },
+ {
+ value: 'rgba(100,255,255, 1)',
+ expected: new CSSRGB(CSS.number(100), CSS.number(255), CSS.number(255), CSS.percent(100)),
+ },
+ {
+ value: "#00bfff",
+ expected: new CSSRGB(CSS.number(0), CSS.number(191), CSS.number(255)),
+ },
+ {
+ value: "hsl(195, 100%, 50%)",
+ expected: new CSSHSL(CSS.deg(195), CSS.percent(100), CSS.percent(50)),
+ },
+ {
+ value: "hsla(123, 100%, 20%, .5)",
+ expected: new CSSHSL(CSS.deg(123), CSS.percent(100), CSS.percent(20), CSS.percent(50)),
+ },
+ {
+ value: "hwb(200 31% 38%)",
+ expected: new CSSHWB(CSS.deg(200), CSS.percent(31), CSS.percent(38)),
+ },
+ {
+ value: "hwb(200 31% 38% / 0.5)",
+ expected: new CSSHWB(CSS.deg(200), CSS.percent(31), CSS.percent(38), CSS.percent(50)),
+ },
+ {
+ value: "blue",
+ expected: new CSSRGB(CSS.number(0), CSS.number(0), CSS.number(255)),
+ },
+ {
+ value: "transparent",
+ expected: new CSSRGB(CSS.number(0), CSS.number(0), CSS.number(0), CSS.percent(0)),
+ },
+]
+
+for(const testCase of PARSING_COLOR_TEST_CASES) {
+ test(()=> {
+ const parsedColor = CSSColorValue.parse(testCase.value)
+ let attrs;
+ switch(testCase.expected.constructor.name) {
+ case "CSSRGB":
+ attrs = rgb_attributes;
+ break;
+ case "CSSHSL":
+ attrs = hsl_attributes;
+ break;
+ case "CSSHWB":
+ attrs = hwb_attributes
+ }
+
+ for (const attr of attrs) {
+ assert_color_channel_approx_equals(parsedColor[attr], testCase.expected[attr]);
+ }
+ }, `Parsing the color string "${testCase.value}"`)
+}
+
+const INVALID_COLOR_TEST_CASES = [
+ "abcdef",
+ "--foo",
+ "--bar",
+ "abc()",
+ "initial",
+ "inherit",
+ "unset",
+ "revert",
+ "revert-layer"
+]
+
+for(const testCase of INVALID_COLOR_TEST_CASES) {
+test(()=> {
+ assert_throws_dom("SyntaxError",
+ () => CSSColorValue.parse(testCase));
+}, `throwing invalid color string "${testCase}`)
+}
+
+const SYSTEM_COLORS = [
+ 'GrayText',
+ 'Canvas'
+]
+
+for(const testCase of SYSTEM_COLORS) {
+ test(()=>{
+ const parsedColor = CSSColorValue.parse(testCase)
+ assert_equals(parsedColor.constructor.name, 'CSSKeywordValue')
+ assert_equals(parsedColor.toString(), testCase.toLowerCase())
+ })
+}
+
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHSL.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHSL.html
new file mode 100644
index 0000000000..b38d740383
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHSL.html
@@ -0,0 +1,85 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSHSL tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshsl">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gUndefinedKeyword = new CSSKeywordValue("undefined");
+
+const gValidHueInputs = [
+ {hue: 180, desc: "a number", expected: CSS.deg(180)},
+ {hue: CSS.deg(180), desc: 'degrees', expected: CSS.deg(180)},
+ {hue: CSS.rad(1), desc: 'radians', expected: CSS.rad(1)},
+ {hue: CSS.grad(81), desc: 'gradians', expected: CSS.grad(81)},
+ {hue: undefined, desc: "undefined", expected: gUndefinedKeyword},
+];
+
+const gInvalidHueInputs = [
+ {hue: CSS.px(1), desc: "css pixels"},
+ {hue: CSS.em(1), desc: "css em"},
+]
+
+for (const {hue, desc, expected} of gValidHueInputs) {
+ test(() => {
+ const result = new CSSHSL(hue, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.h, expected);
+ }, `Constructing a CSSHSL with ${desc} for the hue works as intended.`);
+
+ test(() => {
+ const result = new CSSHSL(CSS.deg(0), 0.5, 0.5);
+ result.h = hue;
+ assert_color_channel_approx_equals(result.h, expected);
+ }, `CSSHSL.h can be updated with a ${desc}.`);
+}
+
+for (const {hue, desc} of gInvalidHueInputs) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSHSL(hue, 0, 0));
+ }, `Constructing a CSSHSL with ${desc} for hue throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSHSL(CSS.deg(27), 0.7, CSS.percent(91));
+ assert_color_channel_approx_equals(result.h, CSS.deg(27));
+ assert_color_channel_approx_equals(result.s, CSS.percent(70));
+ assert_color_channel_approx_equals(result.l, CSS.percent(91));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSHSL can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSHSL(CSS.grad(101), 0.2, 0.3, CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.h, CSS.grad(101));
+ assert_color_channel_approx_equals(result.s, CSS.percent(20));
+ assert_color_channel_approx_equals(result.l, CSS.percent(30));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSHSL can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSHSL(CSS.deg(0), CSS.number(1), 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSHSL(CSS.deg(0), 0, CSS.number(1), 0));
+ assert_throws_dom("SyntaxError", () => new CSSHSL(CSS.deg(0), 0, 0, CSS.number(1)));
+}, `Constructing a CSSHSL with CSS.number for s, l or alpha throws a TypeError`);
+
+for (const attr of ['s', 'l', 'alpha']) {
+ test(() => {
+ const result = new CSSHSL(CSS.deg(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSHSL with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSHSL(CSS.deg(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSHSL.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSHSL(CSS.deg(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSHSL.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHWB.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHWB.html
new file mode 100644
index 0000000000..8fce6133fb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssHWB.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSHWB tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshwb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gValidHueInputs = [
+ {hue: CSS.deg(180), desc: 'degrees'},
+ {hue: CSS.rad(1), desc: 'radians'},
+ {hue: CSS.grad(81), desc: 'gradians'},
+];
+
+const gInvalidHueInputsNotNumericValue = [
+ {hue: 180, desc: "a number"},
+ {hue: undefined, desc: "undefined"},
+]
+
+const gInvalidHueInputsNumericValue = [
+ {hue: CSS.px(1), desc: "css pixels"},
+]
+
+for (const {hue, desc} of gValidHueInputs) {
+ test(() => {
+ const result = new CSSHWB(hue, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.h, hue);
+ }, `Constructing a CSSHWB with ${desc} for the hue works as intended.`);
+
+ test(() => {
+ const result = new CSSHWB(CSS.deg(0), 0.5, 0.5);
+ result.h = hue;
+ assert_color_channel_approx_equals(result.h, hue);
+ }, `CSSHWB.h can be updated with a ${desc}.`);
+}
+
+for (const {hue, desc} of gInvalidHueInputsNotNumericValue) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSHWB(hue, 0, 0));
+ }, `Constructing a CSSHWB with ${desc} for hue throws a TypeError.`);
+}
+
+for (const {hue, desc} of gInvalidHueInputsNumericValue) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSHWB(hue, 0, 0));
+ }, `Constructing a CSSHWB with ${desc} for hue throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSHWB(CSS.deg(27), 0.7, CSS.percent(91));
+ assert_color_channel_approx_equals(result.h, CSS.deg(27));
+ assert_color_channel_approx_equals(result.w, CSS.percent(70));
+ assert_color_channel_approx_equals(result.b, CSS.percent(91));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSHWB can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSHWB(CSS.grad(101), 0.2, 0.3, CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.h, CSS.grad(101));
+ assert_color_channel_approx_equals(result.w, CSS.percent(20));
+ assert_color_channel_approx_equals(result.b, CSS.percent(30));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSHWB can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSHWB(CSS.deg(0), CSS.number(1), 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSHWB(CSS.deg(0), 0, CSS.number(1), 0));
+ assert_throws_dom("SyntaxError", () => new CSSHWB(CSS.deg(0), 0, 0, CSS.number(1)));
+}, `Constructing a CSSHWB with CSS.number for s, l or alpha throws a SyntaxError`);
+
+for (const attr of ['w', 'b', 'alpha']) {
+ test(() => {
+ const result = new CSSHWB(CSS.deg(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSHWB with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSHWB(CSS.deg(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSHWB.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSHWB(CSS.deg(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSHWB.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-invalid.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-invalid.html
new file mode 100644
index 0000000000..69007a1c59
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-invalid.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSKeywordValue Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csskeywordvalue">
+<meta name="assert" content="Test CSSKeywordValue constructor and attributes error handling" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSKeywordValue(''));
+}, 'Constructing CSSKeywordValue with an empty string throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html
new file mode 100644
index 0000000000..ceb39bce5d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue-value.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSKeywordValue.value</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csskeywordvalue-value">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+const gTestArguments = [
+ { keyword: 'initial', description: 'a CSS wide keyword' },
+ { keyword: 'auto', description: 'a CSS keyword' },
+ { keyword: 'lemon', description: 'an unsupported CSS keyword' },
+ { keyword: '3! + 4@', description: 'a string containing multiple tokens' },
+ { keyword: '☺', description: 'a unicode string' },
+];
+
+for (const args of gTestArguments) {
+ test(() => {
+ const result = new CSSKeywordValue(args.keyword);
+ assert_not_equals(result, null, 'a CSSKeywordValue is created');
+ assert_equals(result.value, args.keyword, 'value reflects new value');
+ }, `CSSKeywordValue.value can be updated to ${args.description}`);
+}
+
+test(() => {
+ let result = new CSSKeywordValue('lemon');
+ assert_throws_js(TypeError, () => result.value = '');
+ assert_equals(result.value, 'lemon', 'value does not change');
+}, 'Updating CSSKeywordValue.value with an empty string throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html
new file mode 100644
index 0000000000..1ebbf8de73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssKeywordValue.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSKeywordValue Constructor</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csskeywordvalue-csskeywordvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+const gTestArguments = [
+ { keyword: 'initial', description: 'a CSS wide keyword' },
+ { keyword: 'auto', description: 'a CSS keyword' },
+ { keyword: 'lemon', description: 'an unsupported CSS keyword' },
+ { keyword: '3! + 4@', description: 'a string containing multiple tokens' },
+ { keyword: '☺', description: 'a unicode string' },
+];
+
+for (const args of gTestArguments) {
+ test(() => {
+ const result = new CSSKeywordValue(args.keyword);
+ assert_not_equals(result, null, 'a CSSKeywordValue is created');
+ assert_equals(result.value, args.keyword,
+ 'value is same as given by constructor');
+ }, `CSSKeywordValue can be constructed from ${args.description}`);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLCH.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLCH.html
new file mode 100644
index 0000000000..ffd288f0f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLCH.html
@@ -0,0 +1,81 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSLCH tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshwb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gValidLightnessInputs = [
+ {lightness: CSS.percent(50), desc: 'percent', expected: CSS.percent(50)},
+ {lightness: 0.5, desc: 'number', expected: CSS.percent(50)},
+];
+
+const gInvalidLightnessInputs = [
+ {lightness: CSS.px(1), desc: "css pixels"},
+ {lightness: CSS.deg(180), desc: "degrees"},
+]
+
+for (const {lightness, desc, expected} of gValidLightnessInputs) {
+ test(() => {
+ const result = new CSSLCH(lightness, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `Constructing a CSSLCH with ${desc} for the lightness works as intended.`);
+
+ test(() => {
+ const result = new CSSLCH(CSS.percent(0), 0.5, 0.5);
+ result.l = lightness;
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `CSSLCH.l can be updated with a ${desc}.`);
+}
+
+for (const {lightness, desc} of gInvalidLightnessInputs) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSLCH(lightness, 0, 0));
+ }, `Constructing a CSSLCH with ${desc} for lightness throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSLCH(CSS.percent(27), 0.7, 8);
+ assert_color_channel_approx_equals(result.l, CSS.percent(27));
+ assert_color_channel_approx_equals(result.c, CSS.percent(70));
+ assert_color_channel_approx_equals(result.h, CSS.deg(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSLCH can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSLCH(0.2, 0.7, CSS.rad(8), CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.l, CSS.percent(20));
+ assert_color_channel_approx_equals(result.c, CSS.percent(70));
+ assert_color_channel_approx_equals(result.h, CSS.rad(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSLCH can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSLCH(CSS.number(1), 0, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSLCH(0, CSS.number(1), 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSLCH(0, 0, CSS.number(1), 0));
+ assert_throws_dom("SyntaxError", () => new CSSLCH(0, 0, 0, CSS.number(1)));
+}, `Constructing a CSSLCH with CSS.number for l, c, h or alpha throws a SyntaxError`);
+
+for (const attr of ['l', 'c', 'alpha']) {
+ test(() => {
+ const result = new CSSLCH(CSS.percent(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSLCH with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSLCH(CSS.percent(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSLCH.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSLCH(CSS.percent(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSLCH.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLab.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLab.html
new file mode 100644
index 0000000000..2c396b538e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssLab.html
@@ -0,0 +1,79 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSLab tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshwb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gValidLightnessInputs = [
+ {lightness: CSS.percent(50), desc: 'percent', expected: CSS.percent(50)},
+ {lightness: 0.5, desc: 'number', expected: CSS.percent(50)},
+];
+
+const gInvalidLightnessInputs = [
+ {lightness: CSS.px(1), desc: "css pixels"},
+ {lightness: CSS.deg(180), desc: "degrees"},
+]
+
+for (const {lightness, desc, expected} of gValidLightnessInputs) {
+ test(() => {
+ const result = new CSSLab(lightness, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `Constructing a CSSLab with ${desc} for the lightness works as intended.`);
+
+ test(() => {
+ const result = new CSSLab(CSS.percent(0), 0.5, 0.5);
+ result.l = lightness;
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `CSSLab.l can be updated with a ${desc}.`);
+}
+
+for (const {lightness, desc} of gInvalidLightnessInputs) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSLab(lightness, 0, 0));
+ }, `Constructing a CSSLab with ${desc} for lightness throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSLab(CSS.percent(27), 7, CSS.number(8));
+ assert_color_channel_approx_equals(result.l, CSS.percent(27));
+ assert_color_channel_approx_equals(result.a, CSS.number(7));
+ assert_color_channel_approx_equals(result.b, CSS.number(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSLab can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSLab(0.2, 7, CSS.number(8), CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.l, CSS.percent(20));
+ assert_color_channel_approx_equals(result.a, CSS.number(7));
+ assert_color_channel_approx_equals(result.b, CSS.number(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSLab can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSLab(CSS.number(1), 0, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSLab(0, 0, 0, CSS.number(1)));
+}, `Constructing a CSSLab with CSS.number for l or alpha throws a SyntaxError`);
+
+for (const attr of ['l', 'alpha']) {
+ test(() => {
+ const result = new CSSLab(CSS.percent(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSLab with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSLab(CSS.percent(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSLab.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSLab(CSS.percent(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSLab.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html
new file mode 100644
index 0000000000..2f1fcc1408
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssMatrixComponent.tentative.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSMatrixComponent tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssmatrixcomponent-cssmatrixcomponent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script src="../resources/comparisons.js"></script>
+<script>
+'use strict';
+
+const EPSILON = 1e-6;
+
+const gTestMatrices = [
+ {
+ matrix: new DOMMatrix([0, -1, 3.14, -3.14, 10, 0]),
+ desc: 'a 2D matrix'
+ },
+ {
+ matrix: new DOMMatrix([1.1, 1.2, -13, -1.4, 2, 0, -2, 4, 3.1, 3, 3, 3.4, -4.1, 42, 43, 4.4]),
+ desc: 'a 3D matrix'
+ },
+];
+
+for (const {matrix, desc} of gTestMatrices) {
+ test(() => {
+ const component = new CSSMatrixComponent(matrix, { is2D: true });
+ assert_matrix_approx_equals(component.matrix, matrix, EPSILON);
+ assert_true(component.is2D);
+ }, 'CSSMatrixComponent can be constructed from ' + desc + ' with is2D true');
+
+ test(() => {
+ const component = new CSSMatrixComponent(matrix, { is2D: false });
+ assert_matrix_approx_equals(component.matrix, matrix, EPSILON);
+ assert_false(component.is2D);
+ }, 'CSSMatrixComponent can be constructed from ' + desc + ' with is2D false');
+
+ test(() => {
+ const component = new CSSMatrixComponent(matrix);
+ assert_matrix_approx_equals(component.matrix, matrix, EPSILON);
+ assert_equals(component.is2D, matrix.is2D);
+ }, 'CSSMatrixComponent can be constructed from ' + desc + ' without a CSSMatrixComponentOptions');
+
+ test(() => {
+ const component = new CSSMatrixComponent(matrix, null);
+ assert_matrix_approx_equals(component.matrix, matrix, EPSILON);
+ assert_equals(component.is2D, matrix.is2D);
+ }, 'CSSMatrixComponent can be constructed from ' + desc + ' with an invalid CSSMatrixComponentOptions');
+
+ test(() => {
+ let component = new CSSMatrixComponent(new DOMMatrixReadOnly([
+ 0, 0, 0, 0, 0, 0
+ ]));
+
+ component.matrix = matrix;
+ assert_matrix_approx_equals(component.matrix, matrix, EPSILON);
+ }, 'CSSMatrixComponent.matrix can be updated to ' + desc);
+}
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLCH.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLCH.html
new file mode 100644
index 0000000000..dc3f34fedd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLCH.html
@@ -0,0 +1,81 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSOKLCH tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshwb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gValidLightnessInputs = [
+ {lightness: CSS.percent(50), desc: 'percent', expected: CSS.percent(50)},
+ {lightness: 0.5, desc: 'number', expected: CSS.percent(50)},
+];
+
+const gInvalidLightnessInputs = [
+ {lightness: CSS.px(1), desc: "css pixels"},
+ {lightness: CSS.deg(180), desc: "degrees"},
+]
+
+for (const {lightness, desc, expected} of gValidLightnessInputs) {
+ test(() => {
+ const result = new CSSOKLCH(lightness, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `Constructing a CSSOKLCH with ${desc} for the lightness works as intended.`);
+
+ test(() => {
+ const result = new CSSOKLCH(CSS.percent(0), 0.5, 0.5);
+ result.l = lightness;
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `CSSOKLCH.l can be updated with a ${desc}.`);
+}
+
+for (const {lightness, desc} of gInvalidLightnessInputs) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSOKLCH(lightness, 0, 0));
+ }, `Constructing a CSSOKLCH with ${desc} for lightness throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSOKLCH(CSS.percent(27), 0.7, 8);
+ assert_color_channel_approx_equals(result.l, CSS.percent(27));
+ assert_color_channel_approx_equals(result.c, CSS.percent(70));
+ assert_color_channel_approx_equals(result.h, CSS.deg(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSOKLCH can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSOKLCH(0.2, 0.7, CSS.rad(8), CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.l, CSS.percent(20));
+ assert_color_channel_approx_equals(result.c, CSS.percent(70));
+ assert_color_channel_approx_equals(result.h, CSS.rad(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSOKLCH can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSOKLCH(CSS.number(1), 0, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSOKLCH(0, CSS.number(1), 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSOKLCH(0, 0, CSS.number(1), 0));
+ assert_throws_dom("SyntaxError", () => new CSSOKLCH(0, 0, 0, CSS.number(1)));
+}, `Constructing a CSSOKLCH with CSS.number for l, c, h or alpha throws a SyntaxError`);
+
+for (const attr of ['l', 'c', 'alpha']) {
+ test(() => {
+ const result = new CSSOKLCH(CSS.percent(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSOKLCH with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSOKLCH(CSS.percent(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSOKLCH.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSOKLCH(CSS.percent(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSOKLCH.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLab.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLab.html
new file mode 100644
index 0000000000..b597845a54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssOKLab.html
@@ -0,0 +1,79 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSOKLab tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csshwb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gValidLightnessInputs = [
+ {lightness: CSS.percent(50), desc: 'percent', expected: CSS.percent(50)},
+ {lightness: 0.5, desc: 'number', expected: CSS.percent(50)},
+];
+
+const gInvalidLightnessInputs = [
+ {lightness: CSS.px(1), desc: "css pixels"},
+ {lightness: CSS.deg(180), desc: "degrees"},
+]
+
+for (const {lightness, desc, expected} of gValidLightnessInputs) {
+ test(() => {
+ const result = new CSSOKLab(lightness, 0.5, 0.5);
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `Constructing a CSSOKLab with ${desc} for the lightness works as intended.`);
+
+ test(() => {
+ const result = new CSSOKLab(CSS.percent(0), 0.5, 0.5);
+ result.l = lightness;
+ assert_color_channel_approx_equals(result.l, expected);
+ }, `CSSOKLab.l can be updated with a ${desc}.`);
+}
+
+for (const {lightness, desc} of gInvalidLightnessInputs) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSOKLab(lightness, 0, 0));
+ }, `Constructing a CSSOKLab with ${desc} for lightness throws a SyntaxError.`);
+}
+
+test(() => {
+ const result = new CSSOKLab(CSS.percent(27), 7, CSS.number(8));
+ assert_color_channel_approx_equals(result.l, CSS.percent(27));
+ assert_color_channel_approx_equals(result.a, CSS.number(7));
+ assert_color_channel_approx_equals(result.b, CSS.number(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, 'CSSOKLab can be constructed from three numbers and will get an alpha of 100%.');
+
+test(() => {
+ const result = new CSSOKLab(0.2, 7, CSS.number(8), CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.l, CSS.percent(20));
+ assert_color_channel_approx_equals(result.a, CSS.number(7));
+ assert_color_channel_approx_equals(result.b, CSS.number(8));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, 'CSSOKLab can be constructed from four numbers.');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSOKLab(CSS.number(1), 0, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSOKLab(0, 0, 0, CSS.number(1)));
+}, `Constructing a CSSOKLab with CSS.number for l or alpha throws a SyntaxError`);
+
+for (const attr of ['l', 'alpha']) {
+ test(() => {
+ const result = new CSSOKLab(CSS.percent(0), 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = CSS.number(1));
+ }, `Updating a CSSOKLab with CSS.number for ${attr} throws a SyntaxError`);
+
+ test(() => {
+ const result = new CSSOKLab(CSS.percent(0), 0, 0);
+ result[attr] = 0.5;
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSOKLab.' + attr + ' can be updated to a number.');
+
+ test(() => {
+ const result = new CSSOKLab(CSS.percent(0), 0, 0);
+ result[attr] = CSS.percent(50);
+ assert_color_channel_approx_equals(result[attr], CSS.percent(50));
+ }, 'CSSOKLab.' + attr + ' can be updated with a CSS percent.');
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html
new file mode 100644
index 0000000000..e2d01e32e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssPerspective.tentative.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSPerspective tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssperspective">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { length: 'auto', desc: 'a keyword other than none (string)'},
+ { length: new CSSKeywordValue('auto'), desc: 'a keyword other than none (CSSKeywordValue)'},
+ { length: 3.14, desc: 'a double'},
+ { length: 0, desc: 'a unitless zero'},
+ { length: '10px', desc: 'a string length'},
+ { length: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { length: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { length: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {length, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSPerspective(length));
+ }, 'Constructing a CSSPerspective with ' + desc + ' throws a TypeError');
+}
+
+for (const {length, desc} of gInvalidTestCases) {
+ test(() => {
+ let perspective = new CSSPerspective(CSS.px(0));
+ assert_throws_js(TypeError, () => perspective.length = length);
+ assert_style_value_equals(perspective.length, CSS.px(0));
+ }, 'Updating CSSPerspective.length with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { length: CSS.px(-3.14), desc: 'a length CSSUnitValue' },
+ { length: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+ { length: new CSSKeywordValue('none'), desc: 'none (CSSKeywordValue)' },
+];
+
+for (const {length, desc} of gValidTestCases) {
+ test(() => {
+ const perspective = new CSSPerspective(length);
+ assert_equals(perspective.length, length);
+ assert_false(perspective.is2D);
+ }, 'CSSPerspective can be constructed from ' + desc);
+
+ test(() => {
+ let perspective = new CSSPerspective(CSS.px(0), CSS.px(0));
+ perspective.length = length;
+ assert_style_value_equals(perspective.length, length);
+ }, 'CSSPerspective.length can be updated to ' + desc);
+}
+
+const gConvertingValidTestCases = [
+ { length: "none", expected: new CSSKeywordValue('none'), desc: 'none (string)' },
+];
+
+for (const {length, expected, desc} of gConvertingValidTestCases) {
+ test(() => {
+ const perspective = new CSSPerspective(length);
+ assert_style_value_equals(perspective.length, expected);
+ assert_false(perspective.is2D);
+ }, 'CSSPerspective can be constructed from ' + desc);
+
+ test(() => {
+ let perspective = new CSSPerspective(CSS.px(0), CSS.px(0));
+ perspective.length = length;
+ assert_style_value_equals(perspective.length, expected);
+ }, 'CSSPerspective.length can be updated to ' + desc);
+}
+
+test(() => {
+ let perspective = new CSSPerspective(CSS.px(0), CSS.px(0));
+ perspective.is2D = true;
+ assert_false(perspective.is2D);
+}, 'Modifying CSSPerspective.is2D is a no-op');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRGB.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRGB.html
new file mode 100644
index 0000000000..8ec193da4d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRGB.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSRGB tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssrgb">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+"use strict";
+
+const gInvalidColorTestCases = [
+ { color: CSS.deg(1), desc: "an angle CSSUnitValue"},
+ { color: new CSSMathSum(CSS.px(1)), desc: "a CSSMathValue that doesn\"t match <number>"},
+ // Alpha has a default value and works with undefined
+ { color: undefined, desc: "undefined", skipAlpha: true},
+ { color: "calc(10 + 10%)", desc: "a CSS math calculation"}
+];
+
+const gValidColorTestCases = [
+ { color: 0.5, desc: "a number with the resulting value being a percentage.", result: CSS.percent(50) },
+ { color: CSS.number(0.5), desc: "a CSS number.", skipAlpha: true },
+ { color: CSS.percent(50), desc: "CSS percent.", result: CSS.percent(50) },
+ { color: new CSSMathSum(CSS.percent(10), CSS.percent(20)), desc: "CSS math sum." },
+ { color: new CSSMathProduct(CSS.percent(10), CSS.number(2)), desc: "CSS math product." },
+ { color: new CSSMathMax(CSS.percent(10), CSS.percent(20)), desc: "CSS math max." },
+ { color: new CSSMathMin(CSS.percent(10), CSS.percent(20)), desc: "CSS math min." },
+];
+
+for (const {color, desc, skipAlpha} of gInvalidColorTestCases) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSRGB(color, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSRGB(0, color, 0));
+ assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, color));
+ assert_throws_dom("SyntaxError", () => new CSSRGB(color, 0, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSRGB(0, color, 0, 0));
+ assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, color, 0));
+ if (!skipAlpha) assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, 0, color));
+ }, `Constructing a CSSRGB with ${desc} for the color channels throws a SyntaxError.`);
+}
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, 0, CSS.number(1)));
+}, `Constructing a CSSRGB with a CSS number for the alpha channels throws a SyntaxError.`);
+
+for (const attr of ['r', 'g', 'b', 'alpha']) {
+ for (const {color, desc} of gInvalidColorTestCases) {
+ test(() => {
+ const result = new CSSRGB(0, 0, 0, 0);
+ assert_throws_dom("SyntaxError", () => result[attr] = color);
+ assert_style_value_equals(result[attr], CSS.percent(0));
+ }, `Updating CSSRGB. ${attr} to ${desc} throws a SyntaxError.`);
+ }
+}
+
+test(() => {
+ const result = new CSSRGB(0, 0, 0);
+ assert_throws_dom("SyntaxError", () => result.alpha = CSS.number(1));
+}, "Updating the alpha channel to a CSS number throws a SyntaxError.");
+
+test(() => {
+ const result = new CSSRGB(0.5, CSS.number(73), CSS.percent(91));
+ assert_color_channel_approx_equals(result.r, CSS.percent(50));
+ assert_color_channel_approx_equals(result.g, CSS.number(73));
+ assert_color_channel_approx_equals(result.b, CSS.percent(91));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(100));
+}, "CSSRGB can be constructed from three numbers and will get an alpha of 100%.");
+
+test(() => {
+ const result = new CSSRGB(0.5, CSS.number(0.2), 0.3, CSS.percent(0.4));
+ assert_color_channel_approx_equals(result.r, CSS.percent(50));
+ assert_color_channel_approx_equals(result.g, CSS.number(0.2));
+ assert_color_channel_approx_equals(result.b, CSS.percent(30));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(0.4));
+}, "CSSRGB can be constructed from four numbers.");
+
+for (const attr of ["r", "g", "b", "alpha"]) {
+ for (const testCase of gValidColorTestCases) {
+ if (attr === "alpha" && testCase.skipAlpha)
+ continue;
+ test(() => {
+ const result = new CSSRGB(0, 0, 0);
+ result[attr] = testCase.color;
+ assert_color_channel_approx_equals(result[attr], testCase.result ? testCase.result : testCase.color)
+ }, `CSSRGB.${attr} can be updated with ${testCase.desc}`);
+ }
+}
+
+test(() => {
+ const color = new CSSRGB(
+ new CSSMathSum(CSS.percent(10), CSS.percent(20)),
+ new CSSMathProduct(CSS.percent(10), CSS.number(2)),
+ new CSSMathMax(CSS.percent(10), CSS.percent(50))
+ );
+ assert_color_channel_approx_equals(color.r, new CSSMathSum(CSS.percent(10), CSS.percent(20)));
+ assert_color_channel_approx_equals(color.g, new CSSMathProduct(CSS.percent(10), CSS.number(2)));
+ assert_color_channel_approx_equals(color.b, new CSSMathMax(CSS.percent(10), CSS.percent(50)));
+ let result = color.toRGB();
+ assert_color_channel_approx_equals(result.r, CSS.percent(30));
+ assert_color_channel_approx_equals(result.g, CSS.percent(20));
+ assert_color_channel_approx_equals(result.b, CSS.percent(50));
+}, `toRGB function evaluates sum, product and max objects.`);
+
+test(() => {
+ const color = new CSSRGB(1, 0.5, CSS.number(0.3), CSS.percent(50));
+ let result = color.toRGB();
+ assert_color_channel_approx_equals(result.r, CSS.percent(100));
+ assert_color_channel_approx_equals(result.g, CSS.percent(50));
+ assert_color_channel_approx_equals(result.b, CSS.percent(30));
+ assert_color_channel_approx_equals(result.alpha, CSS.percent(50));
+ for (const attr of ["r", "g", "b", "alpha"]) {
+ color[attr] = 0.7;
+ result = color.toRGB();
+ assert_color_channel_approx_equals(result[attr], CSS.percent(70));
+ }
+}, "toRGB() function works as expected and values can be updated.");
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRotate.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRotate.tentative.html
new file mode 100644
index 0000000000..6c234bc472
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssRotate.tentative.html
@@ -0,0 +1,126 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSRotate tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssrotate">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidAngleTestCases = [
+ { angle: CSS.number(10), desc: 'a CSSUnitValue with type other than angle'},
+ { angle: new CSSMathSum(CSS.s(10)), desc: 'a CSSMathValue that doesn\'t match <angle>'},
+];
+
+const gInvalidCoordTestCases = [
+ { coord: CSS.px(10), desc: 'a CSSUnitValue with type other than number'},
+ { coord: new CSSMathSum(CSS.px(10)), desc: 'a CSSMathValue that doesn\'t match <number>'},
+];
+
+for (const {angle, desc} of gInvalidAngleTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSRotate(angle));
+ assert_throws_js(TypeError, () => new CSSRotate(0, 0, 0, angle));
+ }, 'Constructing a CSSRotate with ' + desc + ' for the angle throws a TypeError');
+}
+
+for (const {coord, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSRotate(coord, 0, 0, CSS.deg(0)));
+ assert_throws_js(TypeError, () => new CSSRotate(0, coord, 0, CSS.deg(0)));
+ assert_throws_js(TypeError, () => new CSSRotate(0, 0, coord, CSS.deg(0)));
+ }, 'Constructing a CSSRotate with ' + desc + ' for the coordinates throws a TypeError');
+}
+
+for (const attr of ['x', 'y', 'z']) {
+ for (const {value, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ let result = new CSSRotate(0, 0, 0, CSS.deg(0));
+ assert_throws_js(TypeError, () => result[attr] = value);
+ assert_style_value_equals(result[attr], CSS.number(0));
+ }, 'Updating CSSRotate.' + attr + ' to ' + desc + ' throws a TypeError');
+ }
+}
+
+for (const {angle, desc} of gInvalidAngleTestCases) {
+ test(() => {
+ let result = new CSSRotate(CSS.deg(0));
+ assert_throws_js(TypeError, () => result.angle = angle);
+ assert_style_value_equals(result.angle, CSS.deg(0));
+ }, 'Updating CSSRotate.angle to ' + desc + ' throws a TypeError');
+}
+
+test(() => {
+ const result = new CSSRotate(CSS.deg(3.14));
+ assert_style_value_equals(result.x, CSS.number(0));
+ assert_style_value_equals(result.y, CSS.number(0));
+ assert_style_value_equals(result.z, CSS.number(1));
+ assert_style_value_equals(result.angle, CSS.deg(3.14));
+ assert_true(result.is2D);
+}, 'CSSRotate can be constructed from a single angle');
+
+test(() => {
+ const result = new CSSRotate(-3.14, CSS.number(3.14), 3.14, CSS.deg(3.14));
+ assert_style_value_equals(result.x, CSS.number(-3.14));
+ assert_style_value_equals(result.y, CSS.number(3.14));
+ assert_style_value_equals(result.z, CSS.number(3.14));
+ assert_style_value_equals(result.angle, CSS.deg(3.14));
+ assert_false(result.is2D);
+}, 'CSSRotate can be constructed from numberish coordinates');
+
+test(() => {
+ const result = new CSSRotate(
+ new CSSMathSum(-3.14),
+ new CSSMathProduct(3.14),
+ new CSSMathNegate(-3.14),
+ new CSSMathMax(CSS.deg(3.14))
+ );
+ assert_style_value_equals(result.x, new CSSMathSum(-3.14));
+ assert_style_value_equals(result.y, new CSSMathProduct(3.14));
+ assert_style_value_equals(result.z, new CSSMathNegate(-3.14));
+ assert_style_value_equals(result.angle, new CSSMathMax(CSS.deg(3.14)));
+ assert_false(result.is2D);
+}, 'CSSRotate can be constructed from CSSMathValues');
+
+for (const attr of ['x', 'y', 'z']) {
+ test(() => {
+ let result = new CSSRotate(0, 0, 0, CSS.deg(0));
+ result[attr] = 3.14;
+ assert_style_value_equals(result[attr], CSS.number(3.14));
+ }, 'CSSRotate.' + attr + ' can be updated to a double');
+
+ test(() => {
+ let result = new CSSRotate(0, 0, 0, CSS.deg(0));
+ result[attr] = CSS.number(3.14);
+ assert_style_value_equals(result[attr], CSS.number(3.14));
+ }, 'CSSRotate.' + attr + ' can be updated to a number CSSUnitValue');
+
+ test(() => {
+ let result = new CSSRotate(0, 0, 0, CSS.deg(0));
+ result[attr] = new CSSMathSum(3.14);
+ assert_style_value_equals(result[attr], new CSSMathSum(3.14));
+ }, 'CSSRotate.' + attr + ' can be updated to a CSSMathValue matching <number>');
+}
+
+test(() => {
+ let rotation = new CSSRotate(CSS.deg(0));
+ rotation.angle = CSS.deg(6);
+ assert_style_value_equals(rotation.angle, CSS.deg(6));
+}, 'CSSRotate.angle can be updated to a degree CSSUnitValue');
+
+test(() => {
+ let rotation = new CSSRotate(CSS.deg(0));
+ rotation.angle = new CSSMathSum(CSS.deg(3.14));
+ assert_style_value_equals(rotation.angle, new CSSMathSum(CSS.deg(3.14)));
+}, 'CSSRotate.angle can be updated to a CSSMathValue matching <angle>');
+
+test(() => {
+ let rotation = new CSSRotate(CSS.deg(0));
+ rotation.is2D = true;
+ assert_true(rotation.is2D);
+ rotation.is2D = false;
+ assert_false(rotation.is2D);
+}, 'Modifying CSSRotate.is2D can be updated to true or false');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html
new file mode 100644
index 0000000000..e5efb93876
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssScale.tentative.html
@@ -0,0 +1,89 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSScale tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssscale">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidCoordTestCases = [
+ { coord: CSS.deg(1), desc: 'an angle CSSUnitValue'},
+ { coord: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue that doesn\'t match <number>'},
+ { coord: new CSSMathProduct(CSS.px(1), new CSSMathInvert(CSS.px(1))), desc: 'an invalid division by px/px'},
+];
+
+for (const {coord, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSScale(coord, 0));
+ assert_throws_js(TypeError, () => new CSSScale(0, coord));
+ assert_throws_js(TypeError, () => new CSSScale(coord, 0, 0));
+ assert_throws_js(TypeError, () => new CSSScale(0, coord, 0));
+ assert_throws_js(TypeError, () => new CSSScale(0, 0, coord));
+ }, 'Constructing a CSSScale with ' + desc + ' for the coordinates throws a TypeError');
+}
+
+for (const attr of ['x', 'y', 'z']) {
+ for (const {value, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ let result = new CSSScale(0, 0, 0);
+ assert_throws_js(TypeError, () => result[attr] = value);
+ assert_style_value_equals(result[attr], CSS.number(0));
+ }, 'Updating CSSScale.' + attr + ' to ' + desc + ' throws a TypeError');
+ }
+}
+
+test(() => {
+ const result = new CSSScale(-3.14, CSS.number(3.14));
+ assert_style_value_equals(result.x, CSS.number(-3.14));
+ assert_style_value_equals(result.y, CSS.number(3.14));
+ assert_style_value_equals(result.z, CSS.number(1));
+ assert_true(result.is2D);
+}, 'CSSScale can be constructed from two number coordinates');
+
+test(() => {
+ const result = new CSSScale(-3.14, CSS.number(3.14), -3.14);
+ assert_style_value_equals(result.x, CSS.number(-3.14));
+ assert_style_value_equals(result.y, CSS.number(3.14));
+ assert_style_value_equals(result.z, CSS.number(-3.14));
+ assert_false(result.is2D);
+}, 'CSSScale can be constructed from three number coordinates');
+
+test(() => {
+ const result = new CSSScale(new CSSMathSum(-3.14), new CSSMathMax(3.14), new CSSMathNegate(-3.14));
+ assert_style_value_equals(result.x, new CSSMathSum(-3.14));
+ assert_style_value_equals(result.y, new CSSMathMax(3.14));
+ assert_style_value_equals(result.z, new CSSMathNegate(-3.14));
+ assert_false(result.is2D);
+}, 'CSSScale can be constructed from CSSMathValue coordinates');
+
+for (const attr of ['x', 'y', 'z']) {
+ test(() => {
+ let result = new CSSScale(0, 0, 0);
+ result[attr] = 3.14;
+ assert_style_value_equals(result[attr], CSS.number(3.14));
+ }, 'CSSScale.' + attr + ' can be updated to a number');
+
+ test(() => {
+ let result = new CSSScale(0, 0, 0);
+ result[attr] = CSS.number(3.14);
+ assert_style_value_equals(result[attr], CSS.number(3.14));
+ }, 'CSSScale.' + attr + ' can be updated to a numberish');
+
+ test(() => {
+ let result = new CSSScale(0, 0, 0);
+ result[attr] = new CSSMathSum(3.14);
+ assert_style_value_equals(result[attr], new CSSMathSum(3.14));
+ }, 'CSSScale.' + attr + ' can be updated to a CSSMathValue');
+}
+
+test(() => {
+ let rotation = new CSSScale(0, 0, 0);
+ rotation.is2D = true;
+ assert_true(rotation.is2D);
+ rotation.is2D = false;
+ assert_false(rotation.is2D);
+}, 'Modifying CSSScale.is2D can be updated to true or false');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html
new file mode 100644
index 0000000000..0a410859b2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkew.tentative.html
@@ -0,0 +1,70 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkew tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskew">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSSkew(value, CSS.deg(0)));
+ assert_throws_js(TypeError, () => new CSSSkew(CSS.deg(0), value));
+ }, 'Constructing a CSSSkew with ' + desc + ' throws a TypeError');
+}
+
+for (const attr of ['ax', 'ay']) {
+ for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skew = new CSSSkew(CSS.deg(0), CSS.deg(0));
+ assert_throws_js(TypeError, () => skew[attr] = value);
+ assert_style_value_equals(skew[attr], CSS.deg(0));
+ }, 'Updating CSSSkew.' + attr + ' with ' + desc + ' throws a TypeError');
+ }
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ax, desc: axDesc} of gValidTestCases) {
+ for (const {value: ay, desc: ayDesc} of gValidTestCases) {
+ test(() => {
+ const skew = new CSSSkew(ax, ay);
+ assert_equals(skew.ax, ax);
+ assert_equals(skew.ay, ay);
+ assert_true(skew.is2D);
+ }, 'CSSSkew can be constructed from ' + axDesc + ' and ' + ayDesc);
+ }
+}
+
+for (const attr of ['ax', 'ay']) {
+ for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skew = new CSSSkew(CSS.deg(0), CSS.deg(0));
+ skew[attr] = value;
+ assert_style_value_equals(skew[attr], value);
+ }, 'CSSSkew.' + attr + ' can be updated to ' + desc);
+ }
+}
+
+test(() => {
+ let skew = new CSSSkew(CSS.deg(0), CSS.deg(0));
+ skew.is2D = false;
+ assert_true(skew.is2D);
+}, 'Modifying CSSSkew.is2D is a no-op');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html
new file mode 100644
index 0000000000..59d7c064ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewX.tentative.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkewX tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewx">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSSkewX(value));
+ }, 'Constructing a CSSSkewX with ' + desc + ' throws a TypeError');
+}
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ assert_throws_js(TypeError, () => skewX.ax = value);
+ assert_style_value_equals(skewX.ax, CSS.deg(0));
+ }, 'Updating CSSSkewX.ax with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ax, desc: axDesc} of gValidTestCases) {
+ test(() => {
+ const skewX = new CSSSkewX(ax);
+ assert_equals(skewX.ax, ax);
+ assert_true(skewX.is2D);
+ }, 'CSSSkewX can be constructed from ' + axDesc);
+}
+
+for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ skewX.ax = value;
+ assert_style_value_equals(skewX.ax, value);
+ }, 'CSSSkew.ax can be updated to ' + desc);
+}
+
+test(() => {
+ let skewX = new CSSSkewX(CSS.deg(0));
+ skewX.is2D = false;
+ assert_true(skewX.is2D);
+}, 'Modifying skewX.is2D is a no-op');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
new file mode 100644
index 0000000000..6a6fe55a97
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssSkewY.tentative.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSSkewY tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssskewy">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { value: 'auto', desc: 'a keyword'},
+ { value: 3.14, desc: 'a double'},
+ { value: 0, desc: 'a unitless zero'},
+ { value: '10deg', desc: 'a string angle'},
+ { value: CSS.number(10), desc: 'a number CSSUnitValue'},
+ { value: CSS.s(10), desc: 'a time dimension CSSUnitValue'},
+ { value: new CSSMathSum(CSS.px(1)), desc: 'a CSSMathValue of length type' },
+];
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSSkewY(value));
+ }, 'Constructing a CSSSkewY with ' + desc + ' throws a TypeError');
+}
+
+for (const {value, desc} of gInvalidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ assert_throws_js(TypeError, () => skewY.ay = value);
+ assert_style_value_equals(skewY.ay, CSS.deg(0));
+ }, 'Updating CSSSkewY.ay with ' + desc + ' throws a TypeError');
+}
+
+const gValidTestCases = [
+ { value: CSS.deg(-3.14), desc: 'an angle CSSUnitValue' },
+ { value: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue of angle type' },
+];
+
+for (const {value: ay, desc: ayDesc} of gValidTestCases) {
+ test(() => {
+ const skewY = new CSSSkewY(ay);
+ assert_equals(skewY.ay, ay);
+ assert_true(skewY.is2D);
+ }, 'CSSSkewY can be constructed from ' + ayDesc);
+}
+
+for (const {value, desc} of gValidTestCases) {
+ test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.ay = value;
+ assert_style_value_equals(skewY.ay, value);
+ }, 'CSSSkewY.ay can be updated to ' + desc);
+}
+
+test(() => {
+ let skewY = new CSSSkewY(CSS.deg(0));
+ skewY.is2D = false;
+ assert_true(skewY.is2D);
+}, 'Modifying skewY.is2D is a no-op');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-2d-flattening.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-2d-flattening.html
new file mode 100644
index 0000000000..33fd7009cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-2d-flattening.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformComponent 2d flattening</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformComponent.toMatrix handles 2d flattening" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gEpsilon = 1e-6;
+
+test(() => {
+ const translate = new CSSTranslate(CSS.px(1), CSS.px(1), CSS.px(1));
+ translate.is2D = true;
+ const expectedTranslate = new DOMMatrix();
+ expectedTranslate.translateSelf(1, 1);
+ assert_matrix_approx_equals(translate.toMatrix(), expectedTranslate, gEpsilon);
+}, 'CSSTranslate.toMatrix() flattens when told it is 2d');
+
+test(() => {
+ const rotate = new CSSRotate(1, 2, 3, CSS.deg(90));
+ rotate.is2D = true;
+ const expectedRotate = new DOMMatrix();
+ expectedRotate.rotateSelf(90);
+ assert_matrix_approx_equals(rotate.toMatrix(), expectedRotate, gEpsilon);
+}, 'CSSRotate.toMatrix() flattens when told it is 2d');
+
+test(() => {
+ const scale = new CSSScale(2, 3, 2);
+ scale.is2D = true;
+ const expectedScale = new DOMMatrix();
+ expectedScale.scaleSelf(2, 3);
+ assert_matrix_approx_equals(scale.toMatrix(), expectedScale, gEpsilon);
+}, 'CSSScale.toMatrix() flattens when told it is 2d');
+
+test(() => {
+ const transformMatrix = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ const matrixComponent = new CSSMatrixComponent(transformMatrix);
+ matrixComponent.is2D = true;
+ const expectedMatrix = new DOMMatrix();
+ expectedMatrix.multiplySelf(new DOMMatrixReadOnly([1, 2, 5, 6, 13, 14]));
+ assert_matrix_approx_equals(matrixComponent.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSMatrixComponent.toMatrix() flattens when told it is 2d');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html
new file mode 100644
index 0000000000..432943b6da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix-relative-units.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformComponent.toMatrix with Relative Units</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformComponent.toMatrix throws when given relative units" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ return new CSSTranslate(
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(1, 'em')
+ ).toMatrix();
+ });
+}, 'CSSTranslate.toMatrix() containing relative units throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ return new CSSPerspective(new CSSUnitValue(1, 'em')).toMatrix();
+ });
+}, 'CSSPerspective.toMatrix() containing relative units throws TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html
new file mode 100644
index 0000000000..d3e510296b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformComponent-toMatrix.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformComponent.toMatrix tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformComponent.toMatrix for each type of component" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gEpsilon = 1e-6;
+
+test(() => {
+ const component = new CSSTranslate(
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(2, 'px'),
+ new CSSUnitValue(3, 'px')
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).translate(1, 2, 3);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, 1e-8);
+}, 'CSSTranslate.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSRotate(
+ new CSSUnitValue(1, 'number'),
+ new CSSUnitValue(2, 'number'),
+ new CSSUnitValue(3, 'number'),
+ new CSSUnitValue(90, 'deg')
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).rotateAxisAngle(1, 2, 3, 90);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSRotate.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSScale(1, 2, 3);
+ const expectedMatrix = (new DOMMatrixReadOnly()).scale(1, 2, 3);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSScale.toMatrix() returns correct matrix');
+
+test(() => {
+ const alpha = 10, beta = 20;
+ const component = new CSSSkew(
+ new CSSUnitValue(alpha, 'rad'),
+ new CSSUnitValue(beta, 'rad')
+ );
+ const expectedMatrix = new DOMMatrixReadOnly(
+ [1, Math.tan(beta), 0, 0, Math.tan(alpha), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkew.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSSkewX(
+ new CSSUnitValue(10, 'deg'),
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).skewX(10);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkewX.toMatrix() returns correct matrix');
+
+test(() => {
+ const component = new CSSSkewY(
+ new CSSUnitValue(10, 'deg'),
+ );
+ const expectedMatrix = (new DOMMatrixReadOnly()).skewY(10);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSSkewY.toMatrix() returns correct matrix');
+
+test(() => {
+ const length = 10;
+ const component = new CSSPerspective(new CSSUnitValue(length, 'px'));
+ const expectedMatrix = new DOMMatrixReadOnly(
+ [1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, -1/length,
+ 0, 0, 0, 1]);
+ assert_matrix_approx_equals(component.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSPerspective.toMatrix() returns correct matrix');
+
+test(() => {
+ const matrix = new DOMMatrixReadOnly(
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ const component = new CSSMatrixComponent(matrix);
+ assert_matrix_approx_equals(component.toMatrix(), matrix, gEpsilon);
+}, 'CSSMatrixComponent.toMatrix() returns correct matrix');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html
new file mode 100644
index 0000000000..c0e0bbc270
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue-toMatrix.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformValue.toMatrix</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-csstransformcomponent-tomatrix">
+<meta name="assert" content="Test CSSTransformValue.toMatrix multiplies component matrices" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gEpsilon = 1e-6;
+
+test(() => {
+ const transformMatrix = new DOMMatrixReadOnly([1, 1, 1, 1, 1, 1]);
+ const transformArray = [
+ new CSSScale(2, 2),
+ new CSSMatrixComponent(transformMatrix),
+ new CSSScale(5, 6)
+ ];
+
+ let expectedMatrix = new DOMMatrix();
+ expectedMatrix.scaleSelf(2, 2);
+ expectedMatrix.multiplySelf(transformMatrix);
+ expectedMatrix.scaleSelf(5, 6);
+
+ const transform = new CSSTransformValue(transformArray);
+ assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSTransformValue.toMatrix() multiplies its component matrices');
+
+test(() => {
+ const transformMatrix = new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
+ let transformArray = [
+ new CSSTranslate(CSS.px(1), CSS.px(1), CSS.px(1)),
+ new CSSRotate(1, 2, 3, CSS.deg(90)),
+ new CSSScale(2, 3, 2),
+ new CSSMatrixComponent(transformMatrix),
+ ];
+
+ transformArray.forEach(transform => transform.is2D = true);
+
+ let expectedMatrix = new DOMMatrix();
+ expectedMatrix.translateSelf(1, 1);
+ expectedMatrix.rotateSelf(90);
+ expectedMatrix.scaleSelf(2, 3);
+ expectedMatrix.multiplySelf(new DOMMatrixReadOnly([1, 2, 5, 6, 13, 14]));
+
+ const transform = new CSSTransformValue(transformArray);
+ assert_matrix_approx_equals(transform.toMatrix(), expectedMatrix, gEpsilon);
+}, 'CSSTransformValue.toMatrix() respects is2D changes in its components');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html
new file mode 100644
index 0000000000..4c1a4861fe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTransformValue.tentative.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTransformValue tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#transformvalue-objects">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script src="../resources/comparisons.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSTransformValue());
+ assert_throws_js(TypeError, () => new CSSTransformValue([]));
+}, 'Constructing a CSSTransformValue with no components throws TypeError');
+
+test(() => {
+ const values = [
+ new CSSScale(1, 1),
+ new CSSTranslate(CSS.px(1), CSS.px(1)),
+ new CSSRotate(CSS.deg(90))
+ ];
+
+ const transform = new CSSTransformValue(values);
+ assert_style_value_array_equals(transform, values);
+}, 'CSSTransformValue can be constructed with multiple transforms');
+
+test(() => {
+ const values = [
+ new CSSScale(1, 1),
+ new CSSTranslate(CSS.px(1), CSS.px(1)),
+ new CSSRotate(CSS.deg(90))
+ ];
+
+ const transform = new CSSTransformValue(values);
+ assert_style_value_array_equals(transform, values);
+
+ values.pop();
+ var new_value = new CSSRotate(CSS.deg(45));
+ values[2] = new_value;
+ transform[2] = new_value;
+ assert_style_value_array_equals(transform, values);
+}, 'CSSTransformValue.set correctly sets the CSSTransformComponent at the given index');
+
+test(() => {
+ const values = [
+ new CSSScale(1, 1),
+ new CSSTranslate(CSS.px(1), CSS.px(1)),
+ new CSSRotate(CSS.deg(90))
+ ];
+
+ const transform = new CSSTransformValue(values);
+ assert_style_value_array_equals(transform, values);
+
+ var new_value = new CSSRotate(CSS.deg(45));
+ values[3] = new_value;
+ transform[3] = new_value;
+ assert_style_value_array_equals(transform, values);
+}, 'Setting a component in CSSTransformValue correctly appends the CSSTransformComponent if index specified is greater than length');
+
+test(() => {
+ const transform = new CSSTransformValue([
+ new CSSScale(1, 1),
+ new CSSTranslate(CSS.px(1), CSS.px(1), CSS.px(1)),
+ new CSSScale(1, 1)
+ ]);
+ assert_equals(transform.is2D, false);
+}, 'CSSTransformValue.is2D is false when given mix of 2D and 3D transforms');
+
+test(() => {
+ const transform = new CSSTransformValue([
+ new CSSScale(1, 1),
+ new CSSTranslate(CSS.px(1), CSS.px(1)),
+ new CSSScale(1, 1)
+ ]);
+ assert_equals(transform.is2D, true);
+}, 'CSSTransformValue.is2D is true when given only 2D transforms');
+
+test(() => {
+ let transform = new CSSTransformValue([new CSSScale(1, 2)]);
+ assert_throws_js(TypeError, () => transform.is2D = false);
+ assert_equals(transform.is2D, true);
+}, 'CSSTransformValue.is2D is readonly');
+
+test(() => {
+ const transformArray = [
+ new CSSScale(2, 2),
+ new CSSMatrixComponent(new DOMMatrixReadOnly([1, 1, 1, 1, 1, 1])),
+ new CSSScale(5, 6)
+ ];
+
+ const transformValue = new CSSTransformValue(transformArray);
+
+ const newTransformArray = [...transformValue];
+ assert_style_value_array_equals([...transformValue], transformArray);
+}, 'Can iterate through CSSTransformValue components');
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTranslate.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTranslate.tentative.html
new file mode 100644
index 0000000000..0554351db3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssTranslate.tentative.html
@@ -0,0 +1,110 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSTranslate tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#csstranslate">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gInvalidCoordTestCases = [
+ { coord: CSS.deg(1), desc: 'a CSSUnitValue with type other than length or percent'},
+ { coord: new CSSMathSum(CSS.deg(1)), desc: 'a CSSMathValue that doesn\'t match <length-percentage>'},
+];
+
+for (const {coord, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ assert_throws_js(TypeError, () => new CSSTranslate(coord, CSS.px(0), CSS.px(0)));
+ assert_throws_js(TypeError, () => new CSSTranslate(CSS.px(0), coord, CSS.px(0)));
+ assert_throws_js(TypeError, () => new CSSTranslate(CSS.px(0), CSS.px(0), coord));
+ }, 'Constructing a CSSTranslate with ' + desc + ' for the coordinates throws a TypeError');
+}
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSTranslate(CSS.px(0), CSS.px(0), CSS.percent(0)));
+}, 'Constructing a CSSTranslate with a percent for the Z coordinate throws a TypeError');
+
+for (const attr of ['x', 'y', 'z']) {
+ for (const {value, desc} of gInvalidCoordTestCases) {
+ test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ assert_throws_js(TypeError, () => result[attr] = value);
+ assert_style_value_equals(result[attr], CSS.px(0));
+ }, 'Updating CSSTranslate.' + attr + ' to ' + desc + ' throws a TypeError');
+ }
+}
+
+test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ assert_throws_js(TypeError, () => result.z = CSS.percent(0));
+ assert_style_value_equals(result.z, CSS.px(0));
+}, 'Updating CSSTranslate.z to a percent throws a TypeError');
+
+test(() => {
+ const result = new CSSTranslate(CSS.px(-3.14), CSS.percent(3.14));
+ assert_style_value_equals(result.x, CSS.px(-3.14));
+ assert_style_value_equals(result.y, CSS.percent(3.14));
+ assert_style_value_equals(result.z, CSS.px(0));
+ assert_true(result.is2D);
+}, 'CSSTranslate can be constructed from two length or percent coordinates');
+
+test(() => {
+ const result = new CSSTranslate(CSS.px(-3.14), CSS.percent(3.14), CSS.px(10));
+ assert_style_value_equals(result.x, CSS.px(-3.14));
+ assert_style_value_equals(result.y, CSS.percent(3.14));
+ assert_style_value_equals(result.z, CSS.px(10));
+ assert_false(result.is2D);
+}, 'CSSTranslate can be constructed from three length or percent coordinates');
+
+test(() => {
+ const result = new CSSTranslate(new CSSMathSum(CSS.px(-3.14)), new CSSMathSum(CSS.percent(3.14)));
+ assert_style_value_equals(result.x, new CSSMathSum(CSS.px(-3.14)));
+ assert_style_value_equals(result.y, new CSSMathSum(CSS.percent(3.14)));
+ assert_style_value_equals(result.z, CSS.px(0));
+ assert_true(result.is2D);
+}, 'CSSTranslate can be constructed from CSSMathValues');
+
+for (const attr of ['x', 'y']) {
+ test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ result[attr] = CSS.px(3.14);
+ assert_style_value_equals(result[attr], CSS.px(3.14));
+ }, 'CSSTranslate.' + attr + ' can be updated to a length');
+
+ test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ result[attr] = CSS.percent(3.14);
+ assert_style_value_equals(result[attr], CSS.percent(3.14));
+ }, 'CSSTranslate.' + attr + ' can be updated to a percent');
+
+ test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ result[attr] = new CSSMathSum(CSS.px(3.14));
+ assert_style_value_equals(result[attr], new CSSMathSum(CSS.px(3.14)));
+ result[attr] = new CSSMathSum(CSS.percent(3.14));
+ assert_style_value_equals(result[attr], new CSSMathSum(CSS.percent(3.14)));
+ }, 'CSSTranslate.' + attr + ' can be updated to a CSSMathValue');
+}
+
+test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ result.z = CSS.px(3.14);
+ assert_style_value_equals(result.z, CSS.px(3.14));
+}, 'CSSTranslate.z can be updated to a length');
+
+test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0), CSS.px(0));
+ result.z = new CSSMathSum(CSS.px(3.14));
+ assert_style_value_equals(result.z, new CSSMathSum(CSS.px(3.14)));
+}, 'CSSTranslate.z can be updated to a CSSMathValue');
+
+test(() => {
+ let result = new CSSTranslate(CSS.px(0), CSS.px(0));
+ result.is2D = true;
+ assert_true(result.is2D);
+ result.is2D = false;
+ assert_false(result.is2D);
+}, 'Modifying CSSTranslate.is2D can be updated to true or false');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-empty.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-empty.html
new file mode 100644
index 0000000000..34f77d922a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-empty.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>CSSUnparsedValue: Don't crash for empty values</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunparsedvalue-cssunparsedvalue">
+<link rel="help" href="https://crbug.com/1169941">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSUnparsedValue(['']);
+ assert_equals('', result.toString()); // Don't crash.
+}, `Don't crash when serializing empty CSSUnparsedValue`);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-indexed-getter-setter.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-indexed-getter-setter.html
new file mode 100644
index 0000000000..65a65ac0df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-indexed-getter-setter.html
@@ -0,0 +1,54 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnparsedValue Indexed Getter and Setter</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunparsedvalue-__getter__-index-index">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunparsedvalue-__setter__-index-val-val">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSUnparsedValue(['foo', 'bar']);
+ assert_equals(result[3], undefined, 'result from out of range index');
+ assert_equals(result[-1], undefined, 'result from negative index');
+}, 'Getting invalid index in CSSUnparsedValue returns undefined');
+
+test(() => {
+ let result = new CSSUnparsedValue([new CSSVariableReferenceValue('--foo')]);
+ result[0] = 'A';
+ assert_equals(result[0], 'A', 'fragment reflects new value');
+}, 'Can update fragment in CSSUnparsedValue to a String');
+
+test(() => {
+ let result = new CSSUnparsedValue(['foo']);
+ result[0] = new CSSVariableReferenceValue('--A');
+ assert_style_value_equals(result[0], new CSSVariableReferenceValue('--A'),
+ 'fragment reflects new value');
+}, 'Can update fragment in CSSUnparsedValue to a CSSVariableReference');
+
+test(() => {
+ let result = new CSSUnparsedValue([]);
+ result[0] = 'foo';
+ assert_equals(result[0], 'foo', 'new fragment is appended');
+}, 'Setting one past the last fragment in a CSSUnparsedValue to a String ' +
+ 'appends the new fragment');
+
+test(() => {
+ let result = new CSSUnparsedValue([' ']);
+ result[1] = new CSSVariableReferenceValue('--A');
+ assert_style_value_equals(result[1], new CSSVariableReferenceValue('--A'),
+ 'new fragment is appended');
+}, 'Setting one past the last fragment in a CSSUnparsedValue to a ' +
+ 'CSSVariableReferenceValue appends the new fragment');
+
+test(() => {
+ let result = new CSSUnparsedValue(['foo', 'bar']);
+ assert_throws_js(RangeError, () => result[3] = 'foo');
+ assert_equals(result[3], undefined, 'fragment does not change');
+}, 'Setting out of range index in CSSUnparsedValue throws RangeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-iterable.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-iterable.html
new file mode 100644
index 0000000000..186ba7329c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-iterable.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnparsedValue Iterable Declaration</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssunparsedvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSUnparsedValue([]);
+ assert_array_equals([...result], [], 'result of iterating');
+}, 'Iterating over an empty CSSUnparsedValue produces nothing');
+
+test(() => {
+ const args = [' ', new CSSVariableReferenceValue('--A')];
+ const result = new CSSUnparsedValue(args);
+ assert_style_value_array_equals([...result], args, 'result of iterating');
+}, 'Iterating over a CSSUnparsedValue produces all fragments');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-length.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-length.html
new file mode 100644
index 0000000000..cb2b9c9b70
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue-length.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnparsedValue.length</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunparsedvalue-length">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSUnparsedValue([]);
+ assert_equals(result.length, 0, 'length');
+}, 'Length of CSSUnparsedValue with no fragments is zero');
+
+test(() => {
+ const result = new CSSUnparsedValue([
+ ' ', new CSSVariableReferenceValue('--A')
+ ]);
+ assert_equals(result.length, 2, 'length');
+}, 'Length of CSSUnparsedValue with multiple fragments is the number of ' +
+ 'fragments');
+
+test(() => {
+ let result = new CSSUnparsedValue([' ']);
+ assert_equals(result.length, 1, 'initial length');
+
+ result[1] = new CSSVariableReferenceValue('--A');
+ assert_equals(result.length, 2, 'length after appending once');
+
+ result[2] = 'lemon';
+ assert_equals(result.length, 3, 'length after appending twice');
+}, 'Length of CSSUnparsedValue updates when fragments are appended');
+
+test(() => {
+ let result = new CSSUnparsedValue([' ']);
+ assert_equals(result.length, 1, 'initial length');
+
+ result[0] = new CSSVariableReferenceValue('--A');
+ assert_equals(result.length, 1, 'length after modification');
+
+ result[0] = 'lemon';
+ assert_equals(result.length, 1, 'length after modification');
+}, 'Length of CSSUnparsedValue does not change when fragments are modified');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
new file mode 100644
index 0000000000..db43fd7ecb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssUnparsedValue.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnparsedValue Constructor</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunparsedvalue-cssunparsedvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+const gTestArguments = [
+ {
+ description: 'no arguments',
+ fragments: [],
+ },
+ {
+ description: 'a single empty string',
+ fragments: [''],
+ },
+ {
+ description: 'a single CSSVariableReferenceValue',
+ fragments: [new CSSVariableReferenceValue('--foo')],
+ },
+ {
+ description: 'a mix of strings and CSSVariableReferenceValues',
+ fragments: [
+ 'foo',
+ 'bar',
+ new CSSVariableReferenceValue('--A'),
+ 'baz',
+ new CSSVariableReferenceValue('--B')
+ ],
+ },
+];
+
+for (const args of gTestArguments) {
+ test(() => {
+ const result = new CSSUnparsedValue(args.fragments);
+ assert_not_equals(result, null, 'a CSSUnparsedValue is created');
+ assert_style_value_array_equals(result, args.fragments,
+ 'fragments are same as given by constructor');
+ }, `CSSUnparsedValue can be constructed from ${args.description}`);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-invalid.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-invalid.html
new file mode 100644
index 0000000000..4da6a322bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-invalid.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSVariableReferenceValue Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssvariablereferencevalue">
+<meta name="assert" content="Test CSSVariableReferenceValue constructor and attributes error handling" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSVariableReferenceValue(''));
+}, 'Constructing a CSSVariableReferenceValue with an empty variable name ' +
+ 'throws a TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSVariableReferenceValue('bar'));
+}, 'Constructing a CSSVariableReferenceValue with an invalid variable name ' +
+ 'throws SyntaxError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-variable.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-variable.html
new file mode 100644
index 0000000000..51b60a8df5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue-variable.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSVariableReferenceValue.variable</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssvariablereferencevalue-variable">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ let result = new CSSVariableReferenceValue('--foo');
+ result.variable = '--bar';
+ assert_equals(result.variable, '--bar', 'variable reflects new value');
+}, 'CSSVariableReferenceValue.variable can updated to a valid custom ' +
+ 'property name');
+
+test(() => {
+ let result = new CSSVariableReferenceValue('--foo');
+ assert_throws_js(TypeError, () => result.variable = '');
+ assert_equals(result.variable, '--foo', 'variable does not change');
+}, 'Updating CSSVariableReferenceValue.variable to the empty string ' +
+ 'throws TypeError');
+
+test(() => {
+ let result = new CSSVariableReferenceValue('--foo');
+ assert_throws_js(TypeError, () => result.variable = 'bar');
+ assert_equals(result.variable, '--foo', 'variable does not change');
+}, 'Updating CSSVariableReferenceValue.variable to an invalid custom ' +
+ 'property name throws TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
new file mode 100644
index 0000000000..9899b210ad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/cssVariableReferenceValue.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSVariableReferenceValue Constructor</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssvariablereferencevalue-cssvariablereferencevalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSVariableReferenceValue('--foo');
+ assert_not_equals(result, null, 'a CSSVariableReferenceValue is created');
+ assert_equals(result.variable, '--foo',
+ 'variable is same as passed by constructor');
+ assert_equals(result.fallback, null, 'fallback');
+}, 'CSSVariableReferenceValue can be constructed with no fallback');
+
+test(() => {
+ const result = new CSSVariableReferenceValue('--foo', null);
+ assert_not_equals(result, null, 'a CSSVariableReferenceValue is created');
+ assert_equals(result.variable, '--foo',
+ 'variable is same as passed by constructor');
+ assert_equals(result.fallback, null, 'fallback');
+}, 'CSSVariableReferenceValue can be constructed with null fallback');
+
+test(() => {
+ const result = new CSSVariableReferenceValue('--foo',
+ new CSSUnparsedValue(['lemon']));
+ assert_not_equals(result, null, 'a CSSVariableReferenceValue is created');
+ assert_equals(result.variable, '--foo',
+ 'variable is same as passed by constructor');
+ assert_not_equals(result.fallback, null, 'fallback');
+ assert_style_value_equals(result.fallback, new CSSUnparsedValue(['lemon']),
+ 'fallback is same as passed by constructor');
+}, 'CSSVariableReferenceValue can be constructed with valid fallback');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/add-two-types.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/add-two-types.tentative.html
new file mode 100644
index 0000000000..3571d542f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/add-two-types.tentative.html
@@ -0,0 +1,60 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Adding Two Numeric Types</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#add-two-types">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ const a = new CSSUnitValue(0, 'number');
+ const b = new CSSUnitValue(0, 'px');
+ assert_throws_js(TypeError, () => new CSSMathSum(a, b));
+}, 'Adding two types with different non-null percent hints throws TypeError');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSUnitValue(0, 'px');
+ const result = new CSSMathSum(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1 });
+}, 'Adding two types with the same nonzero values returns same type');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'number');
+ const b = new CSSUnitValue(0, 'number');
+ const result = new CSSMathSum(a, b);
+ assert_numeric_type_equals(result.type(), { });
+}, 'Adding two types with empty maps with returns empty map');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSUnitValue(0, 'percent');
+ const result = new CSSMathSum(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1, percentHint: 'length' });
+}, 'Adding a type with percent returns type with percent hint');
+
+test(() => {
+ const a = new CSSMathProduct(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'px'));
+ const b = new CSSUnitValue(0, 'percent');
+ assert_throws_js(TypeError, () => new CSSMathSum(a, b));
+}, 'Adding a type with percent 2 returns type with percent hint throws TypeError');
+
+test(() => {
+ const a = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const b = new CSSUnitValue(0, 'px');
+ const result = new CSSMathSum(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1, percentHint: 'length' });
+}, 'Adding a type with a percent hint returns a type with the percent hint');
+
+test(() => {
+ const a = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const b = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const result = new CSSMathSum(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1, percentHint: 'length' });
+}, 'Adding two types with the same percent hint returns a type with the percent hint');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html
new file mode 100644
index 0000000000..46068cc708
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/arithmetic.tentative.html
@@ -0,0 +1,160 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Arithmetic operations on CSSNumericValue tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-add">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-sub">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-mul">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-div">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-min">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-max">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gArithmeticOps = [
+ { methodName: 'add', mathType: CSSMathSum },
+ { methodName: 'sub', mathType: CSSMathSum },
+ { methodName: 'mul', mathType: CSSMathProduct },
+ { methodName: 'div', mathType: CSSMathProduct },
+ { methodName: 'min', mathType: CSSMathMin },
+ { methodName: 'max', mathType: CSSMathMax },
+];
+
+for (const {methodName, mathType} of gArithmeticOps) {
+ test(() => {
+ const result = CSS.number(1)[methodName]();
+ assert_style_value_equals(result, CSS.number(1));
+ }, 'Calling CSSUnitValue.' + methodName + ' with no arguments returns itself');
+
+ test(() => {
+ // Use an arithmetic expression that can't be simplified to a CSSUnitValue
+ const mathValue = new mathType(CSS.px(1), CSS.percent(1));
+ const result = mathValue[methodName]();
+ assert_style_value_equals(result, mathValue);
+ }, 'Calling CSSMathValue.' + methodName + ' with no arguments returns itself');
+
+ test(() => {
+ const result = CSS.px(1)[methodName](CSS.percent(1));
+ assert_equals(result.constructor.name, mathType.name);
+ }, 'Calling CSSNumericValue.' + methodName + ' with a single CSSNumericValue returns correct type');
+
+ test(() => {
+ const result = new mathType(CSS.px(1))[methodName](CSS.percent(1));
+ assert_equals(result.constructor.name, mathType.name);
+ }, 'Calling CSSMathValue.' + methodName + ' with a single CSSNumericValue returns correct type');
+
+ test(() => {
+ const result = CSS.percent(1)[methodName](CSS.px(1), CSS.px(2), CSS.px(3));
+ assert_equals(result.constructor.name, mathType.name);
+ }, 'Calling CSSNumericValue.' + methodName + ' with more than one number CSSNumericValues returns correct type');
+
+ test(() => {
+ const result = CSS.number(1)[methodName](1, CSS.number(2), 3);
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ }, 'Calling CSSNumericValue.' + methodName + ' can take numberish values');
+
+ test(() => {
+ const result = new mathType(CSS.number(1))[methodName](CSS.number(2), CSS.number(3));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.unit, 'number');
+ }, 'Calling ' + mathType.name + '.' + methodName + ' with number CSSUnitValues simplifies to a CSSUnitValue');
+
+ test(() => {
+ assert_throws_js(TypeError, () => new CSS.px(0)[methodName](CSS.px(1), CSS.s(2)));
+ }, 'Calling CSSNumericValue.' + methodName + ' with incompatible types throws TypeError');
+}
+
+test(() => {
+ const result = CSS.px(10).add(CSS.px(5), CSS.px(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 17);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.add with CSSUnitValues with same unit simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.px(10).sub(CSS.px(5), CSS.px(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 3);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.sub with CSSUnitValues with same unit simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(10).mul(CSS.number(5), CSS.number(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 100);
+ assert_equals(result.unit, 'number');
+}, 'Calling CSSUnitValue.mul with all numbers simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(10).mul(CSS.px(5), CSS.number(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 100);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.mul with only one non-number simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(10).mul(CSS.px(5), CSS.px(2));
+ assert_equals(result.constructor.name, CSSMathProduct.name);
+}, 'Calling CSSUnitValue.mul with more than one non-number does not simplify to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(10).div(CSS.number(5), CSS.number(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 1);
+ assert_equals(result.unit, 'number');
+}, 'Calling CSSUnitValue.div with all numbers simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.px(10).div(CSS.number(5), CSS.number(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 1);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.div on a non-number value simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(10).div(CSS.px(5), CSS.number(2));
+ assert_equals(result.constructor.name, CSSMathProduct.name);
+}, 'Calling CSSUnitValue.div with a non-number value in the arguments does not simplify to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.px(10).min(CSS.px(5), CSS.px(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 2);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.min with CSSUnitValues with same unit simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.px(10).max(CSS.px(5), CSS.px(2));
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 10);
+ assert_equals(result.unit, 'px');
+}, 'Calling CSSUnitValue.max with CSSUnitValues with same unit simplifies to a CSSUnitValue');
+
+test(() => {
+ const result = CSS.number(1).sub(CSS.number(1), new CSSMathNegate(1), new CSSMathSum(1));
+ assert_style_value_equals(result,
+ new CSSMathSum(CSS.number(1), CSS.number(-1), CSS.number(1), new CSSMathNegate(new CSSMathSum(1))));
+}, 'Calling CSSNumericValue.sub negates all argument values');
+
+test(() => {
+ const result = CSS.number(2).div(CSS.number(2), CSS.px(2), new CSSMathInvert(2), new CSSMathSum(2));
+ assert_style_value_equals(result,
+ new CSSMathProduct(CSS.number(2), CSS.number(0.5), new CSSMathInvert(CSS.px(2)), CSS.number(2), new CSSMathInvert(new CSSMathSum(2))));
+}, 'Calling CSSNumericValue.div inverts all argument values');
+
+test(() => {
+ assert_throws_js(RangeError, () => CSS.number(2).div(CSS.number(0)));
+ assert_throws_js(RangeError, () => CSS.number(3).div(CSS.px(10) ,CSS.number(0)));
+ assert_throws_js(RangeError, () => CSS.number(2).div(CSS.number(0), CSS.number(0)));
+}, 'Can not divide with CSSUnitValue which has zero value and number type');
+
+for (const methodName of ["add", "sub", "max", "min"]) {
+ test(() => {
+ assert_throws_js(TypeError, () => CSS.number(3)[methodName](CSS.px(10) ,CSS.number(0)));
+ assert_throws_js(TypeError, () => CSS.px(2)[methodName](CSS.deg(10)));
+ }, 'CSSNumericValue.' + methodName + ' should throw TypeError when the types are different.');
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/create-a-type.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/create-a-type.tentative.html
new file mode 100644
index 0000000000..bad9eba8af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/create-a-type.tentative.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Creating Type From A Unit</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#create-a-type">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ const value = new CSSUnitValue(0, 'number');
+ assert_numeric_type_equals(value.type(), {});
+}, 'Creating a type from "number" returns {}');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'percent');
+ assert_numeric_type_equals(value.type(), { percent: 1 });
+}, 'Creating a type from "percent" returns { percent: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'px');
+ assert_numeric_type_equals(value.type(), { length: 1 });
+}, 'Creating a type from <length> returns { length: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'deg');
+ assert_numeric_type_equals(value.type(), { angle: 1 });
+}, 'Creating a type from <angle> returns { angle: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 's');
+ assert_numeric_type_equals(value.type(), { time: 1 });
+}, 'Creating a type from <time> returns { time: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'Hz');
+ assert_numeric_type_equals(value.type(), { frequency: 1 });
+}, 'Creating a type from <frequency> returns { frequency: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'dpi');
+ assert_numeric_type_equals(value.type(), { resolution: 1 });
+}, 'Creating a type from <resolution> returns { resolution: 1 }');
+
+test(() => {
+ const value = new CSSUnitValue(0, 'fr');
+ assert_numeric_type_equals(value.type(), { flex: 1 });
+}, 'Creating a type from <flex> returns { flex: 1 }');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathInvert-type.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathInvert-type.html
new file mode 100644
index 0000000000..61814e34e1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathInvert-type.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSMathInvert.type</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#type-of-a-cssmathvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSMathInvert(new CSSUnitValue(0, 'number'));
+ assert_numeric_type_equals(result.type(), { });
+}, 'Inverting a type with empty map returns the empty map');
+
+test(() => {
+ const x = new CSSMathProduct(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 's'));
+ const result = new CSSMathInvert(x);
+ assert_numeric_type_equals(result.type(), { length: -1, time: -1 });
+}, 'Inverting a type negates all its exponents');
+
+test(() => {
+ const x = new CSSUnitValue(0, 'px');
+ const result = new CSSMathInvert(new CSSMathInvert(x));
+ assert_numeric_type_equals(result.type(), { length: 1 });
+}, 'Inverting an inverted type returns the original type');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathNegate-type.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathNegate-type.html
new file mode 100644
index 0000000000..f1fc73d140
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathNegate-type.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSMathNegate.type</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#type-of-a-cssmathvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSMathNegate(new CSSUnitValue(0, 'number'));
+ assert_numeric_type_equals(result.type(), { });
+}, 'Negating a type with empty map returns the empty map');
+
+test(() => {
+ const result = new CSSMathNegate(new CSSUnitValue(0, 'px'));
+ assert_numeric_type_equals(result.type(), { length: 1 });
+}, 'Negating a type returns the same type');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html
new file mode 100644
index 0000000000..26f6bba3a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssMathValue.tentative.html
@@ -0,0 +1,80 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSMathValue subclass tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#complex-numeric">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+const gVariadicMathValueSubclasses = [
+ { subclass: CSSMathSum, operator: 'sum' },
+ { subclass: CSSMathProduct, operator: 'product' },
+ { subclass: CSSMathMin, operator: 'min' },
+ { subclass: CSSMathMax, operator: 'max' },
+];
+
+for (const {subclass, operator} of gVariadicMathValueSubclasses) {
+ test(() => {
+ assert_throws_dom("SyntaxError", () => new subclass());
+ }, 'Constructing a ' + subclass.name + ' with no arguments throws a SyntaxError');
+
+ test(() => {
+ const result = new subclass(CSS.number(0));
+ assert_equals(result.operator, operator);
+ assert_style_value_array_equals(result.values, [CSS.number(0)]);
+ }, subclass.name + ' can be constructed from a single number CSSUnitValue');
+
+ test(() => {
+ const args = [CSS.number(1), CSS.number(2), CSS.number(3), CSS.number(4), CSS.number(5)]
+ const result = new subclass(...args);
+ assert_equals(result.operator, operator);
+ assert_style_value_array_equals(result.values, args);
+ }, subclass.name + ' can be constructed from more than one number CSSUnitValue');
+
+ test(() => {
+ let result = new subclass(CSS.number(1), CSS.number(2));
+ assert_throws_js(TypeError, () => result.operator = 'foo');
+ }, subclass.name + '.operator is readonly');
+}
+
+const gUnaryMathValueSubclasses = [
+ { subclass: CSSMathNegate, operator: 'negate' },
+ { subclass: CSSMathInvert, operator: 'invert' },
+]
+
+for (const {subclass, operator} of gUnaryMathValueSubclasses) {
+ test(() => {
+ const result1 = new subclass(CSS.number(0));
+ assert_equals(result1.operator, operator);
+ assert_style_value_equals(result1.value, CSS.number(0));
+
+ const result2 = new subclass(0);
+ assert_equals(result2.operator, operator);
+ assert_style_value_equals(result2.value, CSS.number(0));
+ }, subclass.name + ' can be constructed from a single numberish value');
+
+ test(() => {
+ let result = new subclass(CSS.number(1));
+ assert_throws_js(TypeError, () => result.operator = 'foo');
+ }, subclass.name + '.operator is readonly');
+}
+
+// CSSMathClamp test
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathClamp());
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.number(1)));
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.number(1), CSS.number(2)));
+}, 'Constructing a ' + CSSMathClamp.name + ' with less than 3 arguments throws a SyntaxError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.number(1), CSS.px(2), CSS.number(3)));
+}, 'Constructing a ' + CSSMathClamp.name + ' with different unit arguments throws a SyntaxError');
+
+test(() => {
+ let result = new CSSMathClamp(CSS.number(1), CSS.number(2), CSS.number(3));
+ assert_throws_js(TypeError, () => result.operator = 'foo');
+}, CSSMathClamp.name + '.operator is readonly');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-value.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-value.html
new file mode 100644
index 0000000000..4dff735e97
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue-value.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnitValue.value</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssunitvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ const result = new CSSUnitValue(-3.14, 'px');
+ result.value = 3.14;
+ assert_equals(result.value, 3.14, 'value reflects new value');
+ assert_equals(result.unit, 'px', 'unit does not change');
+}, 'CSSUnitValue.value can be updated to a different value');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.html
new file mode 100644
index 0000000000..b44c67129f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssUnitValue.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSSUnitValue Constructor</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssunitvalue-cssunitvalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSUnitValue(0, 'lemon'));
+}, 'Constructing CSSUnitValue with an unknown unit throws a TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSUnitValue(0, ''));
+}, 'Constructing CSSUnitValue with a empty string unit throws a TypeError');
+
+for (const unit of gValidUnits) {
+ test(() => {
+ const result = new CSSUnitValue(-3.14, unit);
+ assert_not_equals(result, null, 'a CSSUnitValue is created');
+ assert_equals(result.value, -3.14,
+ 'value is same as given by constructor');
+ assert_equals(result.unit, unit.toLowerCase(),
+ 'unit is same as given by constructor');
+ }, 'CSSUnitValue can be constructed with ' + unit);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssnumericvalue-multiply-two-types.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssnumericvalue-multiply-two-types.tentative.html
new file mode 100644
index 0000000000..e09c57e641
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/cssnumericvalue-multiply-two-types.tentative.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Multiplying Two Numeric Types</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-multiply-two-types">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(() => {
+ const a = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const b = new CSSMathSum(new CSSUnitValue(0, 's'), new CSSUnitValue(0, 'percent'));
+ assert_throws_js(TypeError, () => new CSSMathProduct(a, b));
+}, 'Multiplying two types with different non-null percent hints throws TypeError');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSUnitValue(0, 'px');
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 2 });
+}, 'Multiplying two types with same base types adds exponents');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSUnitValue(0, 's');
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1, time: 1 });
+}, 'Multiplying two types with different base types adds exponents');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSMathInvert(new CSSUnitValue(0, 's'));
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1, time: -1 });
+}, 'Multiplying two types respects the sign of the exponents');
+
+test(() => {
+ const a = new CSSUnitValue(0, 'px');
+ const b = new CSSUnitValue(0, 'number');
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 1 });
+}, 'Multiplying a type with no exponents is a no-op');
+
+test(() => {
+ const a = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const b = new CSSUnitValue(0, 'px');
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 2, percentHint: 'length' });
+}, 'Multiplying a type with percent hint applies the percent hint');
+
+test(() => {
+ const a = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const b = new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'percent'));
+ const result = new CSSMathProduct(a, b);
+ assert_numeric_type_equals(result.type(), { length: 2, percentHint: 'length' });
+}, 'Multiplying two types with same percent hint applies the percent hint');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html
new file mode 100644
index 0000000000..dc1e7959f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/equals.tentative.html
@@ -0,0 +1,74 @@
+<meta charset="utf-8">
+<title>CSSNumericValue.equals tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-equals">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_true(CSS.px(1).equals(CSS.px(1)));
+}, 'Two CSSUnitValues with same value and unit are equal');
+
+test(() => {
+ assert_false(CSS.px(0).equals(CSS.px(1)));
+}, 'Two CSSUnitValues with different values are not equal');
+
+test(() => {
+ assert_false(CSS.px(1).equals(CSS.number(1)));
+}, 'Two CSSUnitValues with different units are not equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathProduct(0, new CSSMathNegate(0));
+ assert_false(a.equals(b));
+}, 'Two CSSMathValues with different types are not equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathSum(0);
+ assert_false(a.equals(b));
+}, 'Two CSSMathValues with different number of values are not equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathSum(0, new CSSMathNegate(1));
+ assert_false(a.equals(b));
+}, 'Two CSSMathValues with different values are not equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathSum(0, new CSSMathNegate(0));
+ assert_true(a.equals(b));
+}, 'Two CSSMathValues with same structure are equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathSum(0, new CSSMathNegate(0));
+ const c = new CSSMathSum(0, new CSSMathNegate(0));
+ const d = new CSSMathSum(0, new CSSMathNegate(0));
+ assert_true(a.equals(b, c, d));
+}, 'Multiple CSSMathValues with same structure are equal');
+
+test(() => {
+ const a = new CSSMathSum(0, new CSSMathNegate(0));
+ const b = new CSSMathSum(0, new CSSMathNegate(0));
+ const c = new CSSMathSum(0, new CSSMathNegate(1));
+ const d = new CSSMathSum(0, new CSSMathNegate(0));
+ assert_false(a.equals(b, c, d));
+}, 'Multiple CSSMathValues with one different are not equal');
+
+test(() => {
+ const a = new CSSMathClamp(1, 2, 3);
+ const b = new CSSMathClamp(CSS.number(1), CSS.number(2), CSS.number(3));
+ assert_true(a.equals(b));
+}, 'Two CSSMathClamp with same value and unit are equal');
+
+test(() => {
+ const a = new CSSMathClamp(1, 2, 3);
+ const b = new CSSMathClamp(CSS.px(1), CSS.px(2), CSS.px(3));
+ assert_false(a.equals(b));
+}, 'Two CSSMathClamp with different units are not equal');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html
new file mode 100644
index 0000000000..51b282b6ea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/numeric-factory.tentative.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS numeric factory function tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#numeric-factory">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+for (const unit of gValidUnits) {
+ test(() => {
+ const result = CSS[unit](12.3);
+ assert_not_equals(result, null);
+ assert_equals(result.constructor.name, CSSUnitValue.name);
+ assert_equals(result.value, 12.3);
+ assert_equals(result.unit, unit.toLowerCase());
+ }, 'CSS.' + unit + ' returns a CSSUnitValue with correct value and unit');
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html
new file mode 100644
index 0000000000..a453ef0488
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/parse.tentative.html
@@ -0,0 +1,58 @@
+<meta charset="utf-8">
+<title>CSSNumericValue.parse tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-parse">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSSNumericValue.parse('%#('));
+}, 'Parsing an invalid string throws SyntaxError');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSSNumericValue.parse('auto'));
+}, 'Parsing a string with a non numeric token throws SyntaxError');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSSNumericValue.parse('1 2'));
+}, 'Parsing a string with left over numeric tokens throws SyntaxError');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSSNumericValue.parse('calc(calc(1px * 2s) + 3%)'));
+}, 'Parsing a calc with incompatible units throws a SyntaxError');
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSSNumericValue.parse('1xyz'));
+}, 'Parsing a <dimension-token> with invalid units throws a SyntaxError');
+
+test(() => {
+ assert_style_value_equals(new CSSUnitValue(1, 'px'), CSSNumericValue.parse(' 1px '));
+}, 'Parsing ignores surrounding spaces');
+
+test(() => {
+ const expected = new CSSMathMin(CSS.px(10), CSS.percent(10));
+ assert_style_value_equals(expected, CSSNumericValue.parse('min(10px, 10%)'));
+}, 'Parsing min() is successful');
+
+test(() => {
+ const expected = new CSSMathMax(CSS.px(10), CSS.percent(10));
+ assert_style_value_equals(expected, CSSNumericValue.parse('max(10px, 10%)'));
+}, 'Parsing max() is successful');
+
+test(() => {
+ const expected = new CSSMathClamp(CSS.px(10), CSS.percent(10), CSS.px(20));
+ assert_style_value_equals(expected, CSSNumericValue.parse('clamp(10px, 10%, 20px)'));
+}, 'Parsing clamp() is successful');
+
+test(() => {
+ const expected = new CSSMathSum(...[1, 2, 3].map(x => new CSSMathMin(CSS.number(x))));
+ assert_style_value_equals(expected.toString(), 'calc(min(1) + min(2) + min(3))');
+}, 'Parsing sum of multiple min() is successful');
+
+test(() => {
+ const expected = new CSSMathProduct(...[1, 2, 3].map(x => new CSSMathMin(CSS.number(x))));
+ assert_style_value_equals(expected.toString(), 'calc(min(1) * min(2) * min(3))');
+}, 'Parsing product of multiple min() is successful');
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/resources/testhelper.js b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/resources/testhelper.js
new file mode 100644
index 0000000000..42f2c6616d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/resources/testhelper.js
@@ -0,0 +1,9 @@
+function assert_numeric_type_equals(type, expectedType) {
+ const baseTypes = [
+ 'length', 'angle', 'time', 'frequency', 'resolution', 'flex', 'percent'
+ ];
+ for (const baseType of baseTypes) {
+ assert_equals(type[baseType], expectedType[baseType], baseType);
+ }
+ assert_equals(type.percentHint, expectedType.percentHint);
+}
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html
new file mode 100644
index 0000000000..7c40903cbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/to.tentative.html
@@ -0,0 +1,111 @@
+<meta charset="utf-8">
+<title>CSSNumericValue.to tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-to">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSS.px(1).to('lemon'));
+}, 'Converting a CSSUnitValue to an invalid unit throws SyntaxError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathMax(1, CSS.px(1)).to('number'));
+}, 'Converting a CSSNumericValue with invalid sum value throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathProduct(CSS.px(1), CSS.s(1)).to('number'));
+}, 'Converting a CSSNumericValue with sum value containing more than one value throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSS.px(1).to('number'));
+}, 'Converting a CSSUnitValue to an incompatible unit throws TypeError');
+
+test(() => {
+ for (const unit of gValidUnits) {
+ // FIXME(778495): Remove this check onec all the units are supported.
+ if (CSS[unit])
+ assert_style_value_equals(CSS[unit](1).to(unit), CSS[unit](1));
+ }
+}, 'Converting a CSSUnitValue to its own unit returns itself');
+
+// TODO(776173): cssUnitValue_toMethod.html has more comprehensive tests of converting
+// within the same base type. Merge those tests into here.
+test(() => {
+ assert_style_value_equals(CSS.cm(1).to('px'), CSS.px(37.7952755));
+}, 'Converting a CSSUnitValue to its canonical unit returns correct value');
+
+test(() => {
+ assert_style_value_equals(new CSSMathSum(CSS.px(1), CSS.px(1)).to('px'), CSS.px(2));
+ assert_style_value_equals(new CSSMathSum(CSS.px(1), CSS.px(1), CSS.px(1)).to('px'), CSS.px(3));
+}, 'Converting a CSSMathSum to a single unit adds the values');
+
+test(() => {
+ assert_style_value_equals(new CSSMathProduct(CSS.px(2), 3).to('px'), CSS.px(6));
+ assert_style_value_equals(new CSSMathProduct(-1, CSS.px(2), 3).to('px'), CSS.px(-6));
+}, 'Converting a CSSMathProduct to a single unit multiplies the values');
+
+test(() => {
+ assert_style_value_equals(new CSSMathMin(CSS.cm(1), CSS.mm(1)).to('mm'), CSS.mm(1));
+}, 'Converting a CSSMathMin to a single unit finds the min value');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathMin(CSS.px(2), CSS.s(3)).to('px'));
+ assert_throws_js(TypeError, () => new CSSMathMin(CSS.px(2), 3).to('px'));
+}, 'Converting a CSSMathMin to a single unit with different units throws a TypeError');
+
+test(() => {
+ assert_style_value_equals(new CSSMathMax(CSS.cm(1), CSS.mm(1)).to('mm'), CSS.mm(10));
+}, 'Converting a CSSMathMax to a single unit finds the max value');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathMax(CSS.px(2), CSS.s(3)).to('px'));
+ assert_throws_js(TypeError, () => new CSSMathMax(CSS.px(2), 3).to('px'));
+}, 'Converting a CSSMathMax to a single unit with different units throws a TypeError');
+
+test(() => {
+ assert_style_value_equals(new CSSMathClamp(CSS.px(90), CSS.px(100), CSS.px(110)).to("px"), CSS.px(100));
+}, 'Converting a CSSMathClamp to a single unit returns the clamped value');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.px(2), CSS.s(3), CSS.px(4)).to('px'));
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.px(2), CSS.em(3), CSS.px(4)).to('px'));
+ assert_throws_js(TypeError, () => new CSSMathClamp(CSS.px(2), 3, CSS.px(4)).to('px'));
+}, 'Converting a CSSMathClamp to a single unit with different units throws a TypeError');
+
+test(() => {
+ assert_style_value_equals(new CSSMathNegate(CSS.px(1)).to('px'), CSS.px(-1));
+}, 'Converting a CSSMathNegate to a single unit negates its value');
+
+test(() => {
+ const expr = new CSSMathProduct(CSS.px(4), new CSSMathInvert(CSS.px(2)));
+ assert_style_value_equals(expr.to('number'), CSS.number(2));
+}, 'Converting a CSSMathInvert to a single unit inverts its value and units');
+
+test(() => {
+ // max((1s * 1s * 1px * 1px) / (1s * 1px), 2000ms * 2em) / 1em - min(500ms, 1s)
+ const expr = new CSSMathSum(
+ new CSSMathProduct(
+ new CSSMathMax(
+ new CSSMathProduct(
+ new CSSMathProduct(CSS.s(1), CSS.s(1), CSS.px(1), CSS.px(1)),
+ new CSSMathInvert(new CSSMathProduct(CSS.s(1), CSS.px(1))),
+ ),
+ new CSSMathProduct(CSS.ms(2000), CSS.cm(2))
+ ),
+ new CSSMathInvert(CSS.cm(1))
+ ),
+ new CSSMathNegate(
+ new CSSMathMin(
+ CSS.ms(500),
+ CSS.s(1)
+ )
+ )
+ );
+
+ assert_style_value_equals(expr.to('ms'), CSS.ms(3500));
+}, 'Converting a complex expression to a single unit');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html
new file mode 100644
index 0000000000..1e5e1c9b76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/stylevalue-subclasses/numeric-objects/toSum.tentative.html
@@ -0,0 +1,71 @@
+<meta charset="utf-8">
+<title>CSSNumericValue.toSum tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-cssnumericvalue-tosum">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ assert_throws_dom("SyntaxError", () => CSS.px(1).toSum('px', 'lemon'));
+}, 'Converting a CSSNumericValue to a sum with invalid units throws SyntaxError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathMax(1, CSS.px(1)).toSum('number'));
+}, 'Converting a CSSNumericValue with an invalid sum value to a sum throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathProduct(CSS.px(1), CSS.px(1)).to('px'));
+}, 'Converting a CSSNumericValue with compound units to a sum throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSS.px(1).toSum('number'));
+}, 'Converting a CSSNumericValue to a sum with an incompatible unit throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => CSS.px(1).toSum('px', 's'));
+}, 'Converting a CSSNumericValue to a sum with units that are not addable throws TypeError');
+
+test(() => {
+ assert_throws_js(TypeError, () => new CSSMathSum(CSS.px(1), CSS.em(1)).toSum('px'));
+}, 'Converting a CSSNumericValue with leftover units to a sum throws TypeError');
+
+test(() => {
+ assert_style_value_equals(CSS.number(1).toSum('number'), new CSSMathSum(CSS.number(1)));
+ assert_style_value_equals(CSS.px(1).toSum('px'), new CSSMathSum(CSS.px(1)));
+}, 'Converting CSSNumericValue to a sum with its own unit returns itself');
+
+test(() => {
+ assert_style_value_equals(
+ new CSSMathSum(CSS.px(1), CSS.em(1), CSS.vw(1), CSS.rem(1)).toSum(),
+ new CSSMathSum(CSS.em(1), CSS.px(1), CSS.rem(1), CSS.vw(1))
+ );
+}, 'Converting CSSNumericValue to a sum with no arguments returns all the units in sorted order');
+
+// TODO(776173): cssUnitValue_toMethod.html has more comprehensive tests of converting
+// within the same base type. Merge those tests into here.
+test(() => {
+ assert_style_value_equals(CSS.cm(2).toSum('mm'), new CSSMathSum(CSS.mm(20)));
+}, 'Converting CSSNumericValue to a sum with a relative unit converts correctly');
+
+test(() => {
+ assert_style_value_equals(
+ CSS.px(1).toSum('em', 'px', 'vw'),
+ new CSSMathSum(CSS.em(0), CSS.px(1), CSS.vw(0))
+ );
+}, 'Converting CSSNumericValue to a sum containing extra units returns zero for those units');
+
+test(() => {
+ assert_style_value_equals(
+ new CSSMathSum(CSS.cm(1), CSS.mm(10)).toSum('cm', 'mm'),
+ new CSSMathSum(CSS.cm(2), CSS.mm(0))
+ );
+
+ assert_style_value_equals(
+ new CSSMathSum(CSS.cm(1), CSS.mm(10)).toSum('mm', 'cm'),
+ new CSSMathSum(CSS.mm(20), CSS.cm(0))
+ );
+}, 'CSSNumericValue.toSum converts greedily');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
new file mode 100644
index 0000000000..a059787ca1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/computed.tentative.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#computed-stylepropertymapreadonly-objects">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<style>#target { height: 10px; --foo: auto; }</style>
+<div style="width: 50px">
+ <div id="target" style="top: 5px; --bar: 5; width: 50%;"></div>
+</div>
+<script>
+'use strict';
+
+const target = document.getElementById('target');
+const styleMap = target.computedStyleMap();
+
+test(() => {
+ const computedStyle = [...getComputedStyle(target)].sort();
+ const properties = [...styleMap.keys()];
+
+ assert_equals(properties.length, computedStyle.length);
+ for (let i = 0; i < computedStyle.length; i++) {
+ assert_true(properties.includes(computedStyle[i]));
+ assert_not_equals(styleMap.get(computedStyle[i]), null);
+ assert_not_equals(styleMap.getAll(computedStyle[i]).length, 0);
+ assert_true(styleMap.has(computedStyle[i]));
+ }
+}, 'Computed StylePropertyMap contains every CSS property');
+
+test(() => {
+ const result = styleMap.get('height');
+ assert_style_value_equals(result, CSS.px(10));
+}, 'Computed StylePropertyMap contains CSS property declarations in style rules');
+
+test(() => {
+ const result = styleMap.get('--foo');
+ assert_style_value_equals(result, new CSSUnparsedValue(['auto']));
+}, 'Computed StylePropertyMap contains custom property declarations in style rules');
+
+test(() => {
+ const result = styleMap.get('top');
+ assert_style_value_equals(result, CSS.px(5));
+}, 'Computed StylePropertyMap contains CSS property declarations in inline styles');
+
+test(() => {
+ const result = styleMap.get('--bar');
+ assert_style_value_equals(result, new CSSUnparsedValue(['5']));
+}, 'Computed StylePropertyMap contains custom property declarations in inline rules');
+
+test(() => {
+ const computedStyle = getComputedStyle(target);
+ assert_equals(computedStyle.width, '25px');
+
+ const result = styleMap.get('width');
+ assert_style_value_equals(result, CSS.percent(50));
+}, 'Computed StylePropertyMap contains computed values and not resolved values');
+
+test(t => {
+ let target = createDivWithStyle(t, 'width: 10px');
+ const styleMap = target.attributeStyleMap;
+ assert_style_value_equals(styleMap.get('width'), CSS.px(10));
+
+ target.style.width = '20px';
+ assert_style_value_equals(styleMap.get('width'), CSS.px(20));
+}, 'Computed StylePropertyMap is live');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html
new file mode 100644
index 0000000000..3466fb21ca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-auto-min-size.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#valdef-width-auto">
+<meta name="assert" content="Tests computed StylePropertyMap.get of auto minimum sizes." />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<div style="display: flex;">
+ <div id="flex-inflow"></div>
+ <div id="flex-absolute" style="position: absolute;"></div>
+</div>
+<div style="display: grid;">
+ <div id="grid-inflow"></div>
+ <div id="grid-absolute" style="position: absolute;"></div>
+</div>
+<div id="block-inflow"></div>
+<div id="block-absolute" style="position: absolute;"></div>
+<script>
+'use strict';
+
+test(t => {
+ const targetMap = document.getElementById('flex-inflow').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An inflow flex-item computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+test(t => {
+ const targetMap = document.getElementById('flex-absolute').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An absolute flex-child computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+test(t => {
+ const targetMap = document.getElementById('grid-inflow').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An inflow grid-item computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+test(t => {
+ const targetMap = document.getElementById('grid-absolute').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An absolute grid-child computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+test(t => {
+ const targetMap = document.getElementById('block-inflow').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An inflow block computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+test(t => {
+ const targetMap = document.getElementById('block-absolute').computedStyleMap();
+ assert_style_value_equals(targetMap.get('min-width'), new CSSKeywordValue('auto'));
+ assert_style_value_equals(targetMap.get('min-height'), new CSSKeywordValue('auto'));
+}, 'An absolute block computed StylePropertyMap.get reports the auto minimum size correctly.');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-invalid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-invalid.html
new file mode 100644
index 0000000000..403c2691f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-invalid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap.get Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.get('lemon'));
+}, 'Calling StylePropertyMap.get with an unsupported property throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-position.html
new file mode 100644
index 0000000000..20546bfeee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-position.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap.get("position")</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<meta name="assert" content="Test computed StylePropertyMap.get" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'display: table-column; position: sticky');
+ assert_style_value_equals(styleMap.get('position'), new CSSKeywordValue('sticky'));
+}, 'Computed position sticky even if it does not apply');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'display: table-column; position: absolute');
+ assert_style_value_equals(styleMap.get('position'), new CSSKeywordValue('absolute'));
+}, 'Computed position absolute even if it does not apply');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-shorthand.html
new file mode 100644
index 0000000000..a940422adc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get-shorthand.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap.get with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.get('margin');
+ assert_not_equals(result, null, 'Shorthand value must not be null');
+ assert_class_string(result, 'CSSStyleValue',
+ 'Shorthand value must be a base CSSStyleValue');
+}, 'Getting an shorthand property set explicitly in computed style returns ' +
+ 'a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t);
+ const result = styleMap.get('margin');
+ assert_not_equals(result, null, 'Shorthand value must not be null');
+ assert_class_string(result, 'CSSStyleValue',
+ 'Shorthand value must be a base CSSStyleValue');
+}, 'Getting a shorthand property from initial computed style returns ' +
+ 'a base CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get.html
new file mode 100644
index 0000000000..88fe53493c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/get.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap.get</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<meta name="assert" content="Test computed StylePropertyMap.get" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--foo: auto');
+ assert_equals(styleMap.get('--Foo'), null);
+}, 'Getting a custom property not in the computed style returns null');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+}, 'Getting a valid property from computed style returns the correct entry');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_equals(styleMap.get('--foo'),
+ new CSSUnparsedValue(['auto']));
+}, 'Getting a valid custom property from computed style returns the ' +
+ 'correct entry');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t,
+ 'width: 10px; transition-duration: 1s, 2s; height: 10px;');
+ assert_style_value_equals(styleMap.get('transition-duration'),
+ new CSSUnitValue(1, 's'));
+}, 'Getting a list-valued property from computed style returns only ' +
+ 'the first value');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'height: 20px; width: 10px;');
+ assert_style_value_equals(styleMap.get('wIdTh'), new CSSUnitValue(10, 'px'));
+}, 'Computed StylePropertyMap.get is not case-sensitive');
+
+test(t => {
+ const [elem, styleMap] = createElementWithComputedStyleMap(t, 'width: 10px;');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+ elem.style.width = '20px';
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(20, 'px'));
+}, 'Computed StylePropertyMap.get reflects updates in inline style');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-disconnected-element-crash.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-disconnected-element-crash.html
new file mode 100644
index 0000000000..5292ebae1c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-disconnected-element-crash.html
@@ -0,0 +1,7 @@
+<!doctype html>
+<title>Computed StylePropertyMap.getAll with shorthand on disconnected element crash</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall">
+<p>Pass if no crash.</p>
+<script>
+ document.createElement("div").computedStyleMap().getAll("margin");
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-shorthand.html
new file mode 100644
index 0000000000..6d367c8184
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll-shorthand.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Computed StylePropertyMap.getAll with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.getAll('margin');
+ assert_not_equals(result, null, 'Result must not be null');
+ assert_equals(result.length, 1, 'Result must be a list with one item');
+ assert_class_string(result[0], 'CSSStyleValue',
+ 'Only item in result must be a base CSSStyleValue');
+}, 'StylePropertyMap.getAll() with a shorthand property set explicitly in ' +
+ 'computed style returns a list containing a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t);
+ const result = styleMap.getAll('margin');
+ assert_not_equals(result, null, 'Result must not be null');
+ assert_equals(result.length, 1, 'Result must be a list with one item');
+ assert_class_string(result[0], 'CSSStyleValue',
+ 'Only item in result must be a base CSSStyleValue');
+}, 'StylePropertyMap.getAll() with a shorthand property from initial ' +
+ 'computed style returns a list containing a base CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
new file mode 100644
index 0000000000..e6d86ac7b6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/getAll.tentative.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.getAll tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.getAll('lemon'));
+}, 'Calling StylePropertyMap.getAll with an unsupported property throws a TypeError');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--foo: auto');
+ assert_style_value_array_equals(styleMap.getAll('--Foo'), []);
+}, 'Calling StylePropertyMap.getAll with a custom property not in the property model returns an empty list');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('width'), [CSS.px(10)]);
+}, 'Calling StylePropertyMap.getAll with a valid property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'height: 20px; width: 10px');
+ assert_style_value_array_equals(styleMap.getAll('wIdTh'), [CSS.px(10)]);
+}, 'StylePropertyMap.getAll is case-insensitive');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(['auto'])]);
+}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; transition-duration: 1s, 2s; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Calling StylePropertyMap.getAll with a list-valued property returns all the values');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/has.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/has.tentative.html
new file mode 100644
index 0000000000..53924c4a48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/has.tentative.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.has tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#check-if-stylepropertymap-has-a-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createComputedStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.has('lemon'));
+}, 'Calling StylePropertyMap.has with an unsupported property throws a TypeError');
+
+const gTestCases = [
+ { property: '--Foo', expected: false, desc: 'a custom property not in the property model' },
+ { property: 'width', expected: true, desc: 'a valid property' },
+ { property: 'wIdTh', expected: true, desc: 'a valid property in mixed case' },
+ { property: 'margin', expected: true, desc: 'a valid shorthand property' },
+ { property: '--foo', expected: true, desc: 'a valid custom property' },
+ { property: 'transition-duration', expected: true, desc: 'a valid list-valued property' },
+];
+
+for (const {property, expected, desc} of gTestCases) {
+ test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; --foo: auto; transition-duration: 1s, 2s');
+ assert_equals(styleMap.has(property), expected);
+ }, 'Calling StylePropertyMap.has with ' + desc + ' returns ' + expected);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
new file mode 100644
index 0000000000..55e4353708
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/computed/iterable.tentative.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap iterable tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#the-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+function findInStyleMap(styleMap, property) {
+ const index = [...styleMap.keys()].indexOf(property);
+ if (index == -1)
+ return null;
+ return [...styleMap.values()][index];
+}
+
+// Puts normal CSS properties before vendor prefixed ones
+function comparePropertyNames(a, b) {
+ if (a.startsWith('-') == b.startsWith('-'))
+ return a < b ? -1 : 1;
+ return b.startsWith('-') ? -1 : 1;
+}
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--A: A; width: 10px; --C: C; transition-duration: 1s, 2s; color: red; --B: B;');
+ const expectedKeys = [...getComputedStyle(document.body)].sort(comparePropertyNames).concat('--A', '--B', '--C');
+ assert_array_equals([...styleMap.keys()], expectedKeys);
+}, 'StylePropertyMap iterates properties in correct order');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; transition-duration: 1s, 2s; height: 20px');
+ assert_style_value_array_equals(findInStyleMap(styleMap, 'width'), [CSS.px(10)]);
+}, 'StylePropertyMap iterator returns CSS properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, 'width: 10px; transition-duration: 1s, 2s; height: 20px');
+ assert_style_value_array_equals(findInStyleMap(styleMap, 'transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap iterator returns list-valued properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createComputedStyleMap(t, '--A: A; --C: C; color: red; --B: B;');
+ assert_style_value_array_equals(findInStyleMap(styleMap, '--A'), [new CSSUnparsedValue(['A'])]);
+ assert_style_value_array_equals(findInStyleMap(styleMap, '--B'), [new CSSUnparsedValue(['B'])]);
+ assert_style_value_array_equals(findInStyleMap(styleMap, '--C'), [new CSSUnparsedValue(['C'])]);
+}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
+
+test(t => {
+ // This is to test for https://github.com/w3c/css-houdini-drafts/issues/700
+ const styleMap = createComputedStyleMap(t, '--豈: 豈; --💩: 💩;');
+ const keys = [...styleMap.keys()];
+
+ assert_array_equals(keys.slice(-2), ['--💩', '--豈']);
+}, 'Computed StylePropertyMap sorts custom properties in increasing ' +
+ 'code-point order');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/append.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/append.tentative.html
new file mode 100644
index 0000000000..b642c0823a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/append.tentative.html
@@ -0,0 +1,74 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.append tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#append-to-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'lemon', values: ['ade'], desc: 'an unsupported property name' },
+ { property: null, values: ['foo'], desc: 'an null property name' },
+ { property: 'width', values: ['10px'], desc: 'a property that is not list valued' },
+ { property: 'margin', values: ['10px'], desc: 'a shorthand property' },
+ { property: 'transition-duration', values: [CSS.px(10)], desc: 'an invalid CSSStyleValue' },
+ { property: 'transition-duration', values: ['10px'], desc: 'an invalid String value' },
+ { property: 'transition-duration', values: [CSS.s(1), '10px', CSS.px(10)], desc: 'a mix of valid and invalid values' },
+ { property: 'transition-duration', values: [new CSSUnparsedValue([])], desc: 'a CSSUnparsedValue' },
+ { property: 'transition-duration', values: ['var(--A)'], desc: 'a var ref' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.append(property, ...values));
+ }, 'Calling StylePropertyMap.append with ' + desc + ' throws TypeError');
+}
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.append('transition-duration', CSS.s(1), '2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'),
+ [CSS.s(1), CSS.s(2)]);
+
+ styleMap.append('transition-duration', '3s', CSS.s(4));
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'),
+ [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
+}, 'Appending a list-valued property with CSSStyleValue or String updates its values');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.append('transition-duration', '1s, 2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'),
+ [CSS.s(1), CSS.s(2)]);
+
+ styleMap.append('transition-duration', '3s, 4s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'),
+ [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
+}, 'Appending a list-valued property with list-valued string updates its values');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, 'transition-duration: 5s, 10s');
+
+ styleMap.append('tRaNsItIoN-dUrAtIoN', '1s', CSS.s(2));
+ const result = styleMap.getAll('transition-duration');
+ assert_style_value_array_equals(result,
+ [CSS.s(5), CSS.s(10), CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap.append is case-insensitive');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, 'transition-duration: var(--a)');
+ assert_throws_js(TypeError, () => styleMap.append('transition-duration', CSS.s(1)));
+}, 'Appending to a list containing a variable reference should throw');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, 'transition: var(--a)');
+ assert_throws_js(TypeError, () => styleMap.append('transition-duration', CSS.s(1)));
+}, 'Appending to a longhand list containing a variable reference should throw');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/clear.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/clear.html
new file mode 100644
index 0000000000..e6bdd4fffe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/clear.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.clear</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-clear">
+<meta name="assert" content="Test declared StylePropertyMap.clear" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ styleMap.clear();
+ assert_array_equals([...styleMap], []);
+}, 'Clearing an empty CSS rule is a no-op');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '--foo: auto; width: 10px; transition-duration: 1s, 2s');
+
+ styleMap.clear();
+ assert_equals(styleMap.get('--foo'), null,
+ 'Custom properties should be cleared');
+ assert_equals(styleMap.get('width'), null,
+ 'CSS properties should be cleared');
+ assert_equals(styleMap.get('transition-duration'), null,
+ 'List-valued properties should be cleared');
+ assert_array_equals([...styleMap], []);
+}, 'Can clear a CSS rule containing properties');
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t, 'width: 10px;');
+ styleMap.clear();
+
+ assert_equals(rule.style.width, '', 'CSS rule style should be cleared');
+}, 'Declared StylePropertyMap.clear updates the CSS rule');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
new file mode 100644
index 0000000000..f6c5dfdb6a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/declared.tentative.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#declared-stylepropertymap-objects">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<style>
+div {
+ height: 10px;
+ width: 50%;
+ width: 'lemon';
+ --foo: auto;
+ transition-duration: 1s, 2s;
+ color: 10;
+}
+
+#target {
+ height: 20px;
+ --foo: 1s;
+ width: 10%;
+}
+</style>
+<div style="width: 50px">
+ <div id="target" style="top: 5px; --bar: auto;"></div>
+</div>
+<script>
+'use strict';
+
+const target = document.getElementById('target');
+const styleMap = document.styleSheets[0].rules[0].styleMap;
+
+test(() => {
+ const properties = [...styleMap.keys()];
+ assert_array_equals(properties, ['height', 'width', '--foo', 'transition-duration']);
+}, 'Declared StylePropertyMap only contains properties in the style rule');
+
+test(() => {
+ assert_style_value_equals(styleMap.get('height'), CSS.px(10));
+}, 'Declared StylePropertyMap contains CSS property declarations in style rules');
+
+test(() => {
+ assert_equals(styleMap.get('top'), null);
+ assert_equals(styleMap.get('--bar'), null);
+}, 'Declared StylePropertyMap does not contain inline styles');
+
+test(() => {
+ assert_style_value_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
+}, 'Declared StylePropertyMap contains custom property declarations');
+
+test(() => {
+ assert_equals(styleMap.get('color'), null);
+}, 'Declared StylePropertyMap does not contain properties with invalid values');
+
+test(() => {
+ assert_style_value_equals(styleMap.get('width'), CSS.percent(50));
+}, 'Declared StylePropertyMap contains properties with their last valid value');
+
+test(() => {
+ const style = document.createElement('style');
+ document.head.appendChild(style);
+
+ style.sheet.insertRule('.test { width: 10px; }');
+ let rule = style.sheet.rules[0];
+
+ let styleMap = rule.styleMap;
+ assert_style_value_equals(styleMap.get('width'), CSS.px(10));
+
+ rule.style.width = '20px';
+ assert_style_value_equals(styleMap.get('width'), CSS.px(20));
+
+ styleMap.set('width', CSS.px(30));
+ assert_equals(rule.cssText, '.test { width: 30px; }');
+}, 'Declared StylePropertyMap is live');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-invalid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-invalid.html
new file mode 100644
index 0000000000..04dcccf5e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-invalid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.delete Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.delete('lemon'));
+}, 'Deleting an unsupported property name throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-shorthand.html
new file mode 100644
index 0000000000..48d4b49043
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete-shorthand.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.delete() with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let [elem, styleMap] = createRuleWithDeclaredStyleMap(t, '');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+
+ styleMap.delete('margin');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+}, 'Deleting a shorthand property not in the css rule is a no-op');
+
+test(t => {
+ let [elem, styleMap] = createRuleWithDeclaredStyleMap(t, 'margin: 10px');
+ assert_not_equals(elem.style.getPropertyValue('margin'), '');
+
+ styleMap.delete('margin');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+}, 'Deleting a shorthand property in the css rule removes both it and ' +
+ 'its longhands');
+
+test(t => {
+ let [elem, styleMap] = createRuleWithDeclaredStyleMap(t, 'margin: 10px');
+ assert_not_equals(elem.style.getPropertyValue('margin-top'), '');
+
+ styleMap.delete('margin-top');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '10px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '10px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '10px');
+}, 'Deleting a longhand property in the css rule removes both it and ' +
+ 'its shorthand');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete.html
new file mode 100644
index 0000000000..48ac3dc63c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/delete.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.delete</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t, '');
+ assert_equals(rule.style.getPropertyValue('width'), '');
+
+ styleMap.delete('width');
+ assert_equals(rule.style.getPropertyValue('width'), '');
+}, 'Deleting a property not in the css rule is a no-op');
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t, 'width: 10px');
+ assert_not_equals(rule.style.getPropertyValue('width'), '');
+
+ styleMap.delete('width');
+ assert_equals(rule.style.getPropertyValue('width'), '');
+}, 'Deleting a property in the css rule removes it from the css rule');
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t, '--Foo: 10px');
+ assert_not_equals(rule.style.getPropertyValue('--Foo'), '');
+
+ styleMap.delete('--Foo');
+ assert_equals(rule.style.getPropertyValue('--Foo'), '');
+}, 'Deleting a custom property in the css rule removes it from the ' +
+ 'css rule');
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t,
+ 'transition-duration: 1s, 2s');
+ assert_not_equals(rule.style.getPropertyValue('transition-duration'), '');
+
+ styleMap.delete('transition-duration');
+ assert_equals(rule.style.getPropertyValue('transition-duration'), '');
+}, 'Deleting a list-valued property in the css rule removes it from ' +
+ 'the css rule');
+
+test(t => {
+ let [rule, styleMap] = createRuleWithDeclaredStyleMap(t, 'width: 10px');
+ assert_not_equals(rule.style.getPropertyValue('width'), '');
+
+ styleMap.delete('wIdTh');
+ assert_equals(rule.style.getPropertyValue('width'), '');
+}, 'Declared StylePropertyMap.delete is not case-sensitive');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-invalid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-invalid.html
new file mode 100644
index 0000000000..0cd1412945
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-invalid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.get Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.get('lemon'));
+}, 'Calling StylePropertyMap.get with an unsupported property throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-shorthand.html
new file mode 100644
index 0000000000..0a83ca4d09
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get-shorthand.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.get with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.get('margin');
+ assert_not_equals(result, null, 'Shorthand value must not be null');
+ assert_class_string(result, 'CSSStyleValue',
+ 'Shorthand value must be a base CSSStyleValue');
+}, 'Getting a shorthand property set explicitly in css rule returns ' +
+ 'a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'margin-top: 1px');
+ const result = styleMap.get('margin');
+ assert_equals(result, null,
+ 'Shorthand value must be null as it is not explicitly set');
+}, 'Getting a shorthand property that is partially set in css rule ' +
+ 'returns null');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get.html
new file mode 100644
index 0000000000..847b6f6fa7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/get.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.get</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<meta name="assert" content="Test declared StylePropertyMap.get" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--foo: auto');
+ assert_equals(styleMap.get('--Foo'), null);
+}, 'Getting a custom property not in the CSS rule returns null');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '');
+ assert_equals(styleMap.get('width'), null);
+}, 'Getting a valid property not in the CSS rule returns null');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+}, 'Getting a valid property from CSS rule returns the correct entry');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_equals(styleMap.get('--foo'),
+ new CSSUnparsedValue(['auto']));
+}, 'Getting a valid custom property from CSS rule returns the ' +
+ 'correct entry');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t,
+ 'width: 10px; transition-duration: 1s, 2s; height: 10px;');
+ assert_style_value_equals(styleMap.get('transition-duration'),
+ new CSSUnitValue(1, 's'));
+}, 'Getting a list-valued property from CSS rule returns only ' +
+ 'the first value');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'height: 20px; width: 10px;');
+ assert_style_value_equals(styleMap.get('wIdTh'), new CSSUnitValue(10, 'px'));
+}, 'Declared StylePropertyMap.get is not case-sensitive');
+
+test(t => {
+ const [rule, styleMap] = createRuleWithDeclaredStyleMap(t, 'width: 10px;');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+ rule.style.width = '20px';
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(20, 'px'));
+}, 'Declared StylePropertyMap.get reflects changes in the CSS rule');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll-shorthand.html
new file mode 100644
index 0000000000..16dda49366
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll-shorthand.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.getAll with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.getAll('margin');
+ assert_not_equals(result, null, 'Result must not be null');
+ assert_equals(result.length, 1, 'Result must be a list with one item');
+ assert_class_string(result[0], 'CSSStyleValue',
+ 'Only item in result must be a base CSSStyleValue');
+}, 'StylePropertyMap.getAll() with a shorthand property set explicitly in ' +
+ 'css rule returns a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'margin-top: 1px');
+ const result = styleMap.getAll('margin');
+ assert_equals(result.length, 0, 'Result must be an empty list');
+}, 'StylePropertyMap.getAll() with a shorthand property that is partially ' +
+ 'in css rule returns empty list');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
new file mode 100644
index 0000000000..bc557d0a76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/getAll.tentative.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.getAll tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.getAll('lemon'));
+}, 'Calling StylePropertyMap.getAll with an unsupported property throws a TypeError');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t);
+ assert_style_value_array_equals(styleMap.getAll('height'), []);
+}, 'Calling StylePropertyMap.getAll with a property not in the property model returns an empty list');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--foo: auto');
+ assert_style_value_array_equals(styleMap.getAll('--Foo'), []);
+}, 'Calling StylePropertyMap.getAll with a custom property not in the property model returns an empty list');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('width'), [CSS.px(10)]);
+}, 'Calling StylePropertyMap.getAll with a valid property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'height: 20px; width: 10px');
+ assert_style_value_array_equals(styleMap.getAll('wIdTh'), [CSS.px(10)]);
+}, 'StylePropertyMap.getAll is case-insensitive');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(['auto'])]);
+}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'width: 10px; transition-duration: 1s, 2s; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Calling StylePropertyMap.getAll with a list-valued property returns all the values');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/has.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/has.tentative.html
new file mode 100644
index 0000000000..6ea24c7ea9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/has.tentative.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.has tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#check-if-stylepropertymap-has-a-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.has('lemon'));
+}, 'Calling StylePropertyMap.has with an unsupported property throws a TypeError');
+
+const gTestCases = [
+ { property: 'height', expected: false, desc: 'a property not in the property model' },
+ { property: '--Foo', expected: false, desc: 'a custom property not in the property model' },
+ { property: 'width', expected: true, desc: 'a valid property' },
+ { property: 'wIdTh', expected: true, desc: 'a valid property in mixed case' },
+ { property: 'margin', expected: true, desc: 'a valid shorthand specified explicitly' },
+ { property: 'padding', expected: false, desc: 'a valid shorthand only partially specified' },
+ { property: '--foo', expected: true, desc: 'a valid custom property' },
+ { property: 'transition-duration', expected: true, desc: 'a valid list-valued property' },
+];
+
+for (const {property, expected, desc} of gTestCases) {
+ test(t => {
+ const styleMap = createDeclaredStyleMap(t,
+ 'width: 10px; --foo: auto; transition-duration: 1s, 2s; margin: 1px 2px 3px 4px; padding-left: 1px');
+ assert_equals(styleMap.has(property), expected);
+ }, 'Calling StylePropertyMap.has with ' + desc + ' returns ' + expected);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
new file mode 100644
index 0000000000..a13f83716e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/iterable.tentative.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap iterable tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#the-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '');
+ assert_array_equals([...styleMap.entries()], []);
+}, 'Iterating over an empty StylePropertyMap gives a zero-length array');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--A: A; width: 10px; --C: C; transition-duration: 1s, 2s; color: red; --B: B;');
+ assert_array_equals([...styleMap.keys()],
+ ['--A', 'width', '--C', 'transition-duration', 'color', '--B']);
+}, 'StylePropertyMap iterates properties in correct order');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'width: 10px; height: 5px');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['width', 'height']);
+ assert_style_value_array_equals(values[0], [CSS.px(10)]);
+ assert_style_value_array_equals(values[1], [CSS.px(5)]);
+}, 'StylePropertyMap iterator returns CSS properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, 'transition-duration: 1s, 2s');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['transition-duration']);
+ assert_style_value_array_equals(values[0], [CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap iterator returns list-valued properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createDeclaredStyleMap(t, '--A: A; --B: B; --C: C');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['--A', '--B', '--C']);
+ assert_style_value_array_equals(values[0], [new CSSUnparsedValue(['A'])]);
+ assert_style_value_array_equals(values[1], [new CSSUnparsedValue(['B'])]);
+ assert_style_value_array_equals(values[2], [new CSSUnparsedValue(['C'])]);
+}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set-shorthand.html
new file mode 100644
index 0000000000..7a025df647
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set-shorthand.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Declared StylePropertyMap.set() with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#set-a-value-on-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'margin', values: [CSS.deg(0)], desc: 'an invalid CSSStyleValue' },
+ { property: 'margin', values: ['10s'], desc: 'an invalid String' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set(property, ...values));
+ }, 'Setting a shorthand with ' + desc + ' on css rule throws TypeError');
+}
+
+test(t => {
+ let [elem, styleMap] = createRuleWithDeclaredStyleMap(t, 'margin: 1px 2px 3px 4px');
+
+ const result = styleMap.get('margin');
+ elem.style.margin = '';
+ styleMap.set('margin', result);
+
+ assert_equals(elem.style.getPropertyValue('margin'), '1px 2px 3px 4px');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '1px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '2px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '3px');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '4px');
+}, 'Setting a shorthand with a CSSStyleValue updates css rule');
+
+test(t => {
+ let [elem, styleMap] = createRuleWithDeclaredStyleMap(t);
+
+ styleMap.set('margin', '1px 2px 3px 4px');
+
+ assert_equals(elem.style.getPropertyValue('margin'), '1px 2px 3px 4px');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '1px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '2px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '3px');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '4px');
+}, 'Setting a shorthand with a string updates css rule');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
new file mode 100644
index 0000000000..53c3c75d18
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/declared/set.tentative.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.set</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#set-a-value-on-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'lemon', values: ['ade'], desc: 'an unsupported property name' },
+ { property: null, values: ['foo'], desc: 'an null property name' },
+ { property: 'src', values: [new CSSUnparsedValue(['foo'])], desc: 'a descriptor' },
+ { property: 'width', values: [CSS.deg(0)], desc: 'an invalid CSSStyleValue' },
+ { property: 'width', values: ['10s'], desc: 'an invalid String' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set(property, ...values));
+ }, 'Setting a StylePropertyMap with ' + desc + ' throws TypeError');
+}
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set('width', CSS.px(10), CSS.px(10)));
+}, 'Setting a non list-valued property with multiple arguments throws TypeError');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set('width', '1s, 2s'));
+}, 'Setting a non list-valued property with list-valued string throws TypeError');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => {
+ styleMap.set('transition-duration', '1s', new CSSUnparsedValue([]));
+ });
+}, 'Setting a list-valued property with a CSSUnparsedValue and other ' +
+ 'values throws TypeError');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+ assert_throws_js(TypeError, () => {
+ styleMap.set('transition-duration', '1s', 'var(--A)');
+ });
+}, 'Setting a list-valued property with a var ref() and other values ' +
+ 'throws TypeError');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.set('width', CSS.px(10));
+ assert_style_value_array_equals(styleMap.get('width'), CSS.px(10));
+
+ styleMap.set('width', '20px');
+ assert_style_value_array_equals(styleMap.get('width'), CSS.px(20));
+}, 'Setting a property with CSSStyleValue or String updates its value');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.set('transition-duration', CSS.s(1), '2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+
+ styleMap.set('transition-duration', '3s', CSS.s(4));
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(3), CSS.s(4)]);
+}, 'Setting a list-valued property with CSSStyleValue or String updates its values');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.set('transition-duration', '1s, 2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Setting a list-valued property with a list-valued string updates its value');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, '');
+
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
+
+ styleMap.set('--foo', '20px');
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
+}, 'Setting a custom property with CSSStyleValue or String updates its value');
+
+test(t => {
+ let styleMap = createDeclaredStyleMap(t, 'transition-duration: 5s, 10s');
+
+ styleMap.set('tRaNsItIoN-dUrAtIoN', '1s', CSS.s(2));
+ const result = styleMap.getAll('transition-duration');
+ assert_style_value_array_equals(result, [CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap.set is case-insensitive');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/append.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/append.tentative.html
new file mode 100644
index 0000000000..f808756223
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/append.tentative.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.append tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#append-to-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'lemon', values: ['ade'], desc: 'an unsupported property name' },
+ { property: null, values: ['foo'], desc: 'an null property name' },
+ { property: 'width', values: ['10px'], desc: 'a property that is not list valued' },
+ { property: 'margin', values: ['10px'], desc: 'a shorthand property' },
+ { property: 'transition-duration', values: [CSS.px(10)], desc: 'an invalid CSSStyleValue' },
+ { property: 'transition-duration', values: ['10px'], desc: 'an invalid String value' },
+ { property: 'transition-duration', values: [CSS.s(1), '10px', CSS.px(10)], desc: 'a mix of valid and invalid values' },
+ { property: 'transition-duration', values: [new CSSUnparsedValue([])], desc: 'a CSSUnparsedValue' },
+ { property: 'transition-duration', values: ['var(--A)'], desc: 'a var ref' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.append(property, ...values));
+ }, 'Calling StylePropertyMap.append with ' + desc + ' throws TypeError');
+}
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.append('transition-duration', CSS.s(1), '2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+
+ styleMap.append('transition-duration', '3s', CSS.s(4));
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
+}, 'Appending a list-valued property with CSSStyleValue or String updates its values');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.append('transition-duration', '1s, 2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+
+ styleMap.append('transition-duration', '3s, 4s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2), CSS.s(3), CSS.s(4)]);
+}, 'Appending a list-valued property with list-valued string updates its values');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, 'transition-duration: 5s, 10s');
+
+ styleMap.append('tRaNsItIoN-dUrAtIoN', '1s', CSS.s(2));
+ const result = styleMap.getAll('transition-duration');
+ assert_style_value_array_equals(result, [CSS.s(5), CSS.s(10), CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap.append is case-insensitive');
+
+// https://crbug.com/1417176
+test(t => {
+ let styleMap = createInlineStyleMap(t, 'transition-duration: inherit');
+ assert_throws_js(TypeError, () => styleMap.append('transition-duration', '1s'));
+}, 'StylePropertyMap.append rejects appending to CSS-wide keywords');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/clear.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/clear.html
new file mode 100644
index 0000000000..24ca69926b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/clear.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.clear</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-clear">
+<meta name="assert" content="Test inline StylePropertyMap.clear" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ styleMap.clear();
+ assert_array_equals([...styleMap], []);
+}, 'Clearing an empty inline style is a no-op');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '--foo: auto; width: 10px; transition-duration: 1s, 2s');
+
+ styleMap.clear();
+ assert_equals(styleMap.get('--foo'), null,
+ 'Custom properties should be cleared');
+ assert_equals(styleMap.get('width'), null,
+ 'CSS properties should be cleared');
+ assert_equals(styleMap.get('transition-duration'), null,
+ 'List-valued properties should be cleared');
+ assert_array_equals([...styleMap], []);
+}, 'Can clear an inline style containing properties');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'width: 10px;');
+ styleMap.clear();
+
+ assert_equals(elem.style.width, '', 'Element inline style should be cleared');
+}, 'Inline StylePropertyMap.clear updates the element inline style');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-invalid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-invalid.html
new file mode 100644
index 0000000000..a4f1b620b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-invalid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.delete Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.delete('lemon'));
+}, 'Deleting an unsupported property name throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-shorthand.html
new file mode 100644
index 0000000000..065c7544b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete-shorthand.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.delete() with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, '');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+
+ styleMap.delete('margin');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+}, 'Deleting a shorthand property not in the inline style is a no-op');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'margin: 10px');
+ assert_not_equals(elem.style.getPropertyValue('margin'), '');
+
+ styleMap.delete('margin');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '');
+}, 'Deleting a shorthand property in the inline style removes both it and ' +
+ 'its longhands');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'margin: 10px');
+ assert_not_equals(elem.style.getPropertyValue('margin-top'), '');
+
+ styleMap.delete('margin-top');
+ assert_equals(elem.style.getPropertyValue('margin'), '');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '10px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '10px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '10px');
+}, 'Deleting a longhand property in the inline style removes both it and ' +
+ 'its shorthand');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete.html
new file mode 100644
index 0000000000..82b419bfee
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/delete.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.delete</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#delete-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, '');
+ assert_equals(elem.style.getPropertyValue('width'), '');
+
+ styleMap.delete('width');
+ assert_equals(elem.style.getPropertyValue('width'), '');
+}, 'Deleting a property not in the inline style is a no-op');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'width: 10px');
+ assert_not_equals(elem.style.getPropertyValue('width'), '');
+
+ styleMap.delete('width');
+ assert_equals(elem.style.getPropertyValue('width'), '');
+}, 'Deleting a property in the inline style removes it from the inline style');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, '--Foo: 10px');
+ assert_not_equals(elem.style.getPropertyValue('--Foo'), '');
+
+ styleMap.delete('--Foo');
+ assert_equals(elem.style.getPropertyValue('--Foo'), '');
+}, 'Deleting a custom property in the inline style removes it from the ' +
+ 'inline style');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t,
+ 'transition-duration: 1s, 2s');
+ assert_not_equals(elem.style.getPropertyValue('transition-duration'), '');
+
+ styleMap.delete('transition-duration');
+ assert_equals(elem.style.getPropertyValue('transition-duration'), '');
+}, 'Deleting a list-valued property in the inline style removes it from ' +
+ 'the inline style');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'width: 10px');
+ assert_not_equals(elem.style.getPropertyValue('width'), '');
+
+ styleMap.delete('wIdTh');
+ assert_equals(elem.style.getPropertyValue('width'), '');
+}, 'Inline StylePropertyMap.delete is not case-sensitive');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-invalid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-invalid.html
new file mode 100644
index 0000000000..07f4a6dc7c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-invalid.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.get Error Handling</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.get('lemon'));
+}, 'Calling StylePropertyMap.get with an unsupported property throws a TypeError');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-shorthand.html
new file mode 100644
index 0000000000..6ce318d599
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get-shorthand.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.get with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.get('margin');
+ assert_not_equals(result, null, 'Shorthand value must not be null');
+ assert_class_string(result, 'CSSStyleValue',
+ 'Shorthand value must be a base CSSStyleValue');
+}, 'Getting an shorthand property set explicitly in inline style returns ' +
+ 'a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'margin-top: 1px');
+ const result = styleMap.get('margin');
+ assert_equals(result, null,
+ 'Shorthand value must be null as it is not explicitly set');
+}, 'Getting a shorthand property that is partially set in inline style ' +
+ 'returns null');
+
+test(t => {
+ const styleMap = createDivWithoutStyle(t).attributeStyleMap;
+ assert_equals(styleMap.get('margin'), null,
+ 'Shorthand value must be null for element without style');
+}, 'Getting an attributeStyleMap shorthand property from an element without ' +
+ 'a style attribute');
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get.html
new file mode 100644
index 0000000000..1fcc09be6f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/get.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.get</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#get-a-value-from-a-stylepropertymap">
+<meta name="assert" content="Test inline StylePropertyMap.get" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--foo: auto');
+ assert_equals(styleMap.get('--Foo'), null);
+}, 'Getting a custom property not in the inline style returns null');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '');
+ assert_equals(styleMap.get('width'), null);
+}, 'Getting a valid property not in the inline style returns null');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+}, 'Getting a valid property from inline style returns the correct entry');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_equals(styleMap.get('--foo'),
+ new CSSUnparsedValue(['auto']));
+}, 'Getting a valid custom property from inline style returns the ' +
+ 'correct entry');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t,
+ 'width: 10px; transition-duration: 1s, 2s; height: 10px;');
+ assert_style_value_equals(styleMap.get('transition-duration'),
+ new CSSUnitValue(1, 's'));
+}, 'Getting a list-valued property from inline style returns only ' +
+ 'the first value');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'height: 20px; width: 10px;');
+ assert_style_value_equals(styleMap.get('wIdTh'), new CSSUnitValue(10, 'px'));
+}, 'Declared StylePropertyMap.get is not case-sensitive');
+
+test(t => {
+ const [elem, styleMap] = createElementWithInlineStyleMap(t, 'width: 10px;');
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(10, 'px'));
+ elem.style.width = '20px';
+ assert_style_value_equals(styleMap.get('width'), new CSSUnitValue(20, 'px'));
+}, 'Declared StylePropertyMap.get reflects changes in the inline style');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll-shorthand.html
new file mode 100644
index 0000000000..f7051dd09c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll-shorthand.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.getAll with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymapreadonly-getall">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log">
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'margin: 1px 2px 3px 4px');
+ const result = styleMap.getAll('margin');
+ assert_not_equals(result, null, 'Result must not be null');
+ assert_equals(result.length, 1, 'Result must be a list with one item');
+ assert_class_string(result[0], 'CSSStyleValue',
+ 'Only item in result must be a base CSSStyleValue');
+}, 'StylePropertyMap.getAll() with a shorthand property set explicitly in ' +
+ 'inline style returns a base CSSStyleValue');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'margin-top: 1px');
+ const result = styleMap.getAll('margin');
+ assert_equals(result.length, 0, 'Result must be an empty list');
+}, 'StylePropertyMap.getAll() with a shorthand property that is partially ' +
+ 'in inline style returns empty list');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
new file mode 100644
index 0000000000..027f3e0e6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/getAll.tentative.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.getAll tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.getAll('lemon'));
+}, 'Calling StylePropertyMap.getAll with an unsupported property throws a TypeError');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t);
+ assert_style_value_array_equals(styleMap.getAll('height'), []);
+}, 'Calling StylePropertyMap.getAll with a property not in the property model returns an empty list');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--foo: auto');
+ assert_style_value_array_equals(styleMap.getAll('--Foo'), []);
+}, 'Calling StylePropertyMap.getAll with a custom property not in the property model returns an empty list');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'width: 10px; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('width'), [CSS.px(10)]);
+}, 'Calling StylePropertyMap.getAll with a valid property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'height: 20px; width: 10px');
+ assert_style_value_array_equals(styleMap.getAll('wIdTh'), [CSS.px(10)]);
+}, 'StylePropertyMap.getAll is case-insensitive');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--foo: auto; --bar: 10px');
+ assert_style_value_array_equals(styleMap.getAll('--foo'), [new CSSUnparsedValue(['auto'])]);
+}, 'Calling StylePropertyMap.getAll with a valid custom property returns a single element list with the correct entry');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'width: 10px; transition-duration: 1s, 2s; height: 20px');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Calling StylePropertyMap.getAll with a list-valued property returns all the values');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/has.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/has.tentative.html
new file mode 100644
index 0000000000..0427d5a606
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/has.tentative.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.has tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#check-if-stylepropertymap-has-a-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.has('lemon'));
+}, 'Calling StylePropertyMap.has with an unsupported property throws a TypeError');
+
+const gTestCases = [
+ { property: 'height', expected: false, desc: 'a property not in the property model' },
+ { property: '--Foo', expected: false, desc: 'a custom property not in the property model' },
+ { property: 'margin', expected: false, desc: 'a valid property in mixed case' },
+ { property: 'width', expected: true, desc: 'a valid property' },
+ { property: 'wIdTh', expected: true, desc: 'a valid property in mixed case' },
+ { property: '--foo', expected: true, desc: 'a valid custom property' },
+ { property: 'transition-duration', expected: true, desc: 'a valid list-valued property' },
+];
+
+for (const {property, expected, desc} of gTestCases) {
+ test(t => {
+ const styleMap = createInlineStyleMap(t, 'width: 10px; --foo: auto; transition-duration: 1s, 2s');
+ assert_equals(styleMap.has(property), expected);
+ }, 'Calling StylePropertyMap.has with ' + desc + ' returns ' + expected);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
new file mode 100644
index 0000000000..ae4490f4aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/iterable.tentative.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap iterable tests</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#the-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '');
+ assert_array_equals([...styleMap.entries()], []);
+}, 'Iterating over an empty StylePropertyMap gives a zero-length array');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--A: A; width: 10px; --C: C; transition-duration: 1s, 2s; color: red; --B: B;');
+ assert_array_equals([...styleMap.keys()],
+ ['--A', 'width', '--C', 'transition-duration', 'color', '--B']);
+}, 'StylePropertyMap iterates properties in inline style order');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'width: 10px; height: 5px');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['width', 'height']);
+ assert_style_value_array_equals(values[0], [CSS.px(10)]);
+ assert_style_value_array_equals(values[1], [CSS.px(5)]);
+}, 'StylePropertyMap iterator returns CSS properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, 'transition-duration: 1s, 2s');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['transition-duration']);
+ assert_style_value_array_equals(values[0], [CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap iterator returns list-valued properties with the correct CSSStyleValue');
+
+test(t => {
+ const styleMap = createInlineStyleMap(t, '--A: A; --B: B; --C: C');
+ const keys = [...styleMap.keys()], values = [...styleMap.values()];
+
+ assert_array_equals(keys, ['--A', '--B', '--C']);
+ assert_style_value_array_equals(values[0], [new CSSUnparsedValue(['A'])]);
+ assert_style_value_array_equals(values[1], [new CSSUnparsedValue(['B'])]);
+ assert_style_value_array_equals(values[2], [new CSSUnparsedValue(['C'])]);
+}, 'StylePropertyMap iterator returns custom properties with the correct CSSStyleValue');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set-shorthand.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set-shorthand.html
new file mode 100644
index 0000000000..87ecadcb75
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set-shorthand.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Inline StylePropertyMap.set() with shorthands</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#set-a-value-on-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'margin', values: [CSS.deg(0)], desc: 'an invalid CSSStyleValue' },
+ { property: 'margin', values: ['10s'], desc: 'an invalid String' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set(property, ...values));
+ }, 'Setting a shorthand with ' + desc + ' on inline style throws TypeError');
+}
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t, 'margin: 1px 2px 3px 4px');
+
+ const result = styleMap.get('margin');
+ elem.style.margin = '';
+ styleMap.set('margin', result);
+
+ assert_equals(elem.style.getPropertyValue('margin'), '1px 2px 3px 4px');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '1px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '2px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '3px');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '4px');
+}, 'Setting a shorthand with a CSSStyleValue updates inline style');
+
+test(t => {
+ let [elem, styleMap] = createElementWithInlineStyleMap(t);
+
+ styleMap.set('margin', '1px 2px 3px 4px');
+
+ assert_equals(elem.style.getPropertyValue('margin'), '1px 2px 3px 4px');
+ assert_equals(elem.style.getPropertyValue('margin-top'), '1px');
+ assert_equals(elem.style.getPropertyValue('margin-right'), '2px');
+ assert_equals(elem.style.getPropertyValue('margin-bottom'), '3px');
+ assert_equals(elem.style.getPropertyValue('margin-left'), '4px');
+}, 'Setting a shorthand with a string updates inline style');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
new file mode 100644
index 0000000000..50c685b4b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/inline/set.tentative.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>StylePropertyMap.set</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#set-a-value-on-a-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<script>
+'use strict';
+
+const gInvalidTestCases = [
+ { property: 'lemon', values: ['ade'], desc: 'an unsupported property name' },
+ { property: null, values: ['foo'], desc: 'an null property name' },
+ { property: 'src', values: [new CSSUnparsedValue(['foo'])], desc: 'a descriptor' },
+ { property: 'width', values: [CSS.deg(0)], desc: 'an invalid CSSStyleValue' },
+ { property: 'width', values: ['10s'], desc: 'an invalid String' },
+];
+
+for (const {property, values, desc} of gInvalidTestCases) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set(property, ...values));
+ }, 'Setting a StylePropertyMap with ' + desc + ' throws TypeError');
+}
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set('width', CSS.px(10), CSS.px(10)));
+}, 'Setting a non list-valued property with multiple arguments throws TypeError');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => styleMap.set('width', '1s, 2s'));
+}, 'Setting a non list-valued property with list-valued string throws TypeError');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => {
+ styleMap.set('transition-duration', '1s', new CSSUnparsedValue([]));
+ });
+}, 'Setting a list-valued property with a CSSUnparsedValue and other ' +
+ 'values throws TypeError');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+ assert_throws_js(TypeError, () => {
+ styleMap.set('transition-duration', '1s', 'var(--A)');
+ });
+}, 'Setting a list-valued property with a var ref() and other values ' +
+ 'throws TypeError');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.set('width', CSS.px(10));
+ assert_style_value_array_equals(styleMap.get('width'), CSS.px(10));
+
+ styleMap.set('width', '20px');
+ assert_style_value_array_equals(styleMap.get('width'), CSS.px(20));
+}, 'Setting a property with CSSStyleValue or String updates its value');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.set('transition-duration', CSS.s(1), '2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+
+ styleMap.set('transition-duration', '3s', CSS.s(4));
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(3), CSS.s(4)]);
+}, 'Setting a list-valued property with CSSStyleValue or String updates its values');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.set('transition-duration', '1s, 2s');
+ assert_style_value_array_equals(styleMap.getAll('transition-duration'), [CSS.s(1), CSS.s(2)]);
+}, 'Setting a list-valued property with a list-valued string updates its value');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, '');
+
+ styleMap.set('--foo', new CSSUnparsedValue(['auto']));
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['auto']));
+
+ styleMap.set('--foo', '20px');
+ assert_style_value_array_equals(styleMap.get('--foo'), new CSSUnparsedValue(['20px']));
+}, 'Setting a custom property with CSSStyleValue or String updates its value');
+
+test(t => {
+ let styleMap = createInlineStyleMap(t, 'transition-duration: 5s, 10s');
+
+ styleMap.set('tRaNsItIoN-dUrAtIoN', '1s', CSS.s(2));
+ const result = styleMap.getAll('transition-duration');
+ assert_style_value_array_equals(result, [CSS.s(1), CSS.s(2)]);
+}, 'StylePropertyMap.set is case-insensitive');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/accent-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/accent-color.html
new file mode 100644
index 0000000000..8cd0b986e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/accent-color.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>'accent-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('accent-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ },
+ {
+ syntax: 'auto',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('accent-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/alignment-baseline.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/alignment-baseline.html
new file mode 100644
index 0000000000..aab4a6a5c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/alignment-baseline.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'alignment-baseline' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('alignment-baseline', [
+ { syntax: 'baseline' },
+ { syntax: 'text-bottom' },
+ { syntax: 'alphabetic' },
+ { syntax: 'ideographic' },
+ { syntax: 'middle' },
+ { syntax: 'central' },
+ { syntax: 'mathematical' },
+ { syntax: 'text-top' },
+ { syntax: 'bottom' },
+ { syntax: 'center' },
+ { syntax: 'top' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/all.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/all.html
new file mode 100644
index 0000000000..dd618bcde6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/all.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'all' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('all', []);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html
new file mode 100644
index 0000000000..79b9f94617
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-end.tentative.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>'animation-delay-end' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-delay-end', [
+ { syntax: '<time>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html
new file mode 100644
index 0000000000..2fba4d8e51
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay-start.tentative.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>'animation-delay-start' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-delay-start', [
+ { syntax: '<time>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay.html
new file mode 100644
index 0000000000..91ee95ec1d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-delay.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-delay' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-delay', [
+ { syntax: '<time>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
new file mode 100644
index 0000000000..0d4f6c0295
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-direction.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-direction' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-direction', [
+ { syntax: 'normal' },
+ { syntax: 'reverse' },
+ { syntax: 'alternate-reverse' },
+ { syntax: 'alternate' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-duration.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-duration.html
new file mode 100644
index 0000000000..edff11c8a2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-duration.html
@@ -0,0 +1,42 @@
+<meta charset="utf-8">
+<title>'animation-duration' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_time(input, result) {
+ const time = input.to('s');
+
+ if (time.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 's'));
+ else
+ assert_style_value_equals(result, time);
+}
+
+runListValuedPropertyTests('animation-duration', [
+ {
+ syntax: '<time>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_time
+ },
+]);
+
+test((t) => {
+ let div = document.createElement('div');
+ t.add_cleanup(() => {
+ div.remove();
+ });
+ document.body.append(div);
+ let actual = div.computedStyleMap().get('animation-duration').toString();
+ assert_equals(actual, 'auto');
+}, 'Computed value of animation-duration is auto');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-fill-mode.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-fill-mode.html
new file mode 100644
index 0000000000..419b98847c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-fill-mode.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-fill-mode' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-fill-mode', [
+ { syntax: 'none' },
+ { syntax: 'forwards' },
+ { syntax: 'backwards' },
+ { syntax: 'both' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-iteration-count.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-iteration-count.html
new file mode 100644
index 0000000000..627b281c7f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-iteration-count.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-iteration-count' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else
+ assert_style_value_equals(result, number);
+}
+
+runListValuedPropertyTests('animation-iteration-count', [
+ { syntax: 'infinite' },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_number
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-name.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-name.html
new file mode 100644
index 0000000000..df5d44ae38
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-name.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-name' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-name', [
+ { syntax: 'none' },
+ // FIXME: This should be <custom-ident>, but the test harness doesn't
+ // currently support it.
+ { syntax: 'custom-ident' },
+]);
+
+runUnsupportedPropertyTests('animation-name', [
+ '"foo"'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-play-state.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-play-state.html
new file mode 100644
index 0000000000..caa961131d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-play-state.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-play-state' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-play-state', [
+ { syntax: 'running' },
+ { syntax: 'paused' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html
new file mode 100644
index 0000000000..eb9af36a85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation-timing-function.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation-timing-function' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('animation-timing-function', [
+ { syntax: 'linear' },
+ { syntax: 'ease' },
+ { syntax: 'ease-in' },
+ { syntax: 'ease-out' },
+ { syntax: 'ease-in-out' },
+ {
+ syntax: 'step-start',
+ computed: (_, result) => {
+ assert_equals(result.toString(), 'steps(1, start)');
+ }
+ },
+ {
+ syntax: 'step-end',
+ computed: (_, result) => {
+ assert_equals(result.toString(), 'steps(1)');
+ }
+ },
+]);
+
+runUnsupportedPropertyTests('animation-timing-function', [
+ 'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation.html
new file mode 100644
index 0000000000..92a4916747
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/animation.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'animation' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('animation', [
+ 'slidein 3s ease-in 1s infinite reverse both running',
+ 'slidein .5s linear 1s infinite alternate'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backdrop-filter.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backdrop-filter.html
new file mode 100644
index 0000000000..837ceb7c23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backdrop-filter.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'backdrop-filter' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('backdrop-filter', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('filter', [
+ 'blur(2px)',
+ 'url(filters.svg) blur(4px) saturate(150%)',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backface-visibility.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backface-visibility.html
new file mode 100644
index 0000000000..ae9502d647
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/backface-visibility.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'backface-visibility' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('backface-visibility', [
+ { syntax: 'visible' },
+ { syntax: 'hidden' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-attachment.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-attachment.html
new file mode 100644
index 0000000000..77adf0df03
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-attachment.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-attachment' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-attachment', [
+ { syntax: 'scroll' },
+ { syntax: 'fixed' },
+ { syntax: 'local' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-blend-mode.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-blend-mode.html
new file mode 100644
index 0000000000..92082e2f8a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-blend-mode.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-blend-mode' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-blend-mode', [
+ { syntax: 'normal' },
+ { syntax: 'multiply' },
+ { syntax: 'screen' },
+ { syntax: 'overlay' },
+ { syntax: 'darken' },
+ { syntax: 'lighten' },
+ { syntax: 'color-dodge' },
+ { syntax: 'color-burn' },
+ { syntax: 'hard-light' },
+ { syntax: 'soft-light' },
+ { syntax: 'difference' },
+ { syntax: 'exclusion' },
+ { syntax: 'hue' },
+ { syntax: 'saturation' },
+ { syntax: 'color' },
+ { syntax: 'luminosity' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-clip.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-clip.html
new file mode 100644
index 0000000000..46d16a6f60
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-clip.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-clip' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-clip', [
+ { syntax: 'border-box' },
+ { syntax: 'padding-box' },
+ { syntax: 'content-box' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-color.html
new file mode 100644
index 0000000000..f684a40fb6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('background-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('background-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-image.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-image.html
new file mode 100644
index 0000000000..b3dddedbe4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-image.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-image' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-image', [
+ { syntax: 'none' },
+ { syntax: '<image>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-origin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-origin.html
new file mode 100644
index 0000000000..511b5dc5bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-origin.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-origin' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-origin', [
+ { syntax: 'border-box' },
+ { syntax: 'padding-box' },
+ { syntax: 'content-box' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-position.html
new file mode 100644
index 0000000000..8e5b09b10a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-position.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('background-position', [
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-repeat.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-repeat.html
new file mode 100644
index 0000000000..a89e1f7c93
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-repeat.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-repeat' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-repeat', [
+ { syntax: 'repeat-x' },
+ { syntax: 'repeat-y' },
+ { syntax: 'repeat' },
+ { syntax: 'space' },
+ { syntax: 'round' },
+ { syntax: 'no-repeat' },
+]);
+
+runUnsupportedPropertyTests('background-repeat', [
+ 'space repeat'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-size.html
new file mode 100644
index 0000000000..78fae767d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background-size.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background-size' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('background-size', [
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling
+ },
+ { syntax: 'auto' },
+ { syntax: 'cover' },
+ { syntax: 'contain' },
+]);
+
+runUnsupportedPropertyTests('background-size', [
+ '200px 100px'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background.html
new file mode 100644
index 0000000000..8926441fba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/background.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'background' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('background', []);
+runUnsupportedPropertyTests('background', [
+ 'green', 'content-box radial-gradient(crimson, skyblue)',
+ 'no-repeat url("http://foo.com")',
+ 'left 5% / 15% 60% repeat-x url("http://foo.com")',
+ 'center / contain no-repeat url("foo.com"), red'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/baseline-shift.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/baseline-shift.html
new file mode 100644
index 0000000000..c8e90b74c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/baseline-shift.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'baseline-shift' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('baseline-shift', [
+ { syntax: 'sub' },
+ { syntax: 'super' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/block-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/block-size.html
new file mode 100644
index 0000000000..311df4d422
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/block-size.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'block-size' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('block-size', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('min-block-size', [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('max-block-size', [
+ { syntax: 'none' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-collapse.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-collapse.html
new file mode 100644
index 0000000000..3a48ef0e4d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-collapse.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-collapse' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-collapse', [
+ { syntax: 'separate' },
+ { syntax: 'collapse' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-color.html
new file mode 100644
index 0000000000..3ce4ca94fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-color.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-color' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const prefix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests(`border-${prefix}-color`, [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+ ]);
+
+ // <color>s are not supported in level 1
+ runUnsupportedPropertyTests(`border-${prefix}-color`, [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+ ]);
+}
+
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-outset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-outset.html
new file mode 100644
index 0000000000..6ab5f68de6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-outset.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-image-outset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-image-outset', [
+ // Computed value is always four values, which are not supported in
+ // Typed OM level 1.
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+]);
+
+runUnsupportedPropertyTests('border-image-outset', [
+ '1 1.2', '30px 2 45px', '7px 12px 14px 5px'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-repeat.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-repeat.html
new file mode 100644
index 0000000000..885a947923
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-repeat.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-image-repeat' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-image-repeat', [
+ // Computed value is always a pair of values, which are not supported in
+ // Typed OM level 1.
+ {
+ syntax: 'stretch',
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: 'repeat',
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: 'round',
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: 'space',
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+]);
+
+runUnsupportedPropertyTests('border-image-repeat', [
+ 'stretch repeat', 'round space'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-slice.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-slice.html
new file mode 100644
index 0000000000..da05bad352
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-slice.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-image-slice' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-image-slice', [
+ // Computed value is always four values, which are not supported in
+ // Typed OM level 1.
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+]);
+
+runUnsupportedPropertyTests('border-image-slice', [
+ '30 fill', '30 40 50', '30 40 50 60 fill'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-source.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-source.html
new file mode 100644
index 0000000000..b9ddf19ff2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-source.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-image-source' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-image-source', [
+ { syntax: 'none' },
+ { syntax: '<image>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-width.html
new file mode 100644
index 0000000000..381e3b6d1b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-image-width.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'border-image-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('border-image-width', [
+ // Computed value is always four values, which are not supported in
+ // Typed OM level 1.
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: 'auto',
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+]);
+
+runUnsupportedPropertyTests('border-image-width', [
+ '2em 3em', '5% 15% 10%', '5% 2em 10% auto'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-radius.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-radius.html
new file mode 100644
index 0000000000..c6ebcbf381
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-radius.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>border radius properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top-left', 'top-right', 'bottom-left', 'bottom-right']) {
+ // Computed value is always a pair of values, which are not supported in
+ // Typed OM level 1.
+ runPropertyTests('border-' + suffix + '-radius', [
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unsupported(result)
+ },
+ ]);
+}
+
+// shorthand
+runUnsupportedPropertyTests('border-radius', [
+ '30px', '25% 10%', '10% / 50%', '50% 20% / 10% 40%'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-style.html
new file mode 100644
index 0000000000..1328ab1dc7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-style.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>border style properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('border-' + suffix + '-style', [
+ { syntax: 'none' },
+ { syntax: 'solid' },
+ // and other keywords
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-width.html
new file mode 100644
index 0000000000..5066637f73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/border-width.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>border width properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_zero_px(result) {
+ assert_style_value_equals(result, new CSSUnitValue(0, 'px'));
+}
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('border-' + suffix + '-width', [
+ // Computed value is 0 when border-style is 'none'.
+ // FIXME: Add separate test where border-style is not 'none' or 'hidden'.
+ {
+ syntax: 'thin',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'medium',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'thick',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/bottom.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/bottom.html
new file mode 100644
index 0000000000..36fe5145d4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/bottom.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'bottom' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('bottom', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-shadow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-shadow.html
new file mode 100644
index 0000000000..040e992fea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-shadow.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'box-shadow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('box-shadow', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('box-shadow', [
+ '10px 5px 5px red',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-sizing.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-sizing.html
new file mode 100644
index 0000000000..551adbfe4f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/box-sizing.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'box-sizing' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('box-sizing', [
+ { syntax: 'content-box'},
+ { syntax: 'border-box' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/break.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/break.html
new file mode 100644
index 0000000000..66d24beab0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/break.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'break' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['after', 'before']) {
+ runPropertyTests('break-' + suffix, [
+ { syntax: 'auto' },
+ { syntax: 'avoid' },
+ { syntax: 'avoid-column' },
+ { syntax: 'avoid-page' },
+ { syntax: 'avoid-region' },
+ { syntax: 'column' },
+ { syntax: 'left' },
+ { syntax: 'page' },
+ { syntax: 'recto' },
+ { syntax: 'region' },
+ { syntax: 'right' },
+ { syntax: 'verso' },
+ ]);
+}
+
+runPropertyTests('break-inside', [
+ { syntax: 'auto' },
+ { syntax: 'avoid' },
+ { syntax: 'avoid-column' },
+ { syntax: 'avoid-page' },
+ { syntax: 'avoid-region' },
+ ]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caption-side.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caption-side.html
new file mode 100644
index 0000000000..9ae512d2df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caption-side.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'caption-side' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('caption-side', [
+ { syntax: 'top' },
+ { syntax: 'bottom' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caret-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caret-color.html
new file mode 100644
index 0000000000..5ea78a08d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/caret-color.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'caret-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('caret-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ },
+ {
+ syntax: 'auto',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('caret-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/center-coordinate.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/center-coordinate.html
new file mode 100644
index 0000000000..97722ec3d5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/center-coordinate.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'center-coordinate' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('cx', [
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+runPropertyTests('cy', [
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clear.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clear.html
new file mode 100644
index 0000000000..3852dd2542
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clear.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'clear' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('clear', [
+ { syntax: 'none' },
+ { syntax: 'left' },
+ { syntax: 'right' },
+ { syntax: 'both' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-path.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-path.html
new file mode 100644
index 0000000000..d0c7d0ab9a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-path.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'clip-path' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('clip-path', [
+ { syntax: 'none' },
+ { syntax: 'fill-box' },
+ { syntax: 'stroke-box' },
+ { syntax: 'view-box' },
+ { syntax: 'margin-box' },
+ { syntax: 'border-box' },
+ { syntax: 'padding-box' },
+ { syntax: 'content-box' },
+ { syntax: '<url>' },
+]);
+
+runUnsupportedPropertyTests('clip', [
+ 'inset(22% 12% 15px 35px)',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-rule.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-rule.html
new file mode 100644
index 0000000000..9e1c401dc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip-rule.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'clip-rule' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('clip-rule', [
+ { syntax: 'nonzero' },
+ { syntax: 'evenodd' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip.html
new file mode 100644
index 0000000000..fa08eb86ab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/clip.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'clip' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('clip', [
+ { syntax: 'auto' }
+]);
+
+runUnsupportedPropertyTests('clip', [
+ 'rect(0px, 1px, 2px, 3px)'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color-interpolation.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color-interpolation.html
new file mode 100644
index 0000000000..d8324db22e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color-interpolation.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'color-interpolation' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('color-interpolation', [
+ { syntax: 'auto' },
+ { syntax: 'srgb' },
+ { syntax: 'linearrgb' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color.html
new file mode 100644
index 0000000000..f56182977c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-count.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-count.html
new file mode 100644
index 0000000000..9dfca6177b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-count.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-count' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-count', [
+ { syntax: 'auto' },
+ // FIXME: This should say <integer>, but the test harness currently
+ // doesn't support <integer> data type.
+ {
+ syntax: '<number>',
+ // column-count needs to be a positive integer
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && (!Number.isInteger(input.value) || input.value < 1))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (number < 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(Math.round(number.value), 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-color.html
new file mode 100644
index 0000000000..3d35b856d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-rule-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-rule-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('column-rule-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html
new file mode 100644
index 0000000000..8e56f62171
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-style.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-rule-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-rule-style', [
+ { syntax: 'none' },
+ { syntax: 'hidden' },
+ { syntax: 'dotted' },
+ { syntax: 'dashed' },
+ { syntax: 'solid' },
+ { syntax: 'double' },
+ { syntax: 'groove' },
+ { syntax: 'ridge' },
+ { syntax: 'inset' },
+ { syntax: 'outset' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html
new file mode 100644
index 0000000000..bd3c0ac8f4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-rule-width.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-rule-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_zero_px(result) {
+ assert_style_value_equals(result, new CSSUnitValue(0, 'px'));
+}
+
+runPropertyTests('column-rule-width', [
+ // Computed value is 0 when column-rule-style is 'none'.
+ // FIXME: Add separate test where column-rule-style is not 'none' or 'hidden'.
+ {
+ syntax: 'thin',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'medium',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'thick',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-span.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-span.html
new file mode 100644
index 0000000000..28087a1cdd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-span.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-span' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymapreadonly-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#reify-stylevalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-span', [
+ { syntax: 'none' },
+ { syntax: 'all' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-width.html
new file mode 100644
index 0000000000..97a00ffdc1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/column-width.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'column-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymapreadonly-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#reify-stylevalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('column-width', [
+ { syntax: 'auto' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/contain.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/contain.html
new file mode 100644
index 0000000000..f3f50f8143
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/contain.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'contain' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('contain', [
+ { syntax: 'none' },
+ { syntax: 'strict' },
+ { syntax: 'content' },
+ { syntax: 'size' },
+ { syntax: 'layout' },
+ { syntax: 'style' },
+ { syntax: 'paint' },
+ { syntax: 'inline-size' },
+]);
+
+runUnsupportedPropertyTests('contain', [
+ 'size layout', 'paint style layout size'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-name.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-name.html
new file mode 100644
index 0000000000..45d9cbcb8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-name.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'contain' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('container-name', [
+ { syntax: 'none' },
+ // FIXME: This should be <custom-ident>, but the test harness doesn't
+ // currently support it.
+ { syntax: 'my-container' },
+]);
+
+runUnsupportedPropertyTests('container-type', [
+ 'name1 name2'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-type.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-type.html
new file mode 100644
index 0000000000..23474abff4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/container-type.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'container-type' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#the-stylepropertymap">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('container-type', [
+ { syntax: 'normal' },
+ { syntax: 'size' },
+ { syntax: 'inline-size' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/coordinate.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/coordinate.html
new file mode 100644
index 0000000000..31ccbfa9b9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/coordinate.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'coordinate' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('x', [
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+runPropertyTests('y', [
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-increment.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-increment.html
new file mode 100644
index 0000000000..0dba6374fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-increment.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'counter-increment' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('counter-increment', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('counter-increment', [
+ 'chapter', 'chapter 3'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-reset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-reset.html
new file mode 100644
index 0000000000..5323f18902
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-reset.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'counter-reset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('counter-reset', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('counter-reset', [
+ 'chapter', 'chapter 3'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-set.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-set.html
new file mode 100644
index 0000000000..db57f269de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/counter-set.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'counter-set' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('counter-set', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('counter-set', [
+ 'chapter', 'chapter 3'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/cursor.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/cursor.html
new file mode 100644
index 0000000000..7465b1a74a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/cursor.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'cursor' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('cursor', [
+ { syntax: 'auto' },
+ { syntax: 'default' },
+ { syntax: 'none' },
+ { syntax: 'context-menu' },
+ { syntax: 'help' },
+ { syntax: 'pointer' },
+ { syntax: 'progress' },
+ { syntax: 'wait' },
+ { syntax: 'cell' },
+ { syntax: 'crosshair' },
+ { syntax: 'text' },
+ { syntax: 'vertical-text' },
+ { syntax: 'alias' },
+ { syntax: 'copy' },
+ { syntax: 'move' },
+ { syntax: 'no-drop' },
+ { syntax: 'not-allowed' },
+ { syntax: 'grab' },
+ { syntax: 'grabbing' },
+ { syntax: 'e-resize' },
+ { syntax: 'n-resize' },
+ { syntax: 'ne-resize' },
+ { syntax: 'nw-resize' },
+ { syntax: 's-resize' },
+ { syntax: 'se-resize' },
+ { syntax: 'sw-resize' },
+ { syntax: 'w-resize' },
+ { syntax: 'ew-resize' },
+ { syntax: 'ns-resize' },
+ { syntax: 'nesw-resize' },
+ { syntax: 'nwse-resize' },
+ { syntax: 'col-resize' },
+ { syntax: 'row-resize' },
+ { syntax: 'all-scroll' },
+ { syntax: 'zoom-in' },
+ { syntax: 'zoom-out' }
+]);
+
+runUnsupportedPropertyTests('cursor', [
+ 'url(hand.cur), pointer', 'url(cursor1.png) 4 12, auto'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/d.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/d.html
new file mode 100644
index 0000000000..b73daa5067
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/d.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'d' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('d', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('d', [
+ 'path("M 100 100 L 300 100 L 200 300 Z")'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/direction.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/direction.html
new file mode 100644
index 0000000000..0681032a85
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/direction.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'direction' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('direction', [
+ { syntax: 'ltr' },
+ { syntax: 'rtl' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/display.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/display.html
new file mode 100644
index 0000000000..b650431d84
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/display.html
@@ -0,0 +1,59 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'display' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('display', [
+ { syntax: 'none' },
+ { syntax: 'block' },
+ { syntax: 'inline' },
+ { syntax: 'flow-root' },
+ { syntax: 'table' },
+ { syntax: 'flex' },
+ { syntax: 'grid' },
+ { syntax: 'list-item' },
+ { syntax: 'table-row-group' },
+ { syntax: 'table-header-group' },
+ { syntax: 'table-footer-group' },
+ { syntax: 'table-row' },
+ { syntax: 'table-cell' },
+ { syntax: 'table-column-group' },
+ { syntax: 'table-column' },
+ { syntax: 'table-caption' },
+ { syntax: 'contents' },
+ { syntax: 'inline-block' },
+ { syntax: 'inline-table' },
+ { syntax: 'inline-flex' },
+ { syntax: 'inline-grid' },
+]);
+
+// We can not set 'inline math' or 'math inline' via Typed OM.
+// On the other hand, we might get a CSSKeywordValue instance for them instead
+// of a CSSStyleValue because they can be represented as just 'math' in
+// internal representations.
+for (let value of ['inline math', 'math inline']) {
+ test(t => {
+ let element = createDivWithStyle(t);
+ element.style.display = value;
+ const result = element.attributeStyleMap.get('display');
+ assert_not_equals(result, null);
+ assert_in_array({}.toString.call(result),
+ ['[object CSSStyleValue]', '[object CSSKeywordValue]']);
+ }, `'display' does not support setting '${value}'`);
+}
+
+runUnsupportedPropertyTests('display', [
+ 'block math', 'math block'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/dominant-baseline.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/dominant-baseline.html
new file mode 100644
index 0000000000..9774ea2f48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/dominant-baseline.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'dominant-baseline' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('dominant-baseline', [
+ { syntax: 'auto' },
+ { syntax: 'text-bottom' },
+ { syntax: 'alphabetic' },
+ { syntax: 'ideographic' },
+ { syntax: 'middle' },
+ { syntax: 'central' },
+ { syntax: 'mathematical' },
+ { syntax: 'hanging' },
+ { syntax: 'text-top' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/empty-cells.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/empty-cells.html
new file mode 100644
index 0000000000..f05c09c195
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/empty-cells.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'empty-cells' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('empty-cells', [
+ { syntax: 'show' },
+ { syntax: 'hide' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-color.html
new file mode 100644
index 0000000000..5967f496ed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'fill-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('fill-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('fill-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-opacity.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-opacity.html
new file mode 100644
index 0000000000..2ba58f6400
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-opacity.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'fill-opacity' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const number = input.to('percent');
+ const value = number.value / 100.;
+
+ if (value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(value, 'number'));
+}
+
+runPropertyTests('fill-opacity', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping_number
+ },
+ {
+ syntax: '<percentage>',
+ computed: assert_is_equal_with_clamping_percentage
+ }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-rule.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-rule.html
new file mode 100644
index 0000000000..30d5ea912b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill-rule.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'fill-rule' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('fill-rule', [
+ { syntax: 'nonzero' },
+ { syntax: 'evenodd' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill.html
new file mode 100644
index 0000000000..28b3c55647
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/fill.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'fill' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('fill', [
+ 'black',
+ 'red gray',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/filter.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/filter.html
new file mode 100644
index 0000000000..62ddeff008
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/filter.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'filter' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('filter', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('filter', [
+ 'blur(2px)',
+ 'url(filters.svg) blur(4px) saturate(150%)',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-basis.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-basis.html
new file mode 100644
index 0000000000..de0d62ee6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-basis.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-basis' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('flex-basis', [
+ { syntax: 'auto' },
+ { syntax: 'content' },
+ { syntax: 'fit-content' },
+ { syntax: 'min-content' },
+ { syntax: 'max-content' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-direction.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-direction.html
new file mode 100644
index 0000000000..49b7a98331
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-direction.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-direction' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('flex-direction', [
+ { syntax: 'row' },
+ { syntax: 'row-reverse' },
+ { syntax: 'column' },
+ { syntax: 'column-reverse' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-flow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-flow.html
new file mode 100644
index 0000000000..3d6b46f262
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-flow.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-flow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('flex-flow', [
+ 'row', 'column wrap', 'row-reverse wrap-reverse'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-grow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-grow.html
new file mode 100644
index 0000000000..bee9e56eab
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-grow.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-grow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else
+ assert_style_value_equals(result, number);
+}
+
+runPropertyTests('flex-grow', [
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_number
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html
new file mode 100644
index 0000000000..3992fa4749
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-shrink.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-shrink' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else
+ assert_style_value_equals(result, number);
+}
+
+runPropertyTests('flex-shrink', [
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_number
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html
new file mode 100644
index 0000000000..56d14f64cf
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex-wrap.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex-wrap' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('flex-wrap', [
+ { syntax: 'nowrap' },
+ { syntax: 'wrap' },
+ { syntax: 'wrap-reverse' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex.html
new file mode 100644
index 0000000000..99a3e1219d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flex.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flex' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('flex', [
+ 'auto', '2', '1 30px', '2 2 10%'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/float.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/float.html
new file mode 100644
index 0000000000..569bae3439
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/float.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'float' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('float', [
+ { syntax: 'left' },
+ { syntax: 'right' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-color.html
new file mode 100644
index 0000000000..bb3ddc9fc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flood-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('flood-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('flood-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-opacity.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-opacity.html
new file mode 100644
index 0000000000..8a8275131e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/flood-opacity.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'flood-opacity' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const number = input.to('percent');
+ const value = number.value / 100.;
+
+ if (value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(value, 'number'));
+}
+
+runPropertyTests('flood-opacity', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping_number
+ },
+ {
+ syntax: '<percentage>',
+ computed: assert_is_equal_with_clamping_percentage
+ }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-family.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-family.html
new file mode 100644
index 0000000000..eb35ef1799
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-family.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-family' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+// FIXME: font-family is list-valued. Run list-valued tests here too.
+runUnsupportedPropertyTests('font-family', [
+ 'Georgia',
+ '"Gill Sans"',
+ 'sans-serif',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-feature-settings.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-feature-settings.html
new file mode 100644
index 0000000000..4edf7064f9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-feature-settings.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-feature-settings' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-feature-settings', [
+ { syntax: 'normal' }
+]);
+
+runUnsupportedPropertyTests('font-feature-settings', [
+ '"dlig" 1',
+ '"smcp" on',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-kerning.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-kerning.html
new file mode 100644
index 0000000000..4eea684892
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-kerning.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-kerning' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-kerning', [
+ { syntax: 'auto' },
+ { syntax: 'normal' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-language-override.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-language-override.html
new file mode 100644
index 0000000000..daf380389e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-language-override.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-language-override' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-language-override', [
+ { syntax: 'normal' },
+]);
+
+runUnsupportedPropertyTests('font-language-override', [
+ '"SRB"',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-optical-sizing.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-optical-sizing.html
new file mode 100644
index 0000000000..0018ef1390
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-optical-sizing.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-optical-sizing' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-optical-sizing', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-palette.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-palette.html
new file mode 100644
index 0000000000..ad62945f6b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-palette.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-palette' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-palette', [
+ { syntax: 'normal' },
+ { syntax: 'light' },
+ { syntax: 'dark' },
+]);
+
+runUnsupportedPropertyTests('font-palette', [
+ 'Augusta'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-presentation.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-presentation.html
new file mode 100644
index 0000000000..44484660d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-presentation.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-presentation' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-presentation', [
+ { syntax: 'auto' },
+ { syntax: 'text' },
+ { syntax: 'emoji' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size-adjust.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size-adjust.html
new file mode 100644
index 0000000000..be065987ce
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size-adjust.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-size-adjust' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else
+ assert_style_value_equals(result, number);
+}
+
+runPropertyTests('font-size-adjust', [
+ { syntax: 'none' },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_number
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size.html
new file mode 100644
index 0000000000..fc76e0f876
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-size.html
@@ -0,0 +1,72 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-size' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const property of ['font-size', 'font-min-size', 'font-max-size']) {
+ // font-max-size also supports 'infinity' keyword
+ const infinity = property === 'font-max-size' ?
+ [{ syntax: 'infinity'}] : [];
+
+ runPropertyTests(property, [
+ ...infinity,
+ {
+ syntax: 'xx-small',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'x-small',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'small',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'medium',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'large',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'x-large',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'xx-large',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'larger',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: 'smaller',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-stretch.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-stretch.html
new file mode 100644
index 0000000000..40cffaf044
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-stretch.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-stretch' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('font-stretch', [
+ { syntax: 'normal' },
+ { syntax: 'ultra-condensed' },
+ { syntax: 'extra-condensed' },
+ { syntax: 'condensed' },
+ { syntax: 'semi-condensed' },
+ { syntax: 'semi-expanded' },
+ { syntax: 'expanded' },
+ { syntax: 'extra-expanded' },
+ { syntax: 'ultra-expanded' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-style.html
new file mode 100644
index 0000000000..c361e21f42
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-style.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-style', [
+ { syntax: 'normal' },
+ { syntax: 'italic' },
+ { syntax: 'oblique' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-synthesis.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-synthesis.html
new file mode 100644
index 0000000000..0bcce9bd21
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-synthesis.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-synthesis' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+ for (const suffix of ['weight', 'style', 'small-caps']) {
+ runPropertyTests('font-synthesis-' + suffix, [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+ ]);
+}
+
+runUnsupportedPropertyTests('font-synthesis', [
+ 'weight style', 'style small-caps', 'small-caps weight style'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-alternates.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-alternates.html
new file mode 100644
index 0000000000..521eb3a68a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-alternates.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant-alternates' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-alternates', [
+ { syntax: 'normal' },
+ { syntax: 'historical-forms' },
+]);
+
+runUnsupportedPropertyTests('font-variant-alternates', [
+ 'stylistic(foo)',
+ 'styleset(foo)',
+ 'character-variant(foo)',
+ 'swash(foo)',
+ 'ornaments(foo)',
+ 'annotation(foo)',
+ 'swash(foo) annotation(foo2)',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-caps.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-caps.html
new file mode 100644
index 0000000000..6a84bbd6fb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-caps.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant-caps' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-caps', [
+ { syntax: 'normal' },
+ { syntax: 'small-caps' },
+ { syntax: 'all-small-caps' },
+ { syntax: 'petite-caps' },
+ { syntax: 'all-petite-caps' },
+ { syntax: 'unicase' },
+ { syntax: 'titling-caps' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-east-asian.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-east-asian.html
new file mode 100644
index 0000000000..018624e4e4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-east-asian.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant-east-asian' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-east-asian', [
+ { syntax: 'normal' },
+ { syntax: 'jis78' },
+ { syntax: 'jis83' },
+ { syntax: 'jis90' },
+ { syntax: 'jis04' },
+ { syntax: 'simplified' },
+ { syntax: 'traditional' },
+ { syntax: 'full-width' },
+ { syntax: 'proportional-width' },
+ { syntax: 'ruby' },
+]);
+
+runUnsupportedPropertyTests('font-variant-east-asian', [
+ 'jis78 full-width',
+ 'traditional proportional-width ruby',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-emoji.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-emoji.html
new file mode 100644
index 0000000000..9433263fd9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-emoji.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant-emoji' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-emoji', [
+ { syntax: 'normal' },
+ { syntax: 'text' },
+ { syntax: 'emoji' },
+ { syntax: 'unicode' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-ligatures.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-ligatures.html
new file mode 100644
index 0000000000..c640dc219b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-ligatures.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant-ligatures' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-ligatures', [
+ { syntax: 'normal' },
+ { syntax: 'none' },
+ { syntax: 'common-ligatures' },
+ { syntax: 'no-common-ligatures' },
+ { syntax: 'discretionary-ligatures' },
+ { syntax: 'no-discretionary-ligatures' },
+ { syntax: 'historical-ligatures' },
+ { syntax: 'no-historical-ligatures' },
+ { syntax: 'contextual' },
+ { syntax: 'no-contextual' },
+]);
+
+runUnsupportedPropertyTests('font-variant-ligatures', [
+ 'common-ligatures contextual',
+ 'no-common-ligatures discretionary-ligatures no-historical-ligatures no-contextual',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-numeric.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-numeric.html
new file mode 100644
index 0000000000..cbd454da95
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant-numeric.html
@@ -0,0 +1,32 @@
+<meta charset="utf-8">
+<title>'font-variant-numeric' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variant-numeric', [
+ { syntax: 'normal' },
+ { syntax: 'lining-nums' },
+ { syntax: 'oldstyle-nums' },
+ { syntax: 'proportional-nums' },
+ { syntax: 'tabular-nums' },
+ { syntax: 'diagonal-fractions' },
+ { syntax: 'stacked-fractions' },
+ { syntax: 'ordinal' },
+ { syntax: 'slashed-zero' },
+]);
+
+runUnsupportedPropertyTests('font-variant-numeric', [
+ 'lining-nums ordinal',
+ 'oldstyle-nums tabular-nums stacked-fractions ordinal slashed-zero',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant.html
new file mode 100644
index 0000000000..765ce28bd8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variant.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variant' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('font-variant', [
+ 'normal', 'no-common-ligatures proportional-nums',
+ 'common-ligatures tabular-nums', 'small-caps slashed-zero'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variation-settings.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variation-settings.html
new file mode 100644
index 0000000000..12d62618bc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-variation-settings.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-variation-settings' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('font-variation-settings', [
+ { syntax: 'normal' },
+]);
+
+runUnsupportedPropertyTests('font-variation-settings', [
+ '"XHGT" 0.7',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-weight.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-weight.html
new file mode 100644
index 0000000000..7230cfb721
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font-weight.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font-weight' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_font_weight(weight, result) {
+ assert_style_value_equals(result, new CSSUnitValue(weight, 'number'));
+}
+
+runPropertyTests('font-weight', [
+ {
+ syntax: 'normal',
+ computed: (_, result) => assert_is_font_weight(400, result)
+ },
+ {
+ syntax: 'bold',
+ computed: (_, result) => assert_is_font_weight(700, result)
+ },
+ {
+ syntax: 'bolder',
+ computed: (_, result) => assert_is_unit('number', result)
+ },
+ {
+ syntax: 'lighter',
+ computed: (_, result) => assert_is_unit('number', result)
+ },
+ {
+ syntax: '<number>',
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue &&
+ (input.value < 1 || input.value > 1000))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ }
+ },
+]);
+
+</script>
+
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font.html
new file mode 100644
index 0000000000..b8a1e88a27
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/font.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'font' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('font', [
+ '1.2em "Fira Sans", sans-serif',
+ 'italic 1.2em "Fira Sans", serif',
+ 'italic small-caps bold 16px/2 cursive',
+ 'small-caps bold 24px/1 sans-serif',
+ 'caption',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/gap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/gap.html
new file mode 100644
index 0000000000..20ff5816a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/gap.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'*-gap' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymapreadonly-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om/#reify-stylevalue">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+for (const prefix of ['column', 'row']) {
+ runPropertyTests(`${prefix}-gap`, [
+ { syntax: 'normal' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-area.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-area.html
new file mode 100644
index 0000000000..16ac4d517d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-area.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-area' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('grid-area', [
+ 'a', 'a / a', 'auto', 'auto / auto', '2 / 1 / 2',
+ 'span 3', '2 span / a span'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-columns-rows.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-columns-rows.html
new file mode 100644
index 0000000000..37fb103ba3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-columns-rows.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-auto-columns' and 'grid-auto-rows' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+// grid-auto-columns/rows are list-valued.
+// Run list-valued tests here too.
+for (const suffix of ['columns', 'rows']) {
+ runPropertyTests(`grid-auto-${suffix}`, [
+ { syntax: 'min-content' },
+ { syntax: 'max-content' },
+ { syntax: 'auto' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ { syntax: '<flex>' },
+ ]);
+
+ runUnsupportedPropertyTests(`grid-auto-${suffix}`, [
+ 'minmax(100px, auto)', 'fit-content(400px)'
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-flow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-flow.html
new file mode 100644
index 0000000000..d01d0257b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-auto-flow.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-auto-flow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('grid-auto-flow', [
+ { syntax: 'row' },
+ { syntax: 'column' },
+]);
+
+runUnsupportedPropertyTests('grid-auto-flow', [
+ 'column dense',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-gap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-gap.html
new file mode 100644
index 0000000000..c4a41acf59
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-gap.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-gap' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('grid-gap', [
+ '20px', '16%', '20px 10px', '15% 100%', '21px 82%'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-start-end.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-start-end.html
new file mode 100644
index 0000000000..baa48cfb70
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-start-end.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-{row/column}-{start/end}' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const orientation of ['row', 'column']) {
+ for (const suffix of ['start', 'end']) {
+ runPropertyTests(`grid-${orientation}-${suffix}`, [
+ { syntax: 'auto' },
+ ]);
+
+ runUnsupportedPropertyTests(`grid-${orientation}-${suffix}`, [
+ '3', 'span 2', '5 somegridarea span'
+ ]);
+ }
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-areas.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-areas.html
new file mode 100644
index 0000000000..d367f8264b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-areas.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-template-areas' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('grid-template-areas', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('grid-template-areas', [
+ '"a a a"', '"a a a" "b b b"',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-columns-rows.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-columns-rows.html
new file mode 100644
index 0000000000..5a37d2befb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template-columns-rows.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-template-columns' and 'grid-template-rows' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+for (const suffix of ['columns', 'rows']) {
+ runPropertyTests(`grid-template-${suffix}`, [
+ { syntax: 'none' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<flex>',
+ specified: assert_is_equal_with_range_handling
+ }
+ ]);
+
+ runUnsupportedPropertyTests(`grid-template-${suffix}`, [
+ '[linename1] 100px [linename2 linename3]',
+ '200px repeat(auto-fill, 100px) 300px'
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template.html
new file mode 100644
index 0000000000..669b1bd92e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid-template.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid-template' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('grid-template', [
+ 'none', '100px 1fr / 50px 1fr', '[linename] 100px / [columnname1] 30% [columname2] 70%',
+ 'fit-content(100px) / fit-content(40%)', '"a a a" "b b b"',
+ '[header-top] "a a a" [header-bottom] [main-top] "b b b" 1fr [main-bottom] / auto 1fr auto'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid.html
new file mode 100644
index 0000000000..e6e5148e9e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/grid.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'grid' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('grid', [
+ 'auto-flow / 1fr 1fr 1fr', 'auto-flow dense / 40px 40px 1fr',
+ 'repeat(3, 80px) / auto-flow'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/height.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/height.html
new file mode 100644
index 0000000000..51a520c7ff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/height.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'height' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('height', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('min-height', [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('max-height', [
+ { syntax: 'none' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/hyphens.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/hyphens.html
new file mode 100644
index 0000000000..cbbcd0c93f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/hyphens.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'hyphens' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('hyphens', [
+ { syntax: 'none' },
+ { syntax: 'manual' },
+ { syntax: 'auto' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/image-rendering.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/image-rendering.html
new file mode 100644
index 0000000000..c96aa9b370
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/image-rendering.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'image-rendering' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('image-rendering', [
+ { syntax: 'auto' },
+ { syntax: 'smooth' },
+ { syntax: 'high-quality' },
+ { syntax: 'crisp-edges' },
+ { syntax: 'pixelated' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/inline-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/inline-size.html
new file mode 100644
index 0000000000..ba3b07d411
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/inline-size.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'inline-size' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('inline-size', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('min-inline-size', [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('max-inline-size', [
+ { syntax: 'none' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/isolation.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/isolation.html
new file mode 100644
index 0000000000..85f5749f94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/isolation.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'isolation' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('isolation', [
+ { syntax: 'auto' },
+ { syntax: 'isolate' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/left.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/left.html
new file mode 100644
index 0000000000..6e82d2eeb7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/left.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'left' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('left', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/letter-spacing.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/letter-spacing.html
new file mode 100644
index 0000000000..9d313c1395
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/letter-spacing.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'letter-spacing' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_zero_special_handling(input, result) {
+ let is_zero_length = true;
+ if (input instanceof CSSMathSum) {
+ for (let operand of input.values)
+ is_zero_length &&= (operand.value == 0);
+ } else
+ is_zero_length = input.value == 0;
+
+ // Per the specification, a computed letter-spacing of zero yields a resolved value (getComputedStyle()
+ // return value) of normal.
+ if (is_zero_length)
+ assert_style_value_equals(result, new CSSKeywordValue("normal"));
+ else
+ assert_is_unit('px', result); // Same check as in testsuite.js
+}
+
+runPropertyTests('letter-spacing', [
+ { syntax: 'normal' },
+ {
+ syntax: '<length>',
+ computed: assert_is_equal_with_zero_special_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/lighting-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/lighting-color.html
new file mode 100644
index 0000000000..aec1643372
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/lighting-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'lighting-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('lighting-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('lighting-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-break.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-break.html
new file mode 100644
index 0000000000..481a9e97fe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-break.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'line-break' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('line-break', [
+ { syntax: 'auto' },
+ { syntax: 'loose' },
+ { syntax: 'normal' },
+ { syntax: 'strict' },
+ { syntax: 'anywhere' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-height.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-height.html
new file mode 100644
index 0000000000..c09c404617
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/line-height.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'line-height' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('line-height', [
+ { syntax: 'normal' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('number', result)
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-image.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-image.html
new file mode 100644
index 0000000000..a7f8850972
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-image.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'list-style-image' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('list-style-image', [
+ { syntax: 'none' },
+ { syntax: '<image>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-position.html
new file mode 100644
index 0000000000..3c6724fcb6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-position.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'list-style-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('list-style-position', [
+ { syntax: 'inside' },
+ { syntax: 'outside' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-type.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-type.html
new file mode 100644
index 0000000000..61e75407b3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/list-style-type.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'list-style-type' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('list-style-type', [
+ { syntax: 'none' },
+ // FIXME: This should be <custom-ident>, but the test harness doesn't
+ // currently support it.
+ { syntax: 'custom-ident' },
+]);
+
+runUnsupportedPropertyTests('list-style-type', [
+ '"Note: "', 'symbols("*" "A" "B" "C")'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/logical.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/logical.html
new file mode 100644
index 0000000000..2e451d6aa9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/logical.html
@@ -0,0 +1,105 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>logical margin, inset, padding & border properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+const logical = {
+ axes: ['block', 'inline'],
+ sides: ['block-start', 'block-end', 'inline-start', 'inline-end'],
+ corners: ['start-start', 'start-end', 'end-start', 'end-end'],
+};
+
+for (const side of [...logical.sides, ...logical.axes]) {
+ runPropertyTests('margin-' + side, [
+ // TODO: Test 'auto'
+ { syntax: '<percentage>' },
+ { syntax: '<length>' }
+ ]);
+}
+
+for (const side of [...logical.sides, ...logical.axes]) {
+ runPropertyTests('padding-' + side, [
+ // TODO: Test 'auto'
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ ]);
+}
+
+for (const side of [...logical.sides, ...logical.axes]) {
+ runPropertyTests('inset-' + side, [
+ // TODO: Test 'auto'
+ { syntax: '<percentage>' },
+ { syntax: '<length>' }
+ ]);
+}
+
+// BORDERS
+for (const side of [...logical.sides, ...logical.axes]) {
+ runPropertyTests('border-' + side, [
+ //{ syntax: 'thin solid green' },
+ //{ syntax: 'thin solid' },
+ //{ syntax: 'thick' },
+ { syntax: 'none' },
+ ]);
+
+ runPropertyTests(`border-${side}-width`, [
+ { syntax: 'thin' },
+ { syntax: 'medium' },
+ { syntax: 'thick' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ ]);
+
+ runPropertyTests(`border-${side}-color`, [
+ { syntax: 'currentcolor' },
+ //{ syntax: '<color>' },
+ ]);
+
+ runPropertyTests(`border-${side}-style`, [
+ { syntax: 'none' },
+ { syntax: 'solid' },
+ ]);
+}
+
+// border radius
+for (const side of logical.corners) {
+ runPropertyTests(`border-${side}-radius`, [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ ]);
+}
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/margin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/margin.html
new file mode 100644
index 0000000000..3ad126eaf1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/margin.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>margin properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('margin-' + suffix, [
+ {
+ syntax: 'auto',
+ // Depending on which CSS spec is implemented, the computed value
+ // can be 'auto' or a browser specific value.
+ // FIXME: Figure out how to test this.
+ computed: () => {}
+ },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+ ]);
+}
+
+runPropertyTests('margin', []);
+runUnsupportedPropertyTests('margin',
+ ['1px', '1px 2px 3px 4px']
+);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/marker.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/marker.html
new file mode 100644
index 0000000000..9b264613c8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/marker.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'marker-*' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('marker', [
+ 'none', 'url(#m1)'
+]);
+
+for (const suffix of ['start', 'mid', 'end']) {
+ runPropertyTests(`marker-${suffix}`, [
+ { syntax: 'none' },
+ { syntax: '<url>' },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-image.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-image.html
new file mode 100644
index 0000000000..aa858d2e46
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-image.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'mask-image' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('mask-image', [
+ { syntax: 'none' },
+ { syntax: '<image>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-type.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-type.html
new file mode 100644
index 0000000000..35e81fb81c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask-type.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'mask-type' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('mask-type', [
+ { syntax: 'luminance' },
+ { syntax: 'alpha' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask.html
new file mode 100644
index 0000000000..bfdc4c4fd3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mask.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'mask' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('mask', [
+ 'none', 'url(mask.png)'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mix-blend-mode.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mix-blend-mode.html
new file mode 100644
index 0000000000..5509d87813
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/mix-blend-mode.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'mix-blend-mode' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('mix-blend-mode', [
+ { syntax: 'normal' },
+ { syntax: 'multiply' },
+ { syntax: 'screen' },
+ { syntax: 'overlay' },
+ { syntax: 'darken' },
+ { syntax: 'lighten' },
+ { syntax: 'color-dodge' },
+ { syntax: 'color-burn' },
+ { syntax: 'hard-light' },
+ { syntax: 'soft-light' },
+ { syntax: 'difference' },
+ { syntax: 'exclusion' },
+ { syntax: 'hue' },
+ { syntax: 'saturation' },
+ { syntax: 'color' },
+ { syntax: 'luminosity' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-fit.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-fit.html
new file mode 100644
index 0000000000..1d1ee0afd1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-fit.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'object-fit' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('object-fit', [
+ { syntax: 'fill' },
+ { syntax: 'contain' },
+ { syntax: 'cover' },
+ { syntax: 'none' },
+ { syntax: 'scale-down' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-position.html
new file mode 100644
index 0000000000..0dd30e9015
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/object-position.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'object-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('object-position', [
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-anchor.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-anchor.html
new file mode 100644
index 0000000000..590e9eb776
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-anchor.html
@@ -0,0 +1,20 @@
+<meta charset="utf-8">
+<title>'offset-anchor' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('offset-anchor', [
+ { syntax: 'auto' },
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-distance.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-distance.html
new file mode 100644
index 0000000000..fc4adaff9d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-distance.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'offset-distance' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('offset-distance', [
+ { syntax: '<length>' },
+ { syntax: '<percentage>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-path.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-path.html
new file mode 100644
index 0000000000..1cf1b094bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-path.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'offset-path' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('offset-path', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('offset-path', [
+ 'ray(45deg closest-side)',
+ 'path("M 100 100 L 300 100 L 200 300 Z")',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-position.html
new file mode 100644
index 0000000000..ca36226e76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-position.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'offset-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('offset-position', [
+ { syntax: 'normal' },
+ { syntax: 'auto' },
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-rotate.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-rotate.html
new file mode 100644
index 0000000000..c91e27c13c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset-rotate.html
@@ -0,0 +1,26 @@
+<meta charset="utf-8">
+<title>'offset-rotate' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('offset-rotate', [
+ { syntax: 'auto' },
+ { syntax: 'reverse' },
+ { syntax: '<angle>' },
+]);
+
+runUnsupportedPropertyTests('offset-rotate', [
+ 'auto 90deg',
+ 'reverse -90deg',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset.html
new file mode 100644
index 0000000000..5b7e713bec
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/offset.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'offset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('offset', [
+ 'auto', '10px 30px', 'none',
+ 'ray(45deg closest-side)',
+ 'path("M 100 100 L 300 100 L 200 300 z")',
+ 'ray(45deg closest-side) / 40px 20px'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/opacity.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/opacity.html
new file mode 100644
index 0000000000..448040292d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/opacity.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'opacity' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const number = input.to('percent').value / 100.;
+
+ if (number < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number > 1)
+ assert_style_value_equals(result, new CSSUnitValue(100, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(number, 'number'));
+}
+
+runPropertyTests('opacity', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping_number
+ },
+ { syntax: '<percentage>',
+ computed: assert_is_equal_with_clamping_percentage
+ }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/order.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/order.html
new file mode 100644
index 0000000000..35b9d26a39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/order.html
@@ -0,0 +1,35 @@
+<meta charset="utf-8">
+<title>'order' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('order', [
+ {
+ syntax: '<number>',
+ // order needs to be an integer
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && !Number.isInteger(input.value))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(Math.round(number.value), 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/orphans.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/orphans.html
new file mode 100644
index 0000000000..7d7558407a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/orphans.html
@@ -0,0 +1,37 @@
+<meta charset="utf-8">
+<title>'orphans' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('orphans', [
+ {
+ syntax: '<number>',
+ // orphans needs to be a positive integer
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && (!Number.isInteger(input.value) || input.value < 1))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (number < 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(Math.round(number.value), 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-color.html
new file mode 100644
index 0000000000..6bfec87a8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-color.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'outline-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('outline-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+ // FIXME: browsers may or may not support 'invert' keyword.
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('outline-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-offset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-offset.html
new file mode 100644
index 0000000000..f9c0f5643f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-offset.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'outline-offset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('outline-offset', [
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-style.html
new file mode 100644
index 0000000000..2d793f36ae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-style.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'outline-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('outline-style', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+ { syntax: 'dotted' },
+ { syntax: 'dashed' },
+ { syntax: 'solid' },
+ { syntax: 'double' },
+ { syntax: 'groove' },
+ { syntax: 'ridge' },
+ { syntax: 'inset' },
+ { syntax: 'outset' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-width.html
new file mode 100644
index 0000000000..3686741ad1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/outline-width.html
@@ -0,0 +1,41 @@
+<meta charset="utf-8">
+<title>'outline-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_zero_px(result) {
+ assert_style_value_equals(result, new CSSUnitValue(0, 'px'));
+}
+
+runPropertyTests('outline-width', [
+ // Computed value is 0 when outline-style is 'none'.
+ // FIXME: Add separate test where outline-style is not 'none' or 'hidden'.
+ {
+ syntax: 'thin',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'medium',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: 'thick',
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_zero_px(result)
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-anchor.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-anchor.html
new file mode 100644
index 0000000000..f037469fbd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-anchor.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'overflow-anchor' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('overflow-anchor', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-clip-margin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-clip-margin.html
new file mode 100644
index 0000000000..d119641364
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-clip-margin.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'overflow-clip-margin' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('overflow-clip-margin', [
+ 'border-box',
+ 'content-box',
+ 'padding-box',
+ 'padding-box 10px',
+ '10px content-box',
+ '0px',
+ '10px',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-wrap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-wrap.html
new file mode 100644
index 0000000000..0a7bcc7ac3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow-wrap.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'overflow-wrap' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('overflow-wrap', [
+ { syntax: 'normal' },
+ { syntax: 'break-word' },
+ { syntax: 'break-spaces' },
+]);
+
+runUnsupportedPropertyTests('overflow-wrap', [
+ 'break-overflow break-spaces'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow.html
new file mode 100644
index 0000000000..a4692fc178
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overflow.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'overflow' properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['x', 'y']) {
+ runPropertyTests(`overflow-${suffix}`, [
+ { syntax: 'visible' },
+ { syntax: 'hidden' },
+ { syntax: 'clip' },
+ { syntax: 'scroll' },
+ { syntax: 'auto' },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overscroll-behavior.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overscroll-behavior.html
new file mode 100644
index 0000000000..5e440b2595
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/overscroll-behavior.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'overscroll-behavior' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['x', 'y']) {
+ runPropertyTests(`overscroll-behavior-${suffix}`, [
+ { syntax: 'contain' },
+ { syntax: 'none' },
+ { syntax: 'auto' }
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/padding.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/padding.html
new file mode 100644
index 0000000000..9e183f440a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/padding.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>padding properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('padding-' + suffix, [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ ]);
+}
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/page.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/page.html
new file mode 100644
index 0000000000..93255b8a67
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/page.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'page' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('page', [
+ { syntax: 'auto' },
+ // FIXME: This should be <custom-ident>, but the test harness doesn't
+ // currently support it.
+ { syntax: 'custom-ident' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/paint-order.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/paint-order.html
new file mode 100644
index 0000000000..a547a75112
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/paint-order.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'paint-order' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('paint-order', [
+ { syntax: 'normal' },
+ { syntax: 'fill' },
+ { syntax: 'stroke' },
+ { syntax: 'markers' },
+]);
+
+runUnsupportedPropertyTests('paint-order', [
+ 'fill stroke', 'markers fill stroke'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective-origin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective-origin.html
new file mode 100644
index 0000000000..a72f79c503
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective-origin.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'perspective-origin' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('perspective-origin', [
+ { syntax: 'none' },
+ { syntax: '<position>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective.html
new file mode 100644
index 0000000000..d90d9392be
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/perspective.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'perspective' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('perspective', [
+ { syntax: 'none' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/pointer-events.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/pointer-events.html
new file mode 100644
index 0000000000..091e985406
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/pointer-events.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'pointer-events' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('pointer-events', [
+ { syntax: 'bounding-box' },
+ { syntax: 'visiblepainted' },
+ { syntax: 'visiblefill' },
+ { syntax: 'visiblestroke' },
+ { syntax: 'visible' },
+ { syntax: 'painted' },
+ { syntax: 'fill' },
+ { syntax: 'stroke' },
+ { syntax: 'all' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/position.html
new file mode 100644
index 0000000000..4b36ec7bb2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/position.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('position', [
+ { syntax: 'relative' },
+ { syntax: 'absolute' },
+ // and other keywords
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/quotes.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/quotes.html
new file mode 100644
index 0000000000..99e844265d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/quotes.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'quotes' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('quotes', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('quotes', [
+ '"<<" ">>" "<" ">"'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/radius.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/radius.html
new file mode 100644
index 0000000000..a5cea15de0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/radius.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'radius' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('r', [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('rx', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('ry', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resize.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resize.html
new file mode 100644
index 0000000000..c5e0eac70d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resize.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'resize' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('resize', [
+ { syntax: 'none' },
+ { syntax: 'both' },
+ { syntax: 'horizontal' },
+ { syntax: 'vertical' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
new file mode 100644
index 0000000000..cecd72ad92
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/resources/testsuite.js
@@ -0,0 +1,485 @@
+function assert_is_unit(unit, result) {
+ assert_class_string(result, 'CSSUnitValue',
+ 'relative lengths must compute to a CSSUnitValue');
+ assert_equals(result.unit, unit, 'unit');
+}
+
+function assert_is_calc_sum(result) {
+ assert_class_string(result, 'CSSMathSum',
+ 'specified calc must be a CSSMathSum');
+}
+
+function assert_is_equal_with_range_handling(input, result) {
+ if (input instanceof CSSUnitValue && input.value < 0)
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_unsupported(result) {
+ assert_class_string(result, 'CSSStyleValue');
+}
+
+const gCssWideKeywordsExamples = [
+ {
+ description: 'initial keyword',
+ input: new CSSKeywordValue('initial')
+ },
+ {
+ description: 'inherit keyword',
+ input: new CSSKeywordValue('inherit')
+ },
+ {
+ description: 'unset keyword',
+ input: new CSSKeywordValue('unset')
+ },
+ {
+ description: 'revert keyword',
+ input: new CSSKeywordValue('revert')
+ },
+];
+
+const gVarReferenceExamples = [
+ {
+ description: 'a var() reference',
+ input: new CSSUnparsedValue([' ', new CSSVariableReferenceValue('--A')])
+ },
+];
+
+const gTestSyntaxExamples = {
+ '<length>': {
+ description: 'a length',
+ examples: [
+ {
+ description: "zero px",
+ input: new CSSUnitValue(0, 'px')
+ },
+ {
+ description: "a negative em",
+ input: new CSSUnitValue(-3.14, 'em'),
+ // 'ems' are relative units, so just check that it computes to px
+ defaultComputed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ description: "a positive cm",
+ input: new CSSUnitValue(3.14, 'cm'),
+ // 'cms' are relative units, so just check that it computes to px
+ defaultComputed: (_, result) => assert_is_unit('px', result)
+ },
+ {
+ description: "a calc length",
+ input: new CSSMathSum(new CSSUnitValue(0, 'px'), new CSSUnitValue(0, 'em')),
+ // Specified/computed calcs are usually simplified.
+ // FIXME: Test this properly
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => assert_is_unit('px', result)
+ }
+ ],
+ },
+ '<percentage>': {
+ description: 'a percent',
+ examples: [
+ {
+ description: "zero percent",
+ input: new CSSUnitValue(0, 'percent')
+ },
+ {
+ description: "a negative percent",
+ input: new CSSUnitValue(-3.14, 'percent')
+ },
+ {
+ description: "a positive percent",
+ input: new CSSUnitValue(3.14, 'percent')
+ },
+ {
+ description: "a calc percent",
+ input: new CSSMathSum(new CSSUnitValue(0, 'percent'), new CSSUnitValue(0, 'percent')),
+ // Specified/computed calcs are usually simplified.
+ // FIXME: Test this properly
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => assert_is_unit('percent', result)
+ }
+ ],
+ },
+ '<time>': {
+ description: 'a time',
+ examples: [
+ {
+ description: "zero seconds",
+ input: new CSSUnitValue(0, 's')
+ },
+ {
+ description: "negative milliseconds",
+ input: new CSSUnitValue(-3.14, 'ms'),
+ // Computed values use canonical units
+ defaultComputed: (_, result) => assert_style_value_equals(result, new CSSUnitValue(-0.00314, 's'))
+ },
+ {
+ description: "positive seconds",
+ input: new CSSUnitValue(3.14, 's')
+ },
+ {
+ description: "a calc time",
+ input: new CSSMathSum(new CSSUnitValue(0, 's'), new CSSUnitValue(0, 'ms')),
+ // Specified/computed calcs are usually simplified.
+ // FIXME: Test this properly
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => assert_is_unit('s', result)
+ }
+ ],
+ },
+ '<time>': {
+ description: 'a time',
+ examples: [
+ {
+ description: "zero seconds",
+ input: new CSSUnitValue(0, 's')
+ },
+ {
+ description: "negative milliseconds",
+ input: new CSSUnitValue(-3.14, 'ms'),
+ // Computed values use canonical units
+ defaultComputed: (_, result) => assert_style_value_equals(result, new CSSUnitValue(-0.00314, 's'))
+ },
+ {
+ description: "positive seconds",
+ input: new CSSUnitValue(3.14, 's')
+ },
+ {
+ description: "a calc time",
+ input: new CSSMathSum(new CSSUnitValue(0, 's'), new CSSUnitValue(0, 'ms')),
+ specifiedExpected: new CSSMathSum(new CSSUnitValue(0, 's'), new CSSUnitValue(0, 's')),
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => assert_is_unit('s', result)
+ }
+ ],
+ },
+ '<angle>': {
+ description: 'an angle',
+ examples: [
+ {
+ description: "zero degrees",
+ input: new CSSUnitValue(0, 'deg')
+ },
+ {
+ description: "positive radians",
+ input: new CSSUnitValue(3.14, 'rad'),
+ // Computed values use canonical units
+ defaultComputed: (_, result) => assert_style_value_equals(result, new CSSUnitValue(179.908752, 'deg'))
+ },
+ {
+ description: "negative degrees",
+ input: new CSSUnitValue(-3.14, 'deg')
+ },
+ {
+ description: "a calc angle",
+ input: new CSSMathSum(new CSSUnitValue(0, 'rad'), new CSSUnitValue(0, 'deg')),
+ // Specified/computed calcs are usually simplified.
+ // FIXME: Test this properly
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => assert_is_unit('deg', result)
+ }
+ ],
+ },
+ '<flex>': {
+ description: 'a flexible length',
+ examples: [
+ {
+ description: "zero fractions",
+ input: new CSSUnitValue(0, 'fr')
+ },
+ {
+ description: "one fraction",
+ input: new CSSUnitValue(1, 'fr')
+ },
+ // TODO(https://github.com/w3c/css-houdini-drafts/issues/734):
+ // Add calc tests involving 'fr' when that is spec'd in CSS.
+ ],
+ },
+ '<negative-flex>': {
+ description: 'a flexible length',
+ examples: [
+ {
+ description: "negative fraction",
+ input: new CSSUnitValue(-3.14, 'fr')
+ },
+ ],
+ },
+ '<number>': {
+ description: 'a number',
+ examples: [
+ {
+ description: 'the number zero',
+ input: new CSSUnitValue(0, 'number')
+ },
+ {
+ description: 'a negative number',
+ input: new CSSUnitValue(-3.14, 'number')
+ },
+ {
+ description: 'a positive number',
+ input: new CSSUnitValue(3.14, 'number')
+ },
+ {
+ description: "a calc number",
+ input: new CSSMathSum(new CSSUnitValue(2, 'number'), new CSSUnitValue(3, 'number')),
+ defaultSpecified: (_, result) => assert_is_calc_sum(result),
+ defaultComputed: (_, result) => {
+ assert_style_value_equals(result, new CSSUnitValue(5, 'number'));
+ }
+ }
+ ],
+ },
+ '<url>': {
+ description: 'a URL',
+ examples: [
+ // TODO(https://github.com/w3c/css-houdini-drafts/issues/716):
+ // We can't test this until CSSURLValue is spec'd.
+ ],
+ },
+ '<transform>': {
+ description: 'a transform',
+ examples: [
+ {
+ description: 'a transform containing percents',
+ input: new CSSTransformValue([
+ new CSSTranslate(
+ new CSSUnitValue(50, 'percent'),
+ new CSSUnitValue(50, 'percent'),
+ )
+ ]),
+ },
+ {
+ description: 'a transform containing relative values',
+ input: new CSSTransformValue([
+ new CSSPerspective(new CSSUnitValue(10, 'em'))
+ ]),
+ defaultComputed: (_, result) => {
+ // Relative units compute to absolute.
+ assert_class_string(result, 'CSSTransformValue',
+ 'Result must be a CSSTransformValue');
+ assert_class_string(result[0], 'CSSPerspective',
+ 'First component must be a CSSTransformValue');
+ assert_is_unit('px', result[0].length);
+ }
+ },
+ {
+ description: 'a transform containing all the transform components',
+ input: new CSSTransformValue([
+ new CSSTranslate(
+ new CSSUnitValue(0, 'px'),
+ new CSSUnitValue(1, 'px'),
+ new CSSUnitValue(2, 'px'),
+ ),
+ new CSSTranslate(
+ new CSSUnitValue(0, 'px'),
+ new CSSUnitValue(1, 'px'),
+ ),
+ new CSSRotate(1, 2, 3, new CSSUnitValue(45, 'deg')),
+ new CSSRotate(new CSSUnitValue(45, 'deg')),
+ new CSSScale(1, 2, 3),
+ new CSSScale(1, 2),
+ new CSSSkew(new CSSUnitValue(1, 'deg'), new CSSUnitValue(1, 'deg')),
+ new CSSSkewX(new CSSUnitValue(1, 'deg')),
+ new CSSSkewY(new CSSUnitValue(45, 'deg')),
+ new CSSPerspective(new CSSUnitValue(1, 'px')),
+ new CSSMatrixComponent(new DOMMatrixReadOnly(
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
+ ),
+ new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6])),
+ ]),
+ }
+ ],
+ },
+};
+
+// Test setting a value in a style map and then getting it from the inline and
+// computed styles.
+function testPropertyValid(propertyName, examples, specified, computed, description) {
+ for (const example of examples) {
+ test(t => {
+ let element = createDivWithStyle(t);
+
+ element.attributeStyleMap.set(propertyName, example.input);
+
+ // specified style
+ const specifiedResult = element.attributeStyleMap.get(propertyName);
+ assert_not_equals(specifiedResult, null,
+ 'Specified value must not be null');
+ assert_true(specifiedResult instanceof CSSStyleValue,
+ 'Specified value must be a CSSStyleValue');
+
+ if (specified || example.defaultSpecified) {
+ (specified || example.defaultSpecified)(example.specifiedExpected || example.input, specifiedResult);
+ } else {
+ assert_style_value_equals(specifiedResult, example.input,
+ `Setting ${example.description} and getting its specified value`);
+ }
+
+ // computed style
+ const computedResult = element.computedStyleMap().get(propertyName);
+ assert_not_equals(computedResult, null,
+ 'Computed value must not be null');
+ assert_true(computedResult instanceof CSSStyleValue,
+ 'Computed value must be a CSSStyleValue');
+
+ if (computed || example.defaultComputed) {
+ (computed || example.defaultComputed)(example.input, computedResult);
+ } else {
+ assert_style_value_equals(computedResult, example.input,
+ `Setting ${example.description} and getting its computed value`);
+ }
+ }, `Can set '${propertyName}' to ${description}: ${example.input}`);
+ }
+}
+
+// We have to special case CSSImageValue as they cannot be created with a
+// constructor and are completely opaque.
+function testIsImageValidForProperty(propertyName) {
+ test(t => {
+ let element1 = createDivWithStyle(t, `${propertyName}: url("/media/1x1-green.png")`);
+ let element2 = createDivWithStyle(t);
+
+ const result = element1.attributeStyleMap.get(propertyName);
+ assert_not_equals(result, null, 'Image value must not be null');
+ assert_class_string(result, 'CSSImageValue',
+ 'Image value must be a CSSImageValue');
+
+ element2.attributeStyleMap.set(propertyName, result);
+ assert_equals(element2.style[propertyName], element1.style[propertyName],
+ 'Image value can be set on different element');
+ }, `Can set '${propertyName}' to an image`);
+}
+
+// Test that styleMap.set throws for invalid values
+function testPropertyInvalid(propertyName, examples, description) {
+ for (const example of examples) {
+ test(t => {
+ let styleMap = createInlineStyleMap(t);
+ assert_throws_js(TypeError, () => styleMap.set(propertyName, example.input));
+ }, `Setting '${propertyName}' to ${description}: ${example.input} throws TypeError`);
+ }
+}
+
+// Test that styleMap.get/.set roundtrips correctly for unsupported values.
+function testUnsupportedValue(propertyName, cssText) {
+ test(t => {
+ let element1 = createDivWithStyle(t);
+ let element2 = createDivWithStyle(t);
+
+ element1.style[propertyName] = cssText;
+ const result = element1.attributeStyleMap.get(propertyName);
+ assert_not_equals(result, null,
+ 'Unsupported value must not be null');
+ assert_class_string(result, 'CSSStyleValue',
+ 'Unsupported value must be a CSSStyleValue and not one of its subclasses');
+
+ element2.attributeStyleMap.set(propertyName, result);
+ assert_equals(element2.style[propertyName], element1.style[propertyName],
+ 'Unsupported value can be set on different element');
+
+ const resultAll = element2.attributeStyleMap.getAll(propertyName);
+ assert_style_value_equals(resultAll[0], result,
+ `getAll() with single unsupported value returns single-item list ` +
+ `with same result as get()`);
+ }, `'${propertyName}' does not support '${cssText}'`);
+}
+
+function createKeywordExample(keyword) {
+ return {
+ description: `the '${keyword}' keyword`,
+ examples: [ { input: new CSSKeywordValue(keyword) } ]
+ };
+}
+
+// Run a battery of StylePropertyMap tests on |propertyName|.
+// Second argument is a list of test cases. A test case has the form:
+//
+// {
+// syntax: "<length>",
+// specified: /* a callback */ (optional)
+// computed: /* a callback */ (optional)
+// }
+//
+// If a callback is passed to |specified|, then the callback will be passed
+// two arguments:
+// 1. The input test case
+// 2. The result of calling get() on the inline style map (specified values).
+//
+// The callback should check if the result is expected using assert_* functions.
+// If no callback is passed, then we assert that the result is the same as
+// the input.
+//
+// Same goes for |computed|, but with the computed style map (computed values).
+//
+// FIXME: The reason we pass argument #2 is that it's sometimes difficult to
+// compute exactly what the expected result should be (e.g. browser-specific
+// values). Once we can do that, we can remove argument #2 and just return
+// the expected result.
+function runPropertyTests(propertyName, testCases) {
+ let syntaxTested = new Set();
+
+ // Every property should at least support CSS-wide keywords.
+ testPropertyValid(propertyName,
+ gCssWideKeywordsExamples,
+ null, // should be as specified
+ () => {}, // could be anything
+ 'CSS-wide keywords');
+
+ // Every property should support values containing var() references.
+ testPropertyValid(propertyName,
+ gVarReferenceExamples,
+ null, // should be as specified
+ () => {}, // could compute to anything
+ 'var() references');
+
+ for (const testCase of testCases) {
+ // <image> is a special case
+ if (testCase.syntax === '<image>') {
+ testIsImageValidForProperty(propertyName);
+ continue;
+ }
+
+ // Retrieve test examples for this test case's syntax. If the syntax
+ // looks like a keyword, then create an example on the fly.
+ const syntaxExamples = testCase.syntax.toLowerCase().match(/^[a-z0-9\-]+$/) ?
+ createKeywordExample(testCase.syntax) :
+ gTestSyntaxExamples[testCase.syntax];
+
+ if (!syntaxExamples)
+ throw new Error(`'${testCase.syntax}' is not a valid CSS component`);
+
+ testPropertyValid(propertyName,
+ syntaxExamples.examples,
+ testCase.specified,
+ testCase.computed,
+ syntaxExamples.description);
+
+ syntaxTested.add(testCase.syntax);
+ }
+
+ // Also test that styleMap.set rejects invalid CSSStyleValues.
+ for (const [syntax, syntaxExamples] of Object.entries(gTestSyntaxExamples)) {
+ if (!syntaxTested.has(syntax)) {
+ testPropertyInvalid(propertyName,
+ syntaxExamples.examples,
+ syntaxExamples.description);
+ }
+ }
+}
+
+// Same as runPropertyTests but for list-valued properties.
+function runListValuedPropertyTests(propertyName, testCases) {
+ // TODO(https://crbug.com/545318): Run list-valued tests as well.
+ runPropertyTests(propertyName, testCases);
+}
+
+// Check that |propertyName| doesn't "support" examples in |testExamples|.
+// |testExamples| is a list of CSS string values. An "unsupported" value
+// doesn't have a corresponding Typed OM representation. It normalizes as
+// the base CSSStyleValue.
+function runUnsupportedPropertyTests(propertyName, testExamples) {
+ for (const cssText of testExamples) {
+ testUnsupportedValue(propertyName, cssText);
+ }
+}
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/right.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/right.html
new file mode 100644
index 0000000000..17488dfb02
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/right.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'right' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('right', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-behavior.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-behavior.html
new file mode 100644
index 0000000000..83baeb0d26
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-behavior.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scroll-behavior' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scroll-behavior', [
+ { syntax: 'auto' },
+ { syntax: 'smooth' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-margin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-margin.html
new file mode 100644
index 0000000000..8f2cc07593
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-margin.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>scroll-margin related properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('scroll-margin-' + suffix, [
+ { syntax: '<length>' },
+ ]);
+}
+
+for (const suffix of ['inline-start', 'block-start', 'inline-end', 'block-end']) {
+ runPropertyTests('scroll-margin-' + suffix, [
+ { syntax: '<length>' },
+ ]);
+}
+
+runUnsupportedPropertyTests('scroll-margin',
+ ['0px', '1px 2px', '3px 4px 5px', '6px 7px 8px 9px']
+);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-padding.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-padding.html
new file mode 100644
index 0000000000..f4207a0803
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-padding.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>scroll-padding related properties</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+for (const suffix of ['top', 'left', 'right', 'bottom']) {
+ runPropertyTests('scroll-padding-' + suffix, [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ ]);
+}
+
+for (const suffix of ['inline-start', 'block-start', 'inline-end', 'block-end']) {
+ runPropertyTests('scroll-padding-' + suffix, [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ },
+ ]);
+}
+
+runUnsupportedPropertyTests('scroll-padding',
+ ['0%', '1px 2px', '3% 4px 5%', '6px 7% 8% 9px']
+);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-align.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-align.html
new file mode 100644
index 0000000000..fd92a90a0c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-align.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scroll-snap-align' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scroll-snap-align', [
+ {
+ syntax: 'none',
+ computed: assert_is_unsupported
+ },
+ {
+ syntax: 'start',
+ computed: assert_is_unsupported
+ },
+ {
+ syntax: 'end',
+ computed: assert_is_unsupported
+ },
+ {
+ syntax: 'center',
+ computed: assert_is_unsupported
+ },
+]);
+
+runUnsupportedPropertyTests('scroll-snap-align', [
+ 'none center', 'end start'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-stop.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-stop.html
new file mode 100644
index 0000000000..959a240a4f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-stop.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scroll-snap-stop' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scroll-snap-stop', [
+ { syntax: 'normal' },
+ { syntax: 'always' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type.html
new file mode 100644
index 0000000000..4f9c4a46b6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scroll-snap-type' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scroll-snap-type', [
+ { syntax: 'none' },
+ { syntax: 'x' },
+ { syntax: 'y' },
+ { syntax: 'block' },
+ { syntax: 'inline' },
+ { syntax: 'both' },
+]);
+
+runUnsupportedPropertyTests('scroll-snap-type', [
+ 'x mandatory', 'inline proximity'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-gutter.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-gutter.html
new file mode 100644
index 0000000000..8bcdf0f288
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-gutter.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scrollbar-gutter' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scrollbar-gutter', [
+ { syntax: 'auto' },
+ { syntax: 'stable' }
+]);
+runUnsupportedPropertyTests('scrollbar-gutter', [
+ 'stable both-edges'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-width.html
new file mode 100644
index 0000000000..19a6ebd5b9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/scrollbar-width.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'scrollbar-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('scrollbar-width', [
+ { syntax: 'auto' },
+ { syntax: 'thin' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-image-threshold.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-image-threshold.html
new file mode 100644
index 0000000000..d16d892c46
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-image-threshold.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'shape-image-threshold' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+runPropertyTests('shape-image-threshold', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-margin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-margin.html
new file mode 100644
index 0000000000..60adc7aff5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-margin.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'shape-margin' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('shape-margin', [
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-outside.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-outside.html
new file mode 100644
index 0000000000..d514c83806
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-outside.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'shape-outside' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('shape-outside', [
+ { syntax: 'none' },
+ { syntax: 'margin-box' },
+ { syntax: 'border-box' },
+ { syntax: 'padding-box' },
+ { syntax: 'content-box' },
+ { syntax: '<image>' },
+]);
+
+// <basic-shape>s are not supported in level 1
+runUnsupportedPropertyTests('shape-outside', [
+ 'inset(22% 12% 15px 35px)',
+ 'circle(6rem at 12rem 6rem)',
+ 'ellipse(115px 55px at 50% 40%)',
+ 'polygon(50% 20%, 90% 80%, 10% 80%)',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-rendering.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-rendering.html
new file mode 100644
index 0000000000..f7cb4199a5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/shape-rendering.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'shape-rendering' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('shape-rendering', [
+ { syntax: 'auto' },
+ { syntax: 'optimizespeed' },
+ { syntax: 'crispedges' },
+ { syntax: 'geometricprecision' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/speak.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/speak.html
new file mode 100644
index 0000000000..33512fe24a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/speak.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'speak' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('speak', [
+ { syntax: 'auto' },
+ { syntax: 'never' },
+ { syntax: 'always' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-color.html
new file mode 100644
index 0000000000..83dcf0218a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stop-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('stop-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('stop-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-opacity.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-opacity.html
new file mode 100644
index 0000000000..9baf40dd0b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stop-opacity.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stop-opacity' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const number = input.to('percent').value / 100.;
+
+ if (number < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(number, 'number'));
+}
+
+runPropertyTests('stop-opacity', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping_number
+ },
+ {
+ syntax: '<percentage>',
+ computed: assert_is_equal_with_clamping_percentage
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dasharray.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dasharray.html
new file mode 100644
index 0000000000..6c3731cc48
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dasharray.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-dasharray' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('stroke-dasharray', [
+ { syntax: 'none' },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling,
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+]);
+
+runUnsupportedPropertyTests('stroke-dasharray', [
+ '5% 1em 2%',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dashoffset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dashoffset.html
new file mode 100644
index 0000000000..f537d8049b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-dashoffset.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-dashoffset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('stroke-dashoffset', [
+ { syntax: '<length>' },
+ { syntax: '<percentage>' },
+ {
+ syntax: '<number>',
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linecap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linecap.html
new file mode 100644
index 0000000000..227b92274d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linecap.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-linecap' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('stroke-linecap', [
+ { syntax: 'butt' },
+ { syntax: 'round' },
+ { syntax: 'square' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linejoin.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linejoin.html
new file mode 100644
index 0000000000..2f01ee7f2a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-linejoin.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-linejoin' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('stroke-linejoin', [
+ { syntax: 'crop' },
+ { syntax: 'arcs' },
+ { syntax: 'miter' },
+ { syntax: 'bevel' },
+ { syntax: 'round' },
+ { syntax: 'stupid' },
+]);
+
+runUnsupportedPropertyTests('stroke-linejoin', [
+ 'crop bevel', 'round arcs'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-miterlimit.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-miterlimit.html
new file mode 100644
index 0000000000..914422c93d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-miterlimit.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-miterlimit' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('stroke-miterlimit', [
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(number.value, 'number'));
+ }
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-opacity.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-opacity.html
new file mode 100644
index 0000000000..94f5cba025
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-opacity.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-opacity' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_number(input, result) {
+ const number = input.to('number');
+
+ if (number.value < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number.value > 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else
+ assert_style_value_equals(result, input);
+}
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const number = input.to('percent').value / 100.;
+
+ if (number < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (number > 1)
+ assert_style_value_equals(result, new CSSUnitValue(100, 'number'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(number, 'number'));
+}
+
+runPropertyTests('stroke-opacity', [
+ {
+ syntax: '<number>',
+ computed: assert_is_equal_with_clamping_number
+ },
+ { syntax: '<percentage>',
+ computed: assert_is_equal_with_clamping_percentage
+ }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-width.html
new file mode 100644
index 0000000000..abe7098a44
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke-width.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke-width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('stroke-width', [
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (input, result) => {
+ const percent = input.to('percent').value;
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+ }
+ },
+ {
+ syntax: '<number>',
+ specified: assert_is_equal_with_range_handling,
+ computed: (_, result) => assert_is_unit('px', result)
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke.html
new file mode 100644
index 0000000000..ff81024a94
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/stroke.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'stroke' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('stroke', [
+ 'black',
+ 'red gray',
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/tab-size.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/tab-size.html
new file mode 100644
index 0000000000..099349e08e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/tab-size.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'tab-size' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('tab-size', [
+ {
+ // tab-size can be a non-negative number
+ syntax: '<number>',
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && (!Number.isInteger(input.value) || input.value < 0))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (number < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'number'));
+ else if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(number.value, 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/table-layout.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/table-layout.html
new file mode 100644
index 0000000000..e58d019958
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/table-layout.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'table-layout' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('table-layout', [
+ { syntax: 'auto' },
+ { syntax: 'fixed' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align-last.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align-last.html
new file mode 100644
index 0000000000..242906fecb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align-last.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-align-last' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-align-last', [
+ { syntax: 'auto' },
+ { syntax: 'start' },
+ { syntax: 'end' },
+ { syntax: 'left' },
+ { syntax: 'right' },
+ { syntax: 'center' },
+ { syntax: 'justify' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align.html
new file mode 100644
index 0000000000..c3d7f2e8e5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-align.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-align' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-align', [
+ { syntax: 'center' },
+ { syntax: 'justify' },
+ // and other keywords
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-anchor.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-anchor.html
new file mode 100644
index 0000000000..00b04aaed6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-anchor.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-anchor' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-anchor', [
+ { syntax: 'start' },
+ { syntax: 'middle' },
+ { syntax: 'end' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-combine-upright.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-combine-upright.html
new file mode 100644
index 0000000000..c0a7f56643
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-combine-upright.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-combine-upright' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-combine-upright', [
+ { syntax: 'none' },
+ { syntax: 'all' },
+]);
+
+runUnsupportedPropertyTests('text-combine-upright', [
+ 'digits 3'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-color.html
new file mode 100644
index 0000000000..b76f82c3ea
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('text-decoration-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-line.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-line.html
new file mode 100644
index 0000000000..dba12630a4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-line.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-line' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-line', [
+ { syntax: 'none' },
+ { syntax: 'underline' },
+ { syntax: 'overline' },
+ { syntax: 'line-through' },
+ { syntax: 'blink' },
+ { syntax: 'spelling-error' },
+ { syntax: 'grammar-error' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip-ink.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip-ink.html
new file mode 100644
index 0000000000..57d445d7cd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip-ink.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-skip-ink' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-skip-ink', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip.html
new file mode 100644
index 0000000000..796b87790d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-skip.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-skip' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-skip', [
+ { syntax: 'none' },
+ { syntax: 'objects' },
+ { syntax: 'edges' },
+ { syntax: 'box-decoration' },
+ { syntax: 'spaces' },
+]);
+
+runUnsupportedPropertyTests('text-decoration-skip', [
+ 'objects spaces', 'leading-spaces trailing-spaces',
+ 'objects edges box-decoration'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html
new file mode 100644
index 0000000000..956c6e578b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-style.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-style', [
+ { syntax: 'solid' },
+ { syntax: 'double' },
+ { syntax: 'dotted' },
+ { syntax: 'dashed' },
+ { syntax: 'wavy' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html
new file mode 100644
index 0000000000..dfd923ae7b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration-thickness.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration-thickness' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-decoration-thickness', [
+ { syntax: 'auto' },
+ {
+ syntax: '<length>',
+ },
+ {
+ syntax: '<percentage>',
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration.html
new file mode 100644
index 0000000000..e9a9827c13
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-decoration.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-decoration' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('text-decoration', [
+ 'underline', 'underline dotted #ff3028', 'green wavy underline'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-emphasis-color.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-emphasis-color.html
new file mode 100644
index 0000000000..8623d3dfb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-emphasis-color.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-emphasis-color' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-emphasis-color', [
+ {
+ syntax: 'currentcolor',
+ // computes to a <color>, which is not supported in level 1
+ computed: (_, result) => assert_class_string(result, 'CSSStyleValue')
+ }
+]);
+
+// <color>s are not supported in level 1
+runUnsupportedPropertyTests('text-emphasis-color', [
+ 'red', '#bbff00', 'rgb(255, 255, 128)', 'hsl(50, 33%, 25%)',
+ 'transparent'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-indent.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-indent.html
new file mode 100644
index 0000000000..e7f1b8c7df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-indent.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-indent' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-indent', [
+ { syntax: '<length>' },
+ { syntax: '<percentage>' },
+]);
+
+runUnsupportedPropertyTests('text-indent', [
+ '5em each-line', '5em hanging', '5em hanging each-line'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-justify.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-justify.html
new file mode 100644
index 0000000000..29f7e60084
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-justify.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-justify' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-justify', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+ { syntax: 'inter-word' },
+ { syntax: 'inter-character' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-orientation.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-orientation.html
new file mode 100644
index 0000000000..8bc74b7b3c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-orientation.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-orientation' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-orientation', [
+ { syntax: 'mixed' },
+ { syntax: 'upright' },
+ { syntax: 'sideways' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow.html
new file mode 100644
index 0000000000..9d4a915985
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-overflow.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-overflow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-overflow', [
+ { syntax: 'clip' },
+ { syntax: 'ellipsis' },
+ { syntax: 'fade' },
+]);
+
+runUnsupportedPropertyTests('text-overflow', [
+ 'clip ellipsis', '"..."', 'fade(1px, 50%)'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-rendering.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-rendering.html
new file mode 100644
index 0000000000..88ef17da0e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-rendering.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-rendering' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-rendering', [
+ { syntax: 'auto' },
+ { syntax: 'optimizespeed' },
+ { syntax: 'optimizelegibility' },
+ { syntax: 'geometricprecision' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-shadow.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-shadow.html
new file mode 100644
index 0000000000..930da94dc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-shadow.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-shadow' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-shadow', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('text-shadow', [
+ '1px 1px 2px pink', '1px 1px 2px red, 0 0 1em blue, 0 0 0.2em blue'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-size-adjust.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-size-adjust.html
new file mode 100644
index 0000000000..29a60cbb30
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-size-adjust.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-size-adjust' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-size-adjust', [
+ { syntax: 'none' },
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-transform.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-transform.html
new file mode 100644
index 0000000000..8f636fad14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-transform.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-transform' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-transform', [
+ { syntax: 'none' },
+ { syntax: 'capitalize' },
+ { syntax: 'uppercase' },
+ { syntax: 'lowercase' },
+ { syntax: 'full-width' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-offset.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-offset.html
new file mode 100644
index 0000000000..0e54ea8f5a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-offset.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-underline-offset' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-underline-offset', [
+ { syntax: 'auto' },
+ { syntax: '<length>' },
+ { syntax: '<percentage>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-position.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-position.html
new file mode 100644
index 0000000000..f648171395
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/text-underline-position.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'text-underline-position' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('text-underline-position', [
+ { syntax: 'auto' },
+ { syntax: 'under' },
+ { syntax: 'left' },
+ { syntax: 'right' },
+]);
+
+runUnsupportedPropertyTests('text-underline-position', [
+ 'under left', 'right under'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/top.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/top.html
new file mode 100644
index 0000000000..f12a76b286
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/top.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'top' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('top', [
+ { syntax: 'auto' },
+ { syntax: '<percentage>' },
+ { syntax: '<length>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/touch-action.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/touch-action.html
new file mode 100644
index 0000000000..2435e347c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/touch-action.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'touch-action' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('touch-action', [
+ { syntax: 'auto' },
+ { syntax: 'none' },
+ { syntax: 'pan-x' },
+ { syntax: 'pan-left' },
+ { syntax: 'pan-right' },
+ { syntax: 'pan-y' },
+ { syntax: 'pan-up' },
+ { syntax: 'pan-down' },
+ { syntax: 'pinch-zoom' },
+ { syntax: 'manipulation' },
+]);
+
+runUnsupportedPropertyTests('touch-action', [
+ 'pan-x pan-down', 'pan-down pinch-zoom pan-right'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-box.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-box.html
new file mode 100644
index 0000000000..a5556b1079
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-box.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transform-box' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('transform-box', [
+ { syntax: 'border-box' },
+ { syntax: 'fill-box' },
+ { syntax: 'view-box' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-interpolated.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-interpolated.html
new file mode 100644
index 0000000000..526717d99d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-interpolated.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transform' property with an interpolated value</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+// TODO: Try to support this sort of test with testsuite.js
+test(t => {
+ let elem = createDivWithStyle(t);
+ elem.animate({
+ transform: ['translate(1px, 1%)', 'rotate(45deg)']
+ }, {
+ fill: 'forwards',
+ iterationStart: 0.5,
+ });
+
+ // TODO: The computed value in this case is not fully spec'd
+ // See https://github.com/w3c/css-houdini-drafts/issues/425
+ const result = elem.computedStyleMap().get('transform');
+ assert_not_equals(result, null);
+}, 'Computed value for interpolated transforms is not null');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-style.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-style.html
new file mode 100644
index 0000000000..2746db578e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform-style.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transform-style' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('transform-style', [
+ { syntax: 'auto' },
+ { syntax: 'flat' },
+ { syntax: 'preserve-3d' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform.html
new file mode 100644
index 0000000000..7a852545a7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transform.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transform' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('transform', [
+ { syntax: 'none' },
+ { syntax: '<transform>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-delay.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-delay.html
new file mode 100644
index 0000000000..1ee47f4738
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-delay.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transition-delay' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('transition-delay', [
+ { syntax: '<time>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html
new file mode 100644
index 0000000000..c0eb09daa7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-duration.html
@@ -0,0 +1,19 @@
+<meta charset="utf-8">
+<title>'transition-duration' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('transition-duration', [
+ { syntax: '<time>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-property.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-property.html
new file mode 100644
index 0000000000..7f0c48a725
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-property.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transition-property' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('transition-property', [
+ { syntax: 'none' },
+]);
+
+runUnsupportedPropertyTests('transition-property', [
+ 'width', 'width, height', 'all'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html
new file mode 100644
index 0000000000..a4dbfc1933
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition-timing-function.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transition-timing-function' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runListValuedPropertyTests('transition-timing-function', [
+ { syntax: 'linear' },
+ { syntax: 'ease' },
+ { syntax: 'ease-in' },
+ { syntax: 'ease-out' },
+ { syntax: 'ease-in-out' },
+ {
+ syntax: 'step-start',
+ computed: (_, result) => {
+ assert_equals(result.toString(), 'steps(1, start)');
+ }
+ },
+ {
+ syntax: 'step-end',
+ computed: (_, result) => {
+ assert_equals(result.toString(), 'steps(1)');
+ }
+ },
+]);
+
+runUnsupportedPropertyTests('transition-timing-function', [
+ 'cubic-bezier(0.1, 0.7, 1.0, 0.1)', 'steps(4, end)'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition.html
new file mode 100644
index 0000000000..1264550bc9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/transition.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'transition' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runUnsupportedPropertyTests('transition', [
+ 'none', 'none, none', 'margin-right 4s', 'all 0.5s ease-out, color 1s'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/unicode-bidi.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/unicode-bidi.html
new file mode 100644
index 0000000000..5ac27c433d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/unicode-bidi.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'unicode-bidi' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('unicode-bidi', [
+ { syntax: 'normal' },
+ { syntax: 'embed' },
+ { syntax: 'isolate' },
+ { syntax: 'bidi-override' },
+ { syntax: 'isolate-override' },
+ { syntax: 'plaintext' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/user-select.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/user-select.html
new file mode 100644
index 0000000000..47ea14de67
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/user-select.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'user-select' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('user-select', [
+ { syntax: 'auto' },
+ { syntax: 'text' },
+ { syntax: 'none' },
+ { syntax: 'contain' },
+ { syntax: 'all' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vector-effect.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vector-effect.html
new file mode 100644
index 0000000000..692709529f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vector-effect.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'vector-effect' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('vector-effect', [
+ { syntax: 'non-scaling-stroke' },
+ { syntax: 'none' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vertical-align.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vertical-align.html
new file mode 100644
index 0000000000..af022fdae5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/vertical-align.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'vertical-align' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('vertical-align', [
+ { syntax: 'baseline'},
+ // and other keywords
+ { syntax: '<length>' },
+ { syntax: '<percentage>' }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/visibility.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/visibility.html
new file mode 100644
index 0000000000..42a020d313
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/visibility.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'visibility' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('visibility', [
+ { syntax: 'visible'},
+ { syntax: 'hidden' },
+ { syntax: 'collapse' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/white-space.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/white-space.html
new file mode 100644
index 0000000000..87fb9efa10
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/white-space.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'white-space' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('white-space-collapse', [
+ { syntax: 'collapse'},
+ { syntax: 'discard' },
+ { syntax: 'preserve' },
+ { syntax: 'preserve-breaks' },
+ { syntax: 'preserve-spaces' },
+ { syntax: 'break-spaces' },
+]);
+
+runPropertyTests('text-wrap-mode', [
+ { syntax: 'wrap'},
+ { syntax: 'nowrap' },
+]);
+
+runPropertyTests('text-wrap-style', [
+ { syntax: 'auto' },
+ { syntax: 'balance' },
+ { syntax: 'stable' },
+ { syntax: 'pretty' },
+]);
+
+runPropertyTests('white-space-trim', [
+ { syntax: 'none'},
+ { syntax: 'discard-before' },
+ { syntax: 'discard-after' },
+ { syntax: 'discard-inner' },
+]);
+
+runUnsupportedPropertyTests('white-space-trim', [
+ 'discard-before discard-after',
+ 'discard-before discard-inner',
+ 'discard-after discard-inner',
+ 'discard-before discard-after discard-inner'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/widows.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/widows.html
new file mode 100644
index 0000000000..7503bffd8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/widows.html
@@ -0,0 +1,37 @@
+<meta charset="utf-8">
+<title>'widows' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('widows', [
+ {
+ syntax: '<number>',
+ // widows needs to be a positive integer
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && (!Number.isInteger(input.value) || input.value < 1))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (number < 1)
+ assert_style_value_equals(result, new CSSUnitValue(1, 'number'));
+ else if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(Math.round(number.value), 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/width.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/width.html
new file mode 100644
index 0000000000..9f15043733
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/width.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'width' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_is_equal_with_clamping_percentage(input, result) {
+ const percent = input.to('percent').value;
+
+ if (percent < 0)
+ assert_style_value_equals(result, new CSSUnitValue(0, 'percent'));
+ else
+ assert_style_value_equals(result, new CSSUnitValue(percent, 'percent'));
+}
+
+runPropertyTests('width', [
+ { syntax: 'auto' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('min-width', [
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+runPropertyTests('max-width', [
+ { syntax: 'none' },
+ {
+ syntax: '<percentage>',
+ specified: assert_is_equal_with_range_handling,
+ computed: assert_is_equal_with_clamping_percentage
+ },
+ {
+ syntax: '<length>',
+ specified: assert_is_equal_with_range_handling
+ },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/will-change.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/will-change.html
new file mode 100644
index 0000000000..2add50c0df
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/will-change.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'will-change' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('will-change', [
+ { syntax: 'auto' },
+]);
+
+runUnsupportedPropertyTests('will-change', [
+ 'scroll-position', 'contents, foo, scroll-position'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-break.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-break.html
new file mode 100644
index 0000000000..12370df886
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-break.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'word-break' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('word-break', [
+ { syntax: 'normal' },
+ { syntax: 'keep-all' },
+ { syntax: 'break-all' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-spacing.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-spacing.html
new file mode 100644
index 0000000000..9a44c96aad
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-spacing.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'word-spacing' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('word-spacing', [
+ { syntax: 'normal' },
+ { syntax: '<length>' },
+ { syntax: '<percentage>' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-wrap.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-wrap.html
new file mode 100644
index 0000000000..b8ec4fc525
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/word-wrap.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'word-wrap' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('word-wrap', [
+ { syntax: 'normal' },
+ { syntax: 'break-word' },
+ { syntax: 'break-spaces' },
+]);
+
+runUnsupportedPropertyTests('word-wrap', [
+ 'break-word break-spaces'
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/writing-mode.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/writing-mode.html
new file mode 100644
index 0000000000..976a0ea22d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/writing-mode.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'writing-mode' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('writing-mode', [
+ { syntax: 'horizontal-tb' },
+ { syntax: 'vertical-rl' },
+ { syntax: 'vertical-lr' },
+ { syntax: 'sideways-rl' },
+ { syntax: 'sideways-lr' },
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/z-index.html b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/z-index.html
new file mode 100644
index 0000000000..53773fb96f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/the-stylepropertymap/properties/z-index.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>'z-index' property</title>
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-get">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-set">
+<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#property-stle-value-normalization">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../resources/testhelper.js"></script>
+<script src="resources/testsuite.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+runPropertyTests('z-index', [
+ { syntax: 'auto' },
+ {
+ syntax: '<number>',
+ // z-index needs to be an integer
+ specified: (input, result) => {
+ if (input instanceof CSSUnitValue && !Number.isInteger(input.value))
+ assert_style_value_equals(result, new CSSMathSum(input));
+ else
+ assert_style_value_equals(result, input);
+ },
+ computed: (input, result) => {
+ const number = input.to('number');
+ if (!Number.isInteger(number.value))
+ assert_style_value_equals(result, new CSSUnitValue(Math.round(number.value), 'number'));
+ else
+ assert_style_value_equals(result, number);
+ }
+ }
+]);
+
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/width-by-clamp-px-em.html b/testing/web-platform/tests/css/css-typed-om/width-by-clamp-px-em.html
new file mode 100644
index 0000000000..590ac775cb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/width-by-clamp-px-em.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="author" title="Joonghun Park" href="mailto:pjh0718@gmail.com">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="'width' can be set with a CSSMathClamp object.">
+<style>
+#target { font-size: 10px; background-color: green; height: 100px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=target></div>
+<script>
+const width = new CSSMathClamp(CSS.px(90), CSS.em(10), CSS.px(110));
+const target = document.querySelector('#target');
+target.attributeStyleMap.set('width', width);
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/width-by-max-px-em.html b/testing/web-platform/tests/css/css-typed-om/width-by-max-px-em.html
new file mode 100644
index 0000000000..2aac59b707
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/width-by-max-px-em.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="'width' can be set with a CSSMathMax object.">
+<style>
+#target { font-size: 10px; background-color: green; height: 100px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=target></div>
+<script>
+const width = new CSSMathMax(CSS.em(10), CSS.px(90));
+const target = document.querySelector('#target');
+target.attributeStyleMap.set('width', width);
+</script>
diff --git a/testing/web-platform/tests/css/css-typed-om/width-by-min-px-em.html b/testing/web-platform/tests/css/css-typed-om/width-by-min-px-em.html
new file mode 100644
index 0000000000..615cb15708
--- /dev/null
+++ b/testing/web-platform/tests/css/css-typed-om/width-by-min-px-em.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<link rel="author" title="Xiaocheng Hu" href="mailto:xiaochengh@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-typed-om-1/#stylevalue-subclasses">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="'width' can be set with a CSSMathMin object.">
+<style>
+#target { font-size: 10px; background-color: green; height: 100px; }
+</style>
+<p>Test passes if there is a filled green square.</p>
+<div id=target></div>
+<script>
+const width = new CSSMathMin(CSS.em(10), CSS.px(110));
+const target = document.querySelector('#target');
+target.attributeStyleMap.set('width', width);
+</script>