diff --git a/bin/dev-server.js b/bin/dev-server.js index c41c61cbb4..e8b2c41081 100644 --- a/bin/dev-server.js +++ b/bin/dev-server.js @@ -15,11 +15,5 @@ let { app } = toolbox.startDevServer(envConfig, webpackConfig, __dirname); app.use("/integration/examples", express.static("src/test/mochitest/examples")); -app.use("/integration", express.static("src/test/integration/runner")); - -app.get("/integration/mocha.css", function(req, res) { - res.sendFile(path.join(__dirname, "../node_modules/mocha/mocha.css")); -}); - console.log("View debugger examples here:"); console.log("https://github.com/devtools-html/debugger-examples"); diff --git a/docs/integration-tests.md b/docs/integration-tests.md deleted file mode 100644 index 87d46c618f..0000000000 --- a/docs/integration-tests.md +++ /dev/null @@ -1,193 +0,0 @@ -## Integration Tests - -+ [Overview](#overview) -+ [Running the Tests](#running-the-tests) -+ [Gotchas](#gotchas) -+ [Writing Tests](#writing-tests) -+ [Adding a New Test](#adding-a-new-test) - -### Overview - -The integration tests are async functions that drive the debugger in two contexts: firefox and the web. - -**Firefox** the tests are run in the panel with [mochitest]. -**Web** the tests are run in an iframe with [mocha]. - -### Running the Tests - -Open `localhost:8000/integration` - -Tips: - -* You can select tests to run or skip in the `runner.js` by replacing `it` with `it.only` and `xit`. - -### Gotchas - -#### Make sure firefox is running - -The tests communicate with firefox over a websocket like the launchpad, so it's important firefox is running. - -One easy thing to do to start firefox, is click the "launch Firefox" button in the launchpad app. - -#### Make sure the other debugger windows are closed - -Because the tests communicate over the same websocket connection as the launchpad, it's important that the other debugger windows are closed. Keeping them open means that some of the messages could be dropped! - - -### Writing Tests - -* Helpers for writing: [commands], [assertions], and [waiting] on asynchronous actions. -* Utilities for [typing] and [clicking] -* Environment specific utilities [mocha.js] [mochitest.js] -* Assertions: `ok`, `is` -* HTML Examples are [here][examples-dir] - -**Example:** - -```js -async function test2(ctx) { - const { ok, is, info } = ctx; - - // open the debugger and navigate the debuggee to `doc-frames.html` - const dbg = await initDebugger("doc-frames.html"); - - toggleCallStack(dbg); - - // pause inside of startRecursion so that we can test a large call stack - invokeInTab(dbg, "startRecursion"); - await waitForPaused(dbg); - - ok(isFrameSelected(dbg, 1, "recurseA"), "the first frame is selected"); -} -``` - -### Adding a New Test - -There are couple of things to do when adding a new test: - -1. create a new test file -2. add the test to the `tests/index` -3. add the test to web `[runner]` -4. add the test mochitests -5. add the test to browser.ini - - -#### 1. create a new test file - -```diff -diff --git a/src/test/integration/tests/expression.js b/src/test/integration/tests/expression.js -new file mode 100644 -index 0000000..6d8d069 ---- /dev/null -+++ b/src/test/integration/tests/expression.js -@@ -0,0 +1,14 @@ -+const { -+ initDebugger, -+ assertPausedLocation, -+ findSource, -+ addBreakpoint -+} = require("../utils") -+ -+// tests the watch expressions component -+ -+module.exports = async function(ctx) { -+ const { ok, is, info, requestLongerTimeout } = ctx; -+ const dbg = await initDebugger("doc-scripts.html"); -+ await waitForPaused(dbg); -+}); -``` - -#### 2. add the test to the `tests/index` - -```diff -diff --git a/src/test/integration/tests/index.js b/src/test/integration/tests/index.js -index d07089d..f0b699b 100644 ---- a/src/test/integration/tests/index.js -+++ b/src/test/integration/tests/index.js -@@ -3,6 +3,7 @@ module.exports = { - breaking: require("./breaking"), - breakpoints: require("./breakpoints"), - breakpointsCond: require("./breakpoints-cond"), -+ expressions: require("./expressions"), - callStack: require("./call-stack"), - debuggerButtons: require("./debugger-buttons"), -``` - -#### 3. add the test to web `[runner]` - -```diff -diff --git a/src/test/integration/runner.js b/src/test/integration/runner.js -index 2a2a329..63c7d24 100644 ---- a/src/test/integration/runner.js -+++ b/src/test/integration/runner.js -@@ -9,6 +9,7 @@ const { - breakpoints, - breakpointsCond, - callStack, -+ expressions, - debuggerButtons, - editorSelect, - editorGutter, -@@ -92,6 +93,10 @@ describe("Tests", () => { - await editorHighlight(ctx); - }); - -+ it("expressions", async function() { -+ await expressions(ctx); -+ }); -+ -``` - -#### 4. add the test mochitests - -```diff -diff --git a/src/test/mochitest/browser_dbg-expression.js b/src/test/mochitest/browser_dbg-expression.js -new file mode 100644 -index 0000000..43dd018 ---- /dev/null -+++ b/src/test/mochitest/browser_dbg-expression.js -@@ -0,0 +1,12 @@ -+/* Any copyright is dedicated to the Public Domain. -+ * http://creativecommons.org/publicdomain/zero/1.0/ */ -+ -+const { -+ setupTestRunner, -+ expressions -+} = require("devtools/client/debugger/new/integration-tests"); -+ -+add_task(function*() { -+ setupTestRunner(this); -+ yield expressions(this); -+}); -``` - -#### 5. add the test to browser.ini - -```diff -diff --git a/src/test/mochitest/browser.ini b/src/test/mochitest/browser.ini -index 108a3da..d059634 100644 ---- a/src/test/mochitest/browser.ini -+++ b/src/test/mochitest/browser.ini -@@ -46,6 +46,7 @@ skip-if = true - [browser_dbg-breakpoints.js] - [browser_dbg-breakpoints-cond.js] - [browser_dbg-call-stack.js] -+[browser_dbg-expressions.js] - [browser_dbg-scopes.js] - [browser_dbg-chrome-create.js] -``` - - -[commands]: ../src/test/integration/utils/commands.js -[waiting]: ../src/test/integration/utils/wait.js -[assertions]: ../src/test/integration/utils/assert.js -[typing]: ../src/test/integration/utils/type.js -[clicking]: ../src/test/integration/utils/mouse-events.js -[mocha.js]: ../src/test/integration/utils/mocha.js -[mochitest.js]: ../src/test/integration/utils/mochitest.js -[examples-dir]: ../src/test/mochitest/examples -[runner]: ../src/test/integration/runner.js - - -[mochitest]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest -[mocha]: https://mochajs.org/ diff --git a/docs/local-development.md b/docs/local-development.md index 5c4d65f6a7..dfa5d7f425 100644 --- a/docs/local-development.md +++ b/docs/local-development.md @@ -11,7 +11,6 @@ * [Logging](#logging) * [Testing](#testing) * [Unit Tests](#unit-tests) - * [Integration Tests](#integration-tests) * [Linting](#linting) * [Lint JS](#lint-js) * [Lint CSS](#lint-css) @@ -367,17 +366,6 @@ it("should render a button", () => { }); ``` -#### Integration Tests - -The Debugger integration tests are run in two contexts: [firefox][mochitest] and the [web][mocha]. -We recommend running the tests in the browser as it's an easier development environment. - -+ [Overview](./integration-tests.md#overview) -+ [Running the Tests](./integration-tests.md#running-the-tests) -+ [Gotchas](./integration-tests.md#gotchas) -+ [Writing Tests](./integration-tests.md#writing-tests) -+ [Adding a New Test](./integration-tests.md#adding-a-new-test) - ### Linting | Type | Command | diff --git a/docs/mochitests.md b/docs/mochitests.md index d3763e79ed..22d9dc12d9 100644 --- a/docs/mochitests.md +++ b/docs/mochitests.md @@ -1,4 +1,4 @@ -We use [mochitests](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest) to do integration testing. Mochitests are part of Firefox and allow us to test the debugger literally as you would use it (as a devtools panel). While we are developing the debugger locally in a tab, it's important that we test it as a devtools panel. +We use [mochitests] to do integration testing. Mochitests are part of Firefox and allow us to test the debugger literally as you would use it (as a devtools panel). While we are developing the debugger locally in a tab, it's important that we test it as a devtools panel. Mochitests require a local checkout of the Firefox source code. This is because they are used to test a lot of Firefox, and you would usually run them inside Firefox. We are developing the debugger outside of Firefox, but still want to test it as a devtools panel, so we've figured out a way to use them. It may not be elegant, but it allows us to ensure a high quality Firefox debugger. @@ -17,15 +17,13 @@ If you haven't set up the mochitest environment yet, just run this: ./bin/prepare-mochitests-dev ``` -This will set up everything you need. You should run this *every time* to start working on mochitests, as it makes sure your local copy of Firefox is up-to-date. - On the first run, this will download a local copy of Firefox and set up an [artifact build](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Artifact_builds) (just think of a super fast Firefox build). It may take a while (10-15 minutes) to download and build Firefox. Now, you can run the mochitests like this: ``` cd firefox -./mach mochitest --subsuite devtools devtools/client/debugger/new/test/mochitest/ +./mach mochitest devtools/client/debugger/new/test/mochitest/ ``` This works because we've symlinked the local mochitests into where the debugger lives in Firefox. Any changes to the tests in `src/test/mochitest` will be reflected and you can re-run the tests. @@ -50,7 +48,7 @@ In the shell, navigate to the debugger.html project folder, and follow the Getti The mochitest are running against the compiled debugger bundle inside the Firefox checkout. This means that you need to update the bundle whenever you make code changes. `prepare-mochitests-dev` does this for you initially, but you can manually update it with: ``` -npm run copy-assets +yarn copy-assets ``` That will build the debugger and copy over all the relevant files into `firefox`, including mochitests. If you want it to only symlink the mochitests directory, pass `--symlink-mochitests` (which is what `prepare-mochitests-dev` does). @@ -58,7 +56,7 @@ That will build the debugger and copy over all the relevant files into `firefox` It's annoying to have to manually update the bundle every single time though. If you want to automatically update the bundle in Firefox whenever you make a change, run this: ``` -npm run copy-assets-watch +yarn copy-assets-watch ``` Now you can make code changes the the bundle will be automatically built for you inside `firefox`, and you can simply run mochitests and edit code as much as you like. @@ -105,8 +103,17 @@ Here are a few tips for writing mochitests: * `toolbox` - Devtools toolbox * `win` - The current debugger window -* You can assert DOM structure like `is(dbg.win.document.querySelectorAll("#foo").length, 1, "...")` -* If you need to access the content page, use `ContentTask.spawn`: + +### Testing the DOM + +You can find common elements in the debugger with the `findElement` function, +which use shared selectors. You can also find any element with the +`findElementWithSelector` function. + +### Evaluating in the debuggee + +If you want to evaluate a function in the debuggee context you can use +the `invokeInTab` function. Under the hood it is using `ContentTask.spawn`. ```js ContentTask.spawn(gBrowser.selectedBrowser, null, function* () { @@ -115,3 +122,5 @@ ContentTask.spawn(gBrowser.selectedBrowser, null, function* () { ``` The above calls the function `foo` that exists in the page itself. You can also access the DOM this way: `content.document.querySelector`, if you want to click a button or do other things. You can even you use assertions inside this callback to check DOM state. + +[mochitests]: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest diff --git a/src/test/integration/runner.js b/src/test/integration/runner.js deleted file mode 100644 index 0f46b1db5d..0000000000 --- a/src/test/integration/runner.js +++ /dev/null @@ -1,134 +0,0 @@ -require("mocha/mocha"); -import expect from "expect.js"; -let { prefs } = require("../../utils/prefs"); - -import tests from "./tests/index"; -Object.assign(window, { prefs }, tests); - -window.ok = function ok(expected) { - expect(expected).to.be.truthy; -}; - -window.is = function is(expected, actual) { - expect(expected).to.equal(actual); -}; - -window.info = function info(msg) { - console.log(`info: ${msg}\n`); -}; - -window.requestLongerTimeout = function() {}; - -const ctx = { ok, is, info, requestLongerTimeout }; - -mocha.setup({ timeout: 10000, ui: "bdd" }); - -describe("Tests", () => { - beforeEach(function() { - console.log("TEST START", this.currentTest.title); - prefs.pauseOnExceptions = false; - prefs.ignoreCaughtExceptions = false; - prefs.pendingSelectedLocation = {}; - prefs.expressions = []; - prefs.pendingBreakpoints = []; - prefs.tabs = []; - }); - - afterEach(function() { - prefs.pauseOnExceptions = false; - prefs.ignoreCaughtExceptions = false; - prefs.pendingSelectedLocation = {}; - prefs.expressions = []; - prefs.pendingBreakpoints = []; - prefs.tabs = []; - - const err = this.currentTest.err; - const msg = err ? "FAILURE" : "SUCCESS"; - console.log(`TEST ${msg}`, this.currentTest.title); - if (err) { - console.log(err.message); - console.log(err.stack); - } - }); - - it("asm", async () => await asm(ctx)); - - describe("breakpoints", () => { - it("breakpoints - toggle", async () => await breakpoints.toggle(ctx)); - - it("breakpoints - toggleAll", async () => await breakpoints.toggleAll(ctx)); - - it("breaking", async () => await breaking(ctx)); - - it("conditional breakpoints", async () => await breakpointsCond(ctx)); - }); - - it("expressions", async () => await expressions(ctx)); - - describe("editor", () => { - it("editor select", async () => await editorSelect(ctx)); - - it("editor gutter", async () => await editorGutter(ctx)); - - xit("editor highlight", async () => await editorHighlight(ctx)); - - xit("editor preview", async () => await editorPreview(ctx)); - }); - - xit("keyboard navigation", async () => await keyboardNavigation(ctx)); - - xit("keyboard shortcuts", async () => await keyboardShortcuts(ctx)); - - xit("navigation", async () => await navigation(ctx)); - - describe("call stack", () => { - it("test 1", async () => await callStack.test1(ctx)); - - it("test 2", async () => await callStack.test2(ctx)); - }); - - it("debugger buttons", async () => await debuggerButtons(ctx)); - - it("iframes", async () => await iframes(ctx)); - - it("pause on exceptions - button", async () => - await pauseOnExceptions.testButton(ctx)); - - it("pause on exceptions - reloading", async () => - await pauseOnExceptions.testReloading(ctx)); - - it("pretty print", async () => await prettyPrint(ctx)); - - it("pretty print paused", async () => await prettyPrintPaused(ctx)); - - it("returnvalues", async () => await returnvalues(ctx)); - - xit("searching", async () => await searching(ctx)); - - it("scopes - expanding properties", async () => - await scopes.expandingProperties(ctx)); - it("scopes - changing scopes", async () => await scopes.changingScopes(ctx)); - - it("render the expected scopes when variable mutates while stepping", async () => - await scopesMutations(ctx)); - - it("sources", async () => await sources(ctx)); - - describe("source maps", () => { - it("stepping", async () => await sourceMaps(ctx)); - it("reloading", async () => await sourceMapsReloading(ctx)); - it("source maps 2", async () => await sourceMaps2(ctx)); - it("source maps bogus", async () => await sourceMapsBogus(ctx)); - }); - - describe("tabs", () => { - // expected 2 to equal 1 - it("add tabs", async () => await tabs.addTabs(ctx)); - it("reload with tabs", async () => await tabs.reloadWithTabs(ctx)); - it("reload with no tabs", async () => await tabs.reloadWithNoTabs(ctx)); - }); -}); - -mocha.run(failures => { - console.log("WERE DON", failures); -}); diff --git a/src/test/integration/runner/index.html b/src/test/integration/runner/index.html deleted file mode 100644 index 8929807a98..0000000000 --- a/src/test/integration/runner/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - Web Test Runner - - - - -
-
-
- -
-
- - - diff --git a/src/test/integration/runner/styles.css b/src/test/integration/runner/styles.css deleted file mode 100644 index 2897ad0ca3..0000000000 --- a/src/test/integration/runner/styles.css +++ /dev/null @@ -1,32 +0,0 @@ -body { - background: #f5f5f5 -} - -#runner { - display: flex; - margin-top: 80px; -} - -#mocha { - width: 400px; -} - -#mocha-stats { - background-color: white; -} - -#app-container { - flex-grow: 1; - top:80px; - background: white; - - height: 700px; -} - -iframe { - width: 100%; - height: 100%; - border: 0; - background: white; -} -} diff --git a/src/test/integration/tests.js b/src/test/integration/tests.js deleted file mode 100644 index 60686dc0b9..0000000000 --- a/src/test/integration/tests.js +++ /dev/null @@ -1,14 +0,0 @@ -const tests = require("./tests/index"); - -const { setupTestRunner } = require("./utils/mocha"); -const utils = require("./utils"); -const { isDevelopment } = require("devtools-config"); - -if (isDevelopment()) { - require("./runner"); -} - -module.exports = Object.assign({}, tests, { - setupTestRunner, - utils -}); diff --git a/src/test/integration/tests/asm.js b/src/test/integration/tests/asm.js deleted file mode 100644 index 4b48ee2ed2..0000000000 --- a/src/test/integration/tests/asm.js +++ /dev/null @@ -1,45 +0,0 @@ -const { - initDebugger, - invokeInTab, - assertPausedLocation, - clickElement, - findAllElements, - addBreakpoint, - reload, - waitForPaused, - resume, - selectSource, - waitForSources -} = require("../utils"); - -async function asm(ctx) { - const { is } = ctx; - const dbg = await initDebugger("doc-asm.html"); - - const { selectors: { getSelectedSource }, getState } = dbg; - - await reload(dbg); - - // After reload() we are getting getSources notifiction for old sources, - // using the debugger statement to really stop are reloaded page. - await waitForPaused(dbg); - await resume(dbg); - - await waitForSources(dbg, "doc-asm.html", "asm.js"); - - // Expand nodes and make sure more sources appear. - is(findAllElements(dbg, "sourceNodes").length, 2); - - clickElement(dbg, "sourceArrow", 2); - is(findAllElements(dbg, "sourceNodes").length, 4); - - selectSource(dbg, "asm.js"); - - await addBreakpoint(dbg, "asm.js", 7); - invokeInTab(dbg, "runAsm"); - - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "asm.js", 7); -} - -module.exports = asm; diff --git a/src/test/integration/tests/breaking-from-console.js b/src/test/integration/tests/breaking-from-console.js deleted file mode 100644 index 9061f7562a..0000000000 --- a/src/test/integration/tests/breaking-from-console.js +++ /dev/null @@ -1,32 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that `debugger` statements are hit before the debugger even -// initializes and it properly highlights the right location in the -// debugger. - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - const url = EXAMPLE_URL + "doc-script-switching.html"; - const toolbox = await openNewTabAndToolbox(url, "webconsole"); - - // Type "debugger" into console - let jsterm = toolbox.getPanel("webconsole").hud.jsterm; - jsterm.execute("debugger"); - - // Wait for the debugger to be selected and make sure it's paused - await new Promise(resolve => { - toolbox.on("jsdebugger-selected", resolve); - }); - is(toolbox.threadClient.state, "paused"); - - // Create a dbg context - const dbg = createDebuggerContext(toolbox); - const { selectors: { getSelectedSource }, getState } = dbg; - - // Make sure the thread is paused in the right source and location - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - is(dbg.win.cm.getValue(), "debugger"); - const source = getSelectedSource(getState()).toJS(); - assertPausedLocation(dbg, ctx, source, 1); -}; diff --git a/src/test/integration/tests/breaking.js b/src/test/integration/tests/breaking.js deleted file mode 100644 index f24ff8342e..0000000000 --- a/src/test/integration/tests/breaking.js +++ /dev/null @@ -1,45 +0,0 @@ -const { - assertPausedLocation, - findSource, - findElement, - selectSource, - clickElement, - addBreakpoint, - reload, - stepOver, - invokeInTab, - resume, - waitForPaused, - waitForDispatch, - setupTestRunner, - initDebugger -} = require("../utils"); - -module.exports = async function breaking(ctx) { - const { ok, is } = ctx; - const dbg = await initDebugger("doc-scripts.html", "scripts.html"); - const { selectors: { getSelectedSource }, getState } = dbg; - - // Make sure we can set a top-level breakpoint and it will be hit on - // reload. - await addBreakpoint(dbg, "scripts.html", 18); - reload(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "scripts.html", 18); - await resume(dbg); - - const paused = waitForPaused(dbg); - - // Create an eval script that pauses itself. - invokeInTab(dbg, "doEval"); - - await paused; - await resume(dbg); - const source = getSelectedSource(getState()).toJS(); - ok(!source.url, "It is an eval source"); - - await addBreakpoint(dbg, source, 5); - invokeInTab(dbg, "evaledFunc"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, source, 5); -}; diff --git a/src/test/integration/tests/breakpoints-cond.js b/src/test/integration/tests/breakpoints-cond.js deleted file mode 100644 index 6f11b726ac..0000000000 --- a/src/test/integration/tests/breakpoints-cond.js +++ /dev/null @@ -1,66 +0,0 @@ -const { - waitForPaused, - waitForElement, - waitForDispatch, - findSource, - findElement, - findElementWithSelector, - selectSource, - clickElement, - rightClickElement, - selectMenuItem, - type, - pressKey, - initDebugger -} = require("../utils"); - -const cbInput = ".conditional-breakpoint-panel input"; - -function findBreakpoint(dbg, url, line) { - const { selectors: { getBreakpoint }, getState } = dbg; - const source = findSource(dbg, url); - return getBreakpoint(getState(), { sourceId: source.id, line }); -} - -async function setConditionalBreakpoint(dbg, { info }, index, condition) { - info("right click on the gutter"); - rightClickElement(dbg, "gutter", index); - selectMenuItem(dbg, 2); - await waitForElement(dbg, cbInput); - const el = findElementWithSelector(dbg, cbInput); - - type(dbg, condition); - pressKey(dbg, "Enter"); -} - -module.exports = async function breakpointsCond(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-scripts.html", "simple2"); - await selectSource(dbg, "simple2"); - - info("Adding a conditional Breakpoint"); - await setConditionalBreakpoint(dbg, ctx, 5, "1"); - await waitForDispatch(dbg, "ADD_BREAKPOINT"); - let bp = findBreakpoint(dbg, "simple2", 5); - is(bp.condition, "1", "breakpoint is created with the condition"); - - info("Editing a conditional Breakpoint"); - await setConditionalBreakpoint(dbg, ctx, 5, "2"); - await waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION"); - bp = findBreakpoint(dbg, "simple2", 5); - is(bp.condition, "12", "breakpoint is created with the condition"); - - info("Removing a conditional breakpoint"); - clickElement(dbg, "gutter", 5); - await waitForDispatch(dbg, "REMOVE_BREAKPOINT"); - bp = findBreakpoint(dbg, "simple2", 5); - is(bp, undefined, "breakpoint was removed"); - - info("Adding a condition to a breakpoint"); - clickElement(dbg, "gutter", 5); - await waitForDispatch(dbg, "ADD_BREAKPOINT"); - await setConditionalBreakpoint(dbg, ctx, 5, "1"); - bp = findBreakpoint(dbg, "simple2", 5); - is(bp.condition, "1", "breakpoint is created with the condition"); -}; diff --git a/src/test/integration/tests/breakpoints.js b/src/test/integration/tests/breakpoints.js deleted file mode 100644 index 964f07c19b..0000000000 --- a/src/test/integration/tests/breakpoints.js +++ /dev/null @@ -1,107 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findElement, - findSource, - selectSource, - clickElement, - addBreakpoint, - waitForDispatch -} = require("../utils"); - -function toggleBreakpoint(dbg, index) { - const bp = findElement(dbg, "breakpointItem", index); - const input = bp.querySelector("input"); - input.click(); -} - -async function removeBreakpoint(dbg, index) { - const bp = findElement(dbg, "breakpointItem", index); - bp.querySelector(".close-btn").click(); - await waitForDispatch(dbg, "REMOVE_BREAKPOINT"); -} - -async function disableBreakpoint(dbg, index) { - toggleBreakpoint(dbg, index); - await waitForDispatch(dbg, "DISABLE_BREAKPOINT"); -} - -async function enableBreakpoint(dbg, index) { - toggleBreakpoint(dbg, index); - await waitForDispatch(dbg, "ENABLE_BREAKPOINT"); -} - -async function toggleBreakpoints(dbg) { - clickElement(dbg, "toggleBreakpoints"); - await waitForDispatch(dbg, "TOGGLE_BREAKPOINTS"); -} - -function findBreakpoint(dbg, url, line) { - const { selectors: { getBreakpoint }, getState } = dbg; - const source = findSource(dbg, url); - return getBreakpoint(getState(), { sourceId: source.id, line }); -} - -function findBreakpoints(dbg) { - const { selectors: { getBreakpoints }, getState } = dbg; - return getBreakpoints(getState()); -} - -async function toggle(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger("doc-scripts.html", "simple2"); - - // Create two breakpoints - await selectSource(dbg, "simple2"); - await addBreakpoint(dbg, "simple2", 3); - await addBreakpoint(dbg, "simple2", 5); - - // Disable the first one - await disableBreakpoint(dbg, 1); - let bp1 = findBreakpoint(dbg, "simple2", 3); - let bp2 = findBreakpoint(dbg, "simple2", 5); - is(bp1.disabled, true, "first breakpoint is disabled"); - is(bp2.disabled, false, "second breakpoint is enabled"); - - // Disable and Re-Enable the second one - await disableBreakpoint(dbg, 2); - await enableBreakpoint(dbg, 2); - bp2 = findBreakpoint(dbg, "simple2", 5); - is(bp2.disabled, false, "second breakpoint is enabled"); -} - -// toggle all -async function toggleAll(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger("doc-scripts.html"); - - // Create two breakpoints - await selectSource(dbg, "simple2"); - await addBreakpoint(dbg, "simple2", 3); - await addBreakpoint(dbg, "simple2", 5); - - // Disable all of the breakpoints - await toggleBreakpoints(dbg); - let bp1 = findBreakpoint(dbg, "simple2", 3); - let bp2 = findBreakpoint(dbg, "simple2", 5); - is(bp1.disabled, true, "first breakpoint is disabled"); - is(bp2.disabled, true, "second breakpoint is disabled"); - - // Enable all of the breakpoints - await toggleBreakpoints(dbg); - bp1 = findBreakpoint(dbg, "simple2", 3); - bp2 = findBreakpoint(dbg, "simple2", 5); - is(bp1.disabled, false, "first breakpoint is enabled"); - is(bp2.disabled, false, "second breakpoint is enabled"); - - // Remove the breakpoints - await removeBreakpoint(dbg, 1); - await removeBreakpoint(dbg, 1); - const bps = findBreakpoints(dbg); - is(bps.size, 0, "breakpoints are removed"); -} - -module.exports = { - toggle, - toggleAll -}; diff --git a/src/test/integration/tests/call-stack.js b/src/test/integration/tests/call-stack.js deleted file mode 100644 index 456f89cc7a..0000000000 --- a/src/test/integration/tests/call-stack.js +++ /dev/null @@ -1,94 +0,0 @@ -const { - initDebugger, - environment, - assertPausedLocation, - waitForPaused, - invokeInTab, - clickElement, - findElement, - findAllElements, - isPaused, - resume, - reload -} = require("../utils"); - -// checks to see if the frame is selected and the title is correct -function isFrameSelected(dbg, index, title) { - const $frame = findElement(dbg, "frame", index); - const frame = dbg.selectors.getSelectedFrame(dbg.getState()); - - const elSelected = $frame.classList.contains("selected"); - const titleSelected = frame.displayName == title; - - return elSelected && titleSelected; -} - -function toggleButton(dbg) { - const callStackBody = findElement(dbg, "callStackBody"); - return callStackBody.querySelector(".show-more"); -} - -function toggleCallStack(dbg) { - return findElement(dbg, "callStackHeader").click(); -} - -async function test1(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-script-switching.html"); - - toggleCallStack(dbg); - - const notPaused = findElement(dbg, "callStackBody").innerText.trim(); - is(notPaused, "Not Paused", "Not paused message is shown"); - - invokeInTab(dbg, "firstCall"); - await waitForPaused(dbg); - - ok(isFrameSelected(dbg, 1, "secondCall"), "the first frame is selected"); - - clickElement(dbg, "frame", 2); - ok(isFrameSelected(dbg, 2, "firstCall"), "the second frame is selected"); - - let button = toggleButton(dbg); - ok(!button, "toggle button shouldn't be there"); -} - -async function test2(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-frames.html", "frames"); - - // NOTE: The web test runner pauses on the inline debugger statement where the mochitest skips it. - if (isPaused(dbg)) { - await resume(dbg); - } - - toggleCallStack(dbg); - - invokeInTab(dbg, "startRecursion"); - await waitForPaused(dbg); - - ok(isFrameSelected(dbg, 1, "recurseA"), "the first frame is selected"); - - // check to make sure that the toggle button isn't there - let button = toggleButton(dbg); - let frames = findAllElements(dbg, "frames"); - is(button.innerText, "Expand Rows", "toggle button should be expand"); - is(frames.length, 7, "There should be at most seven frames"); - - button.click(); - - button = toggleButton(dbg); - frames = findAllElements(dbg, "frames"); - is(button.innerText, "Collapse Rows", "toggle button should be collapse"); - - // the web runner uses an console eval to call the function, which adds an extra frame - const frameCount = environment == "mocha" ? 23 : 22; - is(frames.length, frameCount, "All of the frames should be shown"); -} - -module.exports = { - test1, - test2 -}; diff --git a/src/test/integration/tests/debugger-buttons.js b/src/test/integration/tests/debugger-buttons.js deleted file mode 100644 index f0feb83c89..0000000000 --- a/src/test/integration/tests/debugger-buttons.js +++ /dev/null @@ -1,63 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - waitForPaused, - invokeInTab, - clickElement, - findElement, - reload -} = require("../utils"); - -function clickStepOver(dbg) { - clickElement(dbg, "stepOver"); - return waitForPaused(dbg); -} - -function clickStepIn(dbg) { - clickElement(dbg, "stepIn"); - return waitForPaused(dbg); -} - -function clickStepOut(dbg) { - clickElement(dbg, "stepOut"); - return waitForPaused(dbg); -} - -/** - * Test debugger buttons - * 1. resume - * 2. stepOver - * 3. stepIn - * 4. stepOver to the end of a function - * 5. stepUp at the end of a function - */ -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-debugger-statements.html"); - - await reload(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 8); - - // resume - clickElement(dbg, "resume"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 12); - - // step over - await clickStepOver(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 13); - - // step into - await clickStepIn(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 18); - - // step over - await clickStepOver(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 20); - - // step out - await clickStepOut(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 20); -}; diff --git a/src/test/integration/tests/editor-gutter.js b/src/test/integration/tests/editor-gutter.js deleted file mode 100644 index af824d7946..0000000000 --- a/src/test/integration/tests/editor-gutter.js +++ /dev/null @@ -1,82 +0,0 @@ -const { - initDebugger, - clickElement, - assertPausedLocation, - findSource, - selectSource, - addBreakpoint, - assertHighlightLocation, - waitForPaused, - waitForDispatch -} = require("../utils"); - -// Tests the breakpoint gutter and making sure breakpoint icons exist -// correctly - -// Utilities for interacting with the editor -function clickGutter(dbg, line) { - clickElement(dbg, "gutter", line); -} - -function getLineEl(dbg, line) { - const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div"); - return lines[line - 1]; -} - -function assertEditorBreakpoint(dbg, ctx, line, shouldExist) { - const { ok } = ctx; - const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint"); - ok( - exists === shouldExist, - "Breakpoint " + - (shouldExist ? "exists" : "does not exist") + - " on line " + - line - ); -} - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-scripts.html"); - const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg; - const source = findSource(dbg, "simple1.js"); - - await selectSource(dbg, source.url); - - // Make sure that clicking the gutter creates a breakpoint icon. - clickGutter(dbg, 4); - await waitForDispatch(dbg, "ADD_BREAKPOINT"); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - assertEditorBreakpoint(dbg, ctx, 4, true); - - // Make sure clicking at the same place removes the icon. - clickGutter(dbg, 4); - await waitForDispatch(dbg, "REMOVE_BREAKPOINT"); - is(getBreakpoints(getState()).size, 0, "No breakpoints exist"); - assertEditorBreakpoint(dbg, ctx, 4, false); - - // Test that a breakpoint icon slides down to the correct line. - clickGutter(dbg, 2); - await waitForDispatch(dbg, "ADD_BREAKPOINT"); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - ok( - getBreakpoint(getState(), { sourceId: source.id, line: 4 }), - "Breakpoint has correct line" - ); - assertEditorBreakpoint(dbg, ctx, 2, false); - assertEditorBreakpoint(dbg, ctx, 4, true); - - // Do the same sliding and make sure it works if there's already a - // breakpoint. - clickGutter(dbg, 2); - await waitForDispatch(dbg, "ADD_BREAKPOINT"); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - assertEditorBreakpoint(dbg, ctx, 2, false); - assertEditorBreakpoint(dbg, ctx, 4, true); - - clickGutter(dbg, 4); - await waitForDispatch(dbg, "REMOVE_BREAKPOINT"); - is(getBreakpoints(getState()).size, 0, "No breakpoints exist"); - assertEditorBreakpoint(dbg, ctx, 4, false); -}; diff --git a/src/test/integration/tests/editor-highlight.js b/src/test/integration/tests/editor-highlight.js deleted file mode 100644 index f14e1939bb..0000000000 --- a/src/test/integration/tests/editor-highlight.js +++ /dev/null @@ -1,59 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - addBreakpoint, - assertHighlightLocation, - selectSource, - findAllElements, - waitForPaused, - waitForDispatch -} = require("../utils"); - -// Tests that the editor will always highight the right line, no -// matter if the source text doesn't exist yet or even if the source -// doesn't exist. - -module.exports = async function(ctx) { - const { ok, is, info, EXAMPLE_URL } = ctx; - - const dbg = await initDebugger("doc-scripts.html"); - const { selectors: { getSourceText }, getState } = dbg; - const sourceUrl = EXAMPLE_URL + "long.js"; - - // The source itself doesn't even exist yet, and using - // `selectSourceURL` will set a pending request to load this source - // and highlight a specific line. - dbg.actions.selectSourceURL(sourceUrl, { line: 66 }); - - // Wait for the source text to load and make sure we're in the right - // place. - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - - // Jump to line 16 and make sure the editor scrolled. - await selectSource(dbg, "long.js", 16); - assertHighlightLocation(dbg, ctx, "long.js", 16); - - // Make sure only one line is ever highlighted and the flash - // animation is cancelled on old lines. - await selectSource(dbg, "long.js", 17); - await selectSource(dbg, "long.js", 18); - assertHighlightLocation(dbg, ctx, "long.js", 18); - is( - findAllElements(dbg, "highlightLine").length, - 1, - "Only 1 line is highlighted" - ); - - // Test jumping to a line in a source that exists but hasn't been - // loaded yet. - selectSource(dbg, "simple1.js", 6); - - // Make sure the source is in the loading state, wait for it to be - // fully loaded, and check the highlighted line. - const simple1 = findSource(dbg, "simple1.js"); - ok(getSourceText(getState(), simple1.id).get("loading")); - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - ok(getSourceText(getState(), simple1.id).get("text")); - assertHighlightLocation(dbg, ctx, "simple1.js", 6); -}; diff --git a/src/test/integration/tests/editor-preview.js b/src/test/integration/tests/editor-preview.js deleted file mode 100644 index 6dfd0728f2..0000000000 --- a/src/test/integration/tests/editor-preview.js +++ /dev/null @@ -1,34 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - addBreakpoint, - assertHighlightLocation, - selectSource, - invokeInTab, - mouseOverEl, - findAllElements, - waitForPaused, - waitForDispatch -} = require("../utils"); - -// Tests that the editor will always highight the right line, no -// matter if the source text doesn't exist yet or even if the source -// doesn't exist. - -module.exports = async function(ctx) { - const { ok, is, info, EXAMPLE_URL } = ctx; - - const dbg = await initDebugger("doc-scripts.html", "long.js"); - await addBreakpoint(dbg, "long.js", 82); - - invokeInTab(dbg, "toggleModel"); - await waitForPaused(dbg); - const el = dbg.win.cm - .getWrapperElement() - .querySelectorAll(".CodeMirror-line ")[50] - .querySelector(".cm-variable-2"); - - mouseOverEl(dbg.win, el); - assertPausedLocation(dbg, ctx, "long.js", 82); -}; diff --git a/src/test/integration/tests/editor-select.js b/src/test/integration/tests/editor-select.js deleted file mode 100644 index f420260f51..0000000000 --- a/src/test/integration/tests/editor-select.js +++ /dev/null @@ -1,68 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - addBreakpoint, - waitForPaused, - invokeInTab, - clickElement, - findElement, - stepIn, - stepOut, - resume, - isVisibleWithin -} = require("../utils"); - -// Tests that the editor highlights the correct location when the -// debugger pauses - -// checks to see if the first breakpoint is visible -function isElementVisible(dbg, elementName) { - const bpLine = findElement(dbg, elementName); - const cm = findElement(dbg, "codeMirror"); - return bpLine && isVisibleWithin(cm, bpLine); -} - -module.exports = async function(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - - // This test runs too slowly on linux debug. I'd like to figure out - // which is the slowest part of this and make it run faster, but to - // fix a frequent failure allow a longer timeout. - requestLongerTimeout(2); - - const dbg = await initDebugger("doc-scripts.html"); - const { selectors: { getSelectedSource }, getState } = dbg; - const simple1 = findSource(dbg, "simple1.js"); - const simple2 = findSource(dbg, "simple2.js"); - - // Set the initial breakpoint. - await addBreakpoint(dbg, simple1, 4); - ok(!getSelectedSource(getState()), "No selected source"); - - // Call the function that we set a breakpoint in. - invokeInTab(dbg, "main"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, simple1, 4); - - // Step through to another file and make sure it's paused in the - // right place. - await stepIn(dbg); - assertPausedLocation(dbg, ctx, simple2, 2); - - // Step back out to the initial file. - await stepOut(dbg); - await stepOut(dbg); - assertPausedLocation(dbg, ctx, simple1, 5); - await resume(dbg); - - // Make sure that we can set a breakpoint on a line out of the - // viewport, and that pausing there scrolls the editor to it. - let longSrc = findSource(dbg, "long.js"); - await addBreakpoint(dbg, longSrc, 66); - - invokeInTab(dbg, "testModel"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, longSrc, 66); - ok(isElementVisible(dbg, "breakpoint"), "Breakpoint is visible"); -}; diff --git a/src/test/integration/tests/expressions.js b/src/test/integration/tests/expressions.js deleted file mode 100644 index f58779fa81..0000000000 --- a/src/test/integration/tests/expressions.js +++ /dev/null @@ -1,78 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - addBreakpoint, - waitForPaused, - waitForDispatch, - type, - pressKey, - findElementWithSelector, - findElement, - findAllElements, - invokeInTab, - clickElement, - dblClickElement -} = require("../utils"); - -/** - * tests the watch expressions component - * 1. add watch expressions - * 2. edit watch expressions - * 3. delete watch expressions - */ - -const selectors = { - input: "input.input-expression" -}; - -function getLabel(dbg, index) { - return findElement(dbg, "expressionNode", index).innerText; -} - -function getValue(dbg, index) { - return findElement(dbg, "expressionValue", index).innerText; -} - -async function addExpression(dbg, input) { - info("Adding an expression"); - findElementWithSelector(dbg, selectors.input).focus(); - type(dbg, input); - pressKey(dbg, "Enter"); - - await waitForDispatch(dbg, "EVALUATE_EXPRESSION"); -} - -async function editExpression(dbg, input) { - info("updating the expression"); - dblClickElement(dbg, "expressionNode", 1); - type(dbg, input); - pressKey(dbg, "Enter"); - await waitForDispatch(dbg, "EVALUATE_EXPRESSION"); -} - -async function deleteExpression(dbg, index) { - info("Deleting the expression"); - const deleteExpression = waitForDispatch(dbg, "DELETE_EXPRESSION"); - clickElement(dbg, "expressionClose", index); - await deleteExpression; -} - -module.exports = async function(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - const dbg = await initDebugger("doc-script-switching.html"); - - invokeInTab(dbg, "firstCall"); - await waitForPaused(dbg); - - await addExpression(dbg, "f"); - is(getLabel(dbg, 1), "f"); - is(getValue(dbg, 1), "(unavailable)"); - - await editExpression(dbg, "oo"); - is(getLabel(dbg, 1), "foo()"); - is(getValue(dbg, 1), ""); - - await deleteExpression(dbg, 1); - is(findAllElements(dbg, "expressionNodes").length, 0); -}; diff --git a/src/test/integration/tests/iframes.js b/src/test/integration/tests/iframes.js deleted file mode 100644 index 97869646cb..0000000000 --- a/src/test/integration/tests/iframes.js +++ /dev/null @@ -1,33 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - reload, - resume, - waitForPaused -} = require("../utils"); - -/** - * Test debugging a page with iframes - * 1. pause in the main thread - * 2. pause in the iframe - */ -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-iframes.html"); - - // test pausing in the main thread - await reload(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "iframes.html", 8); - - // test pausing in the iframe - await resume(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 8); - - // test pausing in the iframe - await resume(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 12); -}; diff --git a/src/test/integration/tests/index.js b/src/test/integration/tests/index.js deleted file mode 100644 index 9721f035bc..0000000000 --- a/src/test/integration/tests/index.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - asm: require("./asm"), - breaking: require("./breaking"), - breakpoints: require("./breakpoints"), - breakpointsCond: require("./breakpoints-cond"), - callStack: require("./call-stack"), - expressions: require("./expressions"), - debuggerButtons: require("./debugger-buttons"), - editorSelect: require("./editor-select"), - editorPreview: require("./editor-preview"), - editorGutter: require("./editor-gutter"), - editorHighlight: require("./editor-highlight"), - keyboardNavigation: require("./keyboard-navigation"), - keyboardShortcuts: require("./keyboard-shortcuts"), - iframes: require("./iframes"), - navigation: require("./navigation"), - pauseOnExceptions: require("./pause-exceptions"), - prettyPrint: require("./pretty-print"), - prettyPrintPaused: require("./pretty-print-paused"), - returnvalues: require("./returnvalues"), - scopes: require("./scopes"), - scopesMutations: require("./scopes-mutations"), - searching: require("./searching"), - sources: require("./sources"), - sourceMaps: require("./sourcemaps"), - sourceMapsReloading: require("./sourcemaps-reloading"), - sourceMaps2: require("./sourcemaps2"), - sourceMapsBogus: require("./sourcemaps-bogus"), - tabs: require("./tabs") -}; diff --git a/src/test/integration/tests/keyboard-navigation.js b/src/test/integration/tests/keyboard-navigation.js deleted file mode 100644 index c4cd81d7a4..0000000000 --- a/src/test/integration/tests/keyboard-navigation.js +++ /dev/null @@ -1,36 +0,0 @@ -const { - initDebugger, - waitForElement, - findElement, - findElementWithSelector, - selectSource, - pressKey -} = require("../utils"); - -async function keyboardNavigation(ctx) { - const { is, info } = ctx; - - const dbg = await initDebugger("doc-scripts.html"); - let doc = dbg.win.document; - - await selectSource(dbg, "simple2"); - - await waitForElement(dbg, ".CodeMirror"); - const editor = findElementWithSelector(dbg, ".CodeMirror"); - const textarea = findElementWithSelector(dbg, "textarea"); - editor.focus(); - - info("Enter code editor"); - pressKey(dbg, "Enter"); - is(textarea, doc.activeElement, "Editor is enabled"); - - info("Exit code editor and focus on container"); - pressKey(dbg, "Escape"); - is(editor, doc.activeElement, "Focused on container"); - - info("Enter code editor"); - pressKey(dbg, "Tab"); - is(textarea, doc.activeElement, "Editor is enabled"); -} - -module.exports = keyboardNavigation; diff --git a/src/test/integration/tests/keyboard-shortcuts.js b/src/test/integration/tests/keyboard-shortcuts.js deleted file mode 100644 index 3821238cf5..0000000000 --- a/src/test/integration/tests/keyboard-shortcuts.js +++ /dev/null @@ -1,51 +0,0 @@ -const { - initDebugger, - waitForElement, - waitForPaused, - assertPausedLocation, - pressKey, - reload -} = require("../utils"); - -function pressResume(dbg) { - pressKey(dbg, "resumeKey"); - return waitForPaused(dbg); -} - -function pressStepOver(dbg) { - pressKey(dbg, "stepOverKey"); - return waitForPaused(dbg); -} - -function pressStepIn(dbg) { - pressKey(dbg, "stepInKey"); - return waitForPaused(dbg); -} - -function pressStepOut(dbg) { - pressKey(dbg, "stepOutKey"); - return waitForPaused(dbg); -} - -async function keyboardShortcuts(ctx) { - const { info } = ctx; - const dbg = await initDebugger("doc-debugger-statements.html"); - - await reload(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 8); - - await pressResume(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 12); - - await pressStepIn(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 13); - - await pressStepOut(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 14); - - await pressStepOver(dbg); - assertPausedLocation(dbg, ctx, "debugger-statements.html", 9); -} - -module.exports = keyboardShortcuts; diff --git a/src/test/integration/tests/navigation.js b/src/test/integration/tests/navigation.js deleted file mode 100644 index c1736550fe..0000000000 --- a/src/test/integration/tests/navigation.js +++ /dev/null @@ -1,62 +0,0 @@ -const { - initDebugger, - invokeInTab, - waitForElement, - navigate, - addBreakpoint, - selectSource, - waitForPaused, - waitForDispatch, - assertPausedLocation, - reload -} = require("../utils"); - -function countSources(dbg) { - const sources = dbg.selectors.getSources(dbg.getState()); - return sources.size; -} - -/** - * Test navigating - * navigating while paused will reset the pause state and sources - */ -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-script-switching.html"); - const { selectors: { getSelectedSource, getPause }, getState } = dbg; - - invokeInTab(dbg, "firstCall"); - await waitForPaused(dbg); - - await navigate(dbg, "doc-scripts.html", "simple1.js"); - await addBreakpoint(dbg, "simple1.js", 4); - invokeInTab(dbg, "main"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "simple1.js", 4); - is(countSources(dbg), 4, "4 sources are loaded."); - - await navigate(dbg, "about:blank"); - await waitForDispatch(dbg, "NAVIGATE"); - is(countSources(dbg), 0, "0 sources are loaded."); - ok(!getPause(getState()), "No pause state exists"); - - await navigate( - dbg, - "doc-scripts.html", - "simple1.js", - "simple2.js", - "long.js", - "scripts.html" - ); - - is(countSources(dbg), 4, "4 sources are loaded."); - - // Test that the current select source persists across reloads - await selectSource(dbg, "long.js"); - await reload(dbg, "long.js"); - ok( - getSelectedSource(getState()).get("url").includes("long.js"), - "Selected source is long.js" - ); -}; diff --git a/src/test/integration/tests/pause-exceptions.js b/src/test/integration/tests/pause-exceptions.js deleted file mode 100644 index 3ac4d347db..0000000000 --- a/src/test/integration/tests/pause-exceptions.js +++ /dev/null @@ -1,82 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - invokeInTab, - togglePauseOnExceptions, - waitForPaused, - isPaused, - resume, - reload -} = require("../utils"); - -function uncaughtException(dbg) { - return invokeInTab(dbg, "uncaughtException").catch(() => {}); -} - -function caughtException(dbg) { - return invokeInTab(dbg, "caughtException"); -} - -function assertPOEState(dbg, ctx, pause, ignore) { - const { is } = ctx; - const { - getState, - selectors: { getShouldPauseOnExceptions, getShouldIgnoreCaughtExceptions } - } = dbg; - - is(getShouldPauseOnExceptions(getState()), pause); - is(getShouldIgnoreCaughtExceptions(getState()), ignore); -} - -/* - Tests Pausing on exception - 1. skip an uncaught exception - 2. pause on an uncaught exception - 3. pause on a caught error - 4. skip a caught error -*/ -async function testButton(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger("doc-exceptions.html"); - - // test skipping an uncaught exception - await togglePauseOnExceptions(dbg, false, false); - await uncaughtException(dbg); - ok(!isPaused(dbg)); - - // Test pausing on an uncaught exception - await togglePauseOnExceptions(dbg, true, false); - uncaughtException(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "exceptions.js", 2); - await resume(dbg); - - // Test pausing on a caught Error - await togglePauseOnExceptions(dbg, true, false); - caughtException(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "exceptions.js", 15); - await resume(dbg); - - // Test skipping a caught error - await togglePauseOnExceptions(dbg, true, true); - caughtException(dbg); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "exceptions.js", 17); - await resume(dbg); -} - -async function testReloading(ctx) { - const { ok, is, info } = ctx; - - let dbg = await initDebugger("doc-exceptions.html"); - - await togglePauseOnExceptions(dbg, true, false); - dbg = await initDebugger("doc-exceptions.html"); - assertPOEState(dbg, ctx, true, false); -} - -module.exports = { - testButton, - testReloading -}; diff --git a/src/test/integration/tests/pretty-print-paused.js b/src/test/integration/tests/pretty-print-paused.js deleted file mode 100644 index 103931484e..0000000000 --- a/src/test/integration/tests/pretty-print-paused.js +++ /dev/null @@ -1,33 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - selectSource, - addBreakpoint, - invokeInTab, - resume, - waitForPaused, - waitForDispatch, - clickElement -} = require("../utils"); - -// Tests pretty-printing a source that is currently paused. - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-minified.html"); - - await selectSource(dbg, "math.min.js"); - await addBreakpoint(dbg, "math.min.js", 2); - - invokeInTab(dbg, "arithmetic"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "math.min.js", 2); - - clickElement(dbg, "prettyPrintButton"); - await waitForDispatch(dbg, "TOGGLE_PRETTY_PRINT"); - - assertPausedLocation(dbg, ctx, "math.min.js:formatted", 18); - - await resume(dbg); -}; diff --git a/src/test/integration/tests/pretty-print.js b/src/test/integration/tests/pretty-print.js deleted file mode 100644 index e461d12c98..0000000000 --- a/src/test/integration/tests/pretty-print.js +++ /dev/null @@ -1,46 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - waitForPaused, - waitForDispatch, - findSource, - findElement, - selectSource, - clickElement, - addBreakpoint, - stepOver, - invokeInTab, - resume -} = require("../utils"); - -async function prettyPrint(ctx) { - const { ok, is } = ctx; - const dbg = await initDebugger("doc-minified.html", "math.min"); - - await selectSource(dbg, "math.min.js"); - - clickElement(dbg, "prettyPrintButton"); - await waitForDispatch(dbg, "TOGGLE_PRETTY_PRINT"); - - const ppSrc = findSource(dbg, "math.min.js:formatted"); - ok(ppSrc, "Pretty-printed source exists"); - - await addBreakpoint(dbg, ppSrc, 18); - - invokeInTab(dbg, "arithmetic"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, ppSrc, 18); - - await stepOver(dbg); - assertPausedLocation(dbg, ctx, ppSrc, 27); - await resume(dbg); - - // The pretty-print button should go away in the pretty-printed - // source. - ok(!findElement(dbg, "editorFooter"), "Footer is hidden"); - - await selectSource(dbg, "math.min.js"); - ok(findElement(dbg, "editorFooter"), "Footer is hidden"); -} - -module.exports = prettyPrint; diff --git a/src/test/integration/tests/returnvalues.js b/src/test/integration/tests/returnvalues.js deleted file mode 100644 index d09925eeb6..0000000000 --- a/src/test/integration/tests/returnvalues.js +++ /dev/null @@ -1,76 +0,0 @@ -const { - evalInTab, - assertNotPaused, - findElement, - initDebugger, - togglePauseOnExceptions, - resume, - stepIn, - waitForPaused -} = require("../utils"); - -function getLabel(dbg, index) { - return findElement(dbg, "scopeNode", index).innerText; -} - -function getValue(dbg, index) { - return findElement(dbg, "scopeValue", index).innerText; -} - -function toggleScopes(dbg) { - return findElement(dbg, "scopesHeader").click(); -} - -async function testReturnValue(dbg, ctx, val) { - const { is, ok } = ctx; - - evalInTab(dbg, `return_something(${val})`); - await waitForPaused(dbg); - - // "Step in" 3 times to get to the point where the debugger can - // see the return value. - await stepIn(dbg); - await stepIn(dbg); - await stepIn(dbg); - is(getLabel(dbg, 1), "return_something", "check for return_something"); - - // We don't show "undefined" but we do show other falsy values. - let label = getLabel(dbg, 2); - if (val === "undefined") { - ok(label !== "", "do not show for undefined"); - } else { - is(label, "", "check for "); - is(getValue(dbg, 2), val, `check value is ${val}`); - } - - await resume(dbg); - assertNotPaused(dbg, ctx); -} - -async function testThrowValue(dbg, ctx, val) { - const { is } = ctx; - evalInTab(dbg, `throw_something(${val})`).catch(() => {}); - await waitForPaused(dbg); - - // "Step in" to get to the exception. - await stepIn(dbg); - - is(getLabel(dbg, 1), "callee", "check for callee"); - is(getLabel(dbg, 2), "", "check for "); - is(getValue(dbg, 2), val, `check exception value is ${val}`); - - await resume(dbg); - await waitForPaused(dbg); - await resume(dbg); - assertNotPaused(dbg, ctx); -} - -module.exports = async function(ctx) { - const { info } = ctx; - const dbg = await initDebugger("doc-return-values.html"); - toggleScopes(dbg); - await togglePauseOnExceptions(dbg, true, false); - - await testReturnValue(dbg, ctx, "57"); - await testThrowValue(dbg, ctx, "57"); -}; diff --git a/src/test/integration/tests/scopes-mutations.js b/src/test/integration/tests/scopes-mutations.js deleted file mode 100644 index 5e5b324f1b..0000000000 --- a/src/test/integration/tests/scopes-mutations.js +++ /dev/null @@ -1,106 +0,0 @@ -const { - clickElement, - evalInTab, - findElement, - initDebugger, - invokeInTab, - resume, - stepOver, - waitForDispatch, - waitForPaused, - waitForTime -} = require("../utils"); - -function getScopeNodeLabel(dbg, index) { - return findElement(dbg, "scopeNode", index).innerText; -} - -function getScopeNodeValue(dbg, index) { - return findElement(dbg, "scopeValue", index).innerText; -} - -function expandNode(dbg, index) { - let onLoadProperties = onLoadObjectProperties(dbg); - clickElement(dbg, "scopeNode", index); - return onLoadProperties; -} - -function toggleScopes(dbg) { - return findElement(dbg, "scopesHeader").click(); -} - -function onLoadObjectProperties(dbg) { - return waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES"); -} - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - console.log(">>> starting"); - const dbg = await initDebugger("doc-script-mutate.html", "script-mutate"); - - toggleScopes(dbg); - - let onPaused = waitForPaused(dbg); - invokeInTab(dbg, "mutate"); - await onPaused; - - is( - getScopeNodeLabel(dbg, 2), - "", - 'The second element in the scope panel is ""' - ); - is( - getScopeNodeLabel(dbg, 3), - "phonebook", - 'The third element in the scope panel is "phonebook"' - ); - - // Expand `phonebook` - await expandNode(dbg, 3); - is( - getScopeNodeLabel(dbg, 4), - "S", - 'The fourth element in the scope panel is "S"' - ); - - // Expand `S` - await expandNode(dbg, 4); - is( - getScopeNodeLabel(dbg, 5), - "sarah", - 'The fifth element in the scope panel is "sarah"' - ); - is( - getScopeNodeLabel(dbg, 6), - "serena", - 'The sixth element in the scope panel is "serena"' - ); - - // Expand `sarah` - await expandNode(dbg, 5); - is( - getScopeNodeLabel(dbg, 6), - "lastName", - 'The sixth element in the scope panel is now "lastName"' - ); - is( - getScopeNodeValue(dbg, 6), - '"Doe"', - 'The "lastName" element has the expected "Doe" value' - ); - - info("Resuming"); - onPaused = waitForPaused(dbg); - await resume(dbg); - await onPaused; - is( - getScopeNodeLabel(dbg, 2), - "", - 'The second element in the scope panel is ""' - ); - is( - getScopeNodeLabel(dbg, 3), - "phonebook", - 'The third element in the scope panel is "phonebook"' - ); -}; diff --git a/src/test/integration/tests/scopes.js b/src/test/integration/tests/scopes.js deleted file mode 100644 index 9c363da88c..0000000000 --- a/src/test/integration/tests/scopes.js +++ /dev/null @@ -1,76 +0,0 @@ -const { - initDebugger, - waitForPaused, - invokeInTab, - evalInTab, - clickElement, - findElement, - waitForTime, - waitForDispatch, - stepOver -} = require("../utils"); - -function toggleNode(dbg, index) { - clickElement(dbg, "scopeNode", index); -} - -function getLabel(dbg, index) { - return findElement(dbg, "scopeNode", index).innerText; -} - -function toggleScopes(dbg) { - return findElement(dbg, "scopesHeader").click(); -} - -async function expandingProperties(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger( - "doc-script-switching.html", - "script-switching-01", - "script-switching-02" - ); - - toggleScopes(dbg); - invokeInTab(dbg, "firstCall"); - - await waitForPaused(dbg); - - is(getLabel(dbg, 1), "secondCall"); - is(getLabel(dbg, 2), ""); - is(getLabel(dbg, 4), "foo()"); - - toggleNode(dbg, 4); - await waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES"); - is(getLabel(dbg, 5), "length"); - - await stepOver(dbg); - is(getLabel(dbg, 4), "foo()"); - is(getLabel(dbg, 5), "Window"); -} - -async function changingScopes(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger( - "doc-script-switching.html", - "script-switching-01", - "script-switching-02" - ); - - toggleScopes(dbg); - invokeInTab(dbg, "firstCall"); - - await waitForPaused(dbg); - - clickElement(dbg, "frame", 2); - is(getLabel(dbg, 1), "firstCall"); - is(getLabel(dbg, 2), ""); - - toggleNode(dbg, 2); - await waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES"); - is(getLabel(dbg, 5), "CSS2Properties()"); -} - -module.exports = { - expandingProperties, - changingScopes -}; diff --git a/src/test/integration/tests/searching.js b/src/test/integration/tests/searching.js deleted file mode 100644 index 24939c094e..0000000000 --- a/src/test/integration/tests/searching.js +++ /dev/null @@ -1,39 +0,0 @@ -const { - initDebugger, - waitForPaused, - pressKey, - findElementWithSelector, - type, - waitForElement, - invokeInTab, - clickElement, - findElement, - waitForDispatch -} = require("../utils"); - -// Testing source search -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger("doc-script-switching.html"); - - pressKey(dbg, "sourceSearch"); - await waitForElement(dbg, "input"); - findElementWithSelector(dbg, "input").focus(); - type(dbg, "sw"); - pressKey(dbg, "Enter"); - - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - let source = dbg.selectors.getSelectedSource(dbg.getState()); - ok(source.get("url").match(/switching-01/), "first source is selected"); - - // 2. arrow keys and check to see if source is selected - pressKey(dbg, "sourceSearch"); - findElementWithSelector(dbg, "input").focus(); - type(dbg, "sw"); - pressKey(dbg, "Down"); - pressKey(dbg, "Enter"); - - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - source = dbg.selectors.getSelectedSource(dbg.getState()); - ok(source.get("url").match(/switching-02/), "second source is selected"); -}; diff --git a/src/test/integration/tests/sourcemaps-bogus.js b/src/test/integration/tests/sourcemaps-bogus.js deleted file mode 100644 index 34cc56e949..0000000000 --- a/src/test/integration/tests/sourcemaps-bogus.js +++ /dev/null @@ -1,32 +0,0 @@ -const { - initDebugger, - countSources, - assertPausedLocation, - selectSource, - addBreakpoint, - invokeInTab, - waitForPaused -} = require("../utils"); - -// Test that an error while loading a sourcemap does not break -// debugging. - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-sourcemap-bogus.html"); - const { selectors: { getSources }, getState } = dbg; - - await selectSource(dbg, "bogus-map.js"); - - // We should still be able to set breakpoints and pause in the - // generated source. - await addBreakpoint(dbg, "bogus-map.js", 4); - invokeInTab(dbg, "runCode"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "bogus-map.js", 4); - - // Make sure that only the single generated source exists. The - // sourcemap failed to download. - is(countSources(dbg), 1, "Only 1 source exists"); -}; diff --git a/src/test/integration/tests/sourcemaps-reloading.js b/src/test/integration/tests/sourcemaps-reloading.js deleted file mode 100644 index 176544afcd..0000000000 --- a/src/test/integration/tests/sourcemaps-reloading.js +++ /dev/null @@ -1,49 +0,0 @@ -const { - initDebugger, - reload, - selectSource, - findElement, - waitForDispatch, - closeTab, - assertPausedLocation, - findSource, - waitForSources, - disableBreakpoint, - addBreakpoint, - waitForPaused -} = require("../utils"); - -function assertBP(dbg, sourceId, { line, disabled = false }) { - const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; - const bp = getBreakpoint(getState(), { sourceId, line }); - - is(bp.location.line, line, "Breakpoint has correct line"); - - is(bp.disabled, disabled); -} - -module.exports = async function sourceMapsReloading(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - - const dbg = await initDebugger("doc-sourcemaps.html"); - const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; - - await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js"); - const entrySrc = findSource(dbg, "entry.js"); - await selectSource(dbg, entrySrc); - - await addBreakpoint(dbg, entrySrc, 13); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - assertBP(dbg, entrySrc.id, { line: 13 }); - - await addBreakpoint(dbg, entrySrc, 15); - await disableBreakpoint(dbg, entrySrc, 15); - - // Test reloading the debugger - await reload(dbg, "times2.js", "opts.js"); - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - - is(getBreakpoints(getState()).size, 2, "One breakpoint exists"); - assertBP(dbg, entrySrc.id, { line: 13 }); - assertBP(dbg, entrySrc.id, { line: 15, disabled: true }); -}; diff --git a/src/test/integration/tests/sourcemaps.js b/src/test/integration/tests/sourcemaps.js deleted file mode 100644 index 198efdd9bb..0000000000 --- a/src/test/integration/tests/sourcemaps.js +++ /dev/null @@ -1,63 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - waitForSources, - selectSource, - addBreakpoint, - stepIn, - stepOut, - stepOver, - invokeInTab, - waitForPaused -} = require("../utils"); - -// Tests loading sourcemapped sources, setting breakpoints, and -// stepping in them. - -module.exports = async function sourceMaps(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-sourcemaps.html"); - const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; - - await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js"); - ok(true, "Original sources exist"); - const entrySrc = findSource(dbg, "entry.js"); - - await selectSource(dbg, entrySrc); - ok( - dbg.win.cm.getValue().includes("window.keepMeAlive"), - "Original source text loaded correctly" - ); - - // Test that breakpoint sliding is not attempted. The breakpoint - // should not move anywhere. - await addBreakpoint(dbg, entrySrc, 13); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - ok( - getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }), - "Breakpoint has correct line" - ); - - // Test breaking on a breakpoint - await addBreakpoint(dbg, "entry.js", 15); - is(getBreakpoints(getState()).size, 2, "Two breakpoints exist"); - ok( - getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15 }), - "Breakpoint has correct line" - ); - - invokeInTab(dbg, "keepMeAlive"); - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, entrySrc, 15); - - await stepIn(dbg); - assertPausedLocation(dbg, ctx, "times2.js", 2); - await stepOver(dbg); - assertPausedLocation(dbg, ctx, "times2.js", 3); - - await stepOut(dbg); - await stepOut(dbg); - assertPausedLocation(dbg, ctx, "entry.js", 16); -}; diff --git a/src/test/integration/tests/sourcemaps2.js b/src/test/integration/tests/sourcemaps2.js deleted file mode 100644 index b7ee5057f3..0000000000 --- a/src/test/integration/tests/sourcemaps2.js +++ /dev/null @@ -1,41 +0,0 @@ -const { - initDebugger, - assertPausedLocation, - findSource, - waitForSources, - selectSource, - addBreakpoint, - invokeInTab, - waitForPaused -} = require("../utils"); - -// Tests loading sourcemapped sources, setting breakpoints, and -// stepping in them. - -// This source map does not have source contents, so it's fetched separately - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - const dbg = await initDebugger("doc-sourcemaps2.html"); - const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg; - - await waitForSources(dbg, "main.js", "main.min.js"); - - ok(true, "Original sources exist"); - const mainSrc = findSource(dbg, "main.js"); - - await selectSource(dbg, mainSrc); - - // Test that breakpoint is not off by a line. - await addBreakpoint(dbg, mainSrc, 4); - is(getBreakpoints(getState()).size, 1, "One breakpoint exists"); - ok( - getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4 }), - "Breakpoint has correct line" - ); - - invokeInTab(dbg, "logMessage"); - - await waitForPaused(dbg); - assertPausedLocation(dbg, ctx, "main.js", 4); -}; diff --git a/src/test/integration/tests/sources.js b/src/test/integration/tests/sources.js deleted file mode 100644 index e35a5771d8..0000000000 --- a/src/test/integration/tests/sources.js +++ /dev/null @@ -1,107 +0,0 @@ -const { - initDebugger, - environment, - clickElement, - invokeInTab, - pressKey, - selectSource, - evalInTab, - findElement, - findAllElements, - findElementWithSelector, - waitForSources, - waitForDispatch, - waitUntil, - waitForTime -} = require("../utils"); - -// Tests that the source tree works. - -function countSources(dbg) { - return findAllElements(dbg, "sourceNodes").length; -} - -function toggleDirectory(dbg, index) { - return clickElement(dbg, "sourceArrow", index); -} - -function clickNode(dbg, index) { - return clickElement(dbg, "sourceNode", index); -} - -function getSourceNode(dbg, index) { - return findElement(dbg, "sourceNode", index).textContent; -} - -function getFocusedNode(dbg) { - return findElementWithSelector(dbg, ".sources-list .focused"); -} - -async function waitForSourceCount(dbg, i) { - // We are forced to wait until the DOM nodes appear because the - // source tree batches its rendering. - await waitUntil(() => { - return countSources(dbg) === i; - }); -} - -module.exports = async function(ctx) { - const { ok, is, info } = ctx; - - const dbg = await initDebugger("doc-sources.html"); - const { selectors: { getSelectedSource }, getState } = dbg; - - await waitForSources( - dbg, - "simple1", - "simple2", - "nested-source", - "long.js", - "doc-sources.html" - ); - - // wait for source render to debounce - await waitForTime(200); - - // Expand nodes and make sure more sources appear. - is(countSources(dbg), 2); - - toggleDirectory(dbg, 2); - is(countSources(dbg), 7); - - toggleDirectory(dbg, 3); - - is(countSources(dbg), 8); - - // Select a source. - ok(!getFocusedNode(dbg), "Source is not focused"); - - const selected = waitForDispatch(dbg, "SELECT_SOURCE"); - clickNode(dbg, 4); - await selected; - - ok(getFocusedNode(dbg), "Source is focused"); - - ok( - getSelectedSource(getState()).get("url").includes("nested-source.js"), - "The right source is selected" - ); - - // Make sure new sources appear in the list. - invokeInTab(dbg, "loadScript"); - await waitForSourceCount(dbg, 9); - - is(getSourceNode(dbg, 7), "math.min.js", "The dynamic script exists"); - - if (environment == "mochitest") { - // Make sure named eval sources appear in the list. - evalInTab(dbg, "window.evaledFunc = function() {} //# sourceURL=evaled.js"); - - await waitForSourceCount(dbg, 11); - is( - findElement(dbg, "sourceNode", 2).textContent, - "evaled.js", - "The eval script exists" - ); - } -}; diff --git a/src/test/integration/tests/tabs.js b/src/test/integration/tests/tabs.js deleted file mode 100644 index b09a3eec2b..0000000000 --- a/src/test/integration/tests/tabs.js +++ /dev/null @@ -1,63 +0,0 @@ -const { - initDebugger, - reload, - selectSource, - findElement, - waitForDispatch, - closeTab -} = require("../utils"); - -function countTabs(dbg) { - return findElement(dbg, "sourceTabs").children.length; -} - -export async function addTabs(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - - let dbg = await initDebugger("doc-scripts.html", "simple1", "simple2"); - - await selectSource(dbg, "simple1"); - await selectSource(dbg, "simple2"); - expect(countTabs(dbg)).to.equal(2); - - // Test reloading the debugger - dbg = await initDebugger("doc-scripts.html", "simple1", "simple2"); - expect(countTabs(dbg)).to.equal(2); - await selectSource(dbg, "simple2"); - - // Test reloading the debuggee - await reload(dbg, "simple1", "simple2"); - await waitForDispatch(dbg, "LOAD_SOURCE_TEXT"); - expect(countTabs(dbg)).to.equal(2); -} - -export async function reloadWithTabs(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - - let dbg = await initDebugger("doc-scripts.html", "simple1", "simple2"); - - // debugger - await selectSource(dbg, "simple1"); - await selectSource(dbg, "simple2"); - expect(countTabs(dbg)).to.equal(2); - - // Test reloading the debugger - await reload(dbg, "simple1", "simple2"); - await waitForDispatch(dbg, "SELECT_SOURCE"); - expect(countTabs(dbg)).to.equal(2); -} - -export async function reloadWithNoTabs(ctx) { - const { ok, is, info, requestLongerTimeout } = ctx; - - let dbg = await initDebugger("doc-scripts.html", "simple1", "simple2"); - - await selectSource(dbg, "simple1"); - await selectSource(dbg, "simple2"); - closeTab(dbg, "simple1"); - closeTab(dbg, "simple2"); - - // Test reloading the debugger - dbg = await initDebugger("doc-scripts.html", "simple1", "simple2"); - expect(countTabs(dbg)).to.equal(0); -} diff --git a/src/test/integration/utils/assert.js b/src/test/integration/utils/assert.js deleted file mode 100644 index 47b68ad568..0000000000 --- a/src/test/integration/utils/assert.js +++ /dev/null @@ -1,61 +0,0 @@ -const get = require("lodash/get"); - -const { - findSource, - findElement, - isVisibleWithin, - isPaused -} = require("./shared"); - -function assertPausedLocation(dbg, ctx, source, line) { - const { selectors: { getSelectedSource, getPause }, getState } = dbg; - source = findSource(dbg, source); - - const { is, ok } = ctx; - - // Check the selected source - is(getSelectedSource(getState()).get("id"), source.id); - - // Check the pause location - const location = get(getPause(getState()), "frame.location"); - is(location.sourceId, source.id); - is(location.line, line); - - // Check the debug line - ok( - dbg.win.cm.lineInfo(line - 1).wrapClass.includes("debug-line"), - "Line is highlighted as paused" - ); -} - -function assertNotPaused(dbg, ctx) { - const { ok } = ctx; - ok(!isPaused(dbg), "not paused"); -} - -function assertHighlightLocation(dbg, ctx, source, line) { - const { selectors: { getSelectedSource, getPause }, getState } = dbg; - const { is, ok } = ctx; - source = findSource(dbg, source); - - // Check the selected source - is(getSelectedSource(getState()).get("url"), source.url); - - // Check the highlight line - const lineEl = findElement(dbg, "highlightLine"); - ok(lineEl, "Line is highlighted"); - ok( - isVisibleWithin(findElement(dbg, "codeMirror"), lineEl), - "Highlighted line is visible" - ); - ok( - dbg.win.cm.lineInfo(line - 1).wrapClass.includes("highlight-line"), - "Line is highlighted" - ); -} - -module.exports = { - assertPausedLocation, - assertNotPaused, - assertHighlightLocation -}; diff --git a/src/test/integration/utils/commands.js b/src/test/integration/utils/commands.js deleted file mode 100644 index e2b18fc3c3..0000000000 --- a/src/test/integration/utils/commands.js +++ /dev/null @@ -1,283 +0,0 @@ -const { - clickEl, - rightClickEl, - dblClickEl, - mouseOverEl -} = require("./mouse-events"); - -function info(msg) { - console.log(`info: ${msg}\n`); -} - -const { - evalInTab, - invokeInTab, - selectMenuItem, - pressKey, - type -} = require("./mocha"); - -const { - selectors, - findSource, - getSelector, - info, - isPaused -} = require("./shared"); -const { - waitForSources, - waitForDispatch, - waitForPaused, - waitForThreadEvents -} = require("./wait"); - -/** -* Closes a tab -* -* @memberof mochitest/actions -* @param {Object} dbg -* @param {String} url -* @return {Promise} -* @static -*/ -function closeTab(dbg, url) { - info("Closing tab: " + url); - const source = findSource(dbg, url); - - dbg.actions.closeTab(source.url); -} - -/** - * Selects the source. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {String} url - * @param {Number} line - * @return {Promise} - * @static - */ -async function selectSource(dbg, url, line) { - info("Selecting source: " + url); - const source = findSource(dbg, url); - const hasSource = !!dbg.selectors.getSource(dbg.getState(), source.id); - dbg.actions.selectSource(source.id, { line }); - if (!hasSource) { - return waitForDispatch(dbg, "SELECT_SOURCE"); - } -} - -/** - * Steps over. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @return {Promise} - * @static - */ -async function stepOver(dbg) { - info("Stepping over"); - dbg.actions.stepOver(); - return waitForPaused(dbg); -} - -/** - * Steps in. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @return {Promise} - * @static - */ -async function stepIn(dbg) { - info("Stepping in"); - dbg.actions.stepIn(); - return waitForPaused(dbg); -} - -/** - * Steps out. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @return {Promise} - * @static - */ -async function stepOut(dbg) { - info("Stepping out"); - dbg.actions.stepOut(); - return waitForPaused(dbg); -} - -/** - * Resumes. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @return {Promise} - * @static - */ -async function resume(dbg) { - info("Resuming"); - dbg.actions.resume(); - return waitForThreadEvents(dbg, "resumed"); -} - -/** - * Reloads the debuggee. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {Array} sources - * @return {Promise} - * @static - */ -async function reload(dbg, ...sources) { - await dbg.client.reload(); - await waitForDispatch(dbg, "NAVIGATE"); - return waitForSources(dbg, ...sources); -} - -/** - * Navigates the debuggee to another url. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {String} url - * @param {Array} sources - * @return {Promise} - * @static - */ -async function navigate(dbg, url, ...sources) { - dbg.client.navigate(url); - return waitForSources(dbg, ...sources); -} - -/** - * Adds a breakpoint to a source at line/col. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {String} source - * @param {Number} line - * @param {Number} col - * @return {Promise} - * @static - */ -async function addBreakpoint(dbg, source, line, col) { - source = findSource(dbg, source); - const sourceId = source.id; - dbg.actions.addBreakpoint({ sourceId, line, col }); - return waitForDispatch(dbg, "ADD_BREAKPOINT"); -} - -/** - * Removes a breakpoint from a source at line/col. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {String} source - * @param {Number} line - * @param {Number} col - * @return {Promise} - * @static - */ -async function removeBreakpoint(dbg, sourceId, line, col) { - return dbg.actions.removeBreakpoint({ sourceId, line, col }); -} - -async function disableBreakpoint(dbg, source, line) { - return dbg.actions.disableBreakpoint({ - sourceId: source.id, - line, - column: undefined - }); -} - -/** - * Toggles the Pause on exceptions feature in the debugger. - * - * @memberof mochitest/actions - * @param {Object} dbg - * @param {Boolean} pauseOnExceptions - * @param {Boolean} ignoreCaughtExceptions - * @return {Promise} - * @static - */ -async function togglePauseOnExceptions( - dbg, - pauseOnExceptions, - ignoreCaughtExceptions -) { - const command = dbg.actions.pauseOnExceptions( - pauseOnExceptions, - ignoreCaughtExceptions - ); - - if (!isPaused(dbg)) { - return waitForThreadEvents(dbg, "resumed"); - } - - return command; -} - -async function clickElement(dbg, elementName, ...args) { - const selector = getSelector(elementName, ...args); - const el = dbg.win.document.querySelector(selector); - clickEl(dbg.win, el); -} - -async function dblClickElement(dbg, elementName, ...args) { - const selector = getSelector(elementName, ...args); - const el = dbg.win.document.querySelector(selector); - dblClickEl(dbg.win, el); -} - -async function rightClickElement(dbg, elementName, ...args) { - const selector = getSelector(elementName, ...args); - const el = dbg.win.document.querySelector(selector); - info("right click on the gutter", el); - rightClickEl(dbg.win, el); -} - -// NOTE: we should fix this for mochitests. It's likely that `this` would work. -const winObj = typeof window == "Object" ? window : {}; -winObj.resumeTest = undefined; - -/** - * Pause the test and let you interact with the debugger. - * The test can be resumed by invoking `resumeTest` in the console. - * - * @memberof mochitest - * @static - */ -function pauseTest() { - info("Test paused. Invoke resumeTest to continue."); - return new Promise(resolve => (resumeTest = resolve)); -} - -module.exports = { - closeTab, - selectSource, - stepOver, - stepIn, - stepOut, - resume, - reload, - navigate, - addBreakpoint, - removeBreakpoint, - disableBreakpoint, - togglePauseOnExceptions, - clickElement, - mouseOverEl, - navigate, - invokeInTab, - evalInTab, - rightClickElement, - dblClickElement, - selectMenuItem, - type, - pressKey, - pauseTest -}; diff --git a/src/test/integration/utils/debuggee.js b/src/test/integration/utils/debuggee.js deleted file mode 100644 index 050a25d193..0000000000 --- a/src/test/integration/utils/debuggee.js +++ /dev/null @@ -1,120 +0,0 @@ -function Debuggee() { - function $(selector) { - const element = document.querySelector(selector); - console.log("$", selector, element); - - if (!element) { - throw new Error("Element not found, try changing the selector"); - } - return element; - } - - function mouseEvent(eventType) { - return new MouseEvent(eventType, { - view: window, - bubbles: true, - cancelable: true - }); - } - - const specialKeysMap = { - "{enter}": 13 - }; - - // Special character examples {enter}, {esc}, {leftarrow} .. - function isSpecialCharacter(text) { - return text.match(/^\{.*\}$/); - } - - function keyInfo(key, eventType) { - let charCodeAt; - - if (key.length > 1) { - charCodeAt = specialKeysMap[key]; - } else { - charCodeAt = key.toUpperCase().charCodeAt(0); - } - - return { - charCode: eventType == "keypress" ? 0 : charCodeAt, - keyCode: charCodeAt, - which: charCodeAt - }; - } - - function keyEvent(eventType, key) { - const event = new Event(eventType, { - bubbles: true, - cancelable: false, - view: window - }); - - const { charCode, keyCode, which } = keyInfo(key, eventType); - - return Object.assign(event, { - charCode: charCode, - keyCode: keyCode, - which: which, - detail: 0, - layerX: 0, - layerY: 0, - pageX: 0, - pageY: 0 - }); - } - - function sendKey(element, key) { - element.dispatchEvent(keyEvent("keydown", key)); - element.dispatchEvent(keyEvent("keypress", key)); - if (key.length == 1) { - element.value += key; - } - element.dispatchEvent(keyEvent("keyup", key)); - } - - function click(selector) { - const element = $(selector); - console.log("click", selector); - element.dispatchEvent(mouseEvent("click")); - } - - function dblclick(selector) { - const element = $(selector); - console.log("dblclick", selector); - element.dispatchEvent(mouseEvent("dblclick")); - } - - function type(selector, text) { - const element = $(selector); - console.log("type", selector, text); - element.select(); - - if (isSpecialCharacter(text)) { - sendKey(element, text); - } else { - const chars = text.split(""); - chars.forEach(char => sendKey(element, char)); - } - } - - return { - click, - dblclick, - type - }; -} - -const debuggeeStatement = `window.dbg = (${Debuggee})()`; -let injectedDebuggee; - -function injectDebuggee(win = window) { - if (injectedDebuggee) { - return Promise.resolve(injectedDebuggee); - } - - return win.client.debuggeeCommand(debuggeeStatement).then(result => { - injectedDebuggee = result; - }); -} - -module.exports = injectDebuggee; diff --git a/src/test/integration/utils/index.js b/src/test/integration/utils/index.js deleted file mode 100644 index 6e8b5cada0..0000000000 --- a/src/test/integration/utils/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const wait = require("./wait"); -const assert = require("./assert"); -const mocha = require("./mocha"); -const commands = require("./commands"); -const shared = require("./shared"); - -module.exports = Object.assign({}, wait, assert, mocha, commands, shared); diff --git a/src/test/integration/utils/mocha.js b/src/test/integration/utils/mocha.js deleted file mode 100644 index a69a2be9c7..0000000000 --- a/src/test/integration/utils/mocha.js +++ /dev/null @@ -1,163 +0,0 @@ -const mapValues = require("lodash/mapValues"); -const injectDebuggee = require("./debuggee"); -const { - waitUntil, - waitForSources, - waitForTargetEvent, - waitForPaused -} = require("./wait"); - -const { type, pressKey } = require("./type"); - -function info(msg) { - console.log(`info: ${msg}\n`); -} - -async function waitForTime(time) { - return new Promise(function(resolve, reject) { - setTimeout(resolve, time); - }); -} - -async function waitForElement(win, selector) { - return waitUntil(() => win.document.querySelector(selector)); -} - -async function debuggee(callback) { - /** - * gets a fat arrow function and returns the function body - * `() => { example }` => `example` - */ - function getFunctionBody(cb) { - const source = cb.toString(); - const firstCurly = source.toString().indexOf("{"); - return source.slice(firstCurly + 1, -1).trim(); - } - - const script = getFunctionBody(callback); - - await injectDebuggee(debuggerWindow); - return debuggerWindow.client.debuggeeCommand(script); -} - -async function invokeInTab(dbg, fnc) { - info(`invoking function ${fnc}()`); - return dbg.client.debuggeeCommand(`${fnc}()`); -} - -async function evalInTab(dbg, script) { - info(`evaling script ${script}`); - return dbg.client.debuggeeCommand(script); -} - -function selectMenuItem(dbg, index) { - const doc = dbg.win.document; - - const popup = doc.querySelector('menupopup[menu-api="true"]'); - const item = popup.querySelector(`menuitem:nth-child(${index})`); - item.click(); -} - -function createDebuggerContext(iframe) { - const win = iframe.contentWindow.window; - - const { - store, - selectors, - actions, - client, - connection: { tabConnection: { threadClient, tabTarget } } - } = win.getGlobalsForTesting(); - - return { - actions, - selectors, - store, - client, - threadClient, - tabTarget, - win, - getState: store.getState - }; -} - -async function waitForLoad(iframe) { - return new Promise(resolve => { - iframe.onload = resolve; - }); -} - -async function createIframe() { - let container = window["app-container"]; - let iframe = document.createElement("iframe"); - iframe.src = "http://localhost:8000"; - let id = document.createAttribute("id"); - id.value = "debuggerWindow"; - container.innerHTML = ""; - const loaded = waitForLoad(iframe); - container.appendChild(iframe); - await loaded; - - await waitForElement(iframe.contentWindow.window, ".tab"); - return iframe; -} - -async function navigateToTab(iframe) { - const win = iframe.contentWindow.window; - const tabs = win.launchpadStore.getState().tabs.get("tabs"); - const tabId = tabs - .find(t => { - return t.get("clientType") == "firefox"; - }) - .get("id"); - - await waitForElement(win, ".tab"); - win.location = `/?firefox-tab=${tabId}`; - await waitForElement(win, ".debugger"); -} - -async function navigate(dbg, url) { - dbg.client.navigate(`${url}`); - - return Promise.race([ - waitForPaused(dbg), - waitForTargetEvent(dbg, "navigate") - ]); -} - -async function initDebugger(url, ...sources) { - const iframe = await createIframe(); - await navigateToTab(iframe); - let dbg = createDebuggerContext(iframe); - await navigate( - dbg, - "http://localhost:8000/integration/examples/doc-minified.html" - ); - await navigate(dbg, `http://localhost:8000/integration/examples/${url}`); - - dbg = createDebuggerContext(iframe); - await waitForSources(dbg, ...sources); - return dbg; -} - -function countSources(dbg) { - const sources = dbg.selectors.getSources(dbg.getState()); - - // the web test runner has one extra source because it injects the debuggee script - return sources.size - 1; -} - -function setupTestRunner() {} - -module.exports = { - invokeInTab, - evalInTab, - selectMenuItem, - type, - pressKey, - countSources, - initDebugger, - setupTestRunner, - info, - environment: "mocha" -}; diff --git a/src/test/integration/utils/mochitest.js b/src/test/integration/utils/mochitest.js deleted file mode 100644 index b53d892051..0000000000 --- a/src/test/integration/utils/mochitest.js +++ /dev/null @@ -1,146 +0,0 @@ -const { info } = require("./shared"); - -var ContentTask, - gBrowser, - isLinux, - isMac, - cmdOrCtrl, - keyMappings, - openNewTabAndToolbox, - Services, - EXAMPLE_URL, - EventUtils; - -function setKeyboardMapping(isLinux, cmdOrCtrl) { - // On Mac, going to beginning/end only works with meta+left/right. On - // Windows, it only works with home/end. On Linux, apparently, either - // ctrl+left/right or home/end work. - const endKey = isMac - ? { code: "VK_RIGHT", modifiers: cmdOrCtrl } - : { code: "VK_END" }; - const startKey = isMac - ? { code: "VK_LEFT", modifiers: cmdOrCtrl } - : { code: "VK_HOME" }; - return { - sourceSearch: { code: "p", modifiers: cmdOrCtrl }, - fileSearch: { code: "f", modifiers: cmdOrCtrl }, - Enter: { code: "VK_RETURN" }, - Up: { code: "VK_UP" }, - Down: { code: "VK_DOWN" }, - Right: { code: "VK_RIGHT" }, - Left: { code: "VK_LEFT" }, - End: endKey, - Start: startKey, - Tab: { code: "VK_TAB" }, - Escape: { code: "VK_ESCAPE" }, - pauseKey: { code: "VK_F8" }, - resumeKey: { code: "VK_F8" }, - stepOverKey: { code: "VK_F10" }, - stepInKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux } }, - stepOutKey: { - code: "VK_F11", - modifiers: { ctrlKey: isLinux, shiftKey: true } - } - }; -} - -function setupTestRunner(context) { - ContentTask = context.ContentTask; - gBrowser = context.gBrowser; - openNewTabAndToolbox = context.openNewTabAndToolbox; - Services = context.Services; - EXAMPLE_URL = context.EXAMPLE_URL; - EventUtils = context.EventUtils; - isLinux = Services.appinfo.OS === "Linux"; - isMac = Services.appinfo.OS === "Darwin"; - cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true }; - keyMappings = setKeyboardMapping(isLinux, cmdOrCtrl); -} - -function invokeInTab(dbg, fnc) { - info(`Invoking function ${fnc} in tab`); - return ContentTask.spawn(gBrowser.selectedBrowser, fnc, function*(fnc) { - content.wrappedJSObject[fnc](); // eslint-disable-line mozilla/no-cpows-in-tests, max-len - }); -} - -function evalInTab(dbg, script) { - info(`evaling script ${script}`); - return ContentTask.spawn(gBrowser.selectedBrowser, script, function(script) { - content.eval(script); - }); -} - -function selectMenuItem(dbg, index) { - // the context menu is in the toolbox window - const doc = dbg.toolbox.win.document; - - // there are several context menus, we want the one with the menu-api - const popup = doc.querySelector('menupopup[menu-api="true"]'); - - const item = popup.querySelector(`menuitem:nth-child(${index})`); - return EventUtils.synthesizeMouseAtCenter(item, {}, dbg.toolbox.win); -} - -/** - * Simulates a key press in the debugger window. - * - * @memberof mochitest/helpers - * @param {Object} dbg - * @param {String} keyName - * @return {Promise} - * @static - */ -function pressKey(dbg, keyName) { - let keyEvent = keyMappings[keyName]; - const { code, modifiers } = keyEvent; - return EventUtils.synthesizeKey(code, modifiers || {}, dbg.win); -} - -function type(dbg, string) { - string.split("").forEach(char => { - EventUtils.synthesizeKey(char, {}, dbg.win); - }); -} - -function countSources(dbg) { - const sources = dbg.selectors.getSources(dbg.getState()); - return sources.size; -} - -function createDebuggerContext(toolbox) { - const win = toolbox.getPanel("jsdebugger").panelWin; - const store = win.Debugger.store; - - return { - actions: win.Debugger.actions, - selectors: win.Debugger.selectors, - getState: store.getState, - store: store, - client: win.Debugger.client, - threadClient: toolbox.threadClient, - toolbox: toolbox, - win: win - }; -} - -async function initDebugger(url, ...sources) { - Services.prefs.clearUserPref("devtools.debugger.tabs"); - Services.prefs.clearUserPref("devtools.debugger.pending-selected-location"); - url = url.startsWith("data:") ? url : EXAMPLE_URL + url; - const toolbox = await openNewTabAndToolbox(url, "jsdebugger"); - return createDebuggerContext(toolbox); -} - -module.exports = { - invokeInTab, - evalInTab, - selectMenuItem, - pressKey, - type, - countSources, - setupTestRunner, - info, - initDebugger, - environment: "mochitest" -}; diff --git a/src/test/integration/utils/mouse-events.js b/src/test/integration/utils/mouse-events.js deleted file mode 100644 index 1c8752998c..0000000000 --- a/src/test/integration/utils/mouse-events.js +++ /dev/null @@ -1,67 +0,0 @@ -function triggerMouseEvent({ type, props = {}, win, el }) { - let event = new win.Event(type, { - view: win, - bubbles: true, - cancelable: true - }); - - const rect = el.getBoundingClientRect(); - event = Object.assign(event, props, { - clientX: (rect.left + rect.right) / 2, - clientY: (rect.top + rect.bottom) / 2 - }); - - el.dispatchEvent(event); -} - -function clickEl(win, el) { - triggerMouseEvent({ - type: "mousedown", - win: win, - el - }); - - triggerMouseEvent({ - type: "click", - win: win, - el - }); - - return triggerMouseEvent({ - type: "mouseup", - win: win, - el - }); -} - -function rightClickEl(win, el) { - return triggerMouseEvent({ - type: "contextmenu", - props: { which: 3 }, - win, - el - }); -} - -function dblClickEl(win, el) { - return triggerMouseEvent({ - type: "dblclick", - win, - el - }); -} - -function mouseOverEl(win, el) { - triggerMouseEvent({ - type: "mouseover", - win: win, - el - }); -} - -module.exports = { - clickEl, - rightClickEl, - dblClickEl, - mouseOverEl -}; diff --git a/src/test/integration/utils/shared.js b/src/test/integration/utils/shared.js deleted file mode 100644 index e42bd4ccd7..0000000000 --- a/src/test/integration/utils/shared.js +++ /dev/null @@ -1,116 +0,0 @@ -const mapValues = require("lodash/mapValues"); - -const selectors = { - callStackHeader: ".call-stack-pane ._header", - callStackBody: ".call-stack-pane .pane", - scopesHeader: ".scopes-pane ._header", - breakpointItem: i => `.breakpoints-list .breakpoint:nth-child(${i})`, - scopeNode: i => `.scopes-list .tree-node:nth-child(${i}) .object-label`, - scopeValue: i => `.scopes-list .tree-node:nth-child(${i}) .object-value`, - expressionNode: i => - `.expressions-list .tree-node:nth-child(${i}) .object-label`, - expressionValue: i => - `.expressions-list .tree-node:nth-child(${i}) .object-value`, - expressionClose: i => - `.expressions-list .expression-container:nth-child(${i}) .close-btn`, - expressionNodes: ".expressions-list .tree-node", - frame: i => `.frames ul li:nth-child(${i})`, - frames: ".frames ul li", - gutter: i => `.CodeMirror-code *:nth-child(${i}) .CodeMirror-linenumber`, - menuitem: i => `menupopup menuitem:nth-child(${i})`, - pauseOnExceptions: ".pause-exceptions", - breakpoint: ".CodeMirror-code > .new-breakpoint", - highlightLine: ".CodeMirror-code > .highlight-line", - codeMirror: ".CodeMirror", - resume: ".resume.active", - stepOver: ".stepOver.active", - stepOut: ".stepOut.active", - stepIn: ".stepIn.active", - toggleBreakpoints: ".breakpoints-toggle", - prettyPrintButton: ".prettyPrint", - sourcesFooter: ".sources-panel .source-footer", - editorFooter: ".editor-pane .source-footer", - sourceNode: i => `.sources-list .tree-node:nth-child(${i}) .node`, - sourceNodes: ".sources-list .tree-node", - sourceArrow: i => `.sources-list .tree-node:nth-child(${i}) .arrow`, - sourceTabs: `.source-tabs` -}; - -function findElement(dbg, elementName, ...args) { - const selector = getSelector(elementName, ...args); - return findElementWithSelector(dbg, selector); -} - -function findElementWithSelector(dbg, selector) { - return dbg.win.document.querySelector(selector); -} - -function findAllElements(dbg, elementName, ...args) { - const selector = getSelector(elementName, ...args); - return dbg.win.document.querySelectorAll(selector); -} - -function getSelector(elementName, ...args) { - let selector = selectors[elementName]; - if (!selector) { - throw new Error(`The selector ${elementName} is not defined`); - } - - if (typeof selector == "function") { - selector = selector(...args); - } - - return selector; -} - -function findSource(dbg, url) { - if (typeof url !== "string") { - // Support passing in a source object itelf all APIs that use this - // function support both styles - return url; - } - - const sources = dbg.selectors.getSources(dbg.getState()); - const source = sources.find(s => { - const sourceUrl = s.get("url"); - return sourceUrl && sourceUrl.includes(url); - }); - - if (!source) { - throw new Error("Unable to find source: " + url); - } - - return source.toJS(); -} - -function isPaused(dbg) { - const { selectors: { getPause }, getState } = dbg; - return !!getPause(getState()); -} - -function isVisibleWithin(outerEl, innerEl) { - const innerRect = innerEl.getBoundingClientRect(); - const outerRect = outerEl.getBoundingClientRect(); - return innerRect.top > outerRect.top && innerRect.bottom < outerRect.bottom; -} - -function info(msg) { - const message = `INFO: ${msg}\n`; - if (typeof dump == "function") { - dump(message); - } - - console.log(message); -} - -module.exports = { - findElement, - findElementWithSelector, - findAllElements, - findSource, - selectors, - getSelector, - isPaused, - isVisibleWithin, - info -}; diff --git a/src/test/integration/utils/type.js b/src/test/integration/utils/type.js deleted file mode 100644 index 43edb07f97..0000000000 --- a/src/test/integration/utils/type.js +++ /dev/null @@ -1,69 +0,0 @@ -const specialKeysMap = { - Enter: 13, - Escape: 27, - Tab: 9 -}; - -function keyEvent(eventType, key, win) { - let event = new win.Event(eventType, { - bubbles: true, - cancelable: false, - view: win - }); - - const { charCode, keyCode, which } = keyInfo(key, eventType); - - event = Object.assign(event, { - charCode: charCode, - keyCode: keyCode, - which: which, - key: key, - code: "", - location: 0, - detail: 0, - layerX: 0, - layerY: 0, - pageX: 0, - pageY: 0, - shiftKey: false, - altKey: false, - ctrlKey: false, - metaKey: false - }); - - return event; -} - -function pressKey(dbg, key) { - const win = dbg.win; - const element = dbg.win.document.activeElement; - - element.dispatchEvent(keyEvent("keydown", key, win)); - element.dispatchEvent(keyEvent("keypress", key, win)); - if (key.length == 1) { - element.value += key; - } - element.dispatchEvent(keyEvent("keyup", key, win)); -} - -function type(dbg, string) { - string.split("").forEach(char => pressKey(dbg, char)); -} - -function keyInfo(key, eventType) { - let charCodeAt; - - if (key.length > 1) { - charCodeAt = specialKeysMap[key]; - } else { - charCodeAt = key.toUpperCase().charCodeAt(0); - } - - return { - charCode: eventType == "keypress" ? 0 : charCodeAt, - keyCode: charCodeAt, - which: charCodeAt - }; -} - -module.exports = { type, pressKey }; diff --git a/src/test/integration/utils/wait.js b/src/test/integration/utils/wait.js deleted file mode 100644 index ecc9b95363..0000000000 --- a/src/test/integration/utils/wait.js +++ /dev/null @@ -1,199 +0,0 @@ -const get = require("lodash/get"); -const { findElementWithSelector, info } = require("./shared"); - -/** - * Waits for `predicate(state)` to be true. `state` is the redux app state. - * - * @memberof mochitest/waits - * @param {Object} dbg - * @param {Function} predicate - * @return {Promise} - * @static - */ -async function waitForState(dbg, predicate) { - return new Promise(resolve => { - const unsubscribe = dbg.store.subscribe(() => { - if (predicate(dbg.store.getState())) { - unsubscribe(); - resolve(); - } - }); - }); -} - -async function waitForPaused(dbg) { - // We want to make sure that we get both a real paused event and - // that the state is fully populated. The client may do some more - // work (call other client methods) before populating the state. - await waitForThreadEvents(dbg, "paused"), await waitForState(dbg, state => { - const pause = dbg.selectors.getPause(state); - // Make sure we have the paused state. - if (!pause) { - return false; - } - // Make sure the source text is completely loaded for the - // source we are paused in. - const sourceId = get(pause, "frame.location.sourceId"); - const source = dbg.selectors.getSourc(dbg.getState(), sourceId); - return source && !source.get("loading"); - }); -} - -/** - * Wait for a specific action type to be dispatch. - * If an async action, will wait for it to be done. - * - * @memberof mochitest/waits - * @param {Object} dbg - * @param {String} type - * @param {Number} eventRepeat - * @return {Promise} - * @static - */ -async function waitForDispatch( - dbg, - type, - { useLaunchpad = false, eventRepeat = 1 } = {} -) { - const store = useLaunchpad ? dbg.launchpadStore : dbg.store; - let count = 0; - - info("Waiting for " + type + " to dispatch " + eventRepeat + " time(s)"); - while (count < eventRepeat) { - await _afterDispatchDone(store, type); - count++; - info(type + " dispatched " + count + " time(s)"); - } -} - -// Wait until an action of `type` is dispatched. If it's part of an -// async operation, wait until the `status` field is "done" or "error" -async function _afterDispatchDone(store, type) { - return new Promise(resolve => { - store.dispatch({ - // Normally we would use `services.WAIT_UNTIL`, but use the - // internal name here so tests aren't forced to always pass it - // in - type: "@@service/waitUntil", - predicate: action => { - if (action.type === type) { - return action.status - ? action.status === "done" || action.status === "error" - : true; - } - }, - run: (dispatch, getState, action) => { - resolve(action); - } - }); - }); -} - -// Wait until an action of `type` is dispatched. This is different -// than `_afterDispatchDone` because it doesn't wait for async actions -// to be done/errored. Use this if you want to listen for the "start" -// action of an async operation (somewhat rare). -async function waitForNextDispatch(store, type) { - return new Promise(resolve => { - store.dispatch({ - // Normally we would use `services.WAIT_UNTIL`, but use the - // internal name here so tests aren't forced to always pass it - // in - type: "@@service/waitUntil", - predicate: action => action.type === type, - run: (dispatch, getState, action) => { - resolve(action); - } - }); - }); -} - -async function waitForTime(time) { - return new Promise(function(resolve, reject) { - setTimeout(resolve, time); - }); -} - -async function waitForSources(dbg, ...sources) { - if (sources.length === 0) { - return Promise.resolve(); - } - - function sourceExists(state, url) { - return getSources(state).some(s => { - const sourceUrl = s.get("url"); - return sourceUrl && sourceUrl.includes(url); - }); - } - - info("Waiting on sources: " + sources.join(", ")); - const { selectors: { getSources }, store } = dbg; - return Promise.all( - sources.map(url => { - if (!sourceExists(store.getState(), url)) { - return waitForState(dbg, () => sourceExists(store.getState(), url)); - } - }) - ); -} - -async function waitForElement(dbg, selector) { - return waitUntil(() => findElementWithSelector(dbg, selector)); -} - -async function waitUntil(predicate, interval = 20) { - return new Promise(resolve => { - const timer = setInterval(() => { - if (predicate()) { - clearInterval(timer); - resolve(); - } - }, interval); - }); -} - -/** - * Waits for specific thread events. - * - * @memberof mochitest/waits - * @param {Object} dbg - * @param {String} eventName - * @return {Promise} - * @static - */ -async function waitForThreadEvents(dbg, eventName) { - info("Waiting for thread event '" + eventName + "' to fire."); - const thread = dbg.threadClient; - - return new Promise(function(resolve, reject) { - thread.addListener(eventName, function onEvent(eventName) { - info("Thread event '" + eventName + "' fired."); - thread.removeListener(eventName, onEvent); - resolve.apply(resolve); - }); - }); -} - -async function waitForTargetEvent(dbg, eventName) { - info("Waiting for target event '" + eventName + "' to fire."); - const tabTarget = dbg.tabTarget; - - return new Promise(function(resolve, reject) { - tabTarget.on(eventName, function onEvent(eventName) { - info("Thread event '" + eventName + "' fired."); - tabTarget.off(eventName, onEvent); - resolve.apply(resolve); - }); - }); -} - -module.exports = { - waitForPaused, - waitForDispatch, - waitForTime, - waitForSources, - waitForElement, - waitForTargetEvent, - waitForThreadEvents, - waitUntil -};