734 lines
21 KiB
JavaScript
734 lines
21 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
// Test the ResourceCommand API around STYLESHEET.
|
|
|
|
const ResourceCommand = require("resource://devtools/shared/commands/resource/resource-command.js");
|
|
|
|
const STYLE_TEST_URL = URL_ROOT_SSL + "style_document.html";
|
|
|
|
const EXISTING_RESOURCES = [
|
|
{
|
|
styleText: "body { color: lime; }",
|
|
href: null,
|
|
nodeHref:
|
|
"https://example.com/browser/devtools/shared/commands/resource/tests/style_document.html",
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
},
|
|
{
|
|
styleText: "body { margin: 1px; }",
|
|
href: "https://example.com/browser/devtools/shared/commands/resource/tests/style_document.css",
|
|
nodeHref:
|
|
"https://example.com/browser/devtools/shared/commands/resource/tests/style_document.html",
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
},
|
|
{
|
|
styleText: "",
|
|
href: null,
|
|
nodeHref: null,
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: true,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
},
|
|
{
|
|
styleText: "body { background-color: pink; }",
|
|
href: null,
|
|
nodeHref:
|
|
"https://example.org/browser/devtools/shared/commands/resource/tests/style_iframe.html",
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
},
|
|
{
|
|
styleText: "body { padding: 1px; }",
|
|
href: "https://example.org/browser/devtools/shared/commands/resource/tests/style_iframe.css",
|
|
nodeHref:
|
|
"https://example.org/browser/devtools/shared/commands/resource/tests/style_iframe.html",
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
},
|
|
];
|
|
|
|
const ADDITIONAL_INLINE_RESOURCE = {
|
|
styleText:
|
|
"@media all { body { color: red; } } @media print { body { color: cyan; } } body { font-size: 10px; }",
|
|
href: null,
|
|
nodeHref:
|
|
"https://example.com/browser/devtools/shared/commands/resource/tests/style_document.html",
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 5,
|
|
atRules: [
|
|
{
|
|
type: "media",
|
|
conditionText: "all",
|
|
matches: true,
|
|
line: 1,
|
|
column: 1,
|
|
},
|
|
{
|
|
type: "media",
|
|
conditionText: "print",
|
|
matches: false,
|
|
line: 1,
|
|
column: 37,
|
|
},
|
|
],
|
|
};
|
|
|
|
const ADDITIONAL_CONSTRUCTED_RESOURCE = {
|
|
styleText: "",
|
|
href: null,
|
|
nodeHref: null,
|
|
isNew: false,
|
|
disabled: false,
|
|
constructed: true,
|
|
ruleCount: 2,
|
|
atRules: [],
|
|
};
|
|
|
|
const ADDITIONAL_FROM_ACTOR_RESOURCE = {
|
|
styleText: "body { font-size: 10px; }",
|
|
href: null,
|
|
nodeHref:
|
|
"https://example.com/browser/devtools/shared/commands/resource/tests/style_document.html",
|
|
isNew: true,
|
|
disabled: false,
|
|
constructed: false,
|
|
ruleCount: 1,
|
|
atRules: [],
|
|
};
|
|
|
|
add_task(async function () {
|
|
// Enable @property
|
|
await pushPref("layout.css.properties-and-values.enabled", true);
|
|
await testResourceAvailableDestroyedFeature();
|
|
await testResourceUpdateFeature();
|
|
await testNestedResourceUpdateFeature();
|
|
});
|
|
|
|
function pushAvailableResource(availableResources) {
|
|
// TODO(bug 1826538): Find a better way of dealing with these.
|
|
return function (resources) {
|
|
for (const resource of resources) {
|
|
if (resource.href?.startsWith("resource://")) {
|
|
continue;
|
|
}
|
|
availableResources.push(resource);
|
|
}
|
|
};
|
|
}
|
|
|
|
async function testResourceAvailableDestroyedFeature() {
|
|
info("Check resource available feature of the ResourceCommand");
|
|
|
|
const tab = await addTab(STYLE_TEST_URL);
|
|
let resourceTimingEntryCounts = await getResourceTimingCount(tab);
|
|
is(
|
|
resourceTimingEntryCounts,
|
|
2,
|
|
"Should have two entires for resource timing"
|
|
);
|
|
|
|
const { client, resourceCommand, targetCommand } =
|
|
await initResourceCommand(tab);
|
|
|
|
info("Check whether ResourceCommand gets existing stylesheet");
|
|
const availableResources = [];
|
|
const destroyedResources = [];
|
|
await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
|
|
onAvailable: pushAvailableResource(availableResources),
|
|
onDestroyed: resources => destroyedResources.push(...resources),
|
|
});
|
|
|
|
is(
|
|
availableResources.length,
|
|
EXISTING_RESOURCES.length,
|
|
"Length of existing resources is correct"
|
|
);
|
|
for (let i = 0; i < availableResources.length; i++) {
|
|
const availableResource = availableResources[i];
|
|
// We can not expect the resources to always be forwarded in the same order.
|
|
// See intermittent Bug 1655016.
|
|
const expectedResource = findMatchingExpectedResource(availableResource);
|
|
ok(expectedResource, "Found a matching expected resource for the resource");
|
|
await assertResource(availableResource, expectedResource);
|
|
}
|
|
|
|
resourceTimingEntryCounts = await getResourceTimingCount(tab);
|
|
is(
|
|
resourceTimingEntryCounts,
|
|
2,
|
|
"Should still have two entires for resource timing after devtools APIs have been triggered"
|
|
);
|
|
|
|
info("Check whether ResourceCommand gets additonal stylesheet");
|
|
await ContentTask.spawn(
|
|
tab.linkedBrowser,
|
|
ADDITIONAL_INLINE_RESOURCE.styleText,
|
|
text => {
|
|
const document = content.document;
|
|
const stylesheet = document.createElement("style");
|
|
stylesheet.id = "inline-from-test";
|
|
stylesheet.textContent = text;
|
|
document.body.appendChild(stylesheet);
|
|
}
|
|
);
|
|
await waitUntil(
|
|
() => availableResources.length === EXISTING_RESOURCES.length + 1
|
|
);
|
|
await assertResource(
|
|
availableResources[availableResources.length - 1],
|
|
ADDITIONAL_INLINE_RESOURCE
|
|
);
|
|
|
|
info("Check whether ResourceCommand gets additonal constructed stylesheet");
|
|
await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
|
const document = content.document;
|
|
const s = new content.CSSStyleSheet();
|
|
// We use the different number of rules to meaningfully differentiate
|
|
// between constructed stylesheets.
|
|
s.replaceSync("foo { color: red } bar { color: blue }");
|
|
// TODO(bug 1751346): wrappedJSObject should be unnecessary.
|
|
document.wrappedJSObject.adoptedStyleSheets.push(s);
|
|
});
|
|
await waitUntil(
|
|
() => availableResources.length === EXISTING_RESOURCES.length + 2
|
|
);
|
|
await assertResource(
|
|
availableResources[availableResources.length - 1],
|
|
ADDITIONAL_CONSTRUCTED_RESOURCE
|
|
);
|
|
|
|
info(
|
|
"Check whether ResourceCommand gets additonal stylesheet which is added by DevTools"
|
|
);
|
|
const styleSheetsFront =
|
|
await targetCommand.targetFront.getFront("stylesheets");
|
|
await styleSheetsFront.addStyleSheet(
|
|
ADDITIONAL_FROM_ACTOR_RESOURCE.styleText
|
|
);
|
|
await waitUntil(
|
|
() => availableResources.length === EXISTING_RESOURCES.length + 3
|
|
);
|
|
await assertResource(
|
|
availableResources[availableResources.length - 1],
|
|
ADDITIONAL_FROM_ACTOR_RESOURCE
|
|
);
|
|
|
|
info("Check resource destroyed feature of the ResourceCommand");
|
|
is(destroyedResources.length, 0, "There was no removed stylesheets yet");
|
|
|
|
info("Remove inline stylesheet added in the test");
|
|
await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
|
content.document.querySelector("#inline-from-test").remove();
|
|
});
|
|
await waitUntil(() => destroyedResources.length === 1);
|
|
assertDestroyed(destroyedResources[0], {
|
|
resourceId: availableResources.at(-3).resourceId,
|
|
});
|
|
|
|
info("Remove existing top-level inline stylesheet");
|
|
await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
|
content.document.querySelector("style").remove();
|
|
});
|
|
await waitUntil(() => destroyedResources.length === 2);
|
|
assertDestroyed(destroyedResources[1], {
|
|
resourceId: availableResources.find(
|
|
resource =>
|
|
findMatchingExpectedResource(resource) === EXISTING_RESOURCES[0]
|
|
).resourceId,
|
|
});
|
|
|
|
info("Remove existing top-level <link> stylesheet");
|
|
await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
|
content.document.querySelector("link").remove();
|
|
});
|
|
await waitUntil(() => destroyedResources.length === 3);
|
|
assertDestroyed(destroyedResources[2], {
|
|
resourceId: availableResources.find(
|
|
resource =>
|
|
findMatchingExpectedResource(resource) === EXISTING_RESOURCES[1]
|
|
).resourceId,
|
|
});
|
|
|
|
info("Remove existing iframe inline stylesheet");
|
|
const iframeBrowsingContext = await SpecialPowers.spawn(
|
|
tab.linkedBrowser,
|
|
[],
|
|
() => content.document.querySelector("iframe").browsingContext
|
|
);
|
|
|
|
await SpecialPowers.spawn(iframeBrowsingContext, [], () => {
|
|
content.document.querySelector("style").remove();
|
|
});
|
|
await waitUntil(() => destroyedResources.length === 4);
|
|
assertDestroyed(destroyedResources[3], {
|
|
resourceId: availableResources.find(
|
|
resource =>
|
|
findMatchingExpectedResource(resource) === EXISTING_RESOURCES[3]
|
|
).resourceId,
|
|
});
|
|
|
|
info("Remove existing iframe <link> stylesheet");
|
|
await SpecialPowers.spawn(iframeBrowsingContext, [], () => {
|
|
content.document.querySelector("link").remove();
|
|
});
|
|
await waitUntil(() => destroyedResources.length === 5);
|
|
assertDestroyed(destroyedResources[4], {
|
|
resourceId: availableResources.find(
|
|
resource =>
|
|
findMatchingExpectedResource(resource) === EXISTING_RESOURCES[4]
|
|
).resourceId,
|
|
});
|
|
|
|
targetCommand.destroy();
|
|
await client.close();
|
|
}
|
|
|
|
async function testResourceUpdateFeature() {
|
|
info("Check resource update feature of the ResourceCommand");
|
|
|
|
const tab = await addTab(STYLE_TEST_URL);
|
|
|
|
const { client, resourceCommand, targetCommand } =
|
|
await initResourceCommand(tab);
|
|
|
|
info("Setup the watcher");
|
|
const availableResources = [];
|
|
const updates = [];
|
|
await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
|
|
onAvailable: pushAvailableResource(availableResources),
|
|
onUpdated: newUpdates => updates.push(...newUpdates),
|
|
});
|
|
is(
|
|
availableResources.length,
|
|
EXISTING_RESOURCES.length,
|
|
"Length of existing resources is correct"
|
|
);
|
|
is(updates.length, 0, "there's no update yet");
|
|
|
|
info("Check toggleDisabled function");
|
|
// Retrieve the stylesheet of the top-level target
|
|
const resource = availableResources.find(
|
|
innerResource => innerResource.targetFront.isTopLevel
|
|
);
|
|
const styleSheetsFront = await resource.targetFront.getFront("stylesheets");
|
|
await styleSheetsFront.toggleDisabled(resource.resourceId);
|
|
await waitUntil(() => updates.length === 1);
|
|
|
|
// Check the content of the update object.
|
|
assertUpdate(updates[0].update, {
|
|
resourceId: resource.resourceId,
|
|
updateType: "property-change",
|
|
});
|
|
is(
|
|
updates[0].update.resourceUpdates.disabled,
|
|
true,
|
|
"resourceUpdates is correct"
|
|
);
|
|
|
|
// Check whether the cached resource is updated correctly.
|
|
is(
|
|
updates[0].resource.disabled,
|
|
true,
|
|
"cached resource is updated correctly"
|
|
);
|
|
|
|
// Check whether the actual stylesheet is updated correctly.
|
|
const styleSheetDisabled = await ContentTask.spawn(
|
|
tab.linkedBrowser,
|
|
null,
|
|
() => {
|
|
const document = content.document;
|
|
const stylesheet = document.styleSheets[0];
|
|
return stylesheet.disabled;
|
|
}
|
|
);
|
|
is(styleSheetDisabled, true, "actual stylesheet was updated correctly");
|
|
|
|
info("Check update function");
|
|
const expectedAtRules = [
|
|
{
|
|
type: "media",
|
|
conditionText: "screen",
|
|
matches: true,
|
|
},
|
|
{
|
|
type: "media",
|
|
conditionText: "print",
|
|
matches: false,
|
|
},
|
|
];
|
|
|
|
const updateCause = "updated-by-test";
|
|
await styleSheetsFront.update(
|
|
resource.resourceId,
|
|
"@media screen { color: red; } @media print { color: green; } body { color: cyan; }",
|
|
false,
|
|
updateCause
|
|
);
|
|
await waitUntil(() => updates.length === 4);
|
|
|
|
assertUpdate(updates[1].update, {
|
|
resourceId: resource.resourceId,
|
|
updateType: "property-change",
|
|
});
|
|
is(
|
|
updates[1].update.resourceUpdates.ruleCount,
|
|
3,
|
|
"resourceUpdates is correct"
|
|
);
|
|
is(updates[1].resource.ruleCount, 3, "cached resource is updated correctly");
|
|
|
|
assertUpdate(updates[2].update, {
|
|
resourceId: resource.resourceId,
|
|
updateType: "style-applied",
|
|
event: {
|
|
cause: updateCause,
|
|
},
|
|
});
|
|
is(
|
|
updates[2].update.resourceUpdates,
|
|
undefined,
|
|
"resourceUpdates is correct"
|
|
);
|
|
|
|
assertUpdate(updates[3].update, {
|
|
resourceId: resource.resourceId,
|
|
updateType: "at-rules-changed",
|
|
});
|
|
assertAtRules(updates[3].update.resourceUpdates.atRules, expectedAtRules);
|
|
|
|
// Check the actual page.
|
|
const styleSheetResult = await getStyleSheetResult(tab);
|
|
|
|
is(
|
|
styleSheetResult.ruleCount,
|
|
3,
|
|
"ruleCount of actual stylesheet is updated correctly"
|
|
);
|
|
assertAtRules(styleSheetResult.atRules, expectedAtRules);
|
|
|
|
targetCommand.destroy();
|
|
await client.close();
|
|
}
|
|
|
|
function resizeToInner(win, wantedInnerWidth, wantedInnerHeight) {
|
|
const diffX = wantedInnerWidth - win.innerWidth;
|
|
const diffY = wantedInnerHeight - win.innerHeight;
|
|
win.resizeBy(diffX, diffY);
|
|
}
|
|
|
|
async function testNestedResourceUpdateFeature() {
|
|
info("Check nested resource update feature of the ResourceCommand");
|
|
|
|
const tab = await addTab(STYLE_TEST_URL);
|
|
const win = tab.ownerGlobal;
|
|
|
|
const { innerWidth: originalWindowWidth, innerHeight: originalWindowHeight } =
|
|
win;
|
|
|
|
registerCleanupFunction(() => {
|
|
resizeToInner(win, originalWindowWidth, originalWindowHeight);
|
|
});
|
|
|
|
const { client, resourceCommand, targetCommand } =
|
|
await initResourceCommand(tab);
|
|
|
|
info("Setup the watcher");
|
|
const availableResources = [];
|
|
const updates = [];
|
|
await resourceCommand.watchResources([resourceCommand.TYPES.STYLESHEET], {
|
|
onAvailable: pushAvailableResource(availableResources),
|
|
onUpdated: newUpdates => updates.push(...newUpdates),
|
|
});
|
|
is(
|
|
availableResources.length,
|
|
EXISTING_RESOURCES.length,
|
|
"Length of existing resources is correct"
|
|
);
|
|
|
|
info("Apply new media query");
|
|
// In order to avoid applying the media query (min-height: 400px).
|
|
if (originalWindowHeight !== 300) {
|
|
await new Promise(resolve => {
|
|
win.addEventListener("resize", resolve, { once: true });
|
|
resizeToInner(win, originalWindowWidth, 300);
|
|
});
|
|
}
|
|
|
|
// Retrieve the stylesheet of the top-level target
|
|
const resource = availableResources.find(
|
|
innerResource => innerResource.targetFront.isTopLevel
|
|
);
|
|
const styleSheetsFront = await resource.targetFront.getFront("stylesheets");
|
|
await styleSheetsFront.update(
|
|
resource.resourceId,
|
|
`@media (min-height: 400px) {
|
|
html {
|
|
color: red;
|
|
}
|
|
@layer myLayer {
|
|
@supports (container-type) {
|
|
:root {
|
|
color: gold;
|
|
container: root inline-size;
|
|
}
|
|
|
|
@container root (width > 10px) {
|
|
body {
|
|
color: gold;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@property --my-property {
|
|
syntax: "<color>";
|
|
inherits: true;
|
|
initial-value: #f06;
|
|
}`,
|
|
false
|
|
);
|
|
await waitUntil(() => updates.length === 3);
|
|
is(
|
|
updates.at(-1).resource.ruleCount,
|
|
8,
|
|
"Resource in update has expected ruleCount"
|
|
);
|
|
|
|
is(resource.atRules[0].matches, false, "Media query is not matched yet");
|
|
|
|
info("Change window size to fire matches-change event");
|
|
resizeToInner(win, originalWindowWidth, 500);
|
|
await waitUntil(() => updates.length === 4);
|
|
|
|
// Check the update content.
|
|
const targetUpdate = updates[3];
|
|
assertUpdate(targetUpdate.update, {
|
|
resourceId: resource.resourceId,
|
|
updateType: "matches-change",
|
|
});
|
|
Assert.strictEqual(
|
|
resource,
|
|
targetUpdate.resource,
|
|
"Update object has the same resource"
|
|
);
|
|
|
|
is(
|
|
JSON.stringify(targetUpdate.update.nestedResourceUpdates[0].path),
|
|
JSON.stringify(["atRules", 0, "matches"]),
|
|
"path of nestedResourceUpdates is correct"
|
|
);
|
|
is(
|
|
targetUpdate.update.nestedResourceUpdates[0].value,
|
|
true,
|
|
"value of nestedResourceUpdates is correct"
|
|
);
|
|
|
|
// Check the resource.
|
|
const expectedAtRules = [
|
|
{
|
|
type: "media",
|
|
conditionText: "(min-height: 400px)",
|
|
matches: true,
|
|
},
|
|
{
|
|
type: "layer",
|
|
layerName: "myLayer",
|
|
},
|
|
{
|
|
type: "support",
|
|
conditionText: "(container-type)",
|
|
},
|
|
{
|
|
type: "container",
|
|
conditionText: "root (width > 10px)",
|
|
},
|
|
{
|
|
type: "property",
|
|
propertyName: "--my-property",
|
|
},
|
|
];
|
|
|
|
assertAtRules(targetUpdate.resource.atRules, expectedAtRules);
|
|
|
|
// Check the actual page.
|
|
const styleSheetResult = await getStyleSheetResult(tab);
|
|
is(
|
|
styleSheetResult.ruleCount,
|
|
8,
|
|
"ruleCount of actual stylesheet is updated correctly"
|
|
);
|
|
assertAtRules(styleSheetResult.atRules, expectedAtRules);
|
|
|
|
resizeToInner(win, originalWindowWidth, originalWindowHeight);
|
|
|
|
targetCommand.destroy();
|
|
await client.close();
|
|
}
|
|
|
|
function findMatchingExpectedResource(resource) {
|
|
return EXISTING_RESOURCES.find(
|
|
expected =>
|
|
resource.href === expected.href &&
|
|
resource.nodeHref === expected.nodeHref &&
|
|
resource.ruleCount === expected.ruleCount &&
|
|
resource.constructed == expected.constructed
|
|
);
|
|
}
|
|
|
|
async function getStyleSheetResult(tab) {
|
|
const result = await ContentTask.spawn(tab.linkedBrowser, null, () => {
|
|
const document = content.document;
|
|
const stylesheet = document.styleSheets[0];
|
|
let ruleCount = 0;
|
|
const atRules = [];
|
|
|
|
const traverseRules = ruleList => {
|
|
for (const rule of ruleList) {
|
|
ruleCount++;
|
|
|
|
if (rule.media) {
|
|
let matches = false;
|
|
try {
|
|
const mql = content.matchMedia(rule.media.mediaText);
|
|
matches = mql.matches;
|
|
} catch (e) {
|
|
// Ignored
|
|
}
|
|
|
|
atRules.push({
|
|
type: "media",
|
|
conditionText: rule.conditionText,
|
|
matches,
|
|
});
|
|
} else if (rule instanceof content.CSSContainerRule) {
|
|
atRules.push({
|
|
type: "container",
|
|
conditionText: rule.conditionText,
|
|
});
|
|
} else if (rule instanceof content.CSSLayerBlockRule) {
|
|
atRules.push({ type: "layer", layerName: rule.name });
|
|
} else if (rule instanceof content.CSSSupportsRule) {
|
|
atRules.push({
|
|
type: "support",
|
|
conditionText: rule.conditionText,
|
|
});
|
|
} else if (rule instanceof content.CSSPropertyRule) {
|
|
atRules.push({
|
|
type: "property",
|
|
propertyName: rule.name,
|
|
});
|
|
}
|
|
|
|
if (rule.cssRules) {
|
|
traverseRules(rule.cssRules);
|
|
}
|
|
}
|
|
};
|
|
traverseRules(stylesheet.cssRules);
|
|
|
|
return { ruleCount, atRules };
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function assertAtRules(atRules, expectedAtRules) {
|
|
is(
|
|
atRules.length,
|
|
expectedAtRules.length,
|
|
"Length of the atRules is correct"
|
|
);
|
|
|
|
for (let i = 0; i < atRules.length; i++) {
|
|
const atRule = atRules[i];
|
|
const expected = expectedAtRules[i];
|
|
is(atRule.type, expected.type, "at-rule is of expected type");
|
|
is(
|
|
atRules[i].conditionText,
|
|
expected.conditionText,
|
|
"conditionText is correct"
|
|
);
|
|
if (expected.type === "media") {
|
|
is(atRule.matches, expected.matches, "matches is correct");
|
|
} else if (expected.type === "layer") {
|
|
is(atRule.layerName, expected.layerName, "layerName is correct");
|
|
} else if (expected.type === "property") {
|
|
is(atRule.propertyName, expected.propertyName, "propertyName is correct");
|
|
}
|
|
|
|
if (expected.line !== undefined) {
|
|
is(atRule.line, expected.line, "line is correct");
|
|
}
|
|
|
|
if (expected.column !== undefined) {
|
|
is(atRule.column, expected.column, "column is correct");
|
|
}
|
|
}
|
|
}
|
|
|
|
async function assertResource(resource, expected) {
|
|
is(
|
|
resource.resourceType,
|
|
ResourceCommand.TYPES.STYLESHEET,
|
|
"Resource type is correct"
|
|
);
|
|
const styleText = (await getStyleSheetResourceText(resource)).trim();
|
|
is(styleText, expected.styleText, "Style text is correct");
|
|
is(resource.href, expected.href, "href is correct");
|
|
is(resource.nodeHref, expected.nodeHref, "nodeHref is correct");
|
|
is(resource.isNew, expected.isNew, "isNew is correct");
|
|
is(resource.disabled, expected.disabled, "disabled is correct");
|
|
is(resource.constructed, expected.constructed, "constructed is correct");
|
|
is(resource.ruleCount, expected.ruleCount, "ruleCount is correct");
|
|
assertAtRules(resource.atRules, expected.atRules);
|
|
}
|
|
|
|
function assertUpdate(update, expected) {
|
|
is(
|
|
update.resourceType,
|
|
ResourceCommand.TYPES.STYLESHEET,
|
|
"Resource type is correct"
|
|
);
|
|
is(update.resourceId, expected.resourceId, "resourceId is correct");
|
|
is(update.updateType, expected.updateType, "updateType is correct");
|
|
if (expected.event?.cause) {
|
|
is(update.event?.cause, expected.event.cause, "cause is correct");
|
|
}
|
|
}
|
|
|
|
function assertDestroyed(resource, expected) {
|
|
is(
|
|
resource.resourceType,
|
|
ResourceCommand.TYPES.STYLESHEET,
|
|
"Resource type is correct"
|
|
);
|
|
is(resource.resourceId, expected.resourceId, "resourceId is correct");
|
|
}
|
|
|
|
function getResourceTimingCount(tab) {
|
|
return ContentTask.spawn(tab.linkedBrowser, [], () => {
|
|
return content.performance.getEntriesByType("resource").length;
|
|
});
|
|
}
|