| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="../../http/tests/inspector/resources/inspector-test.js"></script> | |
| <script> | |
| function test() { | |
| let nodeStyles = null; | |
| let suite = InspectorTest.createAsyncSuite("CSSProperty"); | |
| suite.addTestCase({ | |
| name: "CSSProperty.NameCount", | |
| description: "Ensure that the name counts are being tracked.", | |
| async test() { | |
| InspectorTest.expectGreaterThanOrEqual(WI.CSSProperty._cachedNameCounts["display"], 2, `"display" should have at least 2 counts.`); | |
| InspectorTest.expectGreaterThanOrEqual(WI.CSSProperty._cachedNameCounts["background-repeat"], 1, `"background-repeat" should have at least 1 count.`); | |
| InspectorTest.expectThat(!("background-repeat-x" in WI.CSSProperty._cachedNameCounts), `"background-repeat-x" should not be counted.`); | |
| InspectorTest.expectThat(!("background-repeat-y" in WI.CSSProperty._cachedNameCounts), `"background-repeat-y" should not be counted.`); | |
| InspectorTest.expectThat(!("background-repeat-invalid" in WI.CSSProperty._cachedNameCounts), `"background-repeat-invalid" should not be counted.`); | |
| InspectorTest.expectThat(!("--foo" in WI.CSSProperty._cachedNameCounts), `"--foo" should not be counted.`); | |
| InspectorTest.expectThat(!("--bar" in WI.CSSProperty._cachedNameCounts), `"--bar" should not be counted.`); | |
| InspectorTest.newline(); | |
| const counts = [99, 1, 100, 0, 101, 150, 50, 200]; | |
| let seenProperty = (count) => `Fake Property ${count} Seen`; | |
| let unseenProperty = (count) => `Fake Property ${count} Unseen`; | |
| let createQueryResults = (count, rank) => { | |
| let unseen = new WI.QueryResult(unseenProperty(count), ["not reached"]); | |
| unseen.rankForTesting = rank; | |
| let seen = new WI.QueryResult(seenProperty(count), ["not reached"]); | |
| seen.rankForTesting = rank; | |
| return [unseen, seen]; | |
| } | |
| for (const count of counts) | |
| WI.CSSProperty._cachedNameCounts[seenProperty(count)] = count; | |
| InspectorTest.log("Sorted by usage:"); | |
| InspectorTest.json(counts.flatMap((count) => [unseenProperty(count), seenProperty(count)]).sort(WI.CSSProperty.sortByPropertyNameUsageCount)) | |
| { | |
| let completions = counts.flatMap((count) => createQueryResults(count, count % 2)); | |
| InspectorTest.log(`Initially selected completion when ranked by \`count % 2\`: "${completions[WI.CSSProperty.indexOfCompletionForMostUsedPropertyName(completions)].value}"`); | |
| } | |
| { | |
| let completions = counts.flatMap((count) => createQueryResults(count, count % 3)); | |
| InspectorTest.log(`Initially selected completion when ranked by \`count % 3\`: "${completions[WI.CSSProperty.indexOfCompletionForMostUsedPropertyName(completions)].value}"`); | |
| } | |
| for (const count of counts) | |
| delete WI.CSSProperty._cachedNameCounts[seenProperty(count)]; | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get valid", | |
| description: "Ensure valid, invalid, and internal-only have correct valid state.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.enabledProperties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "--foo": | |
| case "--bar": | |
| InspectorTest.expectThat(property.valid, `"${property.name}" is a valid property.`); | |
| break; | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectFalse(property.valid, `"${property.name}" is an invalid property.`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get anonymous", | |
| description: "Ensure valid, invalid, and internal-only have correct anonymous state.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.enabledProperties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectFalse(property.anonymous, `"${property.name}" is not an anonymous CSS property.`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get implicit", | |
| description: "Ensure valid, invalid, and internal-only have correct implicit state.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.enabledProperties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectFalse(property.implicit, `"${property.name}" is not an implicit CSS property.`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get value", | |
| description: "Ensure valid, invalid, and internal-only have correct value.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.enabledProperties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectEqual(property.value, "repeat", `"${property.name}" has the value "repeat".`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get enabled", | |
| description: "Ensure valid, invalid, and internal-only have correct enabled state.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.properties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectThat(property.enabled, `"${property.name}" is enabled.`); | |
| break; | |
| case "background-color": | |
| InspectorTest.expectThat(!property.enabled, `"${property.name}" is disabled.`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get attached", | |
| description: "Ensure valid, invalid, and internal-only have correct attached state.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| for (let property of rule.style.properties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectThat(property.attached, `"${property.name}" is attached.`); | |
| break; | |
| case "background-color": | |
| InspectorTest.expectThat(!property.attached, `"${property.name}" is detached.`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.get text", | |
| description: "Ensure valid, invalid, and internal-only have correct text.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| // It is necessary to use "_text" because the public "text" getter will attempt to | |
| // synthesize a value for the CSSProperty if it is falsy. This is used for cases | |
| // where a shorthand property is written in the style, since the longhand properties | |
| // (with corresponding values) are still sent to the frontend. | |
| for (let property of rule.style.enabledProperties) { | |
| switch (property.name) { | |
| case "background-repeat": | |
| InspectorTest.expectEqual(property.text, "background-repeat: repeat;", `"${property.name}" has the text "background-repeat: repeat;".`); | |
| InspectorTest.expectEqual(property._text, "background-repeat: repeat;", `"${property.name}" has the _text (private) "background-repeat: repeat;".`); | |
| break; | |
| case "background-repeat-x": | |
| case "background-repeat-y": | |
| case "background-repeat-invalid": | |
| InspectorTest.expectEqual(property.text, `${property.name}: repeat;`, `"${property.name}" has the text "${property.name}: repeat;".`); | |
| InspectorTest.expectEqual(property._text, `${property.name}: repeat;`, `"${property.name}" has the _text (private) "${property.name}: repeat;".`); | |
| break; | |
| } | |
| } | |
| } | |
| resolve(); | |
| } | |
| }); | |
| suite.addTestCase({ | |
| name: "CSSProperty.prototype.remove", | |
| description: "Ensure remove method removes a property from an array of properties.", | |
| test(resolve, reject) { | |
| for (let rule of nodeStyles.matchedRules) { | |
| if (rule.selectorText !== "div#x") | |
| continue; | |
| let propertiesLength = rule.style.properties.length; | |
| let firstProperty = rule.style.properties[0]; | |
| let secondProperty = rule.style.properties[1]; | |
| rule.style.properties[0].remove(); | |
| InspectorTest.expectEqual(rule.style.properties.length, propertiesLength - 1, "The removed property should no longer be in properties array."); | |
| InspectorTest.expectEqual(rule.style.properties[0], secondProperty, "The second property should shift and become the first."); | |
| } | |
| resolve(); | |
| } | |
| }); | |
| WI.domManager.requestDocument((documentNode) => { | |
| documentNode.querySelector("div#x", (contentNodeId) => { | |
| if (contentNodeId) { | |
| let domNode = WI.domManager.nodeForId(contentNodeId); | |
| nodeStyles = WI.cssManager.stylesForNode(domNode); | |
| 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 methods of CSSProperty.</p> | |
| <style> | |
| div#x { | |
| display: initial; | |
| display: initial; | |
| background-repeat: repeat; | |
| background-repeat-x: repeat; | |
| background-repeat-invalid: repeat; | |
| --foo: red; | |
| --bar: blue; | |
| /* background-color: black; */ | |
| /* Not a CSS property */ | |
| /* foo:bar; foo:baz; */ | |
| } | |
| </style> | |
| <div id="x"></div> | |
| </body> | |
| </html> |