Bug 1834946 - [devtools] MDN compat data url is nullable. r=jdescottes,devtools-backward-compat-reviewers,devtools-reviewers.

The `mdn_url` property in the compatibility data is not always defined,
as some properties are not documented on MDN.
Luckily, there's a `spec_url` property that we can default to in such case,
so we return that from the server, and fall back to this in the compatibility
panel and the compatibility tooltip.

We might still have cases where we don't have any link at all, so in such case,
we don't render a link in the compatibility panel, and we don't show the "Learn more"
link in the compatibility tooltip.

In order to properly check the page the user might be taken to, we move
the `simulateLinkClick` helper to `shared-head.js` and use it in both compatibility
panel and compatibility tooltip assertion helpers.

Some tests are then updated to provide the now missing information that those
helpers expect.

Differential Revision: https://phabricator.services.mozilla.com/D179030
This commit is contained in:
Nicolas Chevobbe 2023-05-26 09:37:49 +00:00
parent 09443b4a90
commit 8ae484b5e7
23 changed files with 478 additions and 159 deletions

View File

@ -39,6 +39,12 @@ loader.lazyRequireGetter(
true
);
const MDN_LINK_PARAMS = new URLSearchParams({
utm_source: "devtools",
utm_medium: "inspector-compatibility",
utm_campaign: "default",
});
class IssueItem extends PureComponent {
static get propTypes() {
return {
@ -54,15 +60,9 @@ class IssueItem extends PureComponent {
}
_onLinkClicked(e) {
const { url } = this.props;
e.preventDefault();
e.stopPropagation();
openDocLink(
url +
"?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
);
openDocLink(e.target.href);
}
_getTestDataAttributes() {
@ -148,22 +148,36 @@ class IssueItem extends PureComponent {
);
}
_renderDescription() {
const { property, url } = this.props;
_renderPropertyEl() {
const { property, url, specUrl } = this.props;
const baseCls = "compatibility-issue-item__property devtools-monospace";
if (!url && !specUrl) {
return dom.span({ className: baseCls }, property);
}
const href = url ? `${url}?${MDN_LINK_PARAMS}` : specUrl;
return dom.a(
{
className: `${baseCls} ${
url
? "compatibility-issue-item__mdn-link"
: "compatibility-issue-item__spec-link"
}`,
href,
title: href,
onClick: e => this._onLinkClicked(e),
},
property
);
}
_renderDescription() {
return dom.div(
{
className: "compatibility-issue-item__description",
},
dom.a(
{
className: "compatibility-issue-item__mdn-link devtools-monospace",
href: url,
title: url,
onClick: e => this._onLinkClicked(e),
},
property
),
this._renderPropertyEl(),
this._renderCauses(),
this._renderUnsupportedBrowserList()
);

View File

@ -3,7 +3,7 @@
"use strict";
// Test whether the deprecated CSS property is shown as issue correctly or not.
// Test that unsupported CSS properties are correctly reported as issues.
const {
COMPATIBILITY_ISSUE_TYPE,
@ -15,6 +15,8 @@ const TEST_URI = `
color: blue;
scrollbar-width: thin;
user-modify: read-only;
hyphenate-limit-chars: auto;
overflow-clip-box: padding-box;
}
div {
ruby-align: center;
@ -41,6 +43,22 @@ const TEST_DATA_SELECTED = [
deprecated: true,
experimental: false,
},
{
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "hyphenate-limit-chars",
// No MDN url but a spec one
specUrl:
"https://drafts.csswg.org/css-text-4/#propdef-hyphenate-limit-chars",
deprecated: false,
experimental: false,
},
{
// No MDN url nor spec url
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "overflow-clip-box",
deprecated: false,
experimental: false,
},
];
const TEST_DATA_ALL = [
@ -60,6 +78,11 @@ add_task(async function () {
const { allElementsPane, selectedElementPane } =
await openCompatibilityView();
// If the test fail because the properties used are no longer in the dataset, or they
// now have mdn/spec url although we expected them not to, uncomment the next line
// to get all the properties in the dataset that don't have a MDN url.
// logCssCompatDataPropertiesWithoutMDNUrl()
info("Check the content of the issue list on the selected element");
await assertIssueList(selectedElementPane, TEST_DATA_SELECTED);

View File

@ -22,11 +22,23 @@ const TEST_URI = `
`;
const TEST_DATA_SELECTED = [
{ property: "ruby-align" },
{ property: "user-modify" },
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
{
property: "user-modify",
url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
},
];
const TEST_DATA_ALL = [...TEST_DATA_SELECTED, { property: "scrollbar-width" }];
const TEST_DATA_ALL = [
...TEST_DATA_SELECTED,
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
];
const {
COMPATIBILITY_UPDATE_SELECTED_NODE_FAILURE,

View File

@ -22,8 +22,14 @@ const TEST_URI = `
const TEST_DATA_SELECTED = {
fullRule: {
expectedProperties: [
{ property: "ruby-align" },
{ property: "scrollbar-width" },
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
],
expectedNodes: [
{
@ -37,7 +43,12 @@ const TEST_DATA_SELECTED = {
],
},
classRule: {
expectedProperties: [{ property: "ruby-align" }],
expectedProperties: [
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
],
expectedNodes: [
{
property: "ruby-align",
@ -46,7 +57,12 @@ const TEST_DATA_SELECTED = {
],
},
elementRule: {
expectedProperties: [{ property: "scrollbar-width" }],
expectedProperties: [
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
],
expectedNodes: [
{
property: "scrollbar-width",
@ -59,8 +75,14 @@ const TEST_DATA_SELECTED = {
const TEST_DATA_ALL = {
fullRule: {
expectedProperties: [
{ property: "ruby-align" },
{ property: "scrollbar-width" },
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
],
expectedNodes: [
{
@ -74,7 +96,12 @@ const TEST_DATA_ALL = {
],
},
classRule: {
expectedProperties: [{ property: "ruby-align" }],
expectedProperties: [
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
],
expectedNodes: [
{
property: "ruby-align",
@ -83,7 +110,12 @@ const TEST_DATA_ALL = {
],
},
elementRule: {
expectedProperties: [{ property: "scrollbar-width" }],
expectedProperties: [
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
],
expectedNodes: [
{
property: "scrollbar-width",

View File

@ -30,8 +30,14 @@ const TEST_DATA_SELECTED = [
{
selector: ".has-issue",
expectedIssues: [
{ property: "scrollbar-width" },
{ property: "user-modify" },
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
{
property: "user-modify",
url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
},
],
},
{
@ -40,14 +46,28 @@ const TEST_DATA_SELECTED = [
},
{
selector: "body",
expectedIssues: [{ property: "ruby-align" }],
expectedIssues: [
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
],
},
];
const TEST_DATA_ALL = [
{ property: "ruby-align" },
{ property: "scrollbar-width" },
{ property: "user-modify" },
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
{
property: "user-modify",
url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
},
];
add_task(async function () {

View File

@ -19,10 +19,21 @@ const TEST_DATA_ISSUES = {
<div>test</div>
</body>
`,
expectedIssuesOnSelected: [{ property: "ruby-align" }],
expectedIssuesOnSelected: [
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
],
expectedIssuesOnAll: [
{ property: "ruby-align" },
{ property: "scrollbar-width" },
{
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
},
{
property: "scrollbar-width",
url: "https://developer.mozilla.org/docs/Web/CSS/scrollbar-width",
},
],
};

View File

@ -26,6 +26,7 @@ add_task(async function () {
{
property: "user-modify",
unsupportedBrowsers: targetBrowsers,
url: "https://developer.mozilla.org/docs/Web/CSS/user-modify",
},
];
await assertIssueList(selectedElementPane, expectedIssues);

View File

@ -40,6 +40,7 @@ add_task(async function () {
{ id: "firefox", name: "Firefox", version: "1" },
{ id: "firefox_android", name: "Firefox Android", version: "1" },
],
url: "https://developer.mozilla.org/docs/Web/CSS/border-block-color",
},
];
await assertIssueList(selectedElementPane, expectedIssues);

View File

@ -142,6 +142,61 @@ async function assertIssueList(panel, expectedIssues) {
`The value of ${datasetKey} is correct`
);
}
const propertyEl = issueEl.querySelector(
".compatibility-issue-item__property"
);
const MDN_CLASSNAME = "compatibility-issue-item__mdn-link";
const SPEC_CLASSNAME = "compatibility-issue-item__spec-link";
is(
propertyEl.textContent,
property,
"property name is displayed as expected"
);
is(
propertyEl.classList.contains(MDN_CLASSNAME),
!!expectedIssue.url,
`${property} element ${
expectedIssue.url ? "has" : "does not have"
} mdn link class`
);
is(
propertyEl.classList.contains(SPEC_CLASSNAME),
!!expectedIssue.specUrl,
`${property} element ${
expectedIssue.specUrl ? "has" : "does not have"
} spec link class`
);
if (expectedIssue.url || expectedIssue.specUrl) {
is(
propertyEl.nodeName.toLowerCase(),
"a",
`Link rendered for ${property}`
);
const expectedUrl = expectedIssue.url
? expectedIssue.url +
"?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
: expectedIssue.specUrl;
const { link } = await simulateLinkClick(propertyEl);
is(
link,
expectedUrl,
`Click on ${property} link navigates user to expected url`
);
} else {
is(
propertyEl.nodeName.toLowerCase(),
"span",
`No link rendered for ${property}`
);
const { link } = await simulateLinkClick(propertyEl);
is(link, null, `Click on ${property} does not navigate`);
}
}
}

View File

@ -9,10 +9,10 @@ exports[`IssueItem component renders a deprecated issue of CSS property 1`] = `
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -38,10 +38,10 @@ exports[`IssueItem component renders a prefixNeeded issue of CSS property 1`] =
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -83,10 +83,10 @@ exports[`IssueItem component renders an experimental issue of CSS property 1`] =
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -112,10 +112,10 @@ exports[`IssueItem component renders an issue which has deprecated and experimen
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -157,10 +157,10 @@ exports[`IssueItem component renders an issue which has deprecated and prefixNee
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -202,10 +202,10 @@ exports[`IssueItem component renders an issue which has deprecated, experimental
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -247,10 +247,10 @@ exports[`IssueItem component renders an issue which has experimental and prefixN
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -292,10 +292,10 @@ exports[`IssueItem component renders an issue which has nodes that caused this i
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>
@ -324,10 +324,10 @@ exports[`IssueItem component renders an unsupported issue of CSS property 1`] =
className="compatibility-issue-item__description"
>
<a
className="compatibility-issue-item__mdn-link devtools-monospace"
href="test-url"
className="compatibility-issue-item__property devtools-monospace compatibility-issue-item__mdn-link"
href="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
onClick={[Function]}
title="test-url"
title="test-url?utm_source=devtools&utm_medium=inspector-compatibility&utm_campaign=default"
>
test-property
</a>

View File

@ -30,7 +30,9 @@ const issue = {
// The CSS property which caused this issue.
property: PropTypes.string.isRequired,
// The url of MDN documentation for the CSS property.
url: PropTypes.string.isRequired,
url: PropTypes.string,
// The url of the specification for the CSS property.
specUrl: PropTypes.string,
// Whether the CSS property is deprecated or not.
deprecated: PropTypes.bool.isRequired,
// Whether the CSS property is experimental or not.

View File

@ -333,6 +333,7 @@ class TextProperty {
property: rootProperty,
deprecated,
experimental,
specUrl,
url,
unsupportedBrowsers,
} = compatibilityIssues[indexOfProperty];
@ -358,6 +359,7 @@ class TextProperty {
property,
rootProperty,
msgId,
specUrl,
url,
unsupportedBrowsers,
};

View File

@ -58,6 +58,7 @@ skip-if =
os == "linux" #bug 1657807
os == "win" #bug 1657807
[browser_rules_css-compatibility-check-add-fix.js]
[browser_rules_css-compatibility-learn-more-link.js]
[browser_rules_css-compatibility-toggle-rules.js]
[browser_rules_css-compatibility-tooltip-telemetry.js]
[browser_rules_filtereditor-appears-on-swatch-click.js]

View File

@ -0,0 +1,66 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the Learn More link is displayed when possible,
// and that it links to MDN or the spec if no MDN url is provided.
const TEST_URI = `
<style>
body {
user-select: none;
hyphenate-limit-chars: auto;
overflow-clip-box: padding-box;
}
</style>
<body>
</body>`;
const TEST_DATA_INITIAL = [
{
selector: "body",
rules: [
{},
{
"user-select": {
value: "none",
expected: COMPATIBILITY_TOOLTIP_MESSAGE.default,
// MDN url
expectedLearnMoreUrl:
"https://developer.mozilla.org/docs/Web/CSS/user-select?utm_source=devtools&utm_medium=inspector-css-compatibility&utm_campaign=default",
},
"hyphenate-limit-chars": {
value: "auto",
expected: COMPATIBILITY_TOOLTIP_MESSAGE.default,
// No MDN url, but a spec one
expectedLearnMoreUrl:
"https://drafts.csswg.org/css-text-4/#propdef-hyphenate-limit-chars",
},
"overflow-clip-box": {
expected: COMPATIBILITY_TOOLTIP_MESSAGE.default,
value: "padding-box",
// No MDN nor spec url
expectedLearnMoreUrl: null,
},
},
],
},
];
add_task(async function () {
await pushPref(
"devtools.inspector.ruleview.inline-compatibility-warning.enabled",
true
);
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
const { inspector, view } = await openRuleView();
// If the test fail because the properties used are no longer in the dataset, or they
// now have mdn/spec url although we expected them not to, uncomment the next line
// to get all the properties in the dataset that don't have a MDN url.
// logCssCompatDataPropertiesWithoutMDNUrl()
await runCSSCompatibilityTests(view, inspector, TEST_DATA_INITIAL);
});

View File

@ -890,16 +890,19 @@ function getTextProperty(view, ruleIndex, declaration) {
* The index we expect the rule to have in the rule-view.
* @param {Object} declaration
* An object representing the declaration e.g. { color: "red" }.
* @param {string | undefined} expected
* @param {Object} options
* @param {string | undefined} options.expected
* Expected message ID for the given incompatible property.
* If the expected message is not specified (undefined), the given declaration
* is inferred as cross-browser compatible and is tested for same.
* @param {string | null | undefined} options.expectedLearnMoreUrl
* Expected learn more link. Pass `null` to check that no "Learn more" link is displayed.
*/
async function checkDeclarationCompatibility(
view,
ruleIndex,
declaration,
expected
{ expected, expectedLearnMoreUrl }
) {
const declarations = await getPropertiesForRuleIndex(view, ruleIndex, true);
const [[name, value]] = Object.entries(declaration);
@ -922,6 +925,35 @@ async function checkDeclarationCompatibility(
declaration
);
}
if (expectedLearnMoreUrl !== undefined) {
// Show the tooltip
const tooltip = view.tooltips.getTooltip("interactiveTooltip");
const onTooltipReady = tooltip.once("shown");
const { compatibilityIcon } = declarations.get(dec);
await view.tooltips.onInteractiveTooltipTargetHover(compatibilityIcon);
tooltip.show(compatibilityIcon);
await onTooltipReady;
const learnMoreEl = tooltip.panel.querySelector(".link");
if (expectedLearnMoreUrl === null) {
ok(!learnMoreEl, `"${dec}" has no "Learn more" link`);
} else {
ok(learnMoreEl, `"${dec}" has a "Learn more" link`);
const { link } = await simulateLinkClick(learnMoreEl);
is(
link,
expectedLearnMoreUrl,
`Click on ${dec} "Learn more" link navigates user to expected url`
);
}
// Hide the tooltip.
const onTooltipHidden = tooltip.once("hidden");
tooltip.hide();
await onTooltipHidden;
}
}
/**
@ -1070,6 +1102,7 @@ async function checkInteractiveTooltip(view, type, ruleIndex, declaration) {
* {
* value: "grab",
* expected: INCOMPATIBILITY_TOOLTIP_MESSAGE.default,
* expectedLearnMoreUrl: "https://developer.mozilla.org/en-US/docs/Web/CSS/cursor",
* },
* },
* ],
@ -1091,7 +1124,10 @@ async function runCSSCompatibilityTests(view, inspector, tests) {
{
[rule]: rules[rule].value,
},
rules[rule].expected
{
expected: rules[rule].expected,
expectedLearnMoreUrl: rules[rule].expectedLearnMoreUrl,
}
);
}
}

View File

@ -2135,3 +2135,111 @@ function createVersionizedHttpTestServer(testFolderName) {
},
};
}
/**
* Fake clicking a link and return the URL we would have navigated to.
* This function should be used to check external links since we can't access
* network in tests.
* This can also be used to test that a click will not be fired.
*
* @param ElementNode element
* The <a> element we want to simulate click on.
* @param Object clickEventProps
* The custom properties which would be used to dispatch a click event
* @returns Promise
* A Promise that is resolved when the link click simulation occured or
* when the click is not dispatched.
* The promise resolves with an object that holds the following properties
* - link: url of the link or null(if event not fired)
* - where: "tab" if tab is active or "tabshifted" if tab is inactive
* or null(if event not fired)
*/
function simulateLinkClick(element, clickEventProps) {
return overrideOpenLink(() => {
if (clickEventProps) {
// Click on the link using the event properties.
element.dispatchEvent(clickEventProps);
} else {
// Click on the link.
element.click();
}
});
}
/**
* Override the browserWindow open*Link function, executes the passed function and either
* wait for:
* - the link to be "opened"
* - 1s before timing out
* Then it puts back the original open*Link functions in browserWindow.
*
* @returns {Promise<Object>}: A promise resolving with an object of the following shape:
* - link: The link that was "opened"
* - where: If the link was opened in the background (null) or not ("tab").
*/
function overrideOpenLink(fn) {
const browserWindow = Services.wm.getMostRecentWindow(
gDevTools.chromeWindowType
);
// Override LinkIn methods to prevent navigating.
const oldOpenTrustedLinkIn = browserWindow.openTrustedLinkIn;
const oldOpenWebLinkIn = browserWindow.openWebLinkIn;
const onOpenLink = new Promise(resolve => {
const openLinkIn = function (link, where) {
browserWindow.openTrustedLinkIn = oldOpenTrustedLinkIn;
browserWindow.openWebLinkIn = oldOpenWebLinkIn;
resolve({ link, where });
};
browserWindow.openWebLinkIn = browserWindow.openTrustedLinkIn = openLinkIn;
fn();
});
// Declare a timeout Promise that we can use to make sure openTrustedLinkIn or
// openWebLinkIn was not called.
let timeoutId;
const onTimeout = new Promise(function (resolve) {
timeoutId = setTimeout(() => {
browserWindow.openTrustedLinkIn = oldOpenTrustedLinkIn;
browserWindow.openWebLinkIn = oldOpenWebLinkIn;
timeoutId = null;
resolve({ link: null, where: null });
}, 1000);
});
onOpenLink.then(() => {
if (timeoutId) {
clearTimeout(timeoutId);
}
});
return Promise.race([onOpenLink, onTimeout]);
}
/**
* Since the MDN data is updated frequently, it might happen that the properties used in
* this test are not in the dataset anymore/now have URLs.
* This function will return properties in the dataset that don't have MDN url so you
* can easily find a replacement.
*/
function logCssCompatDataPropertiesWithoutMDNUrl() {
const cssPropertiesCompatData = require("resource://devtools/shared/compatibility/dataset/css-properties.json");
function walk(node) {
for (const propertyName in node) {
const property = node[propertyName];
if (property.__compat) {
if (!property.__compat.mdn_url) {
dump(
`"${propertyName}" - MDN URL: ${
property.__compat.mdn_url || "❌"
} - Spec URL: ${property.__compat.spec_url || "❌"}\n`
);
}
} else if (typeof property == "object") {
walk(property);
}
}
}
walk(cssPropertiesCompatData);
}

View File

@ -216,6 +216,8 @@ class CssCompatibilityTooltipHelper {
* alias: <Array>,
* // Link to MDN documentation for the particular CSS rule
* url: <string>,
* // Link to the spec for the particular CSS rule
* specUrl: <string>,
* deprecated: <boolean>,
* experimental: <boolean>,
* // An array of all the browsers that don't support the given CSS rule
@ -226,10 +228,12 @@ class CssCompatibilityTooltipHelper {
*/
getTemplate(data, tooltip) {
const { doc } = tooltip;
const { url, unsupportedBrowsers } = data;
const { specUrl, url, unsupportedBrowsers } = data;
this.#currentTooltip = tooltip;
this.#currentUrl = `${url}?utm_source=devtools&utm_medium=inspector-css-compatibility&utm_campaign=default`;
this.#currentUrl = url
? `${url}?utm_source=devtools&utm_medium=inspector-css-compatibility&utm_campaign=default`
: specUrl;
const templateNode = this.#createElement(doc, "template");
const tooltipContainer = this.#createElement(doc, "div", [
@ -243,12 +247,14 @@ class CssCompatibilityTooltipHelper {
);
if (browserListContainer) {
tooltipContainer.appendChild(browserListContainer);
this.#renderUnsupportedBrowserList(tooltipContainer, unsupportedBrowsers);
}
tooltipContainer.appendChild(this.#getLearnMoreMessage(doc, data));
templateNode.content.appendChild(tooltipContainer);
if (this.#currentUrl) {
tooltipContainer.appendChild(this.#getLearnMoreMessage(doc, data));
}
this.#renderUnsupportedBrowserList(tooltipContainer, unsupportedBrowsers);
templateNode.content.appendChild(tooltipContainer);
return doc.importNode(templateNode.content, true);
}

View File

@ -129,7 +129,7 @@
color: var(--compatibility-cause-color);
}
.compatibility-issue-item__mdn-link {
.compatibility-issue-item__property {
color: var(--theme-highlight-blue);
unicode-bidi: plaintext;
display: flex;

View File

@ -954,86 +954,6 @@ async function closeConsole(tab = gBrowser.selectedTab) {
}
}
/**
* Fake clicking a link and return the URL we would have navigated to.
* This function should be used to check external links since we can't access
* network in tests.
* This can also be used to test that a click will not be fired.
*
* @param ElementNode element
* The <a> element we want to simulate click on.
* @param Object clickEventProps
* The custom properties which would be used to dispatch a click event
* @returns Promise
* A Promise that is resolved when the link click simulation occured or
* when the click is not dispatched.
* The promise resolves with an object that holds the following properties
* - link: url of the link or null(if event not fired)
* - where: "tab" if tab is active or "tabshifted" if tab is inactive
* or null(if event not fired)
*/
function simulateLinkClick(element, clickEventProps) {
return overrideOpenLink(() => {
if (clickEventProps) {
// Click on the link using the event properties.
element.dispatchEvent(clickEventProps);
} else {
// Click on the link.
element.click();
}
});
}
/**
* Override the browserWindow open*Link function, executes the passed function and either
* wait for:
* - the link to be "opened"
* - 1s before timing out
* Then it puts back the original open*Link functions in browserWindow.
*
* @returns {Promise<Object>}: A promise resolving with an object of the following shape:
* - link: The link that was "opened"
* - where: If the link was opened in the background (null) or not ("tab").
*/
function overrideOpenLink(fn) {
const browserWindow = Services.wm.getMostRecentWindow(
gDevTools.chromeWindowType
);
// Override LinkIn methods to prevent navigating.
const oldOpenTrustedLinkIn = browserWindow.openTrustedLinkIn;
const oldOpenWebLinkIn = browserWindow.openWebLinkIn;
const onOpenLink = new Promise(resolve => {
const openLinkIn = function (link, where) {
browserWindow.openTrustedLinkIn = oldOpenTrustedLinkIn;
browserWindow.openWebLinkIn = oldOpenWebLinkIn;
resolve({ link, where });
};
browserWindow.openWebLinkIn = browserWindow.openTrustedLinkIn = openLinkIn;
fn();
});
// Declare a timeout Promise that we can use to make sure openTrustedLinkIn or
// openWebLinkIn was not called.
let timeoutId;
const onTimeout = new Promise(function (resolve) {
timeoutId = setTimeout(() => {
browserWindow.openTrustedLinkIn = oldOpenTrustedLinkIn;
browserWindow.openWebLinkIn = oldOpenWebLinkIn;
timeoutId = null;
resolve({ link: null, where: null });
}, 1000);
});
onOpenLink.then(() => {
if (timeoutId) {
clearTimeout(timeoutId);
}
});
return Promise.race([onOpenLink, onTimeout]);
}
/**
* Open a network request logged in the webconsole in the netmonitor panel.
*

View File

@ -296,12 +296,12 @@ class MDNCompatibility {
}
const { deprecated, experimental } = compatTable.status || {};
const url = compatTable.mdn_url;
return {
database,
terms,
url,
url: compatTable.mdn_url,
specUrl: compatTable.spec_url,
deprecated,
experimental,
unsupportedBrowsers,

View File

@ -59,6 +59,7 @@ const TEST_DATA = [
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "grid-column",
url: "https://developer.mozilla.org/docs/Web/CSS/grid-column",
specUrl: "https://drafts.csswg.org/css-grid/#placement-shorthands",
deprecated: false,
experimental: false,
unsupportedBrowsers: [FIREFOX_1],
@ -80,6 +81,7 @@ const TEST_DATA = [
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "clip",
url: "https://developer.mozilla.org/docs/Web/CSS/clip",
specUrl: "https://drafts.fxtf.org/css-masking/#clip-property",
deprecated: true,
experimental: false,
unsupportedBrowsers: [],
@ -95,6 +97,7 @@ const TEST_DATA = [
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "ruby-align",
url: "https://developer.mozilla.org/docs/Web/CSS/ruby-align",
specUrl: "https://drafts.csswg.org/css-ruby/#ruby-align-property",
deprecated: false,
experimental: true,
unsupportedBrowsers: [FIREFOX_1],
@ -112,6 +115,7 @@ const TEST_DATA = [
property: "user-select",
aliases: ["-moz-user-select"],
url: "https://developer.mozilla.org/docs/Web/CSS/user-select",
specUrl: "https://drafts.csswg.org/css-ui/#content-selection",
deprecated: false,
experimental: false,
prefixNeeded: true,
@ -133,6 +137,7 @@ const TEST_DATA = [
property: "user-select",
aliases: ["-moz-user-select", "-webkit-user-select"],
url: "https://developer.mozilla.org/docs/Web/CSS/user-select",
specUrl: "https://drafts.csswg.org/css-ui/#content-selection",
deprecated: false,
experimental: false,
prefixNeeded: false,
@ -158,6 +163,7 @@ const TEST_DATA = [
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "-moz-user-input",
url: "https://developer.mozilla.org/docs/Web/CSS/-moz-user-input",
specUrl: undefined,
deprecated: true,
experimental: false,
unsupportedBrowsers: [],

View File

@ -72,6 +72,7 @@ const ISSUE_USER_SELECT = {
property: "user-select",
aliases: ["-moz-user-select"],
url: "https://developer.mozilla.org/docs/Web/CSS/user-select",
specUrl: "https://drafts.csswg.org/css-ui/#content-selection",
deprecated: false,
experimental: false,
prefixNeeded: true,
@ -88,6 +89,7 @@ const ISSUE_CLIP = {
type: COMPATIBILITY_ISSUE_TYPE.CSS_PROPERTY,
property: "clip",
url: "https://developer.mozilla.org/docs/Web/CSS/clip",
specUrl: "https://drafts.fxtf.org/css-masking/#clip-property",
deprecated: true,
experimental: false,
unsupportedBrowsers: [],

View File

@ -22,7 +22,8 @@ types.addDictType("compatibilityissues", {
type: "string",
property: "string",
aliases: "nullable:array:string",
url: "string",
url: "nullable:string",
specUrl: "nullable:string",
deprecated: "boolean",
experimental: "boolean",
unsupportedBrowsers: "array:browsertype",