mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
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:
parent
09443b4a90
commit
8ae484b5e7
@ -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()
|
||||
);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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 () {
|
||||
|
@ -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",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
});
|
@ -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,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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,
|
||||
|
@ -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: [],
|
||||
|
@ -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: [],
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user