Bug 1537598 - Test Column Breakpoints.

Differential Revision: https://phabricator.services.mozilla.com/D26827

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jason Laster 2019-04-10 13:47:32 +00:00
parent e1d04ebd15
commit ead0a1fa52
4 changed files with 150 additions and 151 deletions

View File

@ -51,6 +51,7 @@
"waitForThreadEvents": false,
"waitForState": false,
"waitForElement": false,
"waitForAllElements": false,
"waitForElementWithSelector": false,
"waitForPaused": false,
"waitForSources": false,
@ -59,7 +60,10 @@
"waitForSelectedSource": false,
"waitForBreakpoint": false,
"waitForBreakpointCount": false,
"waitForCondition": false,
"waitForLog": false,
"isPaused": false,
"assertClass": false,
"assertSourceCount": false,
"assertEditorBreakpoint": false,
"assertBreakpointSnippet": false,
@ -92,7 +96,9 @@
"clickDOMElement": false,
"altClickElement": false,
"rightClickElement": false,
"rightClickEl": false,
"clickGutter": false,
"typeInPanel": false,
"selectMenuItem": false,
"selectContextMenuItem": false,
"togglePauseOnExceptions": false,

View File

@ -1,111 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
function getColumnBreakpointElements(dbg) {
return findAllElementsWithSelector(dbg, ".column-breakpoint");
async function enableFirstBreakpoint(dbg) {
getCM(dbg).setCursor({ line: 32, ch: 0 });
await addBreakpoint(dbg, "long", 32);
const bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
ok(bpMarkers.length === 2, "2 column breakpoints");
assertClass(bpMarkers[0], "active");
assertClass(bpMarkers[1], "active", false);
}
async function assertConditionalBreakpointIsFocused(dbg) {
const input = findElement(dbg, "conditionalPanelInput");
await waitForElementFocus(dbg, input);
}
async function enableSecondBreakpoint(dbg) {
let bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
function waitForElementFocus(dbg, el) {
const doc = dbg.win.document;
return waitFor(() => doc.activeElement == el && doc.hasFocus());
}
bpMarkers[1].click();
await waitForBreakpointCount(dbg, 2);
function hasCondition(marker) {
return marker.classList.contains("has-condition");
bpMarkers = findAllElements(dbg, "columnBreakpoints");
assertClass(bpMarkers[1], "active");
await waitForAllElements(dbg, "breakpointItems", 2);
}
async function setConditionalBreakpoint(dbg, index, condition) {
const {
addConditionalBreakpoint,
editConditionalBreakpoint
} = selectors.gutterContextMenu;
// Make this work with either add or edit menu items
const selector = `${addConditionalBreakpoint},${editConditionalBreakpoint}`;
let bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
rightClickEl(dbg, bpMarkers[index]);
selectContextMenuItem(dbg, selectors.addConditionItem);
await typeInPanel(dbg, condition);
await waitForCondition(dbg, condition);
rightClickElement(dbg, "breakpointItem", index);
selectContextMenuItem(dbg, selector);
await waitForElement(dbg, "conditionalPanelInput");
await assertConditionalBreakpointIsFocused(dbg);
// Position cursor reliably at the end of the text.
pressKey(dbg, "End");
type(dbg, condition);
pressKey(dbg, "Enter");
bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
assertClass(bpMarkers[index], "has-condition");
}
function removeBreakpointViaContext(dbg, index) {
rightClickElement(dbg, "breakpointItem", index);
selectContextMenuItem(dbg, "#node-menu-delete-self");
async function setLogPoint(dbg, index, expression) {
let bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
rightClickEl(dbg, bpMarkers[index]);
selectContextMenuItem(dbg, selectors.addLogItem);
await typeInPanel(dbg, expression);
await waitForLog(dbg, expression);
bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
assertClass(bpMarkers[index], "has-log");
}
async function disableBreakpoint(dbg, index) {
rightClickElement(dbg, "columnBreakpoints");
selectContextMenuItem(dbg, selectors.disableItem);
await waitForState(dbg, state => {
const bp = dbg.selectors.getBreakpointsList(state)[index];
return bp.disabled;
});
const bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
assertClass(bpMarkers[0], "disabled");
}
async function removeFirstBreakpoint(dbg) {
let bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
bpMarkers[0].click();
bpMarkers = await waitForAllElements(dbg, "columnBreakpoints");
assertClass(bpMarkers[0], "active", false);
}
async function removeAllBreakpoints(dbg, line, count) {
clickGutter(dbg, 32);
await waitForBreakpointCount(dbg, 0);
ok(findAllElements(dbg, "columnBreakpoints").length == 0);
}
// Test enabling and disabling a breakpoint using the check boxes
add_task(async function() {
const dbg = await initDebugger("doc-scripts.html", "simple1");
await pushPref("devtools.debugger.features.column-breakpoints", false);
await selectSource(dbg, "long");
if(!Services.prefs.getBoolPref("devtools.debugger.features.column-breakpoints")) {
ok(true, "This test only applies when column breakpoints are on");
return;
}
info("1. Add a column breakpoint on line 32");
await enableFirstBreakpoint(dbg);
await selectSource(dbg, "simple1");
info("2. Click on the second breakpoint on line 32");
await enableSecondBreakpoint(dbg);
// Scroll down to desired line so that column breakpoints render
getCM(dbg).setCursor({ line: 15, ch: 0 });
info("3. Add a condition to the first breakpoint");
await setConditionalBreakpoint(dbg, 0, "foo");
// Create a breakpoint at 15:undefined
await addBreakpoint(dbg, "simple1", 15);
info("4. Add a log to the first breakpoint");
await setLogPoint(dbg, 0, "bar");
// Wait for column breakpoint markers
await waitForElementWithSelector(dbg, ".column-breakpoint");
info("5. Disable the first breakpoint");
await disableBreakpoint(dbg, 0);
let columnBreakpointMarkers = getColumnBreakpointElements(dbg);
ok(
columnBreakpointMarkers.length === 2,
"2 column breakpoint markers display"
);
info("6. Remove the first breakpoint");
await removeFirstBreakpoint(dbg);
// Create a breakpoint at 15:8
columnBreakpointMarkers[0].click();
info("7. Add a condition to the second breakpoint");
await setConditionalBreakpoint(dbg, 1, "foo2");
// Create a breakpoint at 15:28
columnBreakpointMarkers[1].click();
// Wait for breakpoints in right panel to render
await waitForState(dbg, state => {
return dbg.win.document.querySelectorAll(".breakpoints-list .breakpoint").length === 3;
})
// Scroll down in secondary pane so element we want to right-click is showing
dbg.win.document.querySelector(".secondary-panes").scrollTop = 100;
// Set a condition at 15:8
await setConditionalBreakpoint(dbg, 4, "Eight");
// Ensure column breakpoint is yellow
await waitForElementWithSelector(dbg, ".column-breakpoint.has-condition");
// Remove the breakpoint from 15:undefined via the secondary pane context menu
removeBreakpointViaContext(dbg, 3);
// Ensure that there's still a marker on line 15
await waitForState(dbg, state => dbg.selectors.getBreakpointCount(state) == 2);
await waitForElementWithSelector(dbg, ".column-breakpoint.has-condition");
columnBreakpointMarkers = getColumnBreakpointElements(dbg);
ok(hasCondition(columnBreakpointMarkers[0]), "First column breakpoint has conditional style");
// Remove the breakpoint from 15:8
removeBreakpointViaContext(dbg, 3);
// Ensure there's still a marker and it has no condition
await waitForState(dbg, state => dbg.selectors.getBreakpointCount(state) == 1);
await waitForElementWithSelector(dbg, ".column-breakpoint");
// Ensure the first column breakpoint has no conditional style
await waitFor(() => !hasCondition(getColumnBreakpointElements(dbg)[0]));
info("8. test removing the breakpoints by clicking in the gutter");
await removeAllBreakpoints(dbg, 32, 0);
});

View File

@ -31,27 +31,6 @@ function assertEditorBreakpoint(
);
}
function waitForElementFocus(dbg, el) {
const doc = dbg.win.document;
return waitFor(() => doc.activeElement == el && doc.hasFocus());
}
function waitForBreakpointWithCondition(dbg, url, line, cond) {
return waitForState(dbg, () => {
const bp = findBreakpoint(dbg, url, line);
return (
bp && bp.options.condition && (!cond || bp.options.condition == cond)
);
});
}
function waitForBreakpointWithLog(dbg, url, line) {
return waitForState(dbg, () => {
const bp = findBreakpoint(dbg, url, line);
return bp && bp.options.logValue;
});
}
function waitForBreakpointWithoutCondition(dbg, url, line) {
return waitForState(dbg, () => {
const bp = findBreakpoint(dbg, url, line);
@ -60,37 +39,21 @@ function waitForBreakpointWithoutCondition(dbg, url, line) {
}
async function setConditionalBreakpoint(dbg, index, condition) {
const {
addConditionalBreakpoint,
editConditionalBreakpoint
} = selectors.gutterContextMenu;
// Make this work with either add or edit menu items
const selector = `${addConditionalBreakpoint},${editConditionalBreakpoint}`;
const { addConditionItem, editConditionItem } = selectors;
const selector = `${addConditionItem},${editConditionItem}`;
rightClickElement(dbg, "gutter", index);
selectContextMenuItem(dbg, selector);
await waitForElement(dbg, "conditionalPanelInput");
// Position cursor reliably at the end of the text.
pressKey(dbg, "End");
type(dbg, condition);
pressKey(dbg, "Enter");
typeInPanel(dbg, condition);
}
async function setLogPoint(dbg, index, value) {
const { addLogPoint, editLogPoint } = selectors.gutterContextMenu;
// Make this work with either add or edit menu items
const selector = `${addLogPoint},${editLogPoint}`;
rightClickElement(dbg, "gutter", index);
selectContextMenuItem(dbg, selector);
await waitForElement(dbg, "conditionalPanelInput");
// Position cursor reliably at the end of the text.
pressKey(dbg, "End");
type(dbg, value);
pressKey(dbg, "Enter");
selectContextMenuItem(
dbg,
`${selectors.addLogItem},${selectors.editLogItem}`
);
await typeInPanel(dbg, value);
}
add_task(async function() {
@ -101,9 +64,9 @@ add_task(async function() {
await selectSource(dbg, "simple2");
await waitForSelectedSource(dbg, "simple2");
info("Set condition `1`");
await setConditionalBreakpoint(dbg, 5, "1");
await waitForDispatch(dbg, "SET_BREAKPOINT");
await waitForBreakpointWithCondition(dbg, "simple2", 5);
await waitForCondition(dbg, 1);
let bp = findBreakpoint(dbg, "simple2", 5);
is(bp.options.condition, "1", "breakpoint is created with the condition");
@ -111,7 +74,7 @@ add_task(async function() {
info("Edit the conditional breakpoint set above");
await setConditionalBreakpoint(dbg, 5, "2");
await waitForBreakpointWithCondition(dbg, "simple2", 5, "12");
await waitForCondition(dbg, 12);
bp = findBreakpoint(dbg, "simple2", 5);
is(bp.options.condition, "12", "breakpoint is created with the condition");
@ -127,7 +90,7 @@ add_task(async function() {
clickElement(dbg, "gutter", 5);
await waitForDispatch(dbg, "SET_BREAKPOINT");
await setConditionalBreakpoint(dbg, 5, "1");
await waitForBreakpointWithCondition(dbg, "simple2", 5);
await waitForCondition(dbg, 1);
bp = findBreakpoint(dbg, "simple2", 5);
is(bp.options.condition, "1", "breakpoint is created with the condition");
@ -142,7 +105,7 @@ add_task(async function() {
info('Add "log point"');
await setLogPoint(dbg, 5, "44");
await waitForBreakpointWithLog(dbg, "simple2", 5);
await waitForLog(dbg, 44);
await assertEditorBreakpoint(dbg, 5, { hasLog: true });
bp = findBreakpoint(dbg, "simple2", 5);

View File

@ -204,11 +204,24 @@ async function waitForElement(dbg, name, ...args) {
return findElement(dbg, name, ...args);
}
async function waitForAllElements(dbg, name, count = 1) {
await waitUntil(() => findAllElements(dbg, name).length >= count);
return findAllElements(dbg, name);
}
async function waitForElementWithSelector(dbg, selector) {
await waitUntil(() => findElementWithSelector(dbg, selector));
return findElementWithSelector(dbg, selector);
}
function assertClass(el, className, exists = true) {
if (exists) {
ok(el.classList.contains(className), `${className} class exists`);
} else {
ok(!el.classList.contains(className), `${className} class does not exist`);
}
}
function waitForSelectedLocation(dbg, line) {
return waitForState(dbg, state => {
const location = dbg.selectors.getSelectedLocation(state);
@ -487,6 +500,22 @@ async function waitForPaused(dbg, url) {
await waitForSelectedSource(dbg, url);
}
function waitForCondition(dbg, condition) {
return waitForState(dbg, state =>
dbg.selectors
.getBreakpointsList(state)
.find(bp => bp.options.condition == condition)
);
}
function waitForLog(dbg, logValue) {
return waitForState(dbg, state =>
dbg.selectors
.getBreakpointsList(state)
.find(bp => bp.options.logValue == logValue)
);
}
/*
* useful for when you want to see what is happening
* e.g await waitForever()
@ -1190,6 +1219,7 @@ const selectors = {
removeOthers: "#node-menu-delete-other",
removeCondition: "#node-menu-remove-condition"
},
columnBreakpoints: ".column-breakpoint",
scopes: ".scopes-list",
scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`,
scopeValue: i =>
@ -1197,15 +1227,13 @@ const selectors = {
frame: i => `.frames [role="list"] [role="listitem"]:nth-child(${i})`,
frames: '.frames [role="list"] [role="listitem"]',
gutter: i => `.CodeMirror-code *:nth-child(${i}) .CodeMirror-linenumber`,
// These work for bobth the breakpoint listing and gutter marker
gutterContextMenu: {
addConditionalBreakpoint:
"#node-menu-add-condition, #node-menu-add-conditional-breakpoint",
editConditionalBreakpoint:
"#node-menu-edit-condition, #node-menu-edit-conditional-breakpoint",
addLogPoint: "#node-menu-add-log-point",
editLogPoint: "#node-menu-edit-log-point"
},
addConditionItem:
"#node-menu-add-condition, #node-menu-add-conditional-breakpoint",
editConditionItem:
"#node-menu-edit-condition, #node-menu-edit-conditional-breakpoint",
addLogItem: "#node-menu-add-log-point",
editLogItem: "#node-menu-edit-log-point",
disableItem: "#node-menu-disable-breakpoint",
menuitem: i => `menupopup menuitem:nth-child(${i})`,
pauseOnExceptions: ".pause-exceptions",
breakpoint: ".CodeMirror-code > .new-breakpoint",
@ -1339,12 +1367,12 @@ function altClickElement(dbg, elementName, ...args) {
function rightClickElement(dbg, elementName, ...args) {
const selector = getSelector(elementName, ...args);
const doc = dbg.win.document;
return rightClickEl(dbg, doc.querySelector(selector));
}
return EventUtils.synthesizeMouseAtCenter(
doc.querySelector(selector),
{ type: "contextmenu" },
dbg.win
);
function rightClickEl(dbg, el) {
const doc = dbg.win.document;
EventUtils.synthesizeMouseAtCenter(el, { type: "contextmenu" }, dbg.win);
}
async function clickGutter(dbg, line) {
@ -1363,6 +1391,15 @@ function selectContextMenuItem(dbg, selector) {
return EventUtils.synthesizeMouseAtCenter(item, {}, dbg.toolbox.win);
}
async function typeInPanel(dbg, text) {
await waitForElement(dbg, "conditionalPanelInput");
// Position cursor reliably at the end of the text.
pressKey(dbg, "End");
type(dbg, text);
pressKey(dbg, "Enter");
}
/**
* Toggles the debugger call stack accordian.
*