blob: 6e8c078fe310222973d38fa5ea8ccd7c0cc7bc30 [file] [log] [blame] [edit]
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="resources/modify-css-property.css">
<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
<script>
function makeNarrow() {
document.getElementById("x").style.width = "50px";
}
function makeWide() {
document.getElementById("x").style.width = "200px";
}
function test() {
let nodeStyles = null;
let suite = InspectorTest.createAsyncSuite("ModifyCSSProperty");
suite.addTestCase({
name: "Update value when CSSStyleDeclaration is not locked",
test(resolve, reject) {
let getMatchedStyleDeclaration = () => {
for (let rule of nodeStyles.matchedRules) {
if (rule.selectorText === ".rule-b")
return rule.style;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getMatchedStyleDeclaration();
for (let property of styleDeclaration.enabledProperties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getMatchedStyleDeclaration();
styleDeclaration.locked = false;
styleDeclaration.singleFireEventListener(WI.CSSStyleDeclaration.Event.PropertiesChanged, function(event) {
let fontProperty = getProperty("font-size");
let relativeRange = fontProperty.styleSheetTextRange.relativeTo(fontProperty.ownerStyle.styleSheetTextRange.startLine, fontProperty.ownerStyle.styleSheetTextRange.startOffset);
relativeRange.resolveOffsets(fontProperty.ownerStyle.text);
let propertyText = fontProperty.ownerStyle.text.slice(relativeRange.startOffset, relativeRange.endOffset);
InspectorTest.expectEqual(propertyText, "font-size: 10px;", `styleSheetTextRange should correspond to "font-size: 10px;"`);
resolve();
});
getProperty("font-size").rawValue = "11px";
getProperty("font-size").rawValue = "10px";
InspectorTest.expectEqual(getProperty("font-size").rawValue, "10px", `"font-size" property value should update immediately.`);
InspectorTest.expectEqual(styleDeclaration.text, `\n font-size: 10px;\n color: antiquewhite;\n`, `Style declaration text should update immediately.`);
}
});
suite.addTestCase({
name: "Update value when CSSStyleDeclaration is locked",
test(resolve, reject) {
let getMatchedStyleDeclaration = () => {
for (let rule of nodeStyles.matchedRules) {
if (rule.selectorText === ".rule-a")
return rule.style;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getMatchedStyleDeclaration();
for (let property of styleDeclaration.enabledProperties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getMatchedStyleDeclaration();
styleDeclaration.locked = true;
getProperty("font-size").rawValue = "15px";
getProperty("font-size").rawValue = "16px";
InspectorTest.expectEqual(getProperty("font-size").rawValue, "16px", `"font-size" property value should update immediately.`);
InspectorTest.expectEqual(styleDeclaration.text, `
font-size: 16px;
color: #333;
margin-left: 0;
margin-top: 1em;
`, `Style declaration text should update immediately.`);
styleDeclaration.locked = false;
resolve();
}
});
suite.addTestCase({
name: "ModifyCSSProperty.PropertiesChangedEvent",
test(resolve, reject) {
let getInlineStyleDeclaration = () => {
for (let styleDeclaration of nodeStyles.orderedStyles) {
if (styleDeclaration.type === styleDeclaration.constructor.Type.Inline)
return styleDeclaration;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getInlineStyleDeclaration();
for (let property of styleDeclaration.properties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getInlineStyleDeclaration();
styleDeclaration.awaitEvent(WI.CSSStyleDeclaration.Event.PropertiesChanged).then((event) => {
InspectorTest.expectThat(!styleDeclaration.locked, `Style declaration is unlocked.`);
InspectorTest.expectEqual(getProperty("width").rawValue, "200px", `"width" property value should update to "200px".`);
InspectorTest.expectEqual(styleDeclaration.text, `width: 200px;`, `Inline style declaration text should update when not locked.`);
resolve();
});
styleDeclaration.locked = true;
// WI.CSSStyleDeclaration.Event.PropertiesChanged event should not fire when the style declaration is locked.
InspectorTest.evaluateInPage(`makeNarrow()`);
styleDeclaration.locked = false;
InspectorTest.evaluateInPage(`makeWide()`);
}
});
suite.addTestCase({
name: "Update inline style value when CSSStyleDeclaration locked and not locked",
test(resolve, reject) {
let getInlineStyleDeclaration = () => {
for (let styleDeclaration of nodeStyles.orderedStyles) {
if (styleDeclaration.type === styleDeclaration.constructor.Type.Inline)
return styleDeclaration;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getInlineStyleDeclaration();
for (let property of styleDeclaration.enabledProperties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getInlineStyleDeclaration();
WI.CSSStyleDeclaration.awaitEvent(WI.CSSStyleDeclaration.Event.PropertiesChanged).then((event) => {
InspectorTest.expectThat(!styleDeclaration.locked, `Style declaration is unlocked.`);
InspectorTest.expectEqual(getProperty("width").rawValue, "128px", `"width" property value should update to "128px".`);
InspectorTest.expectEqual(styleDeclaration.text, `width: 128px;`, `Inline style declaration text should update when not locked.`);
resolve();
});
styleDeclaration.locked = true;
getProperty("width").rawValue = "64px";
InspectorTest.expectEqual(styleDeclaration.text, `width: 64px;`, `Style declaration text should update immediately.`);
// WI.CSSStyleDeclaration.Event.PropertiesChanged event should not fire when the style declaration is locked.
InspectorTest.evaluateInPage(`makeNarrow()`);
styleDeclaration.locked = false;
getProperty("width").rawValue = "128px";
InspectorTest.expectEqual(styleDeclaration.text, `width: 128px;`, `Style declaration text should update immediately.`);
InspectorTest.evaluateInPage(`makeWide()`);
}
});
suite.addTestCase({
name: "ModifyCSSProperty.ConsequentValueChanges",
test(resolve, reject) {
let getInlineStyleDeclaration = () => {
for (let styleDeclaration of nodeStyles.orderedStyles) {
if (styleDeclaration.type === styleDeclaration.constructor.Type.Inline)
return styleDeclaration;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getInlineStyleDeclaration();
for (let property of styleDeclaration.properties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getInlineStyleDeclaration();
styleDeclaration.locked = false;
for (let i = 0; i <= 20; ++i)
getProperty("width").rawValue = i + "px";
InspectorTest.expectEqual(styleDeclaration.text, `width: 20px;`, `Style declaration text should contain most recent value.`);
resolve();
}
});
suite.addTestCase({
name: "ModifyCSSProperty.CommentOutAndUncommentPropertyWithNewlines",
test(resolve, reject) {
let getMatchedStyleDeclaration = () => {
for (let rule of nodeStyles.matchedRules) {
if (rule.selectorText === ".rule-c")
return rule.style;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getMatchedStyleDeclaration();
for (let property of styleDeclaration.properties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getMatchedStyleDeclaration();
styleDeclaration.locked = true;
InspectorTest.expectThat(!getProperty("padding-right").enabled, `Commented out property should be disabled.`);
let disabled = false;
getProperty("padding-right").commentOut(disabled);
let expectedStyleText = `\n /* padding-left: 2em; */\n padding-right: 0px;\n`;
InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with uncommented property.`);
InspectorTest.expectThat(getProperty("padding-right").enabled, `Uncommented property should be enabled.`);
disabled = true;
getProperty("padding-right").commentOut(disabled);
expectedStyleText = `\n /* padding-left: 2em; */\n /* padding-right: 0px; */\n`;
InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with commented out property.`);
InspectorTest.expectThat(!getProperty("padding-right").enabled, `Commented out property should be disabled.`);
resolve();
}
});
suite.addTestCase({
name: "ModifyCSSProperty.CommentOutAndUncommentPropertyWithoutNewlines",
test(resolve, reject) {
let getMatchedStyleDeclaration = () => {
for (let rule of nodeStyles.matchedRules) {
if (rule.selectorText === ".rule-d")
return rule.style;
}
InspectorTest.fail("No declaration found.");
resolve();
};
let getProperty = (propertyName) => {
let styleDeclaration = getMatchedStyleDeclaration();
for (let property of styleDeclaration.properties) {
if (property.name === propertyName)
return property;
}
InspectorTest.fail("No property found.");
resolve();
};
let styleDeclaration = getMatchedStyleDeclaration();
styleDeclaration.locked = true;
InspectorTest.expectThat(!getProperty("font-size").enabled, `Commented out property should be disabled.`);
let disabled = false;
getProperty("font-size").commentOut(disabled);
let expectedStyleText = `\n font-size: 13px;\n /* border: 2px solid brown; */\n`;
InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with uncommented property.`);
InspectorTest.expectThat(getProperty("font-size").enabled, `Uncommented property should be enabled.`);
InspectorTest.expectThat(!getProperty("border").enabled, `Commented out property should be disabled.`);
disabled = false;
getProperty("border").commentOut(disabled);
expectedStyleText = `\n font-size: 13px;\n border: 2px solid brown\n`;
InspectorTest.expectEqual(styleDeclaration.text, expectedStyleText, `Style declaration text should update immediately with commented out property.`);
InspectorTest.expectThat(getProperty("border").enabled, `Uncommented property should be enabled.`);
resolve();
}
});
suite.addTestCase({
name: "ModifyCSSProperty.ReplacePropertyName",
async test() {
let getMatchedStyleDeclaration = () => {
for (let rule of nodeStyles.matchedRules) {
if (rule.selectorText === ".rule-e")
return rule.style;
}
throw "No declaration found.";
};
let getProperty = (propertyName) => {
let styleDeclaration = getMatchedStyleDeclaration();
for (let property of styleDeclaration.properties) {
if (property.name === propertyName)
return property;
}
throw "No property found.";
};
let styleDeclaration = getMatchedStyleDeclaration();
let cssProperty = getProperty("color");
cssProperty.name = "";
InspectorTest.expectEqual(styleDeclaration.text, "", "Style declaration text should be empty.");
cssProperty.name = "border-color";
InspectorTest.expectEqual(styleDeclaration.text, `\n border-color: darkseagreen;\n`, "Style declaration text should have new property name.");
}
});
function addTestCase({name, description, selector, authoredRulesHandler})
{
suite.addTestCase({
name,
description,
async test() {
let documentNode = await WI.domManager.requestDocument();
let nodeId = await documentNode.querySelector(selector);
let domNode = WI.domManager.nodeForId(nodeId);
InspectorTest.assert(domNode, `Should find DOM Node for selector '#item'.`);
let domNodeStyles = WI.cssManager.stylesForNode(domNode);
InspectorTest.assert(domNodeStyles, `Should find CSS Styles for DOM Node.`);
await domNodeStyles.refresh();
let flatInheritedRules = domNodeStyles.inheritedRules.flatMap((inheritedRuleInfo) => inheritedRuleInfo.matchedRules);
let authoredRules = [...domNodeStyles.matchedRules, ...flatInheritedRules].filter((rule) => rule.type === WI.CSSStyleSheet.Type.Author);
await authoredRulesHandler(authoredRules, domNodeStyles);
},
});
}
function findRuleStyleInRules(rules, {selector, nestingRootSelector}) {
for (let rule of rules) {
if (rule.selectorText !== selector)
continue;
if (!nestingRootSelector)
return rule.style;
for (let grouping of rule.groupings) {
if (grouping.type !== WI.CSSGrouping.Type.StyleRule)
continue;
if (grouping.text !== nestingRootSelector)
continue;
return rule.style;
}
}
InspectorTest.fail(`No rule found with selector "${selector}" nested under selector "${nestingRootSelector}".`);
}
function getColorProperty(styleDeclaration) {
for (let property of styleDeclaration.properties) {
if (property.name === "color")
return property;
}
InspectorTest.fail("No color property found in style declaration.");
}
addTestCase({
name: "ModifyCSSProperty.EnsureNestedRulesEditingDoesNotTrampleInnerRules",
description: "",
selector: ".rule-f",
async authoredRulesHandler(authoredRules, domNodeStyles) {
let outerRuleStyle = findRuleStyleInRules(authoredRules, { selector: ".rule-f" });
InspectorTest.expectEqual(outerRuleStyle.text, "\n color: red;\n\n @media(min-width: 0px) {\n &.explicit-nested-rule { \n color: blue;\n }\n\n color: green;\n }\n", "Outer style declaration text should contain the expected `color` property.");
let outerRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(outerRuleStyle).rawValue = "magenta";
await outerRuleStyleChangedPromise;
InspectorTest.expectEqual(outerRuleStyle.text, "\n color: magenta;\n\n @media(min-width: 0px) {\n &.explicit-nested-rule { \n color: blue;\n }\n\n color: green;\n }\n\n", "Outer style declaration text should contain the new `color` value.");
let innerImplicitRuleStyle = findRuleStyleInRules(authoredRules, { selector: "&", nestingRootSelector: ".rule-f" });
InspectorTest.expectEqual(innerImplicitRuleStyle.text, "\n &.explicit-nested-rule { \n color: blue;\n }\n\n color: green;\n ", "Inner implicit style declaration text should contain the expected `color` property.");
let innerImplicitRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(innerImplicitRuleStyle).rawValue = "yellow";
await innerImplicitRuleStyleChangedPromise;
InspectorTest.expectEqual(innerImplicitRuleStyle.text, "\n color: yellow;\n \n &.explicit-nested-rule { \n color: blue;\n }\n\n ", "Inner implicit style declaration text should contain the new `color` value.");
let innerExplicitRuleStyle = findRuleStyleInRules(authoredRules, { selector: "&.explicit-nested-rule", nestingRootSelector: ".rule-f" });
InspectorTest.expectEqual(innerExplicitRuleStyle.text, " \n color: blue;\n ", "Inner explicit style declaration text should contain the expected `color` property.");
let innerExplicitRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(innerExplicitRuleStyle).rawValue = "cyan";
await innerExplicitRuleStyleChangedPromise;
InspectorTest.expectEqual(innerExplicitRuleStyle.text, "\n color: cyan;\n \n ", "Inner explicit style declaration text should contain the new `color` value.");
},
})
addTestCase({
name: "ModifyCSSProperty.EnsureNestedRulesEditingDoesNotTrampleInnerRulesOriginalExcludesNewlines",
description: "",
selector: ".rule-g",
async authoredRulesHandler(authoredRules, domNodeStyles) {
let outerRuleStyle = findRuleStyleInRules(authoredRules, { selector: ".rule-g" });
InspectorTest.expectEqual(outerRuleStyle.text, " color: red; @media(min-width: 0px) { &.explicit-nested-rule { color: blue; } color: green; } ", "Outer style declaration text should contain the expected `color` property.");
let outerRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(outerRuleStyle).rawValue = "magenta";
await outerRuleStyleChangedPromise;
InspectorTest.expectEqual(outerRuleStyle.text, "\n color: magenta;\n\n @media(min-width: 0px) { &.explicit-nested-rule { color: blue; } color: green; }\n\n", "Outer style declaration text should contain the new `color` value.");
let innerImplicitRuleStyle = findRuleStyleInRules(authoredRules, { selector: "&", nestingRootSelector: ".rule-g" });
InspectorTest.expectEqual(innerImplicitRuleStyle.text, " &.explicit-nested-rule { color: blue; } color: green; ", "Inner implicit style declaration text should contain the expected `color` property.");
let innerImplicitRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(innerImplicitRuleStyle).rawValue = "yellow";
await innerImplicitRuleStyleChangedPromise;
InspectorTest.expectEqual(innerImplicitRuleStyle.text, "\n color: yellow;\n \n &.explicit-nested-rule { color: blue; }\n\n ", "Inner implicit style declaration text should contain the new `color` value.");
let innerExplicitRuleStyle = findRuleStyleInRules(authoredRules, { selector: "&.explicit-nested-rule", nestingRootSelector: ".rule-g" });
InspectorTest.expectEqual(innerExplicitRuleStyle.text, " color: blue; ", "Inner explicit style declaration text should contain the expected `color` property.");
let innerExplicitRuleStyleChangedPromise = domNodeStyles.awaitEvent(WI.DOMNodeStyles.Event.Refreshed);
getColorProperty(innerExplicitRuleStyle).rawValue = "cyan";
await innerExplicitRuleStyleChangedPromise;
InspectorTest.expectEqual(innerExplicitRuleStyle.text, "\n color: cyan;\n \n ", "Inner explicit style declaration text should contain the new `color` value.");
},
})
WI.domManager.requestDocument((documentNode) => {
documentNode.querySelector("#x", (contentNodeId) => {
if (contentNodeId) {
let domNode = WI.domManager.nodeForId(contentNodeId);
nodeStyles = WI.cssManager.stylesForNode(domNode);
let flatInheritedRules = nodeStyles.inheritedRules.flatMap((inheritedRuleInfo) => inheritedRuleInfo.matchedRules);
authoredRules = [...nodeStyles.matchedRules, ...flatInheritedRules].filter((rule) => rule.type === WI.CSSStyleSheet.Type.Author);
if (nodeStyles.needsRefresh) {
nodeStyles.singleFireEventListener(WI.DOMNodeStyles.Event.Refreshed, (event) => {
suite.runTestCasesAndFinish()
});
} else
suite.runTestCasesAndFinish();
} else {
InspectorTest.fail("DOM node not found.");
InspectorTest.completeTest();
}
});
});
}
</script>
</head>
<body onload="runTest()">
<p>Testing that CSSStyleDeclaration update immediately after modifying its properties when it is not locked.</p>
<div id="x" class="test-node rule-a rule-b rule-c rule-d rule-e rule-f rule-g explicit-nested-rule" style="width: 100px"></div>
</body>
</html>