<!DOCTYPE html>
<title>CSS Values and Units Test: attr</title>
<meta name="assert" content="test attr values">
<link rel="help" href="https://drafts.csswg.org/css-values-5/#attr-notations">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<html>
<body>
<div id="attr"></div>
<div id="expected"></div>
</body>
</html>
<script>
const dimensionTypeToUnits = {
"length": ["em", "ex", "cap", "ch", "ic", "rem", "lh", "rlh", "vw", "vh ", "vi", "vb", "vmin", "vmax"],
"angle": ["deg", "grad", "rad", "turn"],
"time": ["ms", "ms"],
"frequency": ["Hz", "kHz"],
"flex": ["fr"]
};
const dimensionTypeToProperty = {
"length": ["width"],
"angle": ["font-style"],
"time": ["transition-duration"],
"flex": ["grid-template-columns"]
}
function test_valid_attr(property, attrString, attrValue, expectedValue) {
var elem = document.getElementById("attr");
elem.setAttribute("data-foo", attrValue);
elem.style.setProperty(property, attrString);
var expectedElem = document.getElementById("expected");
expectedElem.style.setProperty(property, expectedValue);
test(() => {
assert_equals(window.getComputedStyle(elem).getPropertyValue(property),
window.getComputedStyle(expectedElem).getPropertyValue(property),
"Value \'" + attrString + "\', where \'data-foo=" + attrValue +
"\' should be valid for the property \'" + property + "\'.");
});
elem.style.setProperty(property, null);
expectedElem.style.setProperty(property, null);
}
function test_invalid_attr(property, attrString, attrValue) {
var elem = document.getElementById("attr");
var expectedValue = window.getComputedStyle(elem).getPropertyValue(property);
elem.setAttribute("data-foo", attrValue);
elem.style.setProperty(property, attrString);
test(() => {
assert_equals(window.getComputedStyle(elem).getPropertyValue(property), expectedValue,
"Setting property \'" + property + "\' to the value \'" + attrString +
"\', where \'data-foo=" + attrValue + "\' should not change it's value.");
});
elem.style.setProperty(property, null);
}
function test_dimension_types_and_units() {
for(const [type, units] of Object.entries(dimensionTypeToUnits)) {
const property = dimensionTypeToProperty[type];
const val = "3";
units.forEach(unit => {
const expectedValue = val + unit;
const dimensionTypeAttrString = 'attr(data-foo ' + type + ')';
test_valid_attr(property, dimensionTypeAttrString, expectedValue, expectedValue);
const dimensionUnitAttrString = 'attr(data-foo ' + unit + ')';
test_valid_attr(property, dimensionUnitAttrString, val, expectedValue);
});
}
}
test_valid_attr('content', 'attr(data-foo string)', 'abc', '"abc"');
test_valid_attr('content', 'attr(data-foo string)', 'attr(data-foo)', '"attr(data-foo)"');
test_valid_attr('animation-name', 'attr(data-foo ident)', 'anim', 'anim');
test_valid_attr('animation-name', 'attr(data-foo ident, anim-fallback)', '"anim"', 'anim-fallback');
test_valid_attr('animation-name', 'attr(data-foo ident, anim-fallback)', 'initial', 'anim-fallback');
test_valid_attr('background-color', 'attr(data-foo color)', 'red', 'red');
test_valid_attr('background-color', 'attr(data-foo color)', '#ff0099aa', '#ff0099aa');
test_valid_attr('background-color', 'attr(data-foo color, red)', '10', 'red');
test_valid_attr('background-color', 'attr(data-foo color, green)', '1000px', 'green');
test_valid_attr('background-color', 'attr(data-foo color, green)', 'rgb(255, 0, 0)', 'green');
test_valid_attr('font-weight', 'attr(data-foo number)', '10', '10');
test_valid_attr('font-weight', 'attr(data-foo number, 30)', '10px', '30');
test_valid_attr('font-weight', 'attr(data-foo number, calc(10 + 20))', '10px', '30');
test_valid_attr('font-size', 'attr(data-foo percentage)', '10%', '10%');
test_valid_attr('font-size', 'attr(data-foo percentage, 10px)', 'abc', '10px');
test_valid_attr('--x', 'attr(data-foo percentage, abc)', '10', 'abc');
test_valid_attr('width', 'attr(data-foo length)', '10px', '10px');
test_valid_attr('width', 'attr(data-foo length, red)', '10px', '10px');
test_valid_attr('width', 'attr(data-foo length, 42px)', 'calc(1px + 3px)', '42px');
test_valid_attr('font-style', 'attr(data-foo angle)', '10deg', '10deg');
test_valid_attr('font-style', 'attr(data-foo angle, 10deg)', '30', '10deg');
test_valid_attr('font-style', 'attr(data-foo angle, italic)', '30', 'italic');
test_valid_attr('transition-duration', 'attr(data-foo time)', '10ms', '10ms');
test_valid_attr('transition-duration', 'attr(data-foo time, 30s)', '10m', '30s');
test_valid_attr('transition-duration', 'attr(data-foo time, calc(10s + 20s))', '10m', '30s');
test_valid_attr('grid-template-columns', '30px attr(data-foo flex)', '1fr', '30px 1fr');
test_valid_attr('grid-template-columns', 'attr(data-foo flex, 3fr)', '1fr 1fr', '3fr');
test_valid_attr('grid-template-columns', 'attr(data-foo flex, calc(1px + 2px))', '10px', '3px');
test_valid_attr('height', 'attr(data-foo px)', '10', '10px');
test_valid_attr('width', 'calc(attr(data-foo px) + 1px)', '10', '11px');
test_valid_attr('--x', 'attr(data-foo px) 11px', '10', '10px 11px');
test_valid_attr('grid-template-columns', 'attr(data-foo fr)', '10', '10fr');
test_valid_attr('grid-template-columns', 'attr(data-foo fr, 3fr)', '10fr', '3fr');
test_dimension_types_and_units();
test_invalid_attr('animation-name', 'attr(data-foo ident)', 'initial');
test_invalid_attr('animation-name', 'attr(data-foo ident)', '"anim"');
test_invalid_attr('animation-name', 'attr(data-foo ident)', '"none"');
test_invalid_attr('background-color', 'attr(data-foo color)', 'rgb(0 255 0)');
test_invalid_attr('background-color', 'attr(data-foo color)', 'color-mix(in lch, red, pink)');
test_invalid_attr('background-color', 'attr(data-foo color)', 'light-dark(#333b3c, #efefec)');
test_invalid_attr('background-color', 'attr(data-foo red)', 'abc');
test_invalid_attr('background-color', 'attr(data-foo, red)', 'abc');
test_invalid_attr('font-size', 'attr(data-foo number)', '10');
test_invalid_attr('font-weight', 'attr(data-foo number,)', '10');
test_invalid_attr('font-weight', 'attr(data-foo number)', 'calc(1 + 3)');
test_invalid_attr('font-size', 'attr(data-foo percentage)', 'abc');
test_invalid_attr('font-size', 'attr(data-foo percentage)', '10% a');
test_invalid_attr('font-size', 'attr(data-foo percentage, 10rad)', 'abc');
test_invalid_attr('width', 'attr(data-foo length)', '10');
test_invalid_attr('width', 'attr(data-foo length, 30)', 'calc(10 + 20)');
test_invalid_attr('width', 'attr(data-foo length, calc(10 + 20))', 'abc');
test_invalid_attr('font-style', 'attr(data-foo angle)', '10%');
test_invalid_attr('font-style', 'attr(data-foo angle)', 'calc(10px + 20px)');
test_invalid_attr('font-style', 'attr(data-foo angle, calc(10 + 20))', 'calc(10px + 20px)');
test_invalid_attr('transition-duration', 'attr(data-foo time)', '10');
test_invalid_attr('transition-duration', 'attr(data-foo time)', '10 ms');
test_invalid_attr('transition-duration', 'attr(data-foo time)', 'calc(1ms + 2ms)s');
test_invalid_attr('grid-template-columns', 'attr(data-foo flex)', '10px');
test_invalid_attr('grid-template-columns', 'attr(data-foo flex)', '"30fr"');
test_invalid_attr('grid-template-columns', 'attr(data-foo flex, calc(1deg + 2deg))', '10px');
test_invalid_attr('width', 'attr(data-foo px)', '10px');
test_invalid_attr('height', 'attr(data-foo fr)', '10');
test_invalid_attr('transition-duration', 'attr(data-foo ms)', '10px');
test_invalid_attr('transition-duration', 'attr(data-foo ms)', '10px foo');
</script>