Backed out 2 changesets (bug 1590493, bug 1592300) for causing ES Lint failure in test_accessible_row_context_menu.html CLOSED TREE

Backed out changeset 1a5752d4bceb (bug 1592300)
Backed out changeset 51eac37a4bbf (bug 1590493)
This commit is contained in:
Noemi Erli
2019-11-28 02:39:42 +02:00
parent c504e59ffd
commit 0c06b25cea
18 changed files with 265 additions and 96 deletions

View File

@@ -47,12 +47,29 @@ class AccessibilityStartup {
try {
this._walker = await this._accessibility.getWalker();
this._supports = {};
[this._supports.simulation] = await Promise.all([
// Added in Firefox 70.
this.target.actorHasMethod("accessibility", "getSimulator"),
]);
// Only works with FF61+ targets
this._supports.enableDisable = await this.target.actorHasMethod(
"accessibility",
"enable"
);
await this._accessibility.bootstrap();
if (this._supports.enableDisable) {
[
this._supports.relations,
this._supports.snapshot,
this._supports.audit,
this._supports.hydration,
this._supports.simulation,
] = await Promise.all([
this.target.actorHasMethod("accessible", "getRelations"),
this.target.actorHasMethod("accessible", "snapshot"),
this.target.actorHasMethod("accessible", "audit"),
this.target.actorHasMethod("accessible", "hydrate"),
this.target.actorHasMethod("accessibility", "getSimulator"),
]);
await this._accessibility.bootstrap();
}
return true;
} catch (e) {

View File

@@ -17,6 +17,9 @@ const { Provider } = require("devtools/client/shared/vendor/react-redux");
// Accessibility Panel
const MainFrame = createFactory(require("./components/MainFrame"));
const OldVersionDescription = createFactory(
require("./components/Description").OldVersionDescription
);
// Store
const createStore = require("devtools/client/shared/redux/create-store");
@@ -62,8 +65,8 @@ AccessibilityView.prototype = {
* - simulator {Object}
* front for simulator actor responsible for setting
* color matrices in docShell
* - toolbox {Object}
* devtools toolbox.
* - toolboxDoc {Document}
* toolbox document that will used by menus.
*/
async initialize({
front,
@@ -71,17 +74,23 @@ AccessibilityView.prototype = {
supports,
fluentBundles,
simulator,
toolbox,
toolboxDoc,
}) {
// Make sure state is reset every time accessibility panel is initialized.
await this.store.dispatch(reset(front, supports));
const container = document.getElementById("content");
if (!supports.enableDisable) {
ReactDOM.render(OldVersionDescription(), container);
return;
}
const mainFrame = MainFrame({
accessibility: front,
accessibilityWalker: walker,
fluentBundles,
simulator,
toolbox,
toolboxDoc,
});
// Render top level component
const provider = createElement(Provider, { store: this.store }, mainFrame);
@@ -98,9 +107,9 @@ AccessibilityView.prototype = {
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_HIGHLIGHTED);
},
async selectNodeAccessible(walker, node) {
async selectNodeAccessible(walker, node, supports) {
let accessible = await walker.getAccessibleFor(node);
if (accessible) {
if (accessible && supports.hydration) {
await accessible.hydrate();
}
@@ -115,7 +124,7 @@ AccessibilityView.prototype = {
accessible = await walker.getAccessibleFor(child);
// indexInParent property is only available with additional request
// for data (hydration) about the accessible object.
if (accessible) {
if (accessible && supports.hydration) {
await accessible.hydrate();
}

View File

@@ -10,16 +10,17 @@ const { UPDATE_DETAILS } = require("../constants");
*
* @param {Object} dom walker front
* @param {Object} accessible front
* @param {Object} list of supported serverside features.
*/
exports.updateDetails = (domWalker, accessible) => dispatch =>
exports.updateDetails = (domWalker, accessible, supports) => dispatch =>
Promise.all([
domWalker.getNodeFromActor(accessible.actorID, [
"rawAccessible",
"DOMNode",
]),
accessible.getRelations(),
accessible.audit(),
accessible.hydrate(),
supports.relations ? accessible.getRelations() : [],
supports.audit ? accessible.audit() : {},
supports.hydration ? accessible.hydrate() : null,
])
.then(response => dispatch({ accessible, type: UPDATE_DETAILS, response }))
.catch(error => dispatch({ accessible, type: UPDATE_DETAILS, error }));

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* global gTelemetry, EVENTS */
/* global gTelemetry, gToolbox, EVENTS */
// React & Redux
const {
@@ -80,9 +80,10 @@ class AccessibilityRow extends Component {
static get propTypes() {
return {
...TreeRow.propTypes,
hasContextMenu: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired,
toolboxDoc: PropTypes.object.isRequired,
scrollContentNodeIntoView: PropTypes.bool.isRequired,
supports: PropTypes.object,
};
}
@@ -150,13 +151,14 @@ class AccessibilityRow extends Component {
const {
dispatch,
member: { object },
supports,
} = this.props;
if (!object.actorID) {
return;
}
const domWalker = (await object.targetFront.getFront("inspector")).walker;
dispatch(updateDetails(domWalker, object));
dispatch(updateDetails(domWalker, object, supports));
window.emit(EVENTS.NEW_ACCESSIBLE_FRONT_SELECTED, object);
}
@@ -251,6 +253,12 @@ class AccessibilityRow extends Component {
}
async printToJSON() {
const { member, supports } = this.props;
if (!supports.snapshot) {
// Debugger server does not support Accessible actor snapshots.
return;
}
if (gTelemetry) {
gTelemetry.keyedScalarAdd(
TELEMETRY_ACCESSIBLE_CONTEXT_MENU_ITEM_ACTIVATED,
@@ -259,7 +267,7 @@ class AccessibilityRow extends Component {
);
}
const snapshot = await this.props.member.object.snapshot();
const snapshot = await member.object.snapshot();
openDocLink(
`${JSON_URL_PREFIX}${encodeURIComponent(JSON.stringify(snapshot))}`
);
@@ -269,20 +277,24 @@ class AccessibilityRow extends Component {
e.stopPropagation();
e.preventDefault();
if (!this.props.toolboxDoc) {
if (!gToolbox) {
return;
}
const menu = new Menu({ id: "accessibility-row-contextmenu" });
menu.append(
new MenuItem({
id: "menu-printtojson",
label: L10N.getStr("accessibility.tree.menu.printToJSON"),
click: () => this.printToJSON(),
})
);
const { supports } = this.props;
menu.popup(e.screenX, e.screenY, this.props.toolboxDoc);
if (supports.snapshot) {
menu.append(
new MenuItem({
id: "menu-printtojson",
label: L10N.getStr("accessibility.tree.menu.printToJSON"),
click: () => this.printToJSON(),
})
);
}
menu.popup(e.screenX, e.screenY, gToolbox.doc);
if (gTelemetry) {
gTelemetry.scalarAdd(TELEMETRY_ACCESSIBLE_CONTEXT_MENU_OPENED, 1);
@@ -297,7 +309,7 @@ class AccessibilityRow extends Component {
const { member } = this.props;
const props = {
...this.props,
onContextMenu: e => this.onContextMenu(e),
onContextMenu: this.props.hasContextMenu && (e => this.onContextMenu(e)),
onMouseOver: () => this.highlight(member.object),
onMouseOut: () => this.unhighlight(member.object),
key: `${member.path}-${member.active ? "active" : "inactive"}`,
@@ -313,8 +325,9 @@ class AccessibilityRow extends Component {
}
const mapStateToProps = ({
ui: { [PREFS.SCROLL_INTO_VIEW]: scrollContentNodeIntoView },
ui: { supports, [PREFS.SCROLL_INTO_VIEW]: scrollContentNodeIntoView },
}) => ({
supports,
scrollContentNodeIntoView,
});

View File

@@ -11,6 +11,8 @@ const {
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { span } = require("devtools/client/shared/vendor/react-dom-factories");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Badges = createFactory(require("./Badges"));
const AuditController = createFactory(require("./AuditController"));
@@ -24,10 +26,16 @@ class AccessibilityRowValue extends Component {
member: PropTypes.shape({
object: PropTypes.object,
}).isRequired,
supports: PropTypes.object.isRequired,
};
}
render() {
const {
member,
supports: { audit },
} = this.props;
return span(
{
role: "presentation",
@@ -37,14 +45,19 @@ class AccessibilityRowValue extends Component {
defaultRep: Grip,
cropLimit: 50,
}),
AuditController(
{
accessibleFront: this.props.member.object,
},
Badges()
)
audit &&
AuditController(
{
accessibleFront: member.object,
},
Badges()
)
);
}
}
module.exports = AccessibilityRowValue;
const mapStateToProps = ({ ui: { supports } }) => {
return { supports };
};
module.exports = connect(mapStateToProps)(AccessibilityRowValue);

View File

@@ -36,12 +36,12 @@ class AccessibilityTree extends Component {
static get propTypes() {
return {
accessibilityWalker: PropTypes.object,
toolboxDoc: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
accessibles: PropTypes.object,
expanded: PropTypes.object,
selected: PropTypes.string,
highlighted: PropTypes.object,
supports: PropTypes.object,
filtered: PropTypes.bool,
};
}
@@ -167,17 +167,21 @@ class AccessibilityTree extends Component {
expanded,
selected,
highlighted: highlightedItem,
supports,
accessibilityWalker,
toolboxDoc,
filtered,
} = this.props;
// Historically, the first context menu item is snapshot function and it is available
// for all accessible object.
const hasContextMenu = supports.snapshot;
const renderRow = rowProps => {
const { object } = rowProps.member;
const highlighted = object === highlightedItem;
return AccessibilityRow(
Object.assign({}, rowProps, {
toolboxDoc,
hasContextMenu,
highlighted,
decorator: {
getRowClass: function() {
@@ -213,29 +217,32 @@ class AccessibilityTree extends Component {
return true;
},
onContextMenuTree: function(e) {
// If context menu event is triggered on (or bubbled to) the TreeView, it was
// done via keyboard. Open context menu for currently selected row.
let row = this.getSelectedRow();
if (!row) {
return;
}
onContextMenuTree:
hasContextMenu &&
function(e) {
// If context menu event is triggered on (or bubbled to) the TreeView, it was
// done via keyboard. Open context menu for currently selected row.
let row = this.getSelectedRow();
if (!row) {
return;
}
row = row.getWrappedInstance();
row.onContextMenu(e);
},
row = row.getWrappedInstance();
row.onContextMenu(e);
},
});
}
}
const mapStateToProps = ({
accessibles,
ui: { expanded, selected, highlighted },
ui: { expanded, selected, supports, highlighted },
audit: { filters },
}) => ({
accessibles,
expanded,
selected,
supports,
highlighted,
filtered: isFiltered(filters),
});

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* global EVENTS, gTelemetry */
/* global EVENTS, gTelemetry, gToolbox */
// React & Redux
const {
@@ -112,7 +112,7 @@ class Accessible extends Component {
labelledby: PropTypes.string.isRequired,
parents: PropTypes.object,
relations: PropTypes.object,
toolbox: PropTypes.object.isRequired,
supports: PropTypes.object,
};
}
@@ -181,7 +181,7 @@ class Accessible extends Component {
}
async update() {
const { dispatch, accessibleFront } = this.props;
const { dispatch, accessibleFront, supports } = this.props;
if (!accessibleFront.actorID) {
return;
}
@@ -189,7 +189,7 @@ class Accessible extends Component {
const domWalker = (await accessibleFront.targetFront.getFront("inspector"))
.walker;
dispatch(updateDetails(domWalker, accessibleFront));
dispatch(updateDetails(domWalker, accessibleFront, supports));
}
setExpanded(item, isExpanded) {
@@ -205,7 +205,7 @@ class Accessible extends Component {
}
async showHighlighter(nodeFront) {
if (!this.props.toolbox) {
if (!gToolbox) {
return;
}
@@ -214,7 +214,7 @@ class Accessible extends Component {
}
async hideHighlighter(nodeFront) {
if (!this.props.toolbox) {
if (!gToolbox) {
return;
}
@@ -238,7 +238,7 @@ class Accessible extends Component {
.catch(error => {
// Only report an error where there's still a toolbox. Ignore cases
// where toolbox is already destroyed.
if (this.props.toolbox) {
if (gToolbox) {
console.error(error);
}
});
@@ -258,23 +258,24 @@ class Accessible extends Component {
accessibilityWalkerFront.unhighlight().catch(error => {
// Only report an error where there's still a toolbox. Ignore cases where
// toolbox is already destroyed.
if (this.props.toolbox) {
if (gToolbox) {
console.error(error);
}
});
}
async selectNode(nodeFront, reason = "accessibility") {
selectNode(nodeFront, reason = "accessibility") {
if (gTelemetry) {
gTelemetry.scalarAdd(TELEMETRY_NODE_INSPECTED_COUNT, 1);
}
if (!this.props.toolbox) {
if (!gToolbox) {
return;
}
const inspector = await this.props.toolbox.selectTool("inspector");
inspector.selection.setNodeFront(nodeFront, reason);
gToolbox
.selectTool("inspector")
.then(() => gToolbox.selection.setNodeFront(nodeFront, reason));
}
async selectAccessible(accessibleFront) {
@@ -539,12 +540,13 @@ const makeParentMap = items => {
return map;
};
const mapStateToProps = ({ details }) => {
const mapStateToProps = ({ details, ui }) => {
const {
accessible: accessibleFront,
DOMNode: nodeFront,
relations,
} = details;
const { supports } = ui;
if (!accessibleFront || !nodeFront) {
return {};
}
@@ -554,7 +556,9 @@ const mapStateToProps = ({ details }) => {
if (key === "DOMNode") {
props.nodeFront = nodeFront;
} else if (key === "relations") {
props.relations = relations;
if (supports.relations) {
props.relations = relations;
}
} else {
props[key] = accessibleFront[key];
}
@@ -565,7 +569,7 @@ const mapStateToProps = ({ details }) => {
);
const parents = makeParentMap(items);
return { accessibleFront, nodeFront, items, parents, relations };
return { accessibleFront, nodeFront, items, parents, relations, supports };
};
module.exports = connect(mapStateToProps)(Accessible);

View File

@@ -93,6 +93,10 @@ class Checks extends Component {
}
const mapStateToProps = ({ details, ui }) => {
if (!ui.supports.audit) {
return {};
}
const { audit } = details;
if (!audit) {
return {};

View File

@@ -30,6 +30,22 @@ const {
A11Y_SERVICE_ENABLED_COUNT,
} = require("../constants");
class OldVersionDescription extends Component {
render() {
return div(
{ className: "description" },
p(
{ className: "general" },
img({
src: "chrome://devtools/skin/images/accessibility.svg",
alt: L10N.getStr("accessibility.logo"),
}),
L10N.getStr("accessibility.description.oldVersion")
)
);
}
}
/**
* Landing UI for the accessibility panel when Accessibility features are
* deactivated.
@@ -144,3 +160,4 @@ const mapStateToProps = ({ ui }) => ({
// Exports from this module
exports.Description = connect(mapStateToProps)(Description);
exports.OldVersionDescription = OldVersionDescription;

View File

@@ -48,7 +48,7 @@ class MainFrame extends Component {
auditing: PropTypes.array.isRequired,
supports: PropTypes.object,
simulator: PropTypes.object,
toolbox: PropTypes.object.isRequired,
toolboxDoc: PropTypes.object.isRequired,
};
}
@@ -118,7 +118,7 @@ class MainFrame extends Component {
enabled,
auditing,
simulator,
toolbox,
toolboxDoc,
} = this.props;
if (!enabled) {
@@ -132,12 +132,7 @@ class MainFrame extends Component {
{ bundles: fluentBundles },
div(
{ className: "mainFrame", role: "presentation" },
Toolbar({
accessibility,
accessibilityWalker,
simulator,
toolboxDoc: toolbox.doc,
}),
Toolbar({ accessibility, accessibilityWalker, simulator, toolboxDoc }),
isAuditing && AuditProgressOverlay(),
span(
{
@@ -157,12 +152,9 @@ class MainFrame extends Component {
className: "main-panel",
role: "presentation",
},
AccessibilityTree({
accessibilityWalker,
toolboxDoc: toolbox.doc,
})
AccessibilityTree({ accessibilityWalker })
),
endPanel: RightSidebar({ toolbox }),
endPanel: RightSidebar(),
vert: this.useLandscapeMode,
})
)

View File

@@ -15,7 +15,7 @@ const Accordion = createFactory(
const Checks = createFactory(require("./Checks"));
// Component that is responsible for rendering accessible panel's sidebar.
function RightSidebar({ toolbox }) {
function RightSidebar() {
const propertiesID = "accessibility-properties";
const checksID = "accessibility-checks";
@@ -38,7 +38,6 @@ function RightSidebar({ toolbox }) {
className: "accessible",
component: Accessible,
componentProps: {
toolbox,
labelledby: `${propertiesID}-header`,
},
header: L10N.getStr("accessibility.properties"),

View File

@@ -86,10 +86,17 @@ AccessibilityPanel.prototype = {
);
this.shouldRefresh = true;
this.panelWin.gToolbox = this._toolbox;
await this.startup.initAccessibility();
this.picker = new Picker(this);
this.simulator = await this.front.getSimulator();
if (this.supports.enableDisable) {
this.picker = new Picker(this);
}
if (this.supports.simulation) {
this.simulator = await this.front.getSimulator();
}
this.fluentBundles = await this.createFluentBundles();
this.updateA11YServiceDurationTimer();
@@ -170,7 +177,7 @@ AccessibilityPanel.prototype = {
supports: this.supports,
fluentBundles: this.fluentBundles,
simulator: this.simulator,
toolbox: this._toolbox,
toolboxDoc: this._toolbox.doc,
});
},
@@ -195,7 +202,12 @@ AccessibilityPanel.prototype = {
);
}
this.postContentMessage("selectNodeAccessible", this.walker, nodeFront);
this.postContentMessage(
"selectNodeAccessible",
this.walker,
nodeFront,
this.supports
);
},
highlightAccessible(accessibleFront) {
@@ -299,6 +311,7 @@ AccessibilityPanel.prototype = {
}
this._telemetry = null;
this.panelWin.gToolbox = null;
this.panelWin.gTelemetry = null;
this.emit("destroyed");

View File

@@ -185,8 +185,10 @@ function onReset(state, { accessibility, supports }) {
enabled,
canBeDisabled,
canBeEnabled,
supports,
};
if (supports) {
newState.supports = supports;
}
return newState;
}

View File

@@ -142,7 +142,7 @@ async function addTestTab(url) {
// Wait for inspector load here to avoid protocol errors on shutdown, since
// accessibility panel test can be too fast.
await panel._toolbox.loadTool("inspector");
await win.gToolbox.loadTool("inspector");
return {
tab,

View File

@@ -43,7 +43,9 @@ window.onload = async function() {
off: () => {},
},
},
ui: { supports: {} }
ui: {
supports: {},
},
};
const mockStore = createStore((state, action) =>
@@ -51,13 +53,28 @@ window.onload = async function() {
const provider = createElement(Provider, { store: mockStore }, a);
const accessible = ReactDOM.render(provider, window.document.body);
ok(accessible, "Should be able to mount Accessible instances");
info("Render accessible object when relations are not supported.");
let relationsNode = document.getElementById("/relations");
ok(!relationsNode, "Relations are not rendered when not supported.");
info("Render accessible object when relations are supported but are empty.");
let state = {
...mockState,
ui: {
supports: {
relations: true,
},
},
};
await mockStore.dispatch({ type: "update", ...state });
relationsNode = document.getElementById("/relations");
ok(relationsNode, "Relations are rendered when supported.");
let arrow = relationsNode.querySelector(".arrow.theme-twisty");
is(arrow.style.visibility, "hidden", "Relations are empty.");
info("Render accessible object with relations.");
const state = {
state = {
details: {
...mockState.details,
relations: {
@@ -69,6 +86,11 @@ window.onload = async function() {
},
},
},
ui: {
supports: {
relations: true,
},
},
};
await mockStore.dispatch({ type: "update", ...state });
relationsNode = document.getElementById("/relations");

View File

@@ -36,11 +36,13 @@ window.onload = async function() {
const { FILTERS } = browserRequire("devtools/client/accessibility/constants");
async function withMockEnv(func) {
const { gTelemetry: originalTelemetry } = window;
const { gToolbox: originalToolbox, gTelemetry: originalTelemetry } = window;
window.gToolbox = { doc: document };
window.gTelemetry = null;
await func();
window.gToolbox = originalToolbox;
window.gTelemetry = originalTelemetry;
}
@@ -86,13 +88,21 @@ window.onload = async function() {
getValue: (object, id) => object[id],
},
hasContextMenu: true,
toolboxDoc: document,
};
const mockProps = {
...defaultProps,
hasContextMenu: null,
};
const auditState = { audit: { filters: { [FILTERS.CONTRAST]: false }}};
const defaultState = {
ui: { supports: {} },
ui: { supports: { snapshot: true }},
...auditState,
};
const mockState = {
ui: { supports: {}},
...auditState,
};
@@ -134,6 +144,23 @@ window.onload = async function() {
browserWindow.openWebLinkIn = defaultOpenWebLinkIn;
menu.remove();
});
info("Check accessibility row when context menu is not supported.");
renderAccessibilityRow(defaultProps, mockState);
row = document.getElementById(ROW_ID);
info("Check contextmenu listener is not called when context menu is not supported.");
Simulate.contextMenu(row);
let menu = menuDoc.getElementById("accessibility-row-contextmenu");
ok(!menu, "contextmenu event handler was never called.");
info("Check accessibility row when no context menu is available.");
renderAccessibilityRow(mockProps, defaultState);
row = document.getElementById(ROW_ID);
Simulate.contextMenu(row);
menu = menuDoc.getElementById("accessibility-row-contextmenu");
ok(!menu, "contextmenu event handler was never called.");
} catch (e) {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
} finally {

View File

@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AccessibilityRowValue component: audit not supported 1`] = `"<span role=\\"presentation\\"><span class=\\"objectBox objectBox-undefined\\">undefined</span></span>"`;
exports[`AccessibilityRowValue component: basic render 1`] = `"<span role=\\"presentation\\"><span class=\\"objectBox objectBox-undefined\\">undefined</span></span>"`;

View File

@@ -21,11 +21,15 @@ const {
} = require("devtools/client/shared/components/reps/reps");
const AuditController = require("devtools/client/accessibility/components/AuditController");
const AccessibilityRowValueClass = require("devtools/client/accessibility/components/AccessibilityRowValue");
const AccessibilityRowValue = createFactory(AccessibilityRowValueClass);
const ConnectedAccessibilityRowValueClass = require("devtools/client/accessibility/components/AccessibilityRowValue");
const AccessibilityRowValueClass =
ConnectedAccessibilityRowValueClass.WrappedComponent;
const AccessibilityRowValue = createFactory(
ConnectedAccessibilityRowValueClass
);
describe("AccessibilityRowValue component:", () => {
it("basic render", () => {
it("audit not supported", () => {
const store = setupStore({
preloadedState: { ui: { supports: {} } },
});
@@ -38,6 +42,29 @@ describe("AccessibilityRowValue component:", () => {
)
);
expect(wrapper.html()).toMatchSnapshot();
const rowValue = wrapper.find(AccessibilityRowValueClass);
expect(rowValue.children().length).toBe(1);
const container = rowValue.childAt(0);
expect(container.type()).toBe("span");
expect(container.prop("role")).toBe("presentation");
expect(container.children().length).toBe(1);
expect(container.childAt(0).type()).toBe(Rep);
});
it("basic render", () => {
const store = setupStore({
preloadedState: { ui: { supports: { audit: true } } },
});
const wrapper = mount(
Provider(
{ store },
AccessibilityRowValue({
member: { object: mockAccessible() },
})
)
);
expect(wrapper.html()).toMatchSnapshot();
const rowValue = wrapper.find(AccessibilityRowValueClass);
expect(rowValue.children().length).toBe(1);