diff --git a/.eslintignore b/.eslintignore index 8b073acb0f..3f4a462199 100644 --- a/.eslintignore +++ b/.eslintignore @@ -94,7 +94,6 @@ devtools/client/framework/** devtools/client/inspector/computed/** devtools/client/inspector/fonts/** devtools/client/inspector/markup/test/** -devtools/client/inspector/rules/** devtools/client/inspector/shared/test/** devtools/client/inspector/test/** devtools/client/inspector/*.js diff --git a/.eslintrc b/.eslintrc index 18f05d6d4e..7a04f51360 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,11 @@ "plugins": [ "mozilla" ], + "rules": { + "mozilla/components-imports": 1, + "mozilla/import-globals": 1, + "mozilla/this-top-level-scope": 1, + }, "env": { "es6": true }, diff --git a/devtools/.eslintrc b/devtools/.eslintrc index 17b611f383..a80346533e 100644 --- a/devtools/.eslintrc +++ b/devtools/.eslintrc @@ -35,6 +35,8 @@ "mozilla/mark-test-function-used": 1, "mozilla/no-aArgs": 1, "mozilla/no-cpows-in-tests": 1, + // See bug 1224289. + "mozilla/reject-importGlobalProperties": 1, "mozilla/var-only-at-top-level": 1, // Disallow using variables outside the blocks they are defined (especially @@ -260,9 +262,8 @@ // Disallow trailing whitespace at the end of lines. "no-trailing-spaces": 2, // Disallow use of undeclared variables unless mentioned in a /*global */ - // block. - // This should really be a 2, but until we define all globals in comments - // and .eslintrc, keeping this as a 1. + // block. Note that globals from head.js are automatically imported in tests + // by the import-headjs-globals rule form the mozilla eslint plugin. "no-undef": 2, // Allow dangling underscores in identifiers (for privates). "no-underscore-dangle": 0, @@ -381,7 +382,7 @@ // disallow labels that share a name with a variable "no-label-var": 0, // disallow use of labeled statements - "no-labels": 0, + "no-labels": 2, // disallow unnecessary nested blocks "no-lone-blocks": 0, // disallow creation of functions within loops diff --git a/devtools/client/aboutdebugging/modules/worker.js b/devtools/client/aboutdebugging/modules/worker.js index 319432bb6a..a767d409b7 100644 --- a/devtools/client/aboutdebugging/modules/worker.js +++ b/devtools/client/aboutdebugging/modules/worker.js @@ -42,7 +42,7 @@ exports.debugWorker = function(client, workerActor) { * - {Array} workers * Array of WorkerActor forms */ -exports.getWorkerForms = Task.async(function*(client) { +exports.getWorkerForms = Task.async(function* (client) { let registrations = []; let workers = []; diff --git a/devtools/client/animationinspector/animation-controller.js b/devtools/client/animationinspector/animation-controller.js index 6346f82e01..3065388d51 100644 --- a/devtools/client/animationinspector/animation-controller.js +++ b/devtools/client/animationinspector/animation-controller.js @@ -35,7 +35,7 @@ var gToolbox, gInspector; * Startup the animationinspector controller and view, called by the sidebar * widget when loading/unloading the iframe into the tab. */ -var startup = Task.async(function*(inspector) { +var startup = Task.async(function* (inspector) { gInspector = inspector; gToolbox = inspector.toolbox; @@ -56,7 +56,7 @@ var startup = Task.async(function*(inspector) { * Shutdown the animationinspector controller and view, called by the sidebar * widget when loading/unloading the iframe into the tab. */ -var shutdown = Task.async(function*() { +var shutdown = Task.async(function* () { yield AnimationsController.destroy(); // Don't assume that AnimationsPanel is defined here, it's in another file. if (typeof AnimationsPanel !== "undefined") { @@ -79,7 +79,7 @@ function destroy() { * @param {Target} target The current toolbox target. * @return {Object} An object with boolean properties. */ -var getServerTraits = Task.async(function*(target) { +var getServerTraits = Task.async(function* (target) { let config = [ { name: "hasToggleAll", actor: "animations", method: "toggleAll" }, @@ -135,7 +135,7 @@ var AnimationsController = { PLAYERS_UPDATED_EVENT: "players-updated", ALL_ANIMATIONS_TOGGLED_EVENT: "all-animations-toggled", - initialize: Task.async(function*() { + initialize: Task.async(function* () { if (this.initialized) { yield this.initialized.promise; return; @@ -169,7 +169,7 @@ var AnimationsController = { this.initialized.resolve(); }), - destroy: Task.async(function*() { + destroy: Task.async(function* () { if (!this.initialized) { return; } @@ -215,13 +215,13 @@ var AnimationsController = { gInspector.sidebar.getCurrentTabID() == "animationinspector"; }, - onPanelVisibilityChange: Task.async(function*() { + onPanelVisibilityChange: Task.async(function* () { if (this.isPanelVisible()) { this.onNewNodeFront(); } }), - onNewNodeFront: Task.async(function*() { + onNewNodeFront: Task.async(function* () { // Ignore if the panel isn't visible or the node selection hasn't changed. if (!this.isPanelVisible() || this.nodeFront === gInspector.selection.nodeFront) { @@ -265,7 +265,7 @@ var AnimationsController = { * if they should be played. * @return {Promise} Resolves when the playState has been changed. */ - toggleCurrentAnimations: Task.async(function*(shouldPause) { + toggleCurrentAnimations: Task.async(function* (shouldPause) { if (this.traits.hasToggleSeveral) { yield this.animationsFront.toggleSeveral(this.animationPlayers, shouldPause); @@ -288,7 +288,7 @@ var AnimationsController = { * @param {Boolean} shouldPause Should the animations be paused too. * @return {Promise} Resolves when the current time has been set. */ - setCurrentTimeAll: Task.async(function*(time, shouldPause) { + setCurrentTimeAll: Task.async(function* (time, shouldPause) { if (this.traits.hasSetCurrentTimes) { yield this.animationsFront.setCurrentTimes(this.animationPlayers, time, shouldPause); @@ -309,7 +309,7 @@ var AnimationsController = { * @param {Number} rate. * @return {Promise} Resolves when the rate has been set. */ - setPlaybackRateAll: Task.async(function*(rate) { + setPlaybackRateAll: Task.async(function* (rate) { if (this.traits.hasSetPlaybackRates) { // If the backend can set all playback rates at the same time, use that. yield this.animationsFront.setPlaybackRates(this.animationPlayers, rate); @@ -327,7 +327,7 @@ var AnimationsController = { // called again. animationPlayers: [], - refreshAnimationPlayers: Task.async(function*(nodeFront) { + refreshAnimationPlayers: Task.async(function* (nodeFront) { this.destroyAnimationPlayers(); this.animationPlayers = yield this.animationsFront diff --git a/devtools/client/animationinspector/animation-panel.js b/devtools/client/animationinspector/animation-panel.js index 01a3c67f10..cb67864481 100644 --- a/devtools/client/animationinspector/animation-panel.js +++ b/devtools/client/animationinspector/animation-panel.js @@ -22,7 +22,7 @@ var AnimationsPanel = { UI_UPDATED_EVENT: "ui-updated", PANEL_INITIALIZED: "panel-initialized", - initialize: Task.async(function*() { + initialize: Task.async(function* () { if (AnimationsController.destroyed) { console.warn("Could not initialize the animation-panel, controller " + "was destroyed"); @@ -79,7 +79,7 @@ var AnimationsPanel = { this.emit(this.PANEL_INITIALIZED); }), - destroy: Task.async(function*() { + destroy: Task.async(function* () { if (!this.initialized) { return; } @@ -205,7 +205,7 @@ var AnimationsPanel = { * Toggle (pause/play) all animations in the current target * and update the UI the toggleAll button. */ - toggleAll: Task.async(function*() { + toggleAll: Task.async(function* () { this.toggleAllButtonEl.classList.toggle("paused"); yield AnimationsController.toggleAll(); }), @@ -280,7 +280,9 @@ var AnimationsPanel = { this.setCurrentTimeAllPromise = AnimationsController.setCurrentTimeAll(time, true) .catch(error => console.error(error)) - .then(() => this.setCurrentTimeAllPromise = null); + .then(() => { + this.setCurrentTimeAllPromise = null; + }); } this.displayTimelineCurrentTime(); @@ -296,7 +298,7 @@ var AnimationsPanel = { * useful after the playState or currentTime has been changed and in case the * animations aren't auto-refreshing), and then refresh the UI. */ - refreshAnimationsStateAndUI: Task.async(function*() { + refreshAnimationsStateAndUI: Task.async(function* () { for (let player of AnimationsController.animationPlayers) { yield player.refreshState(); } @@ -307,7 +309,7 @@ var AnimationsPanel = { * Refresh the list of animations UI. This will empty the panel and re-render * the various components again. */ - refreshAnimationsUI: Task.async(function*() { + refreshAnimationsUI: Task.async(function* () { // Empty the whole panel first. this.togglePlayers(true); diff --git a/devtools/client/animationinspector/components/animation-details.js b/devtools/client/animationinspector/components/animation-details.js index 0d3d797ec4..0558391433 100644 --- a/devtools/client/animationinspector/components/animation-details.js +++ b/devtools/client/animationinspector/components/animation-details.js @@ -62,7 +62,7 @@ AnimationDetails.prototype = { * @return {Object} A list of tracks, one per animated property, each * with a list of keyframes */ - getTracks: Task.async(function*() { + getTracks: Task.async(function* () { let tracks = {}; /* @@ -112,7 +112,7 @@ AnimationDetails.prototype = { return tracks; }), - render: Task.async(function*(animation) { + render: Task.async(function* (animation) { this.unrender(); if (!animation) { diff --git a/devtools/client/animationinspector/components/animation-target-node.js b/devtools/client/animationinspector/components/animation-target-node.js index ed97d0d17e..55e5a60343 100644 --- a/devtools/client/animationinspector/components/animation-target-node.js +++ b/devtools/client/animationinspector/components/animation-target-node.js @@ -41,7 +41,7 @@ AnimationTargetNode.prototype = { this.isDestroyed = true; }, - render: Task.async(function*(playerFront) { + render: Task.async(function* (playerFront) { // Get the nodeFront from the cache if it was stored previously. let nodeFront = nodeFronts.get(playerFront); diff --git a/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js b/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js index d77837e02a..4d0a64c2de 100644 --- a/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js +++ b/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js @@ -21,7 +21,7 @@ const EXPECTED_PROPERTIES = [ "width" ].sort(); -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_keyframes.html"); let {panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js b/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js index b35b95dffc..be0826ad7a 100644 --- a/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js +++ b/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js @@ -7,7 +7,7 @@ // Check that animations displayed in the timeline can be selected by clicking // them, and that this emits the right events and adds the right classes. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js b/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js index ed992dccb8..f6f3ae8405 100644 --- a/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js +++ b/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js @@ -7,7 +7,7 @@ // Test that the controller provides the document.timeline currentTime (at least // the last known version since new animations were added). -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, controller} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js b/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js index a34188dd3d..e68af7f5a3 100644 --- a/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js +++ b/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js @@ -12,7 +12,7 @@ const { LocalizationHelper } = require("devtools/client/shared/l10n"); const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties"; const L10N = new LocalizationHelper(STRINGS_URI); -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel, window} = yield openAnimationInspector(); let {document} = window; diff --git a/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js b/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js index 73541fd704..9088d97af9 100644 --- a/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js +++ b/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js @@ -7,7 +7,7 @@ // Test that animated properties' keyframes can be clicked, and that doing so // sets the current time in the timeline. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_keyframes.html"); let {panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js b/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js index 2a51a4d91a..e8a7ed2860 100644 --- a/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js +++ b/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js @@ -21,7 +21,7 @@ const EXPECTED_PROPERTIES = [ "width" ]; -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_keyframes.html"); let {panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js b/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js index 920efc4ec7..c3d1dfe97f 100644 --- a/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js +++ b/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js @@ -9,7 +9,7 @@ // displayed (which should be true as long as these animations apply to // different nodes). -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_negative_animation.html"); let {controller, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_panel_exists.js b/devtools/client/animationinspector/test/browser_animation_panel_exists.js index e758e19993..1f12605a55 100644 --- a/devtools/client/animationinspector/test/browser_animation_panel_exists.js +++ b/devtools/client/animationinspector/test/browser_animation_panel_exists.js @@ -6,7 +6,7 @@ // Test that the animation panel sidebar exists -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8,welcome to the animation panel"); let {panel, controller} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js b/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js index f89ad17c35..94222cc037 100644 --- a/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js +++ b/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js @@ -8,7 +8,7 @@ // inspector-updated event. This means that the test verifies that the // inspector-updated event is emitted *after* the animation panel is ready. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel, controller} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js b/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js index f8c6079e1b..871cb5d81a 100644 --- a/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js +++ b/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js @@ -7,7 +7,7 @@ // Check that the AnimationPlayerFront objects lifecycle is managed by the // AnimationController. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {controller, inspector} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js b/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js index 3375706c4c..ceefd31947 100644 --- a/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js +++ b/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js @@ -9,7 +9,7 @@ const { ANIMATION_TYPES } = require("devtools/server/actors/animation"); -add_task(function*() { +add_task(function* () { yield new Promise(resolve => { SpecialPowers.pushPrefEnv({"set": [ ["dom.animations-api.core.enabled", true] diff --git a/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js b/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js index 80a4dae6a1..2ff517705d 100644 --- a/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js +++ b/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js @@ -6,7 +6,7 @@ // Test that player widgets display information about target nodes -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js b/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js index de02ee3d1f..c6cc3218c5 100644 --- a/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js +++ b/devtools/client/animationinspector/test/browser_animation_pseudo_elements.js @@ -6,7 +6,7 @@ // Test that animated pseudo-elements do show in the timeline. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_pseudo_elements.html"); let {inspector, panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js b/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js index 24d773b93e..f5f20d4e75 100644 --- a/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js +++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js @@ -6,7 +6,7 @@ // Test that the panel content refreshes when new animations are added. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js b/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js index c55cf06da8..a888cdd1f0 100644 --- a/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js +++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js @@ -6,7 +6,7 @@ // Test that the panel content refreshes when animations are removed. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js b/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js index ac7fd6f694..a544ac0e44 100644 --- a/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js +++ b/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js @@ -6,7 +6,7 @@ // Test that the panel only refreshes when it is visible in the sidebar. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js b/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js index 91cfd03469..aeaf22a5ea 100644 --- a/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js +++ b/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js @@ -12,7 +12,7 @@ const { LocalizationHelper } = require("devtools/client/shared/l10n"); const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties"; const L10N = new LocalizationHelper(STRINGS_URI); -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js b/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js index 21846066e6..5554d4cbbe 100644 --- a/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js +++ b/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js @@ -7,7 +7,7 @@ // Check that when playerFronts are updated, the same number of playerWidgets // are created in the panel. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel, controller} = yield openAnimationInspector(); let timeline = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js b/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js index d6c860a991..795f93efc9 100644 --- a/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js +++ b/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js @@ -7,7 +7,7 @@ // Test that the panel shows an animation player when an animated node is // selected. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js index 12b08fc628..593dbe685c 100644 --- a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js +++ b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js @@ -10,7 +10,7 @@ // because there's an other test that does this : // browser_animation_toggle_button_toggles_animation.js -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, inspector, window, controller} = yield openAnimationInspector(); let {toggleAllButtonEl} = panel; diff --git a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js index 1e818c158d..d407070e01 100644 --- a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js +++ b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js @@ -10,7 +10,7 @@ // There are animations in the test page and since, by default, the node // is selected, animations will be displayed in the timeline, so the timeline // play/resume button will be displayed -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, window} = yield openAnimationInspector(); let {playTimelineButtonEl} = panel; diff --git a/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js b/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js index a8d3045ed9..ec08b73888 100644 --- a/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js +++ b/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js @@ -7,7 +7,7 @@ // Test that the DOM element targets displayed in animation player widgets can // be used to highlight elements in the DOM and select them in the inspector. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {toolbox, inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js b/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js index 24c2ce9990..44cad002f9 100644 --- a/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js +++ b/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js @@ -7,7 +7,7 @@ // Test that the DOM element targets displayed in animation player widgets can // be used to highlight elements in the DOM and select them in the inspector. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js b/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js index f972973013..a4d25ac37a 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js @@ -8,7 +8,7 @@ // changes when animations are playing, gets back to 0 when animations are // rewound, and stops when animations are paused. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_header.js b/devtools/client/animationinspector/test/browser_animation_timeline_header.js index 9e4720ae1c..f2e0a9c338 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_header.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_header.js @@ -12,7 +12,7 @@ const {findOptimalTimeInterval, TimeScale} = require("devtools/client/animationi // animation-timeline.js const TIME_GRADUATION_MIN_SPACING = 40; -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js b/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js index ffdde0c0e1..5116adff33 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_iterationStart.js @@ -6,7 +6,7 @@ // Check that the iteration start is displayed correctly in time blocks. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_script_animation.html"); let {panel} = yield openAnimationInspector(); let timelineComponent = panel.animationsTimelineComponent; diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js index 13da0edb9c..2114e614cd 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js @@ -16,7 +16,7 @@ requestLongerTimeout(2); // And test that clicking the button once the scrubber has reached the end of // the timeline does the right thing. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, inspector} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js b/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js index 5eeb68781d..aa04a6bc77 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js @@ -10,7 +10,7 @@ // all have the same rate, or that it displays the empty value in case they // have mixed rates. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, controller, inspector, toolbox} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js b/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js index 54869e5458..41139553d2 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js @@ -10,7 +10,7 @@ // reset to 0, and that the scrubber stops moving and is positioned to the // start. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, controller} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js index 633001fa95..36f633dcdd 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js @@ -6,7 +6,7 @@ // Check that the timeline does have a scrubber element. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js index 01037b5663..ab7067ff51 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js @@ -10,7 +10,7 @@ // state. // Finally, also check that the scrubber can be moved using the scrubber handle. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js index 85c718866f..3293c7c246 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js @@ -9,7 +9,7 @@ // measures the position of the scrubber once, then waits for some time to pass // and measures its position again. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js b/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js index 6680672c51..fe70e34b00 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js @@ -9,7 +9,7 @@ // Also check that negative delays do not overflow the UI, and are shown like // positive delays. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js b/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js index fe10a9e8a0..2c9f60746e 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_endDelay.js @@ -11,7 +11,7 @@ requestLongerTimeout(2); // Also check that negative endDelays do not overflow the UI, and are shown // like positive endDelays. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_end_delay.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js b/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js index 470c83c780..b042106be4 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js @@ -7,7 +7,7 @@ // Check that the timeline is displays as many iteration elements as there are // iterations in an animation. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js b/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js index ecb1caaff6..6927ab5f3f 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js @@ -9,7 +9,7 @@ requestLongerTimeout(2); // Check that the timeline displays animations' duration, delay iteration // counts and iteration start in tooltips. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, controller} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js b/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js index aa84984ff1..99efea9324 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js @@ -11,7 +11,7 @@ // of which may have a different rate than others. Those that have had their // rate changed have a delay = delay/rate and a duration = duration/rate. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_modify_playbackRate.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_timeline_ui.js b/devtools/client/animationinspector/test/browser_animation_timeline_ui.js index 249d781cd2..f2d7bb7757 100644 --- a/devtools/client/animationinspector/test/browser_animation_timeline_ui.js +++ b/devtools/client/animationinspector/test/browser_animation_timeline_ui.js @@ -6,7 +6,7 @@ // Check that the timeline contains the right elements. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js b/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js index fad64105b5..d9a92b905d 100644 --- a/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js +++ b/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js @@ -8,7 +8,7 @@ requestLongerTimeout(2); // Test that a page navigation resets the state of the global toggle button. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js b/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js index a4647ebf4b..31896857ed 100644 --- a/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js +++ b/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js @@ -9,7 +9,7 @@ // animations have been paused (including inside iframes) because there's an // actor test in /devtools/server/tests/browser/ that does this. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js b/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js index 4a054004fc..5938a30a39 100644 --- a/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js +++ b/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js @@ -9,7 +9,7 @@ // Also test that this toolbar gets replaced by the timeline toolbar when there // are animations to be displayed. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {inspector, window} = yield openAnimationInspector(); let doc = window.document; diff --git a/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js b/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js index e13618c391..39e327f691 100644 --- a/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js +++ b/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js @@ -7,7 +7,7 @@ // Verify that if the animation's duration, iterations or delay change in // content, then the widget reflects the changes. -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_simple_animation.html"); let {panel, controller, inspector} = yield openAnimationInspector(); diff --git a/devtools/client/animationinspector/test/head.js b/devtools/client/animationinspector/test/head.js index 8bbfe49645..c3d0043f5a 100644 --- a/devtools/client/animationinspector/test/head.js +++ b/devtools/client/animationinspector/test/head.js @@ -17,7 +17,7 @@ const COMMON_FRAME_SCRIPT_URL = "chrome://devtools/content/shared/frame-script-u const TAB_NAME = "animationinspector"; // Auto clean-up when a test ends -registerCleanupFunction(function*() { +registerCleanupFunction(function* () { yield closeAnimationInspector(); while (gBrowser.tabs.length > 1) { @@ -75,7 +75,7 @@ function* reloadTab(inspector) { and animations of its subtree are properly displayed. */ var selectNodeAndWaitForAnimations = Task.async( - function*(data, inspector, reason = "test") { + function* (data, inspector, reason = "test") { yield selectNode(data, inspector, reason); // We want to make sure the rest of the test waits for the animations to @@ -107,7 +107,7 @@ function assertAnimationsDisplayed(panel, nbAnimations, msg = "") { * @param {InspectorPanel} inspector * @return {Promise} */ -var waitForAnimationInspectorReady = Task.async(function*(inspector) { +var waitForAnimationInspectorReady = Task.async(function* (inspector) { let win = inspector.sidebar.getWindowForTab(TAB_NAME); let updated = inspector.once("inspector-updated"); @@ -127,7 +127,7 @@ var waitForAnimationInspectorReady = Task.async(function*(inspector) { * sidebar selected. * @return a promise that resolves when the inspector is ready. */ -var openAnimationInspector = Task.async(function*() { +var openAnimationInspector = Task.async(function* () { let {inspector, toolbox} = yield openInspectorSidebarTab(TAB_NAME); info("Waiting for the inspector and sidebar to be ready"); @@ -161,7 +161,7 @@ var openAnimationInspector = Task.async(function*() { * Close the toolbox. * @return a promise that resolves when the toolbox has closed. */ -var closeAnimationInspector = Task.async(function*() { +var closeAnimationInspector = Task.async(function* () { let target = TargetFactory.forTab(gBrowser.selectedTab); yield gDevTools.closeToolbox(target); }); @@ -214,8 +214,8 @@ function executeInContent(name, data = {}, objects = {}, /** * Get the current playState of an animation player on a given node. */ -var getAnimationPlayerState = Task.async(function*(selector, - animationIndex = 0) { +var getAnimationPlayerState = Task.async(function* (selector, + animationIndex = 0) { let playState = yield executeInContent("Test:GetAnimationPlayerState", {selector, animationIndex}); return playState; @@ -236,7 +236,7 @@ function isNodeVisible(node) { * @param {AnimationsPanel} panel * @return {Array} all AnimationTargetNode instances */ -var waitForAllAnimationTargets = Task.async(function*(panel) { +var waitForAllAnimationTargets = Task.async(function* (panel) { let targets = panel.animationsTimelineComponent.targetNodes; yield promise.all(targets.map(t => { if (!t.previewer.nodeFront) { @@ -265,7 +265,9 @@ function* assertScrubberMoving(panel, isMoving) { // If instead we expect the scrubber to remain at its position, just wait // for some time and make sure timeline-data-changed isn't emitted. let hasMoved = false; - timeline.once("timeline-data-changed", () => hasMoved = true); + timeline.once("timeline-data-changed", () => { + hasMoved = true; + }); yield new Promise(r => setTimeout(r, 500)); ok(!hasMoved, "The scrubber is not moving"); } diff --git a/devtools/client/definitions.js b/devtools/client/definitions.js index 2ce75a957c..60120f85fe 100644 --- a/devtools/client/definitions.js +++ b/devtools/client/definitions.js @@ -141,6 +141,7 @@ Tools.webConsole = { } panel.focusInput(); + return undefined; }, isTargetSupported: function() { diff --git a/devtools/client/inspector/computed/test/browser_computed_cycle_color.js b/devtools/client/inspector/computed/test/browser_computed_cycle_color.js index 485dccd369..0a25e7ed05 100644 --- a/devtools/client/inspector/computed/test/browser_computed_cycle_color.js +++ b/devtools/client/inspector/computed/test/browser_computed_cycle_color.js @@ -9,7 +9,7 @@ const TEST_URI = ` Some styled text @@ -26,11 +26,10 @@ add_task(function*() { info("Checking matched selectors"); container = yield getComputedViewMatchedRules(view, "color"); - checkColorCycling(container, view); + yield checkColorCycling(container, view); }); -function checkColorCycling(container, view) { - let swatch = container.querySelector(".computedview-colorswatch"); +function* checkColorCycling(container, view) { let valueNode = container.querySelector(".computedview-color"); let win = view.styleWindow; @@ -38,32 +37,34 @@ function checkColorCycling(container, view) { is(valueNode.textContent, "rgb(255, 0, 0)", "Color displayed as an RGB value."); - // Hex - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "#F00", "Color displayed as a hex value."); + let tests = [{ + value: "red", + comment: "Color displayed as a color name." + }, { + value: "#f00", + comment: "Color displayed as an authored value." + }, { + value: "hsl(0, 100%, 50%)", + comment: "Color displayed as an HSL value again." + }, { + value: "rgb(255, 0, 0)", + comment: "Color displayed as an RGB value again." + }]; - // HSL - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "hsl(0, 100%, 50%)", - "Color displayed as an HSL value."); - - // RGB - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Color name - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "red", - "Color displayed as a color name."); - - // Back to "Authored" - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); + for (let test of tests) { + yield checkSwatchShiftClick(container, win, test.value, test.comment); + } +} + +function* checkSwatchShiftClick(container, win, expectedValue, comment) { + let swatch = container.querySelector(".computedview-colorswatch"); + let valueNode = container.querySelector(".computedview-color"); + + let onUnitChange = swatch.once("unit-change"); + EventUtils.synthesizeMouseAtCenter(swatch, { + type: "mousedown", + shiftKey: true + }, win); + yield onUnitChange; + is(valueNode.textContent, expectedValue, comment); } diff --git a/devtools/client/inspector/inspector.css b/devtools/client/inspector/inspector.css index 2d99492fca..8735790cad 100644 --- a/devtools/client/inspector/inspector.css +++ b/devtools/client/inspector/inspector.css @@ -27,7 +27,7 @@ max-width: 150px; } -.inspector-tabpanel { +.inspector-tabpanel > * { /* * Override `-moz-user-focus:ignore;` from toolkit/content/minimal-xul.css */ diff --git a/devtools/client/inspector/layout/layout.js b/devtools/client/inspector/layout/layout.js index 228a4c8cde..494fa3943b 100644 --- a/devtools/client/inspector/layout/layout.js +++ b/devtools/client/inspector/layout/layout.js @@ -318,7 +318,10 @@ LayoutView.prototype = { let editor = new InplaceEditor({ element: element, initial: initialValue, - + contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE, + property: { + name: dimension.property + }, start: self => { self.elt.parentNode.classList.add("layout-editing"); }, @@ -601,6 +604,7 @@ LayoutView.prototype = { this.elementRules = styleEntries.map(e => e.rule); this.inspector.emit("layoutview-updated"); + return undefined; }).bind(this)).catch(console.error); this._lastRequest = lastRequest; diff --git a/devtools/client/inspector/layout/test/browser_layout.js b/devtools/client/inspector/layout/test/browser_layout.js index e7e797eb23..2daebd0127 100644 --- a/devtools/client/inspector/layout/test/browser_layout.js +++ b/devtools/client/inspector/layout/test/browser_layout.js @@ -126,7 +126,7 @@ var res2 = [ }, ]; -add_task(function*() { +add_task(function* () { let style = "div { position: absolute; top: 42px; left: 42px; " + "height: 100.111px; width: 100px; border: 10px solid black; " + "padding: 20px; margin: 30px auto;}"; diff --git a/devtools/client/inspector/layout/test/browser_layout_editablemodel.js b/devtools/client/inspector/layout/test/browser_layout_editablemodel.js index dae2ba3057..c143b7188f 100644 --- a/devtools/client/inspector/layout/test/browser_layout_editablemodel.js +++ b/devtools/client/inspector/layout/test/browser_layout_editablemodel.js @@ -19,7 +19,7 @@ const TEST_URI = "" + "
"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html," + encodeURIComponent(TEST_URI)); let {inspector, view, testActor} = yield openLayoutView(); diff --git a/devtools/client/inspector/layout/test/browser_layout_editablemodel_border.js b/devtools/client/inspector/layout/test/browser_layout_editablemodel_border.js index e775bf5183..4a03865020 100644 --- a/devtools/client/inspector/layout/test/browser_layout_editablemodel_border.js +++ b/devtools/client/inspector/layout/test/browser_layout_editablemodel_border.js @@ -14,7 +14,7 @@ const TEST_URI = "" + "
"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html," + encodeURIComponent(TEST_URI)); let {inspector, view, testActor} = yield openLayoutView(); diff --git a/devtools/client/inspector/layout/test/browser_layout_editablemodel_stylerules.js b/devtools/client/inspector/layout/test/browser_layout_editablemodel_stylerules.js index a65a2a351f..e27d91e91b 100644 --- a/devtools/client/inspector/layout/test/browser_layout_editablemodel_stylerules.js +++ b/devtools/client/inspector/layout/test/browser_layout_editablemodel_stylerules.js @@ -15,7 +15,7 @@ const TEST_URI = "" + "
"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html," + encodeURIComponent(TEST_URI)); let {inspector, view, testActor} = yield openLayoutView(); diff --git a/devtools/client/inspector/layout/test/browser_layout_guides.js b/devtools/client/inspector/layout/test/browser_layout_guides.js index 94354e99aa..abad54df92 100644 --- a/devtools/client/inspector/layout/test/browser_layout_guides.js +++ b/devtools/client/inspector/layout/test/browser_layout_guides.js @@ -17,7 +17,7 @@ const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML); var highlightedNodeFront, highlighterOptions; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URL); let {toolbox, inspector, view} = yield openLayoutView(); yield selectNode("div", inspector); diff --git a/devtools/client/inspector/layout/test/browser_layout_rotate-labels-on-sides.js b/devtools/client/inspector/layout/test/browser_layout_rotate-labels-on-sides.js index ff47fd095d..5ec5bbff47 100644 --- a/devtools/client/inspector/layout/test/browser_layout_rotate-labels-on-sides.js +++ b/devtools/client/inspector/layout/test/browser_layout_rotate-labels-on-sides.js @@ -30,7 +30,7 @@ const TEST_URI = encodeURIComponent([ ].join("")); const LONG_TEXT_ROTATE_LIMIT = 3; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html," + TEST_URI); let {inspector, view} = yield openLayoutView(); yield selectNode("div", inspector); diff --git a/devtools/client/inspector/layout/test/browser_layout_tooltips.js b/devtools/client/inspector/layout/test/browser_layout_tooltips.js index 3f8020af7d..69aef28e59 100644 --- a/devtools/client/inspector/layout/test/browser_layout_tooltips.js +++ b/devtools/client/inspector/layout/test/browser_layout_tooltips.js @@ -70,7 +70,7 @@ const VALUES_TEST_DATA = [{ }] }]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openLayoutView(); diff --git a/devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js b/devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js index da99e8aece..3d082cddab 100644 --- a/devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js +++ b/devtools/client/inspector/layout/test/browser_layout_update-after-navigation.js @@ -10,7 +10,7 @@ const IFRAME1 = URL_ROOT + "doc_layout_iframe1.html"; const IFRAME2 = URL_ROOT + "doc_layout_iframe2.html"; -add_task(function*() { +add_task(function* () { yield addTab(IFRAME1); let {inspector, view, testActor} = yield openLayoutView(); diff --git a/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js b/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js index 8dda26c85f..1352445dbc 100644 --- a/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js +++ b/devtools/client/inspector/layout/test/browser_layout_update-after-reload.js @@ -6,7 +6,7 @@ // Test that the layout-view continues to work after the page is reloaded -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_layout_iframe1.html"); let {inspector, view, testActor} = yield openLayoutView(); @@ -14,7 +14,7 @@ add_task(function*() { yield assertLayoutView(inspector, view, testActor); info("Reload the page"); - yield testActor.eval("content.location.reload();"); + yield testActor.reload(); yield inspector.once("markuploaded"); info("Test that the layout-view works on the reloaded page"); diff --git a/devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js b/devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js index 38730156a9..1847a38c2a 100644 --- a/devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js +++ b/devtools/client/inspector/layout/test/browser_layout_update-in-iframes.js @@ -7,7 +7,7 @@ // Test that the layout-view for elements within iframes also updates when they // change -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_layout_iframe1.html"); let {inspector, view, testActor} = yield openLayoutView(); diff --git a/devtools/client/inspector/markup/markup.js b/devtools/client/inspector/markup/markup.js index 4988bb59c1..4cf8abeb76 100644 --- a/devtools/client/inspector/markup/markup.js +++ b/devtools/client/inspector/markup/markup.js @@ -468,6 +468,8 @@ MarkupView.prototype = { // and decision to show or not the tooltip return container.isImagePreviewTarget(target, this.tooltip); } + + return undefined; }, /** @@ -534,6 +536,7 @@ MarkupView.prototype = { // Make sure the new selection receives focus so the keyboard can be used. this.maybeFocusNewSelection(); + return undefined; }).catch(e => { if (!this._destroyer) { console.error(e); @@ -609,17 +612,19 @@ MarkupView.prototype = { return; } + // Ignore keystrokes with modifiers to allow native shortcuts (such as save: + // accel + S) to bubble up. + if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) { + return; + } + switch (event.keyCode) { case Ci.nsIDOMKeyEvent.DOM_VK_H: - if (event.metaKey || event.shiftKey) { - handled = false; + let node = this._selectedContainer.node; + if (node.hidden) { + this.walker.unhideNode(node); } else { - let node = this._selectedContainer.node; - if (node.hidden) { - this.walker.unhideNode(node); - } else { - this.walker.hideNode(node); - } + this.walker.hideNode(node); } break; case Ci.nsIDOMKeyEvent.DOM_VK_DELETE: @@ -705,6 +710,7 @@ MarkupView.prototype = { this.cancelDragging(); break; } + // falls through } default: handled = false; @@ -2007,7 +2013,7 @@ MarkupContainer.prototype = { /** * On mouse up, stop dragging. */ - _onMouseUp: Task.async(function*() { + _onMouseUp: Task.async(function* () { this._isPreDragging = false; if (this.isDragging) { @@ -2296,6 +2302,7 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, { }); return true; } + return undefined; }, /** @@ -2325,7 +2332,7 @@ MarkupElementContainer.prototype = Heritage.extend(MarkupContainer.prototype, { Services.prefs.getIntPref("devtools.inspector.imagePreviewTooltipSize"); // Fetch the preview from the server. - this.tooltipDataPromise = Task.spawn(function*() { + this.tooltipDataPromise = Task.spawn(function* () { let preview = yield this.node.getImageData(maxDim); let data = yield preview.data.string(); @@ -2516,6 +2523,11 @@ function TextEditor(container, node, template) { stopOnReturn: true, trigger: "dblclick", multiline: true, + maxWidth: () => { + let elementRect = this.value.getBoundingClientRect(); + let containerRect = this.container.elt.getBoundingClientRect(); + return containerRect.right - elementRect.left - 2; + }, trimOutput: false, done: (val, commit) => { if (!commit) { diff --git a/devtools/client/inspector/markup/test/browser.ini b/devtools/client/inspector/markup/test/browser.ini index 9e77177803..1e7b1bd73d 100644 --- a/devtools/client/inspector/markup/test/browser.ini +++ b/devtools/client/inspector/markup/test/browser.ini @@ -14,6 +14,7 @@ support-files = doc_markup_flashing.html doc_markup_html_mixed_case.html doc_markup_image_and_canvas.html + doc_markup_image_and_canvas_2.html doc_markup_links.html doc_markup_mutation.html doc_markup_navigation.html @@ -104,6 +105,7 @@ skip-if = e10s # Bug 1040751 - CodeMirror editor.destroy() isn't e10s compatible [browser_markup_keybindings_03.js] [browser_markup_keybindings_04.js] [browser_markup_keybindings_delete_attributes.js] +[browser_markup_keybindings_scrolltonode.js] [browser_markup_mutation_01.js] [browser_markup_mutation_02.js] [browser_markup_node_names.js] @@ -129,6 +131,7 @@ skip-if = e10s # Bug 1036409 - The last selected node isn't reselected [browser_markup_tag_edit_12.js] [browser_markup_tag_edit_13-other.js] [browser_markup_textcontent_edit_01.js] +[browser_markup_textcontent_edit_02.js] [browser_markup_toggle_01.js] [browser_markup_toggle_02.js] [browser_markup_toggle_03.js] diff --git a/devtools/client/inspector/markup/test/browser_markup_anonymous_01.js b/devtools/client/inspector/markup/test/browser_markup_anonymous_01.js index dd5a2093ba..fd32251d0e 100644 --- a/devtools/client/inspector/markup/test/browser_markup_anonymous_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_anonymous_01.js @@ -7,7 +7,7 @@ // Test native anonymous content in the markupview. const TEST_URL = URL_ROOT + "doc_markup_anonymous.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let pseudo = yield getNodeFront("#pseudo", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_anonymous_02.js b/devtools/client/inspector/markup/test/browser_markup_anonymous_02.js index 9ff4c7e752..2b5445e9ed 100644 --- a/devtools/client/inspector/markup/test/browser_markup_anonymous_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_anonymous_02.js @@ -7,7 +7,7 @@ // Test XBL anonymous content in the markupview const TEST_URL = "chrome://devtools/content/scratchpad/scratchpad.xul"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let toolbarbutton = yield getNodeFront("toolbarbutton", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js b/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js index 30ae57c3c3..010ce06e07 100644 --- a/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_anonymous_03.js @@ -9,7 +9,7 @@ // of elements should be working. const TEST_URL = URL_ROOT + "doc_markup_anonymous.html"; -add_task(function*() { +add_task(function* () { Services.prefs.setBoolPref("dom.webcomponents.enabled", true); let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_anonymous_04.js b/devtools/client/inspector/markup/test/browser_markup_anonymous_04.js index e91ba216fa..da5e4567d2 100644 --- a/devtools/client/inspector/markup/test/browser_markup_anonymous_04.js +++ b/devtools/client/inspector/markup/test/browser_markup_anonymous_04.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_anonymous.html"; const PREF = "devtools.inspector.showAllAnonymousContent"; -add_task(function*() { +add_task(function* () { Services.prefs.setBoolPref(PREF, true); let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js b/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js index eaca463117..4c98cff26d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js +++ b/devtools/client/inspector/markup/test/browser_markup_copy_image_data.js @@ -7,7 +7,7 @@ // Test that image nodes have the "copy data-uri" contextual menu item enabled // and that clicking it puts the image data into the clipboard -add_task(function*() { +add_task(function* () { yield addTab(URL_ROOT + "doc_markup_image_and_canvas.html"); let {inspector, testActor} = yield openInspector(); diff --git a/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_01.js b/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_01.js index 62e29fe606..4dc049ee92 100644 --- a/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_01.js @@ -69,7 +69,7 @@ const TEST_DATA = [ -1, -1, false] ]; -add_task(function*() { +add_task(function* () { info("Opening the inspector on the test URL"); let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_02.js b/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_02.js index 42c460c289..51a1d4796b 100644 --- a/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_css_completion_style_attribute_02.js @@ -96,7 +96,7 @@ const TEST_DATA_INNER = [ ["VK_RETURN", "style=\"background:url('1'); color:beige\"", -1, -1, false] ]; -add_task(function*() { +add_task(function* () { info("Opening the inspector on the test URL"); let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_autoscroll.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_autoscroll.js index 492cd842bf..a5f3c57de1 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_autoscroll.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_autoscroll.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_dragdrop_autoscroll.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let markup = inspector.markup; let viewHeight = markup.doc.documentElement.clientHeight; diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js index 9b230092ec..3c52936387 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_distance.js @@ -14,7 +14,7 @@ const TEST_NODE = "#test"; // Keep this in sync with DRAG_DROP_MIN_INITIAL_DISTANCE in markup-view.js const MIN_DISTANCE = 10; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Drag the test node by half of the minimum distance"); diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_dragRootNode.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_dragRootNode.js index 17e4992083..8bb4779d5d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_dragRootNode.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_dragRootNode.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html"; const TEST_DATA = ["html", "head", "body"]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); for (let selector of TEST_DATA) { diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js index b43efd4221..f878964ad8 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_draggable.js @@ -22,7 +22,7 @@ const TEST_DATA = [ { node: "input", draggable: true }, { node: "div", draggable: true }, { - node: function*(inspector) { + node: function* (inspector) { let parentFront = yield getNodeFront("#before", inspector); let {nodes} = yield inspector.walker.children(parentFront); // Getting the comment node. @@ -31,7 +31,7 @@ const TEST_DATA = [ draggable: true }, { - node: function*(inspector) { + node: function* (inspector) { let parentFront = yield getNodeFront("#test", inspector); let {nodes} = yield inspector.walker.children(parentFront); // Getting the ::before pseudo element. @@ -41,7 +41,7 @@ const TEST_DATA = [ } ]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); yield inspector.markup.expandAll(); diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_escapeKeyPress.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_escapeKeyPress.js index fad442ae73..075d143521 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_escapeKeyPress.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_escapeKeyPress.js @@ -8,7 +8,7 @@ const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let {markup} = inspector; diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_invalidNodes.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_invalidNodes.js index f5fc9f5167..9eea6a1027 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_invalidNodes.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_invalidNodes.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html"; const PREF = "devtools.inspector.showAllAnonymousContent"; -add_task(function*() { +add_task(function* () { Services.prefs.setBoolPref(PREF, true); let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_reorder.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_reorder.js index 32387fc2b5..0da0084649 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_reorder.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_reorder.js @@ -8,7 +8,7 @@ const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let ids; diff --git a/devtools/client/inspector/markup/test/browser_markup_dragdrop_tooltip.js b/devtools/client/inspector/markup/test/browser_markup_dragdrop_tooltip.js index 94a4a204d8..13cc2e0cd3 100644 --- a/devtools/client/inspector/markup/test/browser_markup_dragdrop_tooltip.js +++ b/devtools/client/inspector/markup/test/browser_markup_dragdrop_tooltip.js @@ -7,7 +7,7 @@ const TEST_URL = "data:text/html;charset=utf8,
"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let {markup} = inspector; diff --git a/devtools/client/inspector/markup/test/browser_markup_events-overflow.js b/devtools/client/inspector/markup/test/browser_markup_events-overflow.js index 6ef442391a..f52877bf15 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events-overflow.js +++ b/devtools/client/inspector/markup/test/browser_markup_events-overflow.js @@ -30,7 +30,7 @@ const TEST_DATA = [ }, ]; -add_task(function*() { +add_task(function* () { let { inspector } = yield openInspectorForURL(TEST_URL); let markupContainer = yield getContainerForSelector("#events", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_events.js b/devtools/client/inspector/markup/test/browser_markup_events.js index 03d484e96a..09420c94e1 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events.js +++ b/devtools/client/inspector/markup/test/browser_markup_events.js @@ -192,6 +192,6 @@ const TEST_DATA = [ // eslint-disable-line }, ]; -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_form.js b/devtools/client/inspector/markup/test/browser_markup_events_form.js index 0bba8ef622..d5fefb2f84 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_form.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_form.js @@ -14,7 +14,7 @@ const TEST_ACTOR_URL = CHROME_URL_ROOT + "actor_events_form.js"; var {EventsFormFront} = require(TEST_ACTOR_URL); -add_task(function*() { +add_task(function* () { info("Opening the Toolbox"); let tab = yield addTab(TEST_PAGE_URL); let toolbox = yield openToolboxForTab(tab, "webconsole"); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.0.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.0.js index e010f2f4c9..d9aa2aa100 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.0.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.0.js @@ -233,6 +233,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.1.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.1.js index d95e132fb4..a63a970b8f 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.1.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.1.js @@ -267,6 +267,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.11.1.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.11.1.js index 280a6b1272..17d59a3174 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.11.1.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.11.1.js @@ -191,6 +191,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.2.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.2.js index be343f7ffe..c26a14d667 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.2.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.2.js @@ -186,6 +186,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.3.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.3.js index 2be64594c6..e0bdab2fdf 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.3.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.3.js @@ -219,6 +219,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.4.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.4.js index c7e0f2c431..9f7d9e2419 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.4.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.4.js @@ -282,6 +282,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.6.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.6.js index 5dcd9198ff..d74a83ea75 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.6.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.6.js @@ -381,6 +381,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.7.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.7.js index 632768e327..96b05ceb6a 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.7.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_1.7.js @@ -227,6 +227,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_events_jquery_2.1.1.js b/devtools/client/inspector/markup/test/browser_markup_events_jquery_2.1.1.js index b1e7d4b8d6..d3d7f78829 100644 --- a/devtools/client/inspector/markup/test/browser_markup_events_jquery_2.1.1.js +++ b/devtools/client/inspector/markup/test/browser_markup_events_jquery_2.1.1.js @@ -189,6 +189,6 @@ const TEST_DATA = [ ]; /*eslint-enable */ -add_task(function*() { +add_task(function* () { yield runEventPopupTests(TEST_URL, TEST_DATA); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js b/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js index 9e361d4c28..9679a5f470 100644 --- a/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_01.js @@ -8,59 +8,64 @@ loadHelperScript("helper_outerhtml_test_runner.js"); -const TEST_DATA = [ - { - selector: "#one", - oldHTML: '
First Div
', - newHTML: '
First Div
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront) { - is(pageNode.textContent, "First Div", "New div has expected text content"); - ok(!getNode("#one em", {expectNoMatch: true}), "No em remaining") - } - }, - { - selector: "#removedChildren", - oldHTML: '
removedChild Italic Bold Underline Normal
', - newHTML: '
removedChild
' - }, - { - selector: "#addedChildren", - oldHTML: '
addedChildren
', - newHTML: '
addedChildren Italic Bold Underline Normal
' - }, - { - selector: "#addedAttribute", - oldHTML: '
addedAttribute
', - newHTML: '
addedAttribute
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront) { - is(pageNodeFront, selectedNodeFront, "Original element is selected"); - is(pageNode.outerHTML, '
addedAttribute
', - "Attributes have been added"); - } - }, - { - selector: "#changedTag", - oldHTML: '
changedTag
', - newHTML: '

changedTag

' - }, - { - selector: "#siblings", - oldHTML: '
siblings
', - newHTML: '
before sibling
' + - '
siblings (updated)
' + - '
after sibling
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { - let beforeSibling = getNode("#siblings-before-sibling"); - let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling", inspector); - let afterSibling = getNode("#siblings-after-sibling"); - - is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected"); - is(pageNode.textContent, "siblings (updated)", "New div has expected text content"); - is(beforeSibling.textContent, "before sibling", "Sibling has been inserted"); - is(afterSibling.textContent, "after sibling", "Sibling has been inserted"); - } +const TEST_DATA = [{ + selector: "#one", + oldHTML: '
First Div
', + newHTML: '
First Div
', + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { + let text = yield testActor.getProperty("#one", "textContent"); + is(text, "First Div", "New div has expected text content"); + let num = yield testActor.getNumberOfElementMatches("#one em"); + is(num, 0, "No em remaining"); } -]; +}, { + selector: "#removedChildren", + oldHTML: "
removedChild " + + "Italic Bold Underline Normal
", + newHTML: "
removedChild
" +}, { + selector: "#addedChildren", + oldHTML: '
addedChildren
', + newHTML: "
addedChildren " + + "Italic Bold Underline Normal
" +}, { + selector: "#addedAttribute", + oldHTML: '
addedAttribute
', + newHTML: "
" + + "addedAttribute
", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { + is(pageNodeFront, selectedNodeFront, "Original element is selected"); + let html = yield testActor.getProperty("#addedAttribute", "outerHTML"); + is(html, "
addedAttribute
", "Attributes have been added"); + } +}, { + selector: "#changedTag", + oldHTML: '
changedTag
', + newHTML: '

changedTag

' +}, { + selector: "#siblings", + oldHTML: '
siblings
', + newHTML: '
before sibling
' + + '
siblings (updated)
' + + '
after sibling
', + validate: function* ({selectedNodeFront, inspector, testActor}) { + let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling", + inspector); + is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected"); + + let text = yield testActor.getProperty("#siblings", "textContent"); + is(text, "siblings (updated)", "New div has expected text content"); + + let beforeText = yield testActor.getProperty("#siblings-before-sibling", + "textContent"); + is(beforeText, "before sibling", "Sibling has been inserted"); + + let afterText = yield testActor.getProperty("#siblings-after-sibling", + "textContent"); + is(afterText, "after sibling", "Sibling has been inserted"); + } +}]; const TEST_URL = "data:text/html," + "" + @@ -70,7 +75,7 @@ const TEST_URL = "data:text/html," + "" + ""; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); inspector.markup._frame.focus(); yield runEditOuterHTMLTests(TEST_DATA, inspector, testActor); diff --git a/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js b/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js index 4653e90dc0..8f6d0fd144 100644 --- a/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_02.js @@ -12,76 +12,94 @@ requestLongerTimeout(2); const TEST_DATA = [ { selector: "#badMarkup1", - oldHTML: '
badMarkup1
', - newHTML: '
badMarkup1
hanging
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { + oldHTML: "
badMarkup1
", + newHTML: "
badMarkup1
hanging", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { is(pageNodeFront, selectedNodeFront, "Original element is selected"); - let textNode = pageNode.nextSibling; - - is(textNode.nodeName, "#text", "Sibling is a text element"); - is(textNode.data, " hanging", "New text node has expected text content"); + let textNodeName = yield testActor.eval(` + content.document.querySelector("#badMarkup1").nextSibling.nodeName + `); + let textNodeData = yield testActor.eval(` + content.document.querySelector("#badMarkup1").nextSibling.data + `); + is(textNodeName, "#text", "Sibling is a text element"); + is(textNodeData, " hanging", "New text node has expected text content"); } }, { selector: "#badMarkup2", - oldHTML: '
badMarkup2
', - newHTML: '
badMarkup2
hanging
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { + oldHTML: "
badMarkup2
", + newHTML: "
badMarkup2
hanging
" + + "", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { is(pageNodeFront, selectedNodeFront, "Original element is selected"); - let textNode = pageNode.nextSibling; - - is(textNode.nodeName, "#text", "Sibling is a text element"); - is(textNode.data, " hanging", "New text node has expected text content"); + let textNodeName = yield testActor.eval(` + content.document.querySelector("#badMarkup2").nextSibling.nodeName + `); + let textNodeData = yield testActor.eval(` + content.document.querySelector("#badMarkup2").nextSibling.data + `); + is(textNodeName, "#text", "Sibling is a text element"); + is(textNodeData, " hanging", "New text node has expected text content"); } }, { selector: "#badMarkup3", - oldHTML: '
badMarkup3
', - newHTML: '
badMarkup3 Emphasized and strong
', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { + oldHTML: "
badMarkup3
", + newHTML: "
badMarkup3 Emphasized " + + "and strong
", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { is(pageNodeFront, selectedNodeFront, "Original element is selected"); - let em = getNode("#badMarkup3 em"); - let strong = getNode("#badMarkup3 strong"); - - is(em.textContent, "Emphasized and strong", " was auto created"); - is(strong.textContent, " and strong", " was auto created"); + let emText = yield testActor.getProperty("#badMarkup3 em", "textContent"); + let strongText = yield testActor.getProperty("#badMarkup3 strong", + "textContent"); + is(emText, "Emphasized and strong", " was auto created"); + is(strongText, " and strong", " was auto created"); } }, { selector: "#badMarkup4", - oldHTML: '
badMarkup4
', - newHTML: '
badMarkup4

', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { + oldHTML: "
badMarkup4
", + newHTML: "
badMarkup4

", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { is(pageNodeFront, selectedNodeFront, "Original element is selected"); - let div = getNode("#badMarkup4"); - let p = getNode("#badMarkup4 p"); + let divText = yield testActor.getProperty("#badMarkup4", "textContent"); + let divTag = yield testActor.getProperty("#badMarkup4", "tagName"); - is(div.textContent, "badMarkup4", "textContent is correct"); - is(div.tagName, "DIV", "did not change to

tag"); - is(p.textContent, "", "The

tag has no children"); - is(p.tagName, "P", "Created an empty

tag"); + let pText = yield testActor.getProperty("#badMarkup4 p", "textContent"); + let pTag = yield testActor.getProperty("#badMarkup4 p", "tagName"); + + is(divText, "badMarkup4", "textContent is correct"); + is(divTag, "DIV", "did not change to

tag"); + is(pText, "", "The

tag has no children"); + is(pTag, "P", "Created an empty

tag"); } }, { selector: "#badMarkup5", - oldHTML: '

badMarkup5

', - newHTML: '

badMarkup5

with a nested div

', - validate: function*(pageNode, pageNodeFront, selectedNodeFront, inspector) { + oldHTML: "

badMarkup5

", + newHTML: "

badMarkup5

with a nested div

", + validate: function* ({pageNodeFront, selectedNodeFront, testActor}) { is(pageNodeFront, selectedNodeFront, "Original element is selected"); - let p = getNode("#badMarkup5"); - let nodiv = getNode("#badMarkup5 div", {expectNoMatch: true}); - let div = getNode("#badMarkup5 ~ div"); + let num = yield testActor.getNumberOfElementMatches("#badMarkup5 div"); - ok(!nodiv, "The invalid markup got created as a sibling"); - is(p.textContent, "badMarkup5 ", "The

tag does not take in the

content"); - is(p.tagName, "P", "Did not change to a
tag"); - is(div.textContent, "with a nested div", "textContent is correct"); - is(div.tagName, "DIV", "Did not change to

tag"); + let pText = yield testActor.getProperty("#badMarkup5", "textContent"); + let pTag = yield testActor.getProperty("#badMarkup5", "tagName"); + + let divText = yield testActor.getProperty("#badMarkup5 ~ div", + "textContent"); + let divTag = yield testActor.getProperty("#badMarkup5 ~ div", "tagName"); + + is(num, 0, "The invalid markup got created as a sibling"); + is(pText, "badMarkup5 ", "The p tag does not take in the div content"); + is(pTag, "P", "Did not change to a

tag"); + is(divText, "with a nested div", "textContent is correct"); + is(divTag, "DIV", "Did not change to

tag"); } } ]; @@ -94,7 +112,7 @@ const TEST_URL = "data:text/html," + "" + ""; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); inspector.markup._frame.focus(); yield runEditOuterHTMLTests(TEST_DATA, inspector, testActor); diff --git a/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js b/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js index 1d35202e42..0491bb48d7 100644 --- a/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_html_edit_03.js @@ -20,163 +20,181 @@ const NEW_HTML = '

Edited
'; requestLongerTimeout(2); -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); inspector.markup._frame.focus(); - info("Checking that pressing escape cancels edits"); - yield testEscapeCancels(inspector); + info("Check that pressing escape cancels edits"); + yield testEscapeCancels(inspector, testActor); - info("Checking that pressing F2 commits edits"); - yield testF2Commits(inspector); + info("Check that pressing F2 commits edits"); + yield testF2Commits(inspector, testActor); - info("Checking that editing the element works like other nodes"); - yield testBody(inspector); + info("Check that editing the element works like other nodes"); + yield testBody(inspector, testActor); - info("Checking that editing the element works like other nodes"); - yield testHead(inspector); + info("Check that editing the element works like other nodes"); + yield testHead(inspector, testActor); - info("Checking that editing the element works like other nodes"); - yield testDocumentElement(inspector); + info("Check that editing the element works like other nodes"); + yield testDocumentElement(inspector, testActor); - info("Checking (again) that editing the element works like other nodes"); - yield testDocumentElement2(inspector); + info("Check (again) that editing the element works like other nodes"); + yield testDocumentElement2(inspector, testActor); }); -function testEscapeCancels(inspector) { - let def = promise.defer(); - let node = getNode(SELECTOR); +function* testEscapeCancels(inspector, testActor) { + yield selectNode(SELECTOR, inspector); - selectNode(SELECTOR, inspector).then(() => { - inspector.markup.htmlEditor.on("popupshown", function onPopupShown() { - inspector.markup.htmlEditor.off("popupshown", onPopupShown); + let onEditorShown = once(inspector.markup.htmlEditor, "popupshown"); + EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); + yield onEditorShown; + ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible"); - ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible"); - is(node.outerHTML, OLD_HTML, "The node is starting with old HTML."); + is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML, + "The node is starting with old HTML."); - inspector.markup.htmlEditor.on("popuphidden", function onPopupHidden() { - inspector.markup.htmlEditor.off("popuphidden", onPopupHidden); - ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible"); + inspector.markup.htmlEditor.editor.setText(NEW_HTML); - let node = getNode(SELECTOR); - is(node.outerHTML, OLD_HTML, "Escape cancels edits"); - def.resolve(); - }); + let onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden"); + EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView); + yield onEditorHiddem; + ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible"); - inspector.markup.htmlEditor.editor.setText(NEW_HTML); - - EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView); - }); - - EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); - }); - - return def.promise; + is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML, + "Escape cancels edits"); } -function testF2Commits(inspector) { - let def = promise.defer(); - let node = getNode(SELECTOR); - - inspector.markup.htmlEditor.on("popupshown", function onPopupShown() { - inspector.markup.htmlEditor.off("popupshown", onPopupShown); - - ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible"); - is(node.outerHTML, OLD_HTML, "The node is starting with old HTML."); - - inspector.once("markupmutation", (e, aMutations) => { - ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible"); - - let node = getNode(SELECTOR); - is(node.outerHTML, NEW_HTML, "F2 commits edits - the node has new HTML."); - def.resolve(); - }); - - inspector.markup.htmlEditor.editor.setText(NEW_HTML); - EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); - }); - +function* testF2Commits(inspector, testActor) { + let onEditorShown = once(inspector.markup.htmlEditor, "popupshown"); inspector.markup._frame.contentDocument.documentElement.focus(); EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); + yield onEditorShown; + ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible"); - return def.promise; + is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML, + "The node is starting with old HTML."); + + let onMutations = inspector.once("markupmutation"); + inspector.markup.htmlEditor.editor.setText(NEW_HTML); + EventUtils.sendKey("F2", inspector.markup._frame.contentWindow); + yield onMutations; + + ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible"); + + is((yield testActor.getProperty(SELECTOR, "outerHTML")), NEW_HTML, + "F2 commits edits - the node has new HTML."); } -function* testBody(inspector) { - let body = getNode("body"); +function* testBody(inspector, testActor) { + let currentBodyHTML = yield testActor.getProperty("body", "outerHTML"); let bodyHTML = '

'; let bodyFront = yield getNodeFront("body", inspector); - let doc = content.document; let onReselected = inspector.markup.once("reselectedonremoved"); - yield inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML, body.outerHTML); + yield inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML, + currentBodyHTML); yield onReselected; - is(getNode("body").outerHTML, bodyHTML, " HTML has been updated"); - is(doc.querySelectorAll("head").length, 1, "no extra s have been added"); + let newBodyHTML = yield testActor.getProperty("body", "outerHTML"); + is(newBodyHTML, bodyHTML, " HTML has been updated"); + + let headsNum = yield testActor.getNumberOfElementMatches("head"); + is(headsNum, 1, "no extra s have been added"); yield inspector.once("inspector-updated"); } -function* testHead(inspector) { - let head = getNode("head"); +function* testHead(inspector, testActor) { yield selectNode("head", inspector); - let headHTML = 'New Title'; + let currentHeadHTML = yield testActor.getProperty("head", "outerHTML"); + let headHTML = "New Title" + + ""; let headFront = yield getNodeFront("head", inspector); - let doc = content.document; let onReselected = inspector.markup.once("reselectedonremoved"); - yield inspector.markup.updateNodeOuterHTML(headFront, headHTML, head.outerHTML); + yield inspector.markup.updateNodeOuterHTML(headFront, headHTML, + currentHeadHTML); yield onReselected; - is(doc.title, "New Title", "New title has been added"); - is(doc.defaultView.foo, undefined, "Script has not been executed"); - is(doc.querySelector("head").outerHTML, headHTML, " HTML has been updated"); - is(doc.querySelectorAll("body").length, 1, "no extra s have been added"); + is((yield testActor.eval("content.document.title")), "New Title", + "New title has been added"); + is((yield testActor.eval("content.foo")), undefined, + "Script has not been executed"); + is((yield testActor.getProperty("head", "outerHTML")), headHTML, + " HTML has been updated"); + is((yield testActor.getNumberOfElementMatches("body")), 1, + "no extra s have been added"); yield inspector.once("inspector-updated"); } -function* testDocumentElement(inspector) { - let doc = content.document; - let docElement = doc.documentElement; - let docElementHTML = 'Updated from document element

Hello

'; +function* testDocumentElement(inspector, testActor) { + let currentDocElementOuterHMTL = yield testActor.eval( + "content.document.documentElement.outerHMTL"); + let docElementHTML = "" + + "Updated from document element" + + "" + + "

Hello

"; let docElementFront = yield inspector.markup.walker.documentElement(); let onReselected = inspector.markup.once("reselectedonremoved"); - yield inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML); + yield inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, + currentDocElementOuterHMTL); yield onReselected; - is(doc.title, "Updated from document element", "New title has been added"); - is(doc.defaultView.foo, undefined, "Script has not been executed"); - is(doc.documentElement.id, "updated", " ID has been updated"); - is(doc.documentElement.className, "", " class has been updated"); - is(doc.documentElement.getAttribute("foo"), "bar", " attribute has been updated"); - is(doc.documentElement.outerHTML, docElementHTML, " HTML has been updated"); - is(doc.querySelectorAll("head").length, 1, "no extra s have been added"); - is(doc.querySelectorAll("body").length, 1, "no extra s have been added"); - is(doc.body.textContent, "Hello", "document.body.textContent has been updated"); + is((yield testActor.eval("content.document.title")), + "Updated from document element", "New title has been added"); + is((yield testActor.eval("content.foo")), + undefined, "Script has not been executed"); + is((yield testActor.getAttribute("html", "id")), + "updated", " ID has been updated"); + is((yield testActor.getAttribute("html", "class")), + null, " class has been updated"); + is((yield testActor.getAttribute("html", "foo")), + "bar", " attribute has been updated"); + is((yield testActor.getProperty("html", "outerHTML")), + docElementHTML, " HTML has been updated"); + is((yield testActor.getNumberOfElementMatches("head")), + 1, "no extra s have been added"); + is((yield testActor.getNumberOfElementMatches("body")), + 1, "no extra s have been added"); + is((yield testActor.getProperty("body", "textContent")), + "Hello", "document.body.textContent has been updated"); } -function* testDocumentElement2(inspector) { - let doc = content.document; - let docElement = doc.documentElement; - let docElementHTML = 'Updated again from document element

Hello again

'; +function* testDocumentElement2(inspector, testActor) { + let currentDocElementOuterHMTL = yield testActor.eval( + "content.document.documentElement.outerHMTL"); + let docElementHTML = "" + + "Updated again from document element" + + "" + + "

Hello again

"; let docElementFront = yield inspector.markup.walker.documentElement(); let onReselected = inspector.markup.once("reselectedonremoved"); - inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML); + inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, + currentDocElementOuterHMTL); yield onReselected; - is(doc.title, "Updated again from document element", "New title has been added"); - is(doc.defaultView.foo, undefined, "Script has not been executed"); - is(doc.documentElement.id, "somethingelse", " ID has been updated"); - is(doc.documentElement.className, "updated", " class has been updated"); - is(doc.documentElement.getAttribute("foo"), null, " attribute has been removed"); - is(doc.documentElement.outerHTML, docElementHTML, " HTML has been updated"); - is(doc.querySelectorAll("head").length, 1, "no extra s have been added"); - is(doc.querySelectorAll("body").length, 1, "no extra s have been added"); - is(doc.body.textContent, "Hello again", "document.body.textContent has been updated"); + is((yield testActor.eval("content.document.title")), + "Updated again from document element", "New title has been added"); + is((yield testActor.eval("content.foo")), + undefined, "Script has not been executed"); + is((yield testActor.getAttribute("html", "id")), + "somethingelse", " ID has been updated"); + is((yield testActor.getAttribute("html", "class")), + "updated", " class has been updated"); + is((yield testActor.getAttribute("html", "foo")), + null, " attribute has been removed"); + is((yield testActor.getProperty("html", "outerHTML")), + docElementHTML, " HTML has been updated"); + is((yield testActor.getNumberOfElementMatches("head")), + 1, "no extra s have been added"); + is((yield testActor.getNumberOfElementMatches("body")), + 1, "no extra s have been added"); + is((yield testActor.getProperty("body", "textContent")), + "Hello again", "document.body.textContent has been updated"); } diff --git a/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js b/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js index d54d7009e6..c767815a0b 100644 --- a/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js +++ b/devtools/client/inspector/markup/test/browser_markup_image_tooltip.js @@ -1,20 +1,12 @@ /* vim: set ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ - "use strict"; // Test that image preview tooltips are shown on img and canvas tags in the // markup-view and that the tooltip actually contains an image and shows the // right dimension label -const PAGE_CONTENT = [ - '', - '', - '', - '' -].join("\n"); - const TEST_NODES = [ {selector: "img.local", size: "192" + " \u00D7 " + "192"}, {selector: "img.data", size: "64" + " \u00D7 " + "64"}, @@ -22,10 +14,8 @@ const TEST_NODES = [ {selector: ".canvas", size: "600" + " \u00D7 " + "600"} ]; -add_task(function*() { - yield addTab("data:text/html,markup view tooltip test"); - createPage(); - +add_task(function* () { + yield addTab(URL_ROOT + "doc_markup_image_and_canvas_2.html"); let {inspector} = yield openInspector(); info("Selecting the first tag"); @@ -38,23 +28,6 @@ add_task(function*() { } }); -function createPage() { - info("Fill the page with the test content"); - content.document.body.innerHTML = PAGE_CONTENT; - - info("Fill the canvas"); - let doc = content.document; - let context = doc.querySelector(".canvas").getContext("2d"); - - context.beginPath(); - context.moveTo(300, 0); - context.lineTo(600, 600); - context.lineTo(0, 600); - context.closePath(); - context.fillStyle = "#ffc821"; - context.fill(); -} - function* getImageTooltipTarget({selector}, inspector) { let nodeFront = yield getNodeFront(selector, inspector); let isImg = nodeFront.tagName.toLowerCase() === "img"; @@ -79,7 +52,8 @@ function checkImageTooltip({selector, size}, {markup}) { is(images.length, 1, "Tooltip for [" + selector + "] contains an image"); let label = markup.tooltip.panel.querySelector(".devtools-tooltip-caption"); - is(label.textContent, size, "Tooltip label for [" + selector + "] displays the right image size"); + is(label.textContent, size, + "Tooltip label for [" + selector + "] displays the right image size"); markup.tooltip.hide(); } diff --git a/devtools/client/inspector/markup/test/browser_markup_image_tooltip_mutations.js b/devtools/client/inspector/markup/test/browser_markup_image_tooltip_mutations.js index 2e91367e7b..5c4e34fdba 100644 --- a/devtools/client/inspector/markup/test/browser_markup_image_tooltip_mutations.js +++ b/devtools/client/inspector/markup/test/browser_markup_image_tooltip_mutations.js @@ -16,7 +16,7 @@ const UPDATED_SRC = URL_ROOT + "doc_markup_tooltip.png"; const INITIAL_SRC_SIZE = "64" + " \u00D7 " + "64"; const UPDATED_SRC_SIZE = "22" + " \u00D7 " + "23"; -add_task(function*() { +add_task(function* () { let { inspector } = yield openInspectorForURL( "data:text/html,

markup view tooltip test

"); diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js index 682667d49a..c03d17e067 100644 --- a/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_01.js @@ -8,7 +8,7 @@ const TEST_URL = "data:text/html;charset=utf8,
"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Focusing the tag editor of the test element"); diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_02.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_02.js index 8c81f88ccb..0e4b8a8029 100644 --- a/devtools/client/inspector/markup/test/browser_markup_keybindings_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_02.js @@ -9,7 +9,7 @@ const TEST_URL = "data:text/html;charset=utf8,
"; -add_task(function*() { +add_task(function* () { let {inspector, toolbox} = yield openInspectorForURL(TEST_URL); info("Focusing the tag editor of the test element"); diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_03.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_03.js index c657b9e0e2..1a94c92704 100644 --- a/devtools/client/inspector/markup/test/browser_markup_keybindings_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_03.js @@ -11,7 +11,7 @@ const TEST_URL = `data:text/html;charset=utf8,
Text node`; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let {walker} = inspector; diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_04.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_04.js index 0023b8cef6..dad2e4a018 100644 --- a/devtools/client/inspector/markup/test/browser_markup_keybindings_04.js +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_04.js @@ -12,7 +12,7 @@ requestLongerTimeout(2); const TEST_URL = "data:text/html;charset=utf8,
test element
"; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Select the test node with the browser ctx menu"); diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js index e4c875e0bf..277735d24d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_delete_attributes.js @@ -7,7 +7,7 @@ // Tests that attributes can be deleted from the markup-view with the delete key // when they are focused. -const HTML = `
`; +const HTML = '
'; const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML); // List of all the test cases. Each item is an object with the following props: @@ -24,7 +24,7 @@ const TEST_DATA = [{ attribute: "data-id" }]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let {walker} = inspector; diff --git a/devtools/client/inspector/markup/test/browser_markup_keybindings_scrolltonode.js b/devtools/client/inspector/markup/test/browser_markup_keybindings_scrolltonode.js new file mode 100644 index 0000000000..c8fb443b99 --- /dev/null +++ b/devtools/client/inspector/markup/test/browser_markup_keybindings_scrolltonode.js @@ -0,0 +1,87 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the keyboard shortcut "S" used to scroll to the selected node. + +const HTML = + `
+
+ TOP
+
+ BOTTOM
+
`; +const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML); + +add_task(function* () { + let { inspector, testActor } = yield openInspectorForURL(TEST_URL); + + info("Make sure the markup frame has the focus"); + inspector.markup._frame.focus(); + + info("Before test starts, #scroll-top is visible, #scroll-bottom is hidden"); + yield checkElementIsInViewport("#scroll-top", true, testActor); + yield checkElementIsInViewport("#scroll-bottom", false, testActor); + + info("Select the #scroll-bottom node"); + yield selectNode("#scroll-bottom", inspector); + info("Press S to scroll to the bottom node"); + let waitForScroll = testActor.waitForEventOnNode("scroll"); + yield EventUtils.synthesizeKey("S", {}, inspector.panelWin); + yield waitForScroll; + ok(true, "Scroll event received"); + + info("#scroll-top should be scrolled out, #scroll-bottom should be visible"); + yield checkElementIsInViewport("#scroll-top", false, testActor); + yield checkElementIsInViewport("#scroll-bottom", true, testActor); + + info("Select the #scroll-top node"); + yield selectNode("#scroll-top", inspector); + info("Press S to scroll to the top node"); + waitForScroll = testActor.waitForEventOnNode("scroll"); + yield EventUtils.synthesizeKey("S", {}, inspector.panelWin); + yield waitForScroll; + ok(true, "Scroll event received"); + + info("#scroll-top should be visible, #scroll-bottom should be scrolled out"); + yield checkElementIsInViewport("#scroll-top", true, testActor); + yield checkElementIsInViewport("#scroll-bottom", false, testActor); + + info("Select #scroll-bottom node"); + yield selectNode("#scroll-bottom", inspector); + info("Press shift + S, nothing should happen due to the modifier"); + yield EventUtils.synthesizeKey("S", {shiftKey: true}, inspector.panelWin); + + info("Same state, #scroll-top is visible, #scroll-bottom is scrolled out"); + yield checkElementIsInViewport("#scroll-top", true, testActor); + yield checkElementIsInViewport("#scroll-bottom", false, testActor); +}); + +/** + * Verify that the element matching the provided selector is either in or out + * of the viewport, depending on the provided "expected" argument. + * Returns a promise that will resolve when the test has been performed. + * + * @param {String} selector + * css selector for the element to test + * @param {Boolean} expected + * true if the element is expected to be in the viewport, false otherwise + * @param {TestActor} testActor + * current test actor + * @return {Promise} promise + */ +function* checkElementIsInViewport(selector, expected, testActor) { + let isInViewport = yield testActor.eval(` + let node = content.document.querySelector("${selector}"); + let rect = node.getBoundingClientRect(); + rect.bottom >= 0 && rect.right >= 0 && + rect.top <= content.innerHeight && rect.left <= content.innerWidth; + `); + + is(isInViewport, expected, + selector + " in the viewport: expected to be " + expected); +} diff --git a/devtools/client/inspector/markup/test/browser_markup_links_01.js b/devtools/client/inspector/markup/test/browser_markup_links_01.js index ec5185ca29..4ef3ba4b98 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_01.js @@ -100,7 +100,9 @@ const TEST_DATA = [{ }] }]; -add_task(function*() { +requestLongerTimeout(2); + +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); for (let {selector, attributes} of TEST_DATA) { diff --git a/devtools/client/inspector/markup/test/browser_markup_links_02.js b/devtools/client/inspector/markup/test/browser_markup_links_02.js index 5096560994..83893281c3 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_02.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_links.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Adding a contextmenu attribute to the body node"); diff --git a/devtools/client/inspector/markup/test/browser_markup_links_03.js b/devtools/client/inspector/markup/test/browser_markup_links_03.js index 170656904d..a54ccb4980 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_03.js @@ -8,12 +8,12 @@ const TEST_URL = URL_ROOT + "doc_markup_links.html"; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Adding a contextmenu attribute to the body node via the content"); let onMutated = inspector.once("markupmutation"); - yield setNodeAttribute("body", "contextmenu", "menu1", testActor); + yield testActor.setAttribute("body", "contextmenu", "menu1"); yield onMutated; info("Checking for links in the new attribute"); @@ -26,7 +26,7 @@ add_task(function*() { info("Editing the contextmenu attribute on the body node"); onMutated = inspector.once("markupmutation"); - yield setNodeAttribute("body", "contextmenu", "menu2", testActor); + yield testActor.setAttribute("body", "contextmenu", "menu2"); yield onMutated; info("Checking for links in the updated attribute"); diff --git a/devtools/client/inspector/markup/test/browser_markup_links_04.js b/devtools/client/inspector/markup/test/browser_markup_links_04.js index 87fe8cb3d8..d4f98b429e 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_04.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_04.js @@ -74,7 +74,7 @@ const TEST_DATA = [{ isLinkCopyItemVisible: false }]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let linkFollow = inspector.panelDoc.getElementById("node-menu-link-follow"); diff --git a/devtools/client/inspector/markup/test/browser_markup_links_05.js b/devtools/client/inspector/markup/test/browser_markup_links_05.js index a5c9bd6820..8e1f6fa8ad 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_05.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_05.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_links.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Select a node with a URI attribute"); diff --git a/devtools/client/inspector/markup/test/browser_markup_links_06.js b/devtools/client/inspector/markup/test/browser_markup_links_06.js index 3c440da2e0..7321d7e07e 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_06.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_06.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_links.html"; -add_task(function*() { +add_task(function* () { let {toolbox, inspector} = yield openInspectorForURL(TEST_URL); info("Select a node with a cssresource attribute"); diff --git a/devtools/client/inspector/markup/test/browser_markup_links_07.js b/devtools/client/inspector/markup/test/browser_markup_links_07.js index 66df058adf..ef88d96f87 100644 --- a/devtools/client/inspector/markup/test/browser_markup_links_07.js +++ b/devtools/client/inspector/markup/test/browser_markup_links_07.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_links.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Select a node with a URI attribute"); diff --git a/devtools/client/inspector/markup/test/browser_markup_load_01.js b/devtools/client/inspector/markup/test/browser_markup_load_01.js index aceae10111..bf7a6d5e97 100644 --- a/devtools/client/inspector/markup/test/browser_markup_load_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_load_01.js @@ -14,10 +14,10 @@ const server = createTestHTTPServer(); // a reload and the load event firing. server.registerContentType("gif", "image/gif"); server.registerPathHandler("/slow.gif", function (metadata, response) { - info ("Image has been requested"); + info("Image has been requested"); response.processAsync(); setTimeout(() => { - info ("Image is responding"); + info("Image is responding"); response.finish(); }, 500); }); @@ -32,22 +32,24 @@ const TEST_URL = "data:text/html," + "" + ""; -add_task(function*() { +add_task(function* () { let {inspector, testActor, tab} = yield openInspectorForURL(TEST_URL); let domContentLoaded = waitForLinkedBrowserEvent(tab, "DOMContentLoaded"); let pageLoaded = waitForLinkedBrowserEvent(tab, "load"); - ok (inspector.markup, "There is a markup view"); + ok(inspector.markup, "There is a markup view"); // Select an element while the tab is in the middle of a slow reload. - reloadTab(testActor); + testActor.eval("location.reload()"); yield domContentLoaded; yield chooseWithInspectElementContextMenu("img", testActor); yield pageLoaded; yield inspector.once("markuploaded"); - ok (inspector.markup, "There is a markup view"); - is (inspector.markup._elt.children.length, 1, "The markup view is rendering"); + yield waitForMultipleChildrenUpdates(inspector); + + ok(inspector.markup, "There is a markup view"); + is(inspector.markup._elt.children.length, 1, "The markup view is rendering"); }); function* chooseWithInspectElementContextMenu(selector, testActor) { diff --git a/devtools/client/inspector/markup/test/browser_markup_mutation_01.js b/devtools/client/inspector/markup/test/browser_markup_mutation_01.js index 9f8801c9d8..0948f0a935 100644 --- a/devtools/client/inspector/markup/test/browser_markup_mutation_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_mutation_01.js @@ -17,11 +17,10 @@ const TEST_URL = URL_ROOT + "doc_markup_mutation.html"; const TEST_DATA = [ { desc: "Adding an attribute", - test: () => { - let node1 = getNode("#node1"); - node1.setAttribute("newattr", "newattrval"); + test: function* (testActor) { + yield testActor.setAttribute("#node1", "newattr", "newattrval"); }, - check: function*(inspector) { + check: function* (inspector) { let {editor} = yield getContainerForSelector("#node1", inspector); ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => { return attr.textContent.trim() === "newattr=\"newattrval\""; @@ -30,11 +29,10 @@ const TEST_DATA = [ }, { desc: "Removing an attribute", - test: () => { - let node1 = getNode("#node1"); - node1.removeAttribute("newattr"); + test: function* (testActor) { + yield testActor.removeAttribute("#node1", "newattr"); }, - check: function*(inspector) { + check: function* (inspector) { let {editor} = yield getContainerForSelector("#node1", inspector); ok(![...editor.attrList.querySelectorAll(".attreditor")].some(attr => { return attr.textContent.trim() === "newattr=\"newattrval\""; @@ -43,11 +41,10 @@ const TEST_DATA = [ }, { desc: "Re-adding an attribute", - test: () => { - let node1 = getNode("#node1"); - node1.setAttribute("newattr", "newattrval"); + test: function* (testActor) { + yield testActor.setAttribute("#node1", "newattr", "newattrval"); }, - check: function*(inspector) { + check: function* (inspector) { let {editor} = yield getContainerForSelector("#node1", inspector); ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => { return attr.textContent.trim() === "newattr=\"newattrval\""; @@ -56,11 +53,10 @@ const TEST_DATA = [ }, { desc: "Changing an attribute", - test: () => { - let node1 = getNode("#node1"); - node1.setAttribute("newattr", "newattrchanged"); + test: function* (testActor) { + yield testActor.setAttribute("#node1", "newattr", "newattrchanged"); }, - check: function*(inspector) { + check: function* (inspector) { let {editor} = yield getContainerForSelector("#node1", inspector); ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => { return attr.textContent.trim() === "newattr=\"newattrchanged\""; @@ -70,11 +66,13 @@ const TEST_DATA = [ { desc: "Adding ::after element", numMutations: 2, - test: () => { - let node1 = getNode("#node1"); - node1.classList.add("pseudo"); + test: function* (testActor) { + yield testActor.eval(` + let node1 = content.document.querySelector("#node1"); + node1.classList.add("pseudo"); + `); }, - check: function*(inspector) { + check: function* (inspector) { let {children} = yield getContainerForSelector("#node1", inspector); is(children.childNodes.length, 2, "Node1 now has 2 children (text child and ::after"); @@ -83,22 +81,23 @@ const TEST_DATA = [ { desc: "Removing ::after element", numMutations: 2, - test: () => { - let node1 = getNode("#node1"); - node1.classList.remove("pseudo"); + test: function* (testActor) { + yield testActor.eval(` + let node1 = content.document.querySelector("#node1"); + node1.classList.remove("pseudo"); + `); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(container.singleTextChild, "Has single text child."); } }, { desc: "Updating the text-content", - test: () => { - let node1 = getNode("#node1"); - node1.textContent = "newtext"; + test: function* (testActor) { + yield testActor.setProperty("#node1", "textContent", "newtext"); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(container.singleTextChild, "Has single text child."); ok(!container.canExpand, "Can't expand container with singleTextChild."); @@ -109,12 +108,14 @@ const TEST_DATA = [ }, { desc: "Adding a second text child", - test: () => { - let node1 = getNode("#node1"); - let newText = node1.ownerDocument.createTextNode("more"); - node1.appendChild(newText); + test: function* (testActor) { + yield testActor.eval(` + let node1 = content.document.querySelector("#node1"); + let newText = node1.ownerDocument.createTextNode("more"); + node1.appendChild(newText); + `); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(!container.singleTextChild, "Does not have single text child."); ok(container.canExpand, "Can expand container with child nodes."); @@ -124,11 +125,10 @@ const TEST_DATA = [ }, { desc: "Go from 2 to 1 text child", - test: () => { - let node1 = getNode("#node1"); - node1.textContent = "newtext"; + test: function* (testActor) { + yield testActor.setProperty("#node1", "textContent", "newtext"); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(container.singleTextChild, "Has single text child."); ok(!container.canExpand, "Can't expand container with singleTextChild."); @@ -139,11 +139,10 @@ const TEST_DATA = [ }, { desc: "Removing an only text child", - test: () => { - let node1 = getNode("#node1"); - node1.innerHTML = ""; + test: function* (testActor) { + yield testActor.setProperty("#node1", "innerHTML", ""); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(!container.singleTextChild, "Does not have single text child."); ok(!container.canExpand, "Can't expand empty container."); @@ -153,11 +152,10 @@ const TEST_DATA = [ }, { desc: "Go from 0 to 1 text child", - test: () => { - let node1 = getNode("#node1"); - node1.textContent = "newtext"; + test: function* (testActor) { + yield testActor.setProperty("#node1", "textContent", "newtext"); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node1", inspector); ok(container.singleTextChild, "Has single text child."); ok(!container.canExpand, "Can't expand container with singleTextChild."); @@ -169,11 +167,11 @@ const TEST_DATA = [ { desc: "Updating the innerHTML", - test: () => { - let node2 = getNode("#node2"); - node2.innerHTML = "
foo
"; + test: function* (testActor) { + yield testActor.setProperty("#node2", "innerHTML", + "
foo
"); }, - check: function*(inspector) { + check: function* (inspector) { let container = yield getContainerForSelector("#node2", inspector); let openTags = container.children.querySelectorAll(".open .tag"); @@ -187,25 +185,29 @@ const TEST_DATA = [ }, { desc: "Removing child nodes", - test: () => { - let node4 = getNode("#node4"); - while (node4.firstChild) { - node4.removeChild(node4.firstChild); - } + test: function* (testActor) { + yield testActor.eval(` + let node4 = content.document.querySelector("#node4"); + while (node4.firstChild) { + node4.removeChild(node4.firstChild); + } + `); }, - check: function*(inspector) { + check: function* (inspector) { let {children} = yield getContainerForSelector("#node4", inspector); is(children.innerHTML, "", "Children have been removed"); } }, { desc: "Appending a child to a different parent", - test: () => { - let node17 = getNode("#node17"); - let node2 = getNode("#node2"); - node2.appendChild(node17); + test: function* (testActor) { + yield testActor.eval(` + let node17 = content.document.querySelector("#node17"); + let node2 = content.document.querySelector("#node2"); + node2.appendChild(node17); + `); }, - check: function*(inspector) { + check: function* (inspector) { let {children} = yield getContainerForSelector("#node16", inspector); is(children.innerHTML, "", "Node17 has been removed from its node16 parent"); @@ -231,16 +233,16 @@ const TEST_DATA = [ // node21 // node18 // node19 - test: () => { - let node18 = getNode("#node18"); - let node20 = getNode("#node20"); - - let node1 = getNode("#node1"); - - node1.appendChild(node20); - node20.appendChild(node18); + test: function* (testActor) { + yield testActor.eval(` + let node18 = content.document.querySelector("#node18"); + let node20 = content.document.querySelector("#node20"); + let node1 = content.document.querySelector("#node1"); + node1.appendChild(node20); + node20.appendChild(node18); + `); }, - check: function*(inspector) { + check: function* (inspector) { yield inspector.markup.expandAll(); let {children} = yield getContainerForSelector("#node1", inspector); @@ -264,8 +266,8 @@ const TEST_DATA = [ } ]; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Expanding all markup-view nodes"); yield inspector.markup.expandAll(); @@ -276,22 +278,22 @@ add_task(function*() { numMutations = numMutations || 1; info("Executing the test markup mutation"); - yield new Promise((resolve) => { - // If a test expects more than one mutation it may come through in a - // single event or possibly in multiples. - let seenMutations = 0; - inspector.on("markupmutation", function onmutation(e, mutations) { - seenMutations += mutations.length; - info("Receieved " + seenMutations + - " mutations, expecting at least " + numMutations); - if (seenMutations >= numMutations) { - inspector.off("markupmutation", onmutation); - resolve(); - } - }); - test(); + // If a test expects more than one mutation it may come through in a single + // event or possibly in multiples. + let def = promise.defer(); + let seenMutations = 0; + inspector.on("markupmutation", function onmutation(e, mutations) { + seenMutations += mutations.length; + info("Receieved " + seenMutations + + " mutations, expecting at least " + numMutations); + if (seenMutations >= numMutations) { + inspector.off("markupmutation", onmutation); + def.resolve(); + } }); + yield test(testActor); + yield def.promise; info("Expanding all markup-view nodes to make sure new nodes are imported"); yield inspector.markup.expandAll(); diff --git a/devtools/client/inspector/markup/test/browser_markup_mutation_02.js b/devtools/client/inspector/markup/test/browser_markup_mutation_02.js index 2c0dad5835..7d097ade64 100644 --- a/devtools/client/inspector/markup/test/browser_markup_mutation_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_mutation_02.js @@ -13,7 +13,7 @@ const TEST_URL = URL_ROOT + "doc_markup_flashing.html"; // The test data contains a list of mutations to test. // Each item is an object: // - desc: a description of the test step, for better logging -// - mutate: a function that should make changes to the content DOM +// - mutate: a generator function that should make changes to the content DOM // - attribute: if set, the test will expect the corresponding attribute to // flash instead of the whole node // - flashedNode: [optional] the css selector of the node that is expected to @@ -21,69 +21,82 @@ const TEST_URL = URL_ROOT + "doc_markup_flashing.html"; // If missing, the rootNode (".list") will be expected to flash const TEST_DATA = [{ desc: "Adding a new node should flash the new node", - mutate: (doc, rootNode) => { - let newLi = doc.createElement("LI"); - newLi.textContent = "new list item"; - rootNode.appendChild(newLi); + mutate: function* (testActor) { + yield testActor.eval(` + let newLi = content.document.createElement("LI"); + newLi.textContent = "new list item"; + content.document.querySelector(".list").appendChild(newLi); + `); }, flashedNode: ".list li:nth-child(3)" }, { desc: "Removing a node should flash its parent", - mutate: (doc, rootNode) => { - rootNode.removeChild(rootNode.lastElementChild); + mutate: function* (testActor) { + yield testActor.eval(` + let root = content.document.querySelector(".list"); + root.removeChild(root.lastElementChild); + `); } }, { desc: "Re-appending an existing node should only flash this node", - mutate: (doc, rootNode) => { - rootNode.appendChild(rootNode.firstElementChild); + mutate: function* (testActor) { + yield testActor.eval(` + let root = content.document.querySelector(".list"); + root.appendChild(root.firstElementChild); + `); }, flashedNode: ".list .item:last-child" }, { desc: "Adding an attribute should flash the attribute", attribute: "test-name", - mutate: (doc, rootNode) => { - rootNode.setAttribute("test-name", "value-" + Date.now()); + mutate: function* (testActor) { + yield testActor.setAttribute(".list", "test-name", "value-" + Date.now()); } }, { desc: "Adding an attribute with css reserved characters should flash the " + "attribute", attribute: "one:two", - mutate: (doc, rootNode) => { - rootNode.setAttribute("one:two", "value-" + Date.now()); + mutate: function* (testActor) { + yield testActor.setAttribute(".list", "one:two", "value-" + Date.now()); } }, { desc: "Editing an attribute should flash the attribute", attribute: "class", - mutate: (doc, rootNode) => { - rootNode.setAttribute("class", "list value-" + Date.now()); + mutate: function* (testActor) { + yield testActor.setAttribute(".list", "class", "list value-" + Date.now()); } }, { desc: "Multiple changes to an attribute should flash the attribute", attribute: "class", - mutate: (doc, rootNode) => { - rootNode.removeAttribute("class"); - rootNode.setAttribute("class", "list value-" + Date.now()); - rootNode.setAttribute("class", "list value-" + Date.now()); - rootNode.removeAttribute("class"); - rootNode.setAttribute("class", "list value-" + Date.now()); - rootNode.setAttribute("class", "list value-" + Date.now()); + mutate: function* (testActor) { + yield testActor.eval(` + let root = content.document.querySelector(".list"); + root.removeAttribute("class"); + root.setAttribute("class", "list value-" + Date.now()); + root.setAttribute("class", "list value-" + Date.now()); + root.removeAttribute("class"); + root.setAttribute("class", "list value-" + Date.now()); + root.setAttribute("class", "list value-" + Date.now()); + `); } }, { desc: "Removing an attribute should flash the node", - mutate: (doc, rootNode) => { - rootNode.removeAttribute("class"); + mutate: function* (testActor) { + yield testActor.eval(` + let root = content.document.querySelector(".list"); + root.removeAttribute("class"); + `); } }]; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); // Make sure mutated nodes flash for a very long time so we can more easily // assert they do inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60; info("Getting the root node to test mutations on"); - let rootNode = getNode(".list"); let rootNodeFront = yield getNodeFront(".list", inspector); info("Selecting the last element of the root node before starting"); @@ -93,9 +106,14 @@ add_task(function*() { info("Starting test: " + desc); info("Mutating the DOM and listening for markupmutation event"); - let mutated = inspector.once("markupmutation"); - mutate(content.document, rootNode); - yield mutated; + let onMutation = inspector.once("markupmutation"); + yield mutate(testActor); + let mutations = yield onMutation; + + info("Wait for the breadcrumbs widget to update if it needs to"); + if (inspector.breadcrumbs._hasInterestingMutations(mutations)) { + yield inspector.once("breadcrumbs-updated"); + } info("Asserting that the correct markup-container is flashing"); let flashingNodeFront = rootNodeFront; diff --git a/devtools/client/inspector/markup/test/browser_markup_navigation.js b/devtools/client/inspector/markup/test/browser_markup_navigation.js index 6fd3cad568..a64a448566 100644 --- a/devtools/client/inspector/markup/test/browser_markup_navigation.js +++ b/devtools/client/inspector/markup/test/browser_markup_navigation.js @@ -66,7 +66,7 @@ const TEST_DATA = [ ["down", "head"] ]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Making sure the markup-view frame is focused"); diff --git a/devtools/client/inspector/markup/test/browser_markup_node_names.js b/devtools/client/inspector/markup/test/browser_markup_node_names.js index 6a6b8e6e8c..a8afad5e9d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_node_names.js +++ b/devtools/client/inspector/markup/test/browser_markup_node_names.js @@ -7,7 +7,7 @@ // Test element node name in the markupview const TEST_URL = URL_ROOT + "doc_markup_html_mixed_case.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); // Get and open the svg element to show its children diff --git a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_01.js b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_01.js index cc6bce5c03..18304490e8 100644 --- a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_01.js @@ -21,7 +21,7 @@ const TEST_DATA = [ {selector: "#visibility-hidden", isDisplayed: true} ]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); for (let {selector, isDisplayed} of TEST_DATA) { diff --git a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js index af38333a6d..b0a3f07b27 100644 --- a/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_node_not_displayed_02.js @@ -13,11 +13,13 @@ const TEST_DATA = [ desc: "Hiding a node by creating a new stylesheet", selector: "#normal-div", before: true, - changeStyle: (doc, node) => { - let div = doc.createElement("div"); - div.id = "new-style"; - div.innerHTML = ""; - doc.body.appendChild(div); + changeStyle: function* (testActor) { + yield testActor.eval(` + let div = content.document.createElement("div"); + div.id = "new-style"; + div.innerHTML = ""; + content.document.body.appendChild(div); + `); }, after: false }, @@ -25,8 +27,10 @@ const TEST_DATA = [ desc: "Showing a node by deleting an existing stylesheet", selector: "#normal-div", before: false, - changeStyle: (doc, node) => { - doc.getElementById("new-style").remove(); + changeStyle: function* (testActor) { + yield testActor.eval(` + content.document.getElementById("new-style").remove(); + `); }, after: true }, @@ -34,8 +38,11 @@ const TEST_DATA = [ desc: "Hiding a node by changing its style property", selector: "#display-none", before: false, - changeStyle: (doc, node) => { - node.style.display = "block"; + changeStyle: function* (testActor) { + yield testActor.eval(` + let node = content.document.querySelector("#display-none"); + node.style.display = "block"; + `); }, after: true }, @@ -43,8 +50,11 @@ const TEST_DATA = [ desc: "Showing a node by removing its hidden attribute", selector: "#hidden-true", before: false, - changeStyle: (doc, node) => { - node.removeAttribute("hidden"); + changeStyle: function* (testActor) { + yield testActor.eval(` + content.document.querySelector("#hidden-true") + .removeAttribute("hidden"); + `); }, after: true }, @@ -52,8 +62,8 @@ const TEST_DATA = [ desc: "Hiding a node by adding a hidden attribute", selector: "#hidden-true", before: true, - changeStyle: (doc, node) => { - node.setAttribute("hidden", "true"); + changeStyle: function* (testActor) { + yield testActor.setAttribute("#hidden-true", "hidden", "true"); }, after: false }, @@ -61,8 +71,12 @@ const TEST_DATA = [ desc: "Showing a node by changin a stylesheet's rule", selector: "#hidden-via-stylesheet", before: false, - changeStyle: (doc, node) => { - doc.styleSheets[0].cssRules[0].style.setProperty("display", "inline"); + changeStyle: function* (testActor) { + yield testActor.eval(` + content.document.styleSheets[0] + .cssRules[0].style + .setProperty("display", "inline"); + `); }, after: true }, @@ -70,9 +84,11 @@ const TEST_DATA = [ desc: "Hiding a node by adding a new rule to a stylesheet", selector: "#hidden-via-stylesheet", before: true, - changeStyle: (doc, node) => { - doc.styleSheets[0].insertRule( - "#hidden-via-stylesheet {display: none;}", 1); + changeStyle: function* (testActor) { + yield testActor.eval(` + content.document.styleSheets[0].insertRule( + "#hidden-via-stylesheet {display: none;}", 1); + `); }, after: false }, @@ -80,25 +96,29 @@ const TEST_DATA = [ desc: "Hiding a node by adding a class that matches an existing rule", selector: "#normal-div", before: true, - changeStyle: (doc, node) => { - doc.styleSheets[0].insertRule( - ".a-new-class {display: none;}", 2); - node.classList.add("a-new-class"); + changeStyle: function* (testActor) { + yield testActor.eval(` + content.document.styleSheets[0].insertRule( + ".a-new-class {display: none;}", 2); + content.document.querySelector("#normal-div") + .classList.add("a-new-class"); + `); }, after: false } ]; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); for (let data of TEST_DATA) { info("Running test case: " + data.desc); - yield runTestData(inspector, data); + yield runTestData(inspector, testActor, data); } }); -function* runTestData(inspector, {selector, before, changeStyle, after}) { +function* runTestData(inspector, testActor, + {selector, before, changeStyle, after}) { info("Getting the " + selector + " test node"); let nodeFront = yield getNodeFront(selector, inspector); let container = getContainerForNodeFront(nodeFront, inspector); @@ -110,7 +130,7 @@ function* runTestData(inspector, {selector, before, changeStyle, after}) { inspector.markup.walker.once("display-change", onDisplayChanged.resolve); info("Making style changes"); - changeStyle(content.document, getNode(selector)); + yield changeStyle(testActor); let nodes = yield onDisplayChanged.promise; info("Verifying that the list of changed nodes include our container"); diff --git a/devtools/client/inspector/markup/test/browser_markup_pagesize_01.js b/devtools/client/inspector/markup/test/browser_markup_pagesize_01.js index dd3a1311fe..a9ba9fc050 100644 --- a/devtools/client/inspector/markup/test/browser_markup_pagesize_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_pagesize_01.js @@ -37,7 +37,7 @@ const TEST_DATA = [{ expected: "*more*uvwxy*more*" }]; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Start iterating through the test data"); diff --git a/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js b/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js index b5be179f6a..549a36b0db 100644 --- a/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_pagesize_02.js @@ -13,19 +13,19 @@ const TEST_URL = URL_ROOT + "doc_markup_pagesize_02.html"; // Make sure nodes are hidden when there are more than 5 in a row Services.prefs.setIntPref("devtools.markup.pagesize", 5); -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Selecting the UL node"); yield clickContainer("ul", inspector); info("Reloading the page with the UL node selected will expand its children"); - yield reloadPage(inspector); + yield reloadPage(inspector, testActor); yield inspector.markup._waitForChildren(); info("Click on the 'show all nodes' button in the UL's list of children"); yield showAllNodes(inspector); - yield assertAllNodesAreVisible(inspector); + yield assertAllNodesAreVisible(inspector, testActor); }); function* showAllNodes(inspector) { @@ -38,9 +38,10 @@ function* showAllNodes(inspector) { yield inspector.markup._waitForChildren(); } -function* assertAllNodesAreVisible(inspector) { +function* assertAllNodesAreVisible(inspector, testActor) { let container = yield getContainerForSelector("ul", inspector); ok(!container.elt.querySelector("button"), "All nodes button isn't here anymore"); - is(container.children.childNodes.length, getNode("ul").children.length); + let numItems = yield testActor.getNumberOfElementMatches("ul > *"); + is(container.children.childNodes.length, numItems); } diff --git a/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js b/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js index 9db222b693..7d6d034e37 100644 --- a/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js +++ b/devtools/client/inspector/markup/test/browser_markup_remove_xul_attributes.js @@ -9,20 +9,21 @@ const TEST_URL = URL_ROOT + "doc_markup_xul.xul"; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); - let panel = yield getNode("#test", inspector); let panelFront = yield getNodeFront("#test", inspector); - ok(panelFront.hasAttribute("id"), "panelFront has id attribute in the beginning"); info("Removing panel's id attribute"); - panel.removeAttribute("id"); + let onMutation = inspector.once("markupmutation"); + let onInspectorUpdated = inspector.once("inspector-updated"); + yield testActor.removeAttribute("#test", "id"); - info("Waiting for markupmutation"); - yield inspector.once("markupmutation"); + info("Waiting for markupmutation and inspector-updated"); + yield onMutation; + yield onInspectorUpdated; is(panelFront.hasAttribute("id"), false, "panelFront doesn't have id attribute anymore"); diff --git a/devtools/client/inspector/markup/test/browser_markup_search_01.js b/devtools/client/inspector/markup/test/browser_markup_search_01.js index 4a50181315..68f0c04db6 100644 --- a/devtools/client/inspector/markup/test/browser_markup_search_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_search_01.js @@ -10,7 +10,7 @@ const TEST_URL = URL_ROOT + "doc_markup_search.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); let container = yield getContainerForSelector("em", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_01.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_01.js index cbd1c2c8c4..b1b4f7115b 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_01.js @@ -62,7 +62,7 @@ var TEST_DATA = [{ } }]; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield runEditAttributesTests(TEST_DATA, inspector, testActor); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js index 27eb407ca9..f6f89bcb92 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_02.js @@ -9,7 +9,7 @@ const TEST_URL = `data:text/html,
Test modifying my ID attribute
`; -add_task(function*() { +add_task(function* () { info("Opening the inspector on the test page"); let {inspector, testActor} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js index bad15b7530..058fd80c7f 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_03.js @@ -9,7 +9,7 @@ const TEST_URL = `data:text/html;charset=utf-8,
`; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield inspector.markup.expandAll(); @@ -21,11 +21,11 @@ add_task(function*() { let container = yield getContainerForSelector("#retag-me", inspector); ok(container.expanded, "The container is expanded"); - let parentInfo = yield getNodeInfo("#retag-me", testActor); + let parentInfo = yield testActor.getNodeInfo("#retag-me"); is(parentInfo.tagName.toLowerCase(), "div", "We've got #retag-me element, it's a DIV"); is(parentInfo.numChildren, 1, "#retag-me has one child"); - let childInfo = yield getNodeInfo("#retag-me > *", testActor); + let childInfo = yield testActor.getNodeInfo("#retag-me > *"); is(childInfo.attributes[0].value, "retag-me-2", "#retag-me's only child is #retag-me-2"); @@ -41,11 +41,11 @@ add_task(function*() { ok(container.selected, "The container is still selected"); info("Checking that the tagname change was done"); - parentInfo = yield getNodeInfo("#retag-me", testActor); + parentInfo = yield testActor.getNodeInfo("#retag-me"); is(parentInfo.tagName.toLowerCase(), "p", "The #retag-me element is now a P"); is(parentInfo.numChildren, 1, "#retag-me still has one child"); - childInfo = yield getNodeInfo("#retag-me > *", testActor); + childInfo = yield testActor.getNodeInfo("#retag-me > *"); is(childInfo.attributes[0].value, "retag-me-2", "#retag-me's only child is #retag-me-2"); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js index 2d4758218c..5337f74c9d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_04.js @@ -48,12 +48,14 @@ const TEST_DATA = [{ key: "back_space", focusedSelector: "#second" }, { - setup: function*(inspector) { + setup: function* (inspector, testActor) { // Removing the siblings of #first in order to test with an only child. let mutated = inspector.once("markupmutation"); - for (let node of content.document.querySelectorAll("#second, #third")) { - node.remove(); - } + yield testActor.eval(` + for (let node of content.document.querySelectorAll("#second, #third")) { + node.remove(); + } + `); yield mutated; }, selector: "#first", @@ -65,12 +67,12 @@ const TEST_DATA = [{ focusedSelector: "#parent" }]; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); for (let {setup, selector, key, focusedSelector} of TEST_DATA) { if (setup) { - yield setup(inspector); + yield setup(inspector, testActor); } yield checkDeleteAndSelection(inspector, key, selector, focusedSelector); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_05.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_05.js index 8001989c1a..54a1dab44a 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_05.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_05.js @@ -71,7 +71,7 @@ var TEST_DATA = [{ } }]; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_06.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_06.js index 026ff2c06a..8202bd0a29 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_06.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_06.js @@ -79,7 +79,7 @@ var TEST_DATA = [{ } }]; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js index 59d4bb5407..8de15a76f3 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_07.js @@ -48,7 +48,7 @@ var TEST_DATA = [{ expectedAttributes: { "style": DATA_URL_INLINE_STYLE }, - validate: (element, container, inspector) => { + validate: (container, inspector) => { let editor = container.editor; let visibleAttrText = editor.attrElements.get("style") .querySelector(".attr-value") @@ -62,7 +62,7 @@ var TEST_DATA = [{ expectedAttributes: { "data-long": LONG_ATTRIBUTE }, - validate: (element, container, inspector) => { + validate: (container, inspector) => { let editor = container.editor; let visibleAttrText = editor.attrElements.get("data-long") .querySelector(".attr-value") @@ -76,7 +76,7 @@ var TEST_DATA = [{ expectedAttributes: { "src": DATA_URL_ATTRIBUTE }, - validate: (element, container, inspector) => { + validate: (container, inspector) => { let editor = container.editor; let visibleAttrText = editor.attrElements.get("src") .querySelector(".attr-value").textContent; @@ -92,7 +92,7 @@ var TEST_DATA = [{ setUp: function(inspector) { Services.prefs.setBoolPref("devtools.markup.collapseAttributes", false); }, - validate: (element, container, inspector) => { + validate: (container, inspector) => { let editor = container.editor; let visibleAttrText = editor.attrElements .get("data-long") @@ -112,7 +112,7 @@ var TEST_DATA = [{ setUp: function(inspector) { Services.prefs.setIntPref("devtools.markup.collapseAttributeLength", 2); }, - validate: (element, container, inspector) => { + validate: (container, inspector) => { let firstChar = LONG_ATTRIBUTE[0]; let lastChar = LONG_ATTRIBUTE[LONG_ATTRIBUTE.length - 1]; let collapsed = firstChar + "\u2026" + lastChar; @@ -128,7 +128,7 @@ var TEST_DATA = [{ } }]; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor); }); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js index de3712e345..9c8a4f96be 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_08.js @@ -13,7 +13,7 @@ const LONG_ATTRIBUTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-AB const LONG_ATTRIBUTE_COLLAPSED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEF\u2026UVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /*eslint-enable */ -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield inspector.markup.expandAll(); @@ -27,8 +27,8 @@ function* testCollapsedLongAttribute(inspector, testActor) { info("Adding test attributes to the node"); let onMutated = inspector.once("markupmutation"); - yield setNodeAttribute("#node24", "class", "", testActor); - yield setNodeAttribute("#node24", "data-long", LONG_ATTRIBUTE, testActor); + yield testActor.setAttribute("#node24", "class", ""); + yield testActor.setAttribute("#node24", "data-long", LONG_ATTRIBUTE); yield onMutated; yield assertAttributes("#node24", { diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js index bebb2c55f0..c34f85f36b 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_09.js @@ -8,7 +8,7 @@ const TEST_URL = URL_ROOT + "doc_markup_svg_attributes.html"; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield inspector.markup.expandAll(); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js index 6994afca98..728a71d2e7 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_10.js @@ -8,7 +8,7 @@ const TEST_URL = "data:text/html;charset=utf-8,
"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); yield inspector.markup.expandAll(); yield selectNode("div", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js index 015b10243e..56f741851c 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_11.js @@ -9,7 +9,7 @@ const TEST_URL = "data:text/html;charset=utf-8,
"; -add_task(function*() { +add_task(function* () { let isEditTagNameCalled = false; let {inspector} = yield openInspectorForURL(TEST_URL); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js index d8f07a9f9c..5f746a7cd9 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_12.js @@ -11,7 +11,7 @@ const TEST_URL = "data:text/html;charset=utf8," + "
" + "
"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); yield testAttributeEditing(inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_tag_edit_13-other.js b/devtools/client/inspector/markup/test/browser_markup_tag_edit_13-other.js index 5c27620d99..188e12cbc4 100644 --- a/devtools/client/inspector/markup/test/browser_markup_tag_edit_13-other.js +++ b/devtools/client/inspector/markup/test/browser_markup_tag_edit_13-other.js @@ -9,7 +9,7 @@ const TEST_URL = `data:text/html;charset=utf8,
`; -add_task(function*() { +add_task(function* () { let {inspector, testActor} = yield openInspectorForURL(TEST_URL); yield testOriginalAttributesOrder(inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js index 90941629fc..adbe4d606d 100644 --- a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_01.js @@ -8,37 +8,48 @@ const TEST_URL = URL_ROOT + "doc_markup_edit.html"; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Expanding all nodes"); yield inspector.markup.expandAll(); yield waitForMultipleChildrenUpdates(inspector); - yield editContainer(inspector, { + yield editContainer(inspector, testActor, { selector: ".node6", newValue: "New text", oldValue: "line6" }); - yield editContainer(inspector, { + yield editContainer(inspector, testActor, { selector: "#node17", - newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.", - oldValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec posuere placerat magna et imperdiet.", + newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " + + "DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.", + oldValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " + + "Donec posuere placerat magna et imperdiet.", shortValue: true }); - yield editContainer(inspector, { + yield editContainer(inspector, testActor, { selector: "#node17", newValue: "New value", - oldValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.", + oldValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " + + "DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.", shortValue: true }); }); -function* editContainer(inspector, {selector, newValue, oldValue, shortValue}) { - let node = getNode(selector).firstChild; - is(node.nodeValue, oldValue, "The test node's text content is correct"); +function* getNodeValue(selector, testActor) { + let nodeValue = yield testActor.eval(` + content.document.querySelector("${selector}").firstChild.nodeValue; + `); + return nodeValue; +} + +function* editContainer(inspector, testActor, + {selector, newValue, oldValue, shortValue}) { + let nodeValue = yield getNodeValue(selector, testActor); + is(nodeValue, oldValue, "The test node's text content is correct"); info("Changing the text content"); let onMutated = inspector.once("markupmutation"); @@ -46,7 +57,9 @@ function* editContainer(inspector, {selector, newValue, oldValue, shortValue}) { let field = container.elt.querySelector("pre"); if (shortValue) { - is(oldValue.indexOf(field.textContent.substring(0, field.textContent.length - 1)), 0, + is(oldValue.indexOf( + field.textContent.substring(0, field.textContent.length - 1)), + 0, "The shortened value starts with the full value " + field.textContent); ok(oldValue.length > field.textContent.length, "The shortened value is short"); @@ -69,7 +82,8 @@ function* editContainer(inspector, {selector, newValue, oldValue, shortValue}) { info("Listening to the markupmutation event"); yield onMutated; - is(node.nodeValue, newValue, "The test node's text content has changed"); + nodeValue = yield getNodeValue(selector, testActor); + is(nodeValue, newValue, "The test node's text content has changed"); info("Selecting the to reset the selection"); let bodyContainer = yield getContainerForSelector("body", inspector); diff --git a/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_02.js b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_02.js new file mode 100644 index 0000000000..c55ab59c6e --- /dev/null +++ b/devtools/client/inspector/markup/test/browser_markup_textcontent_edit_02.js @@ -0,0 +1,124 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that using UP/DOWN next to a number when editing a text node does not +// increment or decrement but simply navigates inside the editable field. + +const TEST_URL = URL_ROOT + "doc_markup_edit.html"; +const SELECTOR = ".node6"; + +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); + + info("Expanding all nodes"); + yield inspector.markup.expandAll(); + yield waitForMultipleChildrenUpdates(inspector); + + let nodeValue = yield getNodeValue(SELECTOR, testActor); + let expectedValue = "line6"; + is(nodeValue, expectedValue, "The test node's text content is correct"); + + info("Open editable field for .node6"); + let nodeFront = yield getNodeFront(SELECTOR, inspector); + let container = getContainerForNodeFront(nodeFront, inspector); + let field = container.elt.querySelector("pre"); + field.focus(); + EventUtils.sendKey("return", inspector.panelWin); + let editor = inplaceEditor(field); + + info("Initially, all the input content should be selected"); + checkSelectionPositions(editor, 0, expectedValue.length); + + info("Navigate using 'RIGHT': move the caret to the end"); + yield sendKey("VK_RIGHT", {}, editor, inspector.panelWin); + is(editor.input.value, expectedValue, "Value should not have changed"); + checkSelectionPositions(editor, expectedValue.length, expectedValue.length); + + info("Navigate using 'DOWN': no effect, already at the end"); + yield sendKey("VK_DOWN", {}, editor, inspector.panelWin); + is(editor.input.value, expectedValue, "Value should not have changed"); + checkSelectionPositions(editor, expectedValue.length, expectedValue.length); + + info("Navigate using 'UP': move to the start"); + yield sendKey("VK_UP", {}, editor, inspector.panelWin); + is(editor.input.value, expectedValue, "Value should not have changed"); + checkSelectionPositions(editor, 0, 0); + + info("Navigate using 'DOWN': move to the end"); + yield sendKey("VK_DOWN", {}, editor, inspector.panelWin); + is(editor.input.value, expectedValue, "Value should not have changed"); + checkSelectionPositions(editor, expectedValue.length, expectedValue.length); + + info("Type 'b' in the editable field"); + yield sendKey("b", {}, editor, inspector.panelWin); + expectedValue += "b"; + is(editor.input.value, expectedValue, "Value should be updated"); + + info("Type 'a' in the editable field"); + yield sendKey("a", {}, editor, inspector.panelWin); + expectedValue += "a"; + is(editor.input.value, expectedValue, "Value should be updated"); + + info("Create a new line using shift+RETURN"); + yield sendKey("VK_RETURN", {shiftKey: true}, editor, inspector.panelWin); + expectedValue += "\n"; + is(editor.input.value, expectedValue, "Value should have a new line"); + checkSelectionPositions(editor, expectedValue.length, expectedValue.length); + + info("Type '1' in the editable field"); + yield sendKey("1", {}, editor, inspector.panelWin); + expectedValue += "1"; + is(editor.input.value, expectedValue, "Value should be updated"); + checkSelectionPositions(editor, expectedValue.length, expectedValue.length); + + info("Navigate using 'UP': move back to the first line"); + yield sendKey("VK_UP", {}, editor, inspector.panelWin); + is(editor.input.value, expectedValue, "Value should not have changed"); + info("Caret should be back on the first line"); + checkSelectionPositions(editor, 1, 1); + + info("Commit the new value with RETURN, wait for the markupmutation event"); + let onMutated = inspector.once("markupmutation"); + yield sendKey("VK_RETURN", {}, editor, inspector.panelWin); + yield onMutated; + + nodeValue = yield getNodeValue(SELECTOR, testActor); + is(nodeValue, expectedValue, "The test node's text content is correct"); +}); + +function* getNodeValue(selector, testActor) { + let nodeValue = yield testActor.eval(` + content.document.querySelector("${selector}").firstChild.nodeValue; + `); + return nodeValue; +} + +/** + * Check that the editor selection is at the expected positions. + */ +function checkSelectionPositions(editor, expectedStart, expectedEnd) { + is(editor.input.selectionStart, expectedStart, + "Selection should start at " + expectedStart); + is(editor.input.selectionEnd, expectedEnd, + "Selection should end at " + expectedEnd); +} + +/** + * Send a key and expect to receive a keypress event on the editor's input. + */ +function sendKey(key, options, editor, win) { + return new Promise(resolve => { + info("Adding event listener for down|left|right|back_space|return keys"); + editor.input.addEventListener("keypress", function onKeypress() { + if (editor.input) { + editor.input.removeEventListener("keypress", onKeypress); + } + executeSoon(resolve); + }); + + EventUtils.synthesizeKey(key, options, win); + }); +} diff --git a/devtools/client/inspector/markup/test/browser_markup_toggle_01.js b/devtools/client/inspector/markup/test/browser_markup_toggle_01.js index e2b8418095..a481f685e8 100644 --- a/devtools/client/inspector/markup/test/browser_markup_toggle_01.js +++ b/devtools/client/inspector/markup/test/browser_markup_toggle_01.js @@ -8,8 +8,8 @@ const TEST_URL = URL_ROOT + "doc_markup_toggle.html"; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Getting the container for the html element"); let container = yield getContainerForSelector("html", inspector); @@ -32,7 +32,8 @@ add_task(function*() { yield onUpdated; info("Checking that child LI elements have been created"); - for (let i = 0; i < content.document.querySelectorAll("li").length; i++) { + let numLi = yield testActor.getNumberOfElementMatches("li"); + for (let i = 0; i < numLi; i++) { let liContainer = yield getContainerForSelector( `li:nth-child(${i + 1})`, inspector); ok(liContainer, "A container for the child LI element was created"); @@ -46,7 +47,8 @@ add_task(function*() { inspector.markup.doc.defaultView); info("Checking that child LI elements have been hidden"); - for (let i = 0; i < content.document.querySelectorAll("li").length; i++) { + numLi = yield testActor.getNumberOfElementMatches("li"); + for (let i = 0; i < numLi; i++) { let liContainer = yield getContainerForSelector( `li:nth-child(${i + 1})`, inspector); is(liContainer.elt.getClientRects().length, 0, diff --git a/devtools/client/inspector/markup/test/browser_markup_toggle_02.js b/devtools/client/inspector/markup/test/browser_markup_toggle_02.js index 3851ba879d..481f0bf58b 100644 --- a/devtools/client/inspector/markup/test/browser_markup_toggle_02.js +++ b/devtools/client/inspector/markup/test/browser_markup_toggle_02.js @@ -8,8 +8,8 @@ const TEST_URL = URL_ROOT + "doc_markup_toggle.html"; -add_task(function*() { - let {inspector} = yield openInspectorForURL(TEST_URL); +add_task(function* () { + let {inspector, testActor} = yield openInspectorForURL(TEST_URL); info("Getting the container for the UL parent element"); let container = yield getContainerForSelector("ul", inspector); @@ -23,7 +23,8 @@ add_task(function*() { yield onUpdated; info("Checking that child LI elements have been created"); - for (let i = 0; i < content.document.querySelectorAll("li").length; i++) { + let numLi = yield testActor.getNumberOfElementMatches("li"); + for (let i = 0; i < numLi; i++) { let liContainer = yield getContainerForSelector( "li:nth-child(" + (i + 1) + ")", inspector); ok(liContainer, "A container for the child LI element was created"); @@ -37,7 +38,8 @@ add_task(function*() { inspector.markup.doc.defaultView); info("Checking that child LI elements have been hidden"); - for (let i = 0; i < content.document.querySelectorAll("li").length; i++) { + numLi = yield testActor.getNumberOfElementMatches("li"); + for (let i = 0; i < numLi; i++) { let liContainer = yield getContainerForSelector( "li:nth-child(" + (i + 1) + ")", inspector); is(liContainer.elt.getClientRects().length, 0, diff --git a/devtools/client/inspector/markup/test/browser_markup_toggle_03.js b/devtools/client/inspector/markup/test/browser_markup_toggle_03.js index e1c34c40a2..fb3529c8e0 100644 --- a/devtools/client/inspector/markup/test/browser_markup_toggle_03.js +++ b/devtools/client/inspector/markup/test/browser_markup_toggle_03.js @@ -9,7 +9,7 @@ const TEST_URL = URL_ROOT + "doc_markup_toggle.html"; -add_task(function*() { +add_task(function* () { let {inspector} = yield openInspectorForURL(TEST_URL); info("Getting the container for the UL parent element"); diff --git a/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js b/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js index 038ec5a953..55e771599f 100644 --- a/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js +++ b/devtools/client/inspector/markup/test/browser_markup_update-on-navigtion.js @@ -10,13 +10,13 @@ const URL_1 = SCHEMA + "
ONE
"; const URL_2 = SCHEMA + "
TWO
"; add_task(function* () { - let { inspector, toolbox } = yield openInspectorForURL(URL_1); + let {inspector, testActor} = yield openInspectorForURL(URL_1); assertMarkupViewIsLoaded(); yield selectNode("#one", inspector); - let willNavigate = toolbox.target.once("will-navigate"); - content.location = URL_2; + let willNavigate = inspector.toolbox.target.once("will-navigate"); + yield testActor.eval(`content.location = "${URL_2}"`); info("Waiting for will-navigate"); yield willNavigate; diff --git a/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html b/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html new file mode 100644 index 0000000000..c1e4e4ff0e --- /dev/null +++ b/devtools/client/inspector/markup/test/doc_markup_image_and_canvas_2.html @@ -0,0 +1,25 @@ + + + + + Image and Canvas markup-view test + + + + + + + + + diff --git a/devtools/client/inspector/markup/test/head.js b/devtools/client/inspector/markup/test/head.js index 4d241a6e65..3f7aa58209 100644 --- a/devtools/client/inspector/markup/test/head.js +++ b/devtools/client/inspector/markup/test/head.js @@ -20,7 +20,9 @@ SimpleTest.requestCompleteLog(); // Set the testing flag on DevToolsUtils and reset it when the test ends DevToolsUtils.testing = true; -registerCleanupFunction(() => DevToolsUtils.testing = false); +registerCleanupFunction(() => { + DevToolsUtils.testing = false; +}); // Clear preferences that may be set during the course of tests. registerCleanupFunction(() => { @@ -52,75 +54,13 @@ function loadHelperScript(filePath) { * @return a promise that resolves when the inspector has emitted the event * new-root */ -function reloadPage(inspector) { +function reloadPage(inspector, testActor) { info("Reloading the page"); let newRoot = inspector.once("new-root"); - content.location.reload(); + testActor.reload(); return newRoot; } -/** - * Reload the current tab location. - * @param {TestActorFront} testActor An instance of the current TestActorFront - * instantiated when the test started. - */ -function reloadTab(testActor) { - return testActor.eval("location.reload()"); -} - -/** - * Simple DOM node accesor function that takes either a node or a string css - * selector as argument and returns the corresponding node - * @param {String|DOMNode} nodeOrSelector - * @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which - * doesn't implement *all* of the DOMNode's properties - */ -function getNode(nodeOrSelector) { - info("Getting the node for '" + nodeOrSelector + "'"); - return typeof nodeOrSelector === "string" ? - content.document.querySelector(nodeOrSelector) : - nodeOrSelector; -} - -/** - * Get information about a DOM element, identified by its selector. - * @param {String} selector. - * @return {Promise} a promise that resolves to the element's information. - */ -function getNodeInfo(selector, testActor) { - return testActor.getNodeInfo(selector); -} - -/** - * Set the value of an attribute of a DOM element, identified by its selector. - * @param {String} selector. - * @param {String} attributeName. - * @param {String} attributeValue. - * @param {TestActorFront} testActor The current TestActorFront instance. - * @return {Promise} resolves when done. - */ -function setNodeAttribute(selector, attributeName, attributeValue, testActor) { - return testActor.setAttribute(selector, attributeName, attributeValue); -} - -/** - * Highlight a node and set the inspector's current selection to the node or - * the first match of the given css selector. - * @param {String|DOMNode} nodeOrSelector - * @param {InspectorPanel} inspector - * The instance of InspectorPanel currently loaded in the toolbox - * @return a promise that resolves when the inspector is updated with the new - * node - */ -function selectAndHighlightNode(nodeOrSelector, inspector) { - info("Highlighting and selecting the node " + nodeOrSelector); - - let node = getNode(nodeOrSelector); - let updated = inspector.toolbox.once("highlighter-ready"); - inspector.selection.setNode(node, "test-highlight"); - return updated; -} - /** * Get the MarkupContainer object instance that corresponds to the given * NodeFront @@ -141,7 +81,7 @@ function getContainerForNodeFront(nodeFront, {markup}) { * loaded in the toolbox * @return {MarkupContainer} */ -var getContainerForSelector = Task.async(function*(selector, inspector) { +var getContainerForSelector = Task.async(function* (selector, inspector) { info("Getting the markup-container for node " + selector); let nodeFront = yield getNodeFront(selector, inspector); let container = getContainerForNodeFront(nodeFront, inspector); @@ -174,7 +114,7 @@ function waitForChildrenUpdated({markup}) { * loaded in the toolbox * @return {Promise} Resolves when the node has been selected. */ -var clickContainer = Task.async(function*(selector, inspector) { +var clickContainer = Task.async(function* (selector, inspector) { info("Clicking on the markup-container for node " + selector); let nodeFront = yield getNodeFront(selector, inspector); @@ -217,7 +157,7 @@ function setEditableFieldValue(field, value, inspector) { * loaded in the toolbox * @return a promise that resolves when the node has mutated */ -var addNewAttributes = Task.async(function*(selector, text, inspector) { +var addNewAttributes = Task.async(function* (selector, text, inspector) { info(`Entering text "${text}" in new attribute field for node ${selector}`); let container = yield getContainerForSelector(selector, inspector); @@ -240,8 +180,8 @@ var addNewAttributes = Task.async(function*(selector, text, inspector) { * Note that node.getAttribute() returns attribute values provided by the HTML * parser. The parser only provides unescaped entities so & will return &. */ -var assertAttributes = Task.async(function*(selector, expected, testActor) { - let {attributes: actual} = yield getNodeInfo(selector, testActor); +var assertAttributes = Task.async(function* (selector, expected, testActor) { + let {attributes: actual} = yield testActor.getNodeInfo(selector); is(actual.length, Object.keys(expected).length, "The node " + selector + " has the expected number of attributes."); @@ -325,7 +265,7 @@ function searchUsingSelectorSearch(selector, inspector) { */ function wait(ms) { let def = promise.defer(); - content.setTimeout(def.resolve, ms); + setTimeout(def.resolve, ms); return def.promise; } @@ -339,7 +279,7 @@ function wait(ms) { * the menu items are disabled once the menu has been checked. */ var isEditingMenuDisabled = Task.async( -function*(nodeFront, inspector, assert = true) { +function* (nodeFront, inspector, assert = true) { let doc = inspector.panelDoc; let deleteMenuItem = doc.getElementById("node-menu-delete"); let editHTMLMenuItem = doc.getElementById("node-menu-edithtml"); @@ -377,7 +317,7 @@ function*(nodeFront, inspector, assert = true) { * the menu items are enabled once the menu has been checked. */ var isEditingMenuEnabled = Task.async( -function*(nodeFront, inspector, assert = true) { +function* (nodeFront, inspector, assert = true) { let doc = inspector.panelDoc; let deleteMenuItem = doc.getElementById("node-menu-delete"); let editHTMLMenuItem = doc.getElementById("node-menu-edithtml"); @@ -410,7 +350,7 @@ function*(nodeFront, inspector, assert = true) { * @param {DOMNode} menu A menu that implements hidePopup/openPopup * @return a promise that resolves once the menu is opened. */ -var reopenMenu = Task.async(function*(menu) { +var reopenMenu = Task.async(function* (menu) { // First close it is if it is already opened. if (menu.state == "closing" || menu.state == "open") { let popuphidden = once(menu, "popuphidden", true); @@ -484,7 +424,7 @@ function checkFocusedAttribute(attrName, editMode) { * A promise that resolves with an array of attribute names * (e.g. ["id", "class", "href"]) */ -var getAttributesFromEditor = Task.async(function*(selector, inspector) { +var getAttributesFromEditor = Task.async(function* (selector, inspector) { let nodeList = (yield getContainerForSelector(selector, inspector)) .tagLine.querySelectorAll("[data-attr]"); @@ -502,6 +442,7 @@ function* waitForMultipleChildrenUpdates(inspector) { yield waitForChildrenUpdated(inspector); return yield waitForMultipleChildrenUpdates(inspector); } + return undefined; } /** diff --git a/devtools/client/inspector/markup/test/helper_attributes_test_runner.js b/devtools/client/inspector/markup/test/helper_attributes_test_runner.js index 7cee64d19c..4a49d5ea66 100644 --- a/devtools/client/inspector/markup/test/helper_attributes_test_runner.js +++ b/devtools/client/inspector/markup/test/helper_attributes_test_runner.js @@ -23,7 +23,7 @@ */ function runAddAttributesTests(tests, nodeOrSelector, inspector, testActor) { info("Running " + tests.length + " add-attributes tests"); - return Task.spawn(function*() { + return Task.spawn(function* () { info("Selecting the test node"); yield selectNode("div", inspector); @@ -58,7 +58,6 @@ function* runAddAttributesTest(test, selector, inspector, testActor) { if (test.setUp) { test.setUp(inspector); } - let element = getNode(selector); info("Starting add-attribute test: " + test.desc); yield addNewAttributes(selector, test.text, inspector); @@ -68,7 +67,7 @@ function* runAddAttributesTest(test, selector, inspector, testActor) { if (test.validate) { let container = yield getContainerForSelector(selector, inspector); - test.validate(element, container, inspector); + test.validate(container, inspector); } info("Undo the change"); @@ -97,7 +96,7 @@ function* runAddAttributesTest(test, selector, inspector, testActor) { */ function runEditAttributesTests(tests, inspector, testActor) { info("Running " + tests.length + " edit-attributes tests"); - return Task.spawn(function*() { + return Task.spawn(function* () { info("Expanding all nodes in the markup-view"); yield inspector.markup.expandAll(); diff --git a/devtools/client/inspector/markup/test/helper_events_test_runner.js b/devtools/client/inspector/markup/test/helper_events_test_runner.js index 95300e07e5..d7072b30a2 100644 --- a/devtools/client/inspector/markup/test/helper_events_test_runner.js +++ b/devtools/client/inspector/markup/test/helper_events_test_runner.js @@ -70,8 +70,7 @@ function* checkEventsForNode(test, inspector, testActor) { info("tooltip shown"); // Check values - let content = tooltip.content; - let headers = content.querySelectorAll(".event-header"); + let headers = tooltip.content.querySelectorAll(".event-header"); let nodeFront = container.node; let cssSelector = nodeFront.nodeName + "#" + nodeFront.id; diff --git a/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js b/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js index e250c85908..a7f21b82af 100644 --- a/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js +++ b/devtools/client/inspector/markup/test/helper_outerhtml_test_runner.js @@ -22,7 +22,7 @@ function runEditOuterHTMLTests(tests, inspector, testActor) { info("Running " + tests.length + " edit-outer-html tests"); return Task.spawn(function* () { - for (let step of TEST_DATA) { + for (let step of tests) { yield runEditOuterHTMLTest(step, inspector, testActor); } }); @@ -59,14 +59,14 @@ function* runEditOuterHTMLTest(test, inspector, testActor) { let selectedNodeFront = inspector.selection.nodeFront; let pageNodeFront = yield inspector.walker.querySelector( inspector.walker.rootNode, test.selector); - let pageNode = getNode(test.selector); if (test.validate) { - yield test.validate(pageNode, pageNodeFront, selectedNodeFront, inspector); + yield test.validate({pageNodeFront, selectedNodeFront, + inspector, testActor}); } else { is(pageNodeFront, selectedNodeFront, "Original node (grabbed by selector) is selected"); - let {outerHTML} = yield getNodeInfo(test.selector, testActor); + let {outerHTML} = yield testActor.getNodeInfo(test.selector); is(outerHTML, test.newHTML, "Outer HTML has been updated"); } diff --git a/devtools/client/inspector/rules/models/element-style.js b/devtools/client/inspector/rules/models/element-style.js index fed8eee44f..395d548558 100644 --- a/devtools/client/inspector/rules/models/element-style.js +++ b/devtools/client/inspector/rules/models/element-style.js @@ -130,6 +130,8 @@ ElementStyle.prototype = { r.editor.destroy(); } } + + return undefined; }).then(null, e => { // populate is often called after a setTimeout, // the connection may already be closed. diff --git a/devtools/client/inspector/rules/rules.js b/devtools/client/inspector/rules/rules.js index e6181e59dd..e268c3d8af 100644 --- a/devtools/client/inspector/rules/rules.js +++ b/devtools/client/inspector/rules/rules.js @@ -265,7 +265,7 @@ CssRuleView.prototype = { * * @return {Promise} Resolves to the instance of the highlighter. */ - getSelectorHighlighter: Task.async(function*() { + getSelectorHighlighter: Task.async(function* () { let utils = this.inspector.toolbox.highlighterUtils; if (!utils.supportsCustomHighlighters()) { return null; @@ -323,7 +323,7 @@ CssRuleView.prototype = { }, Cu.reportError); }, - highlightSelector: Task.async(function*(selector) { + highlightSelector: Task.async(function* (selector) { let node = this.inspector.selection.nodeFront; let highlighter = yield this.getSelectorHighlighter(); @@ -338,7 +338,7 @@ CssRuleView.prototype = { }); }), - unhighlightSelector: Task.async(function*() { + unhighlightSelector: Task.async(function* () { let highlighter = yield this.getSelectorHighlighter(); if (!highlighter) { return; @@ -466,7 +466,8 @@ CssRuleView.prototype = { try { let text = ""; - if (target && target.nodeName === "input") { + let nodeName = target && target.nodeName; + if (nodeName === "input" || nodeName == "textarea") { let start = Math.min(target.selectionStart, target.selectionEnd); let end = Math.max(target.selectionStart, target.selectionEnd); let count = end - start; @@ -877,6 +878,7 @@ CssRuleView.prototype = { if (this._elementStyle === elementStyle) { return this._populate(); } + return undefined; }).then(() => { if (this._elementStyle === elementStyle) { if (!refresh) { @@ -961,7 +963,7 @@ CssRuleView.prototype = { let elementStyle = this._elementStyle; return this._elementStyle.populate().then(() => { if (this._elementStyle !== elementStyle || this.isDestroyed) { - return; + return null; } this._clearRules(); @@ -1701,8 +1703,8 @@ RuleViewTool.prototype = { let target = this.inspector.target; if (Tools.styleEditor.isTargetSupported(target)) { gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) { - let sheet = source || href; - toolbox.getCurrentPanel().selectStyleSheet(sheet, line, column); + let url = source || href; + toolbox.getCurrentPanel().selectStyleSheet(url, line, column); }); } return; diff --git a/devtools/client/inspector/rules/test/browser.ini b/devtools/client/inspector/rules/test/browser.ini index 11c555aecd..5e331639b4 100644 --- a/devtools/client/inspector/rules/test/browser.ini +++ b/devtools/client/inspector/rules/test/browser.ini @@ -13,6 +13,9 @@ support-files = doc_custom.html doc_filter.html doc_frame_script.js + doc_inline_sourcemap.html + doc_invalid_sourcemap.css + doc_invalid_sourcemap.html doc_keyframeanimation.css doc_keyframeanimation.html doc_keyframeLineNumbers.html @@ -46,8 +49,11 @@ support-files = [browser_rules_add-rule_02.js] [browser_rules_add-rule_03.js] [browser_rules_add-rule_04.js] +[browser_rules_add-rule_05.js] [browser_rules_add-rule_pseudo_class.js] [browser_rules_authored.js] +[browser_rules_authored_color.js] +[browser_rules_authored_override.js] [browser_rules_colorpicker-and-image-tooltip_01.js] [browser_rules_colorpicker-and-image-tooltip_02.js] [browser_rules_colorpicker-appears-on-swatch-click.js] @@ -65,6 +71,7 @@ support-files = [browser_rules_completion-new-property_02.js] [browser_rules_completion-new-property_03.js] [browser_rules_completion-new-property_04.js] +[browser_rules_completion-new-property_multiline.js] [browser_rules_computed-lists_01.js] [browser_rules_computed-lists_02.js] [browser_rules_completion-popup-hidden-after-navigation.js] @@ -80,8 +87,10 @@ skip-if = e10s && debug && os == 'win' # Bug 1250058 - Docshell leak on win debu [browser_rules_cubicbezier-commit-on-ENTER.js] [browser_rules_cubicbezier-revert-on-ESC.js] [browser_rules_custom.js] +[browser_rules_cycle-angle.js] [browser_rules_cycle-color.js] [browser_rules_edit-property-cancel.js] +[browser_rules_edit-property-click.js] [browser_rules_edit-property-commit.js] [browser_rules_edit-property-computed.js] [browser_rules_edit-property-increments.js] @@ -99,6 +108,8 @@ skip-if = e10s && debug && os == 'win' # Bug 1250058 - Docshell leak on win debu [browser_rules_edit-property_08.js] [browser_rules_edit-property_09.js] [browser_rules_edit-selector-click.js] +[browser_rules_edit-selector-click-on-scrollbar.js] +skip-if = os == "mac" # Bug 1245996 : click on scrollbar not working on OSX [browser_rules_edit-selector-commit.js] [browser_rules_edit-selector_01.js] [browser_rules_edit-selector_02.js] @@ -118,6 +129,8 @@ skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s. [browser_rules_inherited-properties_01.js] [browser_rules_inherited-properties_02.js] [browser_rules_inherited-properties_03.js] +[browser_rules_inline-source-map.js] +[browser_rules_invalid-source-map.js] [browser_rules_keybindings.js] [browser_rules_keyframes-rule_01.js] [browser_rules_keyframes-rule_02.js] diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js b/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js index 39218018fd..90662e41a0 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js @@ -9,7 +9,7 @@ const TEST_URI = URL_ROOT + "doc_content_stylesheet.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URI); let {inspector, view} = yield openRuleView(); yield selectNode("#target", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js index 2098701651..c6ceab4fe5 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_01.js @@ -18,16 +18,13 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testCancelNew(view); -}); -function* testCancelNew(view) { let elementRuleEditor = getRuleViewRuleEditor(view, 0); - let editor = yield focusEditableField(view, elementRuleEditor.closeBrace); + let editor = yield focusNewRuleViewProperty(elementRuleEditor); is(inplaceEditor(elementRuleEditor.newPropSpan), editor, "The new property editor got focused"); @@ -37,12 +34,10 @@ function* testCancelNew(view) { yield onBlur; info("Checking the state of cancelling a new property name editor"); - ok(!elementRuleEditor.rule._applyingModifications, - "Shouldn't have an outstanding request after a cancel."); is(elementRuleEditor.rule.textProps.length, 0, "Should have cancelled creating a new text property."); ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties."); is(view.styleDocument.activeElement, view.styleDocument.documentElement, "Correct element has focus"); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_02.js b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_02.js index 08bc5c210c..58d22d07ce 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_02.js @@ -15,53 +15,18 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); info("Test creating a new property and escaping"); - - let elementRuleEditor = getRuleViewRuleEditor(view, 1); - - info("Focusing a new property name in the rule-view"); - let editor = yield focusEditableField(view, elementRuleEditor.closeBrace); - - is(inplaceEditor(elementRuleEditor.newPropSpan), editor, - "The new property editor got focused."); - - info("Entering a value in the property name editor"); - editor.input.value = "color"; - - info("Pressing return to commit and focus the new value field"); - let onValueFocus = once(elementRuleEditor.element, "focus", true); - let onRuleViewChanged = view.once("ruleview-changed"); - EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow); - yield onValueFocus; - yield onRuleViewChanged; - - // Getting the new value editor after focus - editor = inplaceEditor(view.styleDocument.activeElement); - let textProp = elementRuleEditor.rule.textProps[1]; - - is(elementRuleEditor.rule.textProps.length, 2, - "Created a new text property."); - is(elementRuleEditor.propertyList.children.length, 2, - "Created a property editor."); - is(editor, inplaceEditor(textProp.editor.valueSpan), - "Editing the value span now."); - - info("Entering a property value"); - editor.input.value = "red"; - - info("Escaping out of the field"); - onRuleViewChanged = view.once("ruleview-changed"); - EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); - yield onRuleViewChanged; + yield addProperty(view, 1, "color", "red", "VK_ESCAPE", false); is(view.styleDocument.documentElement, view.styleDocument.activeElement, "Correct element has focus"); + let elementRuleEditor = getRuleViewRuleEditor(view, 1); is(elementRuleEditor.rule.textProps.length, 1, "Removed the new text property."); is(elementRuleEditor.propertyList.children.length, 1, diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js index d903f9d0a8..9cb9dc2759 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-cancel_03.js @@ -9,29 +9,23 @@ const TEST_URI = ` -
Styled Node
+
Test node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); - yield selectNode("#testid", inspector); - yield testCancelNewOnEscape(inspector, view); -}); + yield selectNode("div", inspector); -function* testCancelNewOnEscape(inspector, view) { - // Start at the beginning: start to add a rule to the element's style - // declaration, add some text, then press escape. + // Add a property to the element's style declaration, add some text, + // then press escape. - let elementRuleEditor = getRuleViewRuleEditor(view, 0); - let editor = yield focusEditableField(view, elementRuleEditor.closeBrace); + let elementRuleEditor = getRuleViewRuleEditor(view, 1); + let editor = yield focusNewRuleViewProperty(elementRuleEditor); is(inplaceEditor(elementRuleEditor.newPropSpan), editor, "Next focused editor should be the new property editor."); @@ -42,12 +36,8 @@ function* testCancelNewOnEscape(inspector, view) { EventUtils.synthesizeKey("VK_ESCAPE", {}); yield onBlur; - ok(!elementRuleEditor.rule._applyingModifications, - "Shouldn't have an outstanding modification request after a cancel."); - is(elementRuleEditor.rule.textProps.length, 0, + is(elementRuleEditor.rule.textProps.length, 1, "Should have canceled creating a new text property."); - ok(!elementRuleEditor.propertyList.hasChildNodes(), - "Should not have any properties."); is(view.styleDocument.documentElement, view.styleDocument.activeElement, "Correct element has focus"); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-commented.js b/devtools/client/inspector/rules/test/browser_rules_add-property-commented.js index 6b847f85f7..eacf5db5a7 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-commented.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-commented.js @@ -8,7 +8,7 @@ const TEST_URI = "
"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property-svg.js b/devtools/client/inspector/rules/test/browser_rules_add-property-svg.js index 3c0c324a37..a53421db3a 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property-svg.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-svg.js @@ -9,53 +9,14 @@ var TEST_URL = "chrome://global/skin/icons/warning.svg"; var TEST_SELECTOR = "path"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URL); let {inspector, view} = yield openRuleView(); yield selectNode(TEST_SELECTOR, inspector); - yield testCreateNew(view); -}); -function* testCreateNew(ruleView) { info("Test creating a new property"); - - let elementRuleEditor = getRuleViewRuleEditor(ruleView, 0); - - info("Focusing a new property name in the rule-view"); - let editor = yield focusEditableField(ruleView, elementRuleEditor.closeBrace); - - is(inplaceEditor(elementRuleEditor.newPropSpan), editor, - "Next focused editor should be the new property editor."); - - let input = editor.input; - - info("Entering the property name"); - input.value = "fill"; - - info("Pressing RETURN and waiting for the value field focus"); - let onFocus = once(elementRuleEditor.element, "focus", true); - EventUtils.sendKey("return", ruleView.styleWindow); - yield onFocus; - yield elementRuleEditor.rule._applyingModifications; - - editor = inplaceEditor(ruleView.styleDocument.activeElement); - - is(elementRuleEditor.rule.textProps.length, 1, - "Should have created a new text property."); - is(elementRuleEditor.propertyList.children.length, 1, - "Should have created a property editor."); - let textProp = elementRuleEditor.rule.textProps[0]; - is(editor, inplaceEditor(textProp.editor.valueSpan), - "Should be editing the value span now."); - - editor.input.value = "red"; - let onBlur = once(editor.input, "blur"); - EventUtils.sendKey("return", ruleView.styleWindow); - yield onBlur; - yield elementRuleEditor.rule._applyingModifications; - - is(textProp.value, "red", "Text prop should have been changed."); + yield addProperty(view, 0, "fill", "red"); is((yield getComputedStyleProperty(TEST_SELECTOR, null, "fill")), - "rgb(255, 0, 0)", "The fill was changed to red"); -} + "rgb(255, 0, 0)", "The fill was changed to red"); +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_add-property_01.js b/devtools/client/inspector/rules/test/browser_rules_add-property_01.js index 80072a4fad..1d7068d54a 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-property_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property_01.js @@ -4,9 +4,7 @@ "use strict"; -// Testing various inplace-editor behaviors in the rule-view -// FIXME: To be split in several test files, and some of the inplace-editor -// focus/blur/commit/revert stuff should be factored out in head.js +// Test adding an invalid property. const TEST_URI = ` +
Styled Node
+ This is a span + Multiple classes + Multiple classes +

Empty

+

Invalid characters in class

+

Invalid characters in id

+`; + +const TEST_DATA = [ + { node: "#testid", expected: "#testid" }, + { node: ".testclass2", expected: ".testclass2" }, + { node: ".class1.class2", expected: ".class1.class2" }, + { node: ".class3.class4", expected: ".class3.class4" }, + { node: "p", expected: "p" }, + { node: "h1", expected: ".asd\\@\\@\\@\\@a\\!\\!\\!\\!\\:\\:\\:\\@asd" }, + { node: "h2", expected: "#asd\\@\\@\\@a\\!\\!2a" } +]; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view, testActor} = yield openRuleView(); + + for (let data of TEST_DATA) { + let {node, expected} = data; + yield selectNode(node, inspector); + yield addNewRuleFromContextMenu(inspector, view); + yield testNewRule(view, expected, 1); + + info("Resetting page content"); + yield testActor.eval( + "content.document.body.innerHTML = `" + TEST_URI + "`;"); + } +}); + +function* addNewRuleFromContextMenu(inspector, view) { + info("Waiting for context menu to be shown"); + let onPopup = once(view._contextmenu._menupopup, "popupshown"); + let win = view.styleWindow; + + EventUtils.synthesizeMouseAtCenter(view.element, + {button: 2, type: "contextmenu"}, win); + yield onPopup; + + ok(!view._contextmenu.menuitemAddRule.hidden, "Add rule is visible"); + + info("Adding the new rule"); + view._contextmenu.menuitemAddRule.click(); + view._contextmenu._menupopup.hidePopup(); + + info("Waiting for rule view to change"); + yield view.once("ruleview-changed"); +} + +function* testNewRule(view, expected, index) { + let idRuleEditor = getRuleViewRuleEditor(view, index); + let editor = idRuleEditor.selectorText.ownerDocument.activeElement; + is(editor.value, expected, + "Selector editor value is as expected: " + expected); + + info("Entering the escape key"); + EventUtils.synthesizeKey("VK_ESCAPE", {}); + + is(idRuleEditor.selectorText.textContent, expected, + "Selector text value is as expected: " + expected); + + info("Adding new properties to new rule: " + expected); + let onRuleViewChanged = view.once("ruleview-changed"); + idRuleEditor.addProperty("font-weight", "bold", ""); + yield onRuleViewChanged; + + let textProps = idRuleEditor.rule.textProps; + let lastRule = textProps[textProps.length - 1]; + is(lastRule.name, "font-weight", "Last rule name is font-weight"); + is(lastRule.value, "bold", "Last rule value is bold"); +} diff --git a/devtools/client/inspector/rules/test/browser_rules_add-rule_pseudo_class.js b/devtools/client/inspector/rules/test/browser_rules_add-rule_pseudo_class.js index 2b64aabcc7..30847982fb 100644 --- a/devtools/client/inspector/rules/test/browser_rules_add-rule_pseudo_class.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-rule_pseudo_class.js @@ -19,7 +19,7 @@ const TEST_DATA = [ [":focus"] ]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#element", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_authored.js b/devtools/client/inspector/rules/test/browser_rules_authored.js index f40dedb7b2..cb0dd11866 100644 --- a/devtools/client/inspector/rules/test/browser_rules_authored.js +++ b/devtools/client/inspector/rules/test/browser_rules_authored.js @@ -6,25 +6,19 @@ // Test for as-authored styles. -add_task(function*() { - yield basicTest(); - yield overrideTest(); - yield colorEditingTest(); -}); - function* createTestContent(style) { - let content = `
Styled Node
`; - yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(content)); + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(html)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); return view; } -function* basicTest() { +add_task(function* () { let view = yield createTestContent("#testid {" + // Invalid property. " something: random;" + @@ -52,78 +46,4 @@ function* basicTest() { is(prop.overridden, expected[i].overridden, "test overridden for prop " + i); } -} - -function* overrideTest() { - let gradientText = "(45deg, rgba(255,255,255,0.2) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.2) 75%, transparent 75%, transparent);"; - - let view = - yield createTestContent("#testid {" + - " background-image: -moz-linear-gradient" + - gradientText + - " background-image: -webkit-linear-gradient" + - gradientText + - " background-image: linear-gradient" + - gradientText + - "} "); - - let elementStyle = view._elementStyle; - let rule = elementStyle.rules[1]; - - // Initially the last property should be active. - for (let i = 0; i < 3; ++i) { - let prop = rule.textProps[i]; - is(prop.name, "background-image", "check the property name"); - is(prop.overridden, i !== 2, "check overridden for " + i); - } - - rule.textProps[2].setEnabled(false); - yield rule._applyingModifications; - - // Now the first property should be active. - for (let i = 0; i < 3; ++i) { - let prop = rule.textProps[i]; - is(prop.overridden || !prop.enabled, i !== 0, - "post-change check overridden for " + i); - } -} - -function* colorEditingTest() { - let colors = [ - {name: "hex", text: "#f0c", result: "#0f0"}, - {name: "rgb", text: "rgb(0,128,250)", result: "rgb(0, 255, 0)"}, - // Test case preservation. - {name: "hex", text: "#F0C", result: "#0F0"}, - ]; - - Services.prefs.setCharPref("devtools.defaultColorUnit", "authored"); - - for (let color of colors) { - let view = yield createTestContent("#testid {" + - " color: " + color.text + ";" + - "} "); - - let cPicker = view.tooltips.colorPicker; - let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan - .querySelector(".ruleview-colorswatch"); - let onShown = cPicker.tooltip.once("shown"); - swatch.click(); - yield onShown; - - let testNode = yield getNode("#testid"); - - yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], { - element: testNode, - name: "color", - value: "rgb(0, 255, 0)" - }); - - let spectrum = yield cPicker.spectrum; - let onHidden = cPicker.tooltip.once("hidden"); - EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); - yield onHidden; - - is(getRuleViewPropertyValue(view, "#testid", "color"), color.result, - "changing the color preserved the unit for " + color.name); - } -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_authored_color.js b/devtools/client/inspector/rules/test/browser_rules_authored_color.js new file mode 100644 index 0000000000..40c7bf7599 --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_authored_color.js @@ -0,0 +1,65 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for as-authored styles. + +function* createTestContent(style) { + let html = ` +
Styled Node
`; + let tab = yield addTab("data:text/html;charset=utf-8," + + encodeURIComponent(html)); + + let {inspector, view} = yield openRuleView(); + yield selectNode("#testid", inspector); + return {view, tab}; +} + +add_task(function* () { + let colors = [ + {name: "hex", text: "#f0c", result: "#0f0"}, + {name: "rgb", text: "rgb(0,128,250)", result: "rgb(0, 255, 0)"}, + // Test case preservation. + {name: "hex", text: "#F0C", result: "#0F0"}, + ]; + + Services.prefs.setCharPref("devtools.defaultColorUnit", "authored"); + + for (let color of colors) { + let {view, tab} = yield createTestContent("#testid {" + + " color: " + color.text + ";" + + "} "); + + let cPicker = view.tooltips.colorPicker; + let swatch = getRuleViewProperty(view, "#testid", "color").valueSpan + .querySelector(".ruleview-colorswatch"); + let onShown = cPicker.tooltip.once("shown"); + swatch.click(); + yield onShown; + + yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], { + selector: "#testid", + name: "color", + value: "rgb(0, 255, 0)" + }); + + let spectrum = yield cPicker.spectrum; + let onHidden = cPicker.tooltip.once("hidden"); + // Validating the color change ends up updating the rule view twice + let onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); + EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); + yield onHidden; + yield onRuleViewChanged; + + is(getRuleViewPropertyValue(view, "#testid", "color"), color.result, + "changing the color preserved the unit for " + color.name); + + let target = TargetFactory.forTab(tab); + yield gDevTools.closeToolbox(target); + gBrowser.removeCurrentTab(); + } +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_authored_override.js b/devtools/client/inspector/rules/test/browser_rules_authored_override.js new file mode 100644 index 0000000000..7305e57124 --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_authored_override.js @@ -0,0 +1,53 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for as-authored styles. + +function* createTestContent(style) { + let html = ` +
Styled Node
`; + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(html)); + + let {inspector, view} = yield openRuleView(); + yield selectNode("#testid", inspector); + return view; +} + +add_task(function* () { + let gradientText1 = "(orange, blue);"; + let gradientText2 = "(pink, teal);"; + + let view = + yield createTestContent("#testid {" + + " background-image: linear-gradient" + + gradientText1 + + " background-image: -ms-linear-gradient" + + gradientText2 + + " background-image: linear-gradient" + + gradientText2 + + "} "); + + let elementStyle = view._elementStyle; + let rule = elementStyle.rules[1]; + + // Initially the last property should be active. + for (let i = 0; i < 3; ++i) { + let prop = rule.textProps[i]; + is(prop.name, "background-image", "check the property name"); + is(prop.overridden, i !== 2, "check overridden for " + i); + } + + yield togglePropStatus(view, rule.textProps[2]); + + // Now the first property should be active. + for (let i = 0; i < 3; ++i) { + let prop = rule.textProps[i]; + is(prop.overridden || !prop.enabled, i !== 0, + "post-change check overridden for " + i); + } +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorUnit.js b/devtools/client/inspector/rules/test/browser_rules_colorUnit.js index 632290f9a6..3ff6495e22 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorUnit.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorUnit.js @@ -15,7 +15,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { let TESTS = [ {name: "hex", result: "#0f0"}, {name: "rgb", result: "rgb(0, 255, 0)"} @@ -25,11 +25,16 @@ add_task(function*() { info("starting test for " + name); Services.prefs.setCharPref("devtools.defaultColorUnit", name); - yield addTab("data:text/html;charset=utf-8," + - encodeURIComponent(TEST_URI)); + let tab = yield addTab("data:text/html;charset=utf-8," + + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); + yield selectNode("#testid", inspector); yield basicTest(view, name, result); + + let target = TargetFactory.forTab(tab); + yield gDevTools.closeToolbox(target); + gBrowser.removeCurrentTab(); } }); @@ -41,18 +46,19 @@ function* basicTest(view, name, result) { swatch.click(); yield onShown; - let testNode = yield getNode("#testid"); - yield simulateColorPickerChange(view, cPicker, [0, 255, 0, 1], { - element: testNode, + selector: "#testid", name: "color", value: "rgb(0, 255, 0)" }); let spectrum = yield cPicker.spectrum; let onHidden = cPicker.tooltip.once("hidden"); + // Validating the color change ends up updating the rule view twice + let onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); yield onHidden; + yield onRuleViewChanged; is(getRuleViewPropertyValue(view, "#testid", "color"), result, "changing the color used the " + name + " unit"); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js index 3454205f8b..9d312f1b76 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_01.js @@ -17,7 +17,7 @@ const TEST_URI = ` Testing the color picker tooltip! `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); let value = getRuleViewProperty(view, "body", "background").valueSpan; @@ -39,15 +39,17 @@ function* testImageTooltipAfterColorChange(swatch, url, ruleView) { swatch.click(); yield onShown; yield simulateColorPickerChange(ruleView, picker, [0, 0, 0, 1], { - element: content.document.body, - name: "backgroundImage", + selector: "body", + name: "background-image", value: 'url("chrome://global/skin/icons/warning-64.png"), linear-gradient(rgb(0, 0, 0), rgb(255, 0, 102) 400px)' }); let spectrum = yield picker.spectrum; let onHidden = picker.tooltip.once("hidden"); + let onModifications = ruleView.once("ruleview-changed"); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); yield onHidden; + yield onModifications; info("Verify again that the image preview tooltip works"); // After a color change, the property is re-populated, we need to get the new diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js index dd2f3ce634..684c8be331 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-and-image-tooltip_02.js @@ -20,11 +20,7 @@ const TEST_URI = ` Testing the color picker tooltip! `; -const PAGE_CONTENT = [ - -].join("\n"); - -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); yield testColorChangeIsntRevertedWhenOtherTooltipIsShown(view); @@ -41,14 +37,17 @@ function* testColorChangeIsntRevertedWhenOtherTooltipIsShown(ruleView) { yield onShown; yield simulateColorPickerChange(ruleView, picker, [0, 0, 0, 1], { - element: content.document.body, - name: "backgroundColor", + selector: "body", + name: "background-color", value: "rgb(0, 0, 0)" }); + let spectrum = yield picker.spectrum; + let onModifications = ruleView.once("ruleview-changed"); let onHidden = picker.tooltip.once("hidden"); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); yield onHidden; + yield onModifications; info("Open the image preview tooltip"); let value = getRuleViewProperty(ruleView, "body", "background").valueSpan; diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js index fca9008847..311b45d02b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-appears-on-swatch-click.js @@ -18,7 +18,7 @@ const TEST_URI = ` Testing the color picker tooltip! `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); @@ -49,5 +49,6 @@ function* testColorPickerAppearsOnColorSwatchClick(view, swatch) { ok(true, "The color picker was shown on click of the color swatch"); ok(!inplaceEditor(swatch.parentNode), "The inplace editor wasn't shown as a result of the color swatch click"); - cPicker.hide(); + + yield hideTooltipAndWaitForRuleViewChanged(cPicker, view); } diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js index 21213a6f32..6fbf87ec91 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-commit-on-ENTER.js @@ -16,7 +16,7 @@ const TEST_URI = ` Testing the color picker tooltip! `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); @@ -33,8 +33,8 @@ function* testPressingEnterCommitsChanges(swatch, ruleView) { yield onShown; yield simulateColorPickerChange(ruleView, cPicker, [0, 255, 0, .5], { - element: content.document.body, - name: "borderLeftColor", + selector: "body", + name: "border-left-color", value: "rgba(0, 255, 0, 0.5)" }); @@ -44,12 +44,14 @@ function* testPressingEnterCommitsChanges(swatch, ruleView) { "2em solid rgba(0, 255, 0, 0.5)", "The text of the border css property was updated"); + let onModified = ruleView.once("ruleview-changed"); let spectrum = yield cPicker.spectrum; let onHidden = cPicker.tooltip.once("hidden"); EventUtils.sendKey("RETURN", spectrum.element.ownerDocument.defaultView); yield onHidden; + yield onModified; - is(content.getComputedStyle(content.document.body).borderLeftColor, + is((yield getComputedStyleProperty("body", null, "border-left-color")), "rgba(0, 255, 0, 0.5)", "The element's border was kept after RETURN"); is(swatch.style.backgroundColor, "rgba(0, 255, 0, 0.5)", "The color swatch's background was kept after RETURN"); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js index d161f2700f..b8c89ccdf6 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-edit-gradient.js @@ -16,7 +16,7 @@ const TEST_URI = ` Updating a gradient declaration with the color picker tooltip `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); @@ -51,26 +51,27 @@ function* testPickingNewColor(view) { let swatchEl = ruleEl.valueSpan.querySelector(".ruleview-colorswatch"); let colorEl = ruleEl.valueSpan.querySelector(".ruleview-color"); - info("Getting the color picker tooltip and clicking on the swatch to show it"); + info("Get the color picker tooltip and clicking on the swatch to show it"); let cPicker = view.tooltips.colorPicker; let onShown = cPicker.tooltip.once("shown"); swatchEl.click(); yield onShown; let change = { - element: content.document.body, - name: "backgroundImage", - value: "linear-gradient(to left, rgb(1, 1, 1) 25%, rgb(51, 51, 51) 95%, rgb(0, 0, 0) 100%)" + selector: "body", + name: "background-image", + value: "linear-gradient(to left, rgb(1, 1, 1) 25%, " + + "rgb(51, 51, 51) 95%, rgb(0, 0, 0) 100%)" }; yield simulateColorPickerChange(view, cPicker, [1, 1, 1, 1], change); is(swatchEl.style.backgroundColor, "rgb(1, 1, 1)", "The color swatch's background was updated"); is(colorEl.textContent, "#010101", "The color text was updated"); - is(content.getComputedStyle(content.document.body).backgroundImage, + is((yield getComputedStyleProperty("body", null, "background-image")), "linear-gradient(to left, rgb(1, 1, 1) 25%, rgb(51, 51, 51) 95%, " + "rgb(0, 0, 0) 100%)", "The gradient has been updated correctly"); - cPicker.hide(); + yield hideTooltipAndWaitForRuleViewChanged(cPicker, view); } diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js index f4845acfb6..6facb94381 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-hides-on-tooltip.js @@ -18,7 +18,7 @@ const TEST_URI = ` Testing the color picker tooltip! `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js index 58a374f7d5..5546cbb7c3 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-multiple-changes.js @@ -25,7 +25,7 @@ const TEST_URI = `

Testing the color picker tooltip!

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); @@ -55,7 +55,7 @@ function* testSimpleMultipleColorChanges(inspector, ruleView) { ]; for (let {rgba, computed} of colors) { yield simulateColorPickerChange(ruleView, picker, rgba, { - element: content.document.querySelector("p"), + selector: "p", name: "color", value: computed }); @@ -83,16 +83,14 @@ function* testComplexMultipleColorChanges(inspector, ruleView) { ]; for (let {rgba, computed} of colors) { yield simulateColorPickerChange(ruleView, picker, rgba, { - element: content.document.body, - name: "backgroundColor", + selector: "body", + name: "background-color", value: computed }); } info("Closing the color picker"); - let onHidden = picker.tooltip.once("hidden"); - picker.tooltip.hide(); - yield onHidden; + yield hideTooltipAndWaitForRuleViewChanged(picker.tooltip, ruleView); } function* testOverriddenMultipleColorChanges(inspector, ruleView) { @@ -116,11 +114,11 @@ function* testOverriddenMultipleColorChanges(inspector, ruleView) { ]; for (let {rgba, computed} of colors) { yield simulateColorPickerChange(ruleView, picker, rgba, { - element: content.document.body, + selector: "body", name: "color", value: computed }); - is(content.getComputedStyle(content.document.querySelector("p")).color, + is((yield getComputedStyleProperty("p", null, "color")), "rgb(200, 200, 200)", "The color of the P tag is still correct"); } } diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js index 8e6c2e9f99..0fbe7e2d98 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-release-outside-frame.js @@ -9,7 +9,7 @@ const TEST_URI = "Test page for bug 1160720"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); @@ -44,7 +44,8 @@ add_task(function*() { info("Moving mouse over color picker without any buttons pressed."); EventUtils.synthesizeMouse(spectrum.dragger, 10, 10, { - button: -1, // -1 = no buttons are pressed down + // -1 = no buttons are pressed down + button: -1, type: "mousemove", }, spectrum.dragger.ownerDocument.defaultView); }); diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js index fbdd4e4130..66910492cf 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-revert-on-ESC.js @@ -15,7 +15,7 @@ const TEST_URI = ` `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); yield testPressingEscapeRevertsChanges(view); @@ -23,20 +23,12 @@ add_task(function*() { }); function* testPressingEscapeRevertsChanges(view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; - let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch"); - let cPicker = view.tooltips.colorPicker; - - let onShown = cPicker.tooltip.once("shown"); - swatch.click(); - yield onShown; - - yield simulateColorPickerChange(view, cPicker, [0, 0, 0, 1], { - element: content.document.body, - name: "backgroundColor", - value: "rgb(0, 0, 0)" - }); + let {swatch, propEditor, cPicker} = yield openColorPickerAndSelectColor(view, + 1, 0, [0, 0, 0, 1], { + selector: "body", + name: "background-color", + value: "rgb(0, 0, 0)" + }); is(swatch.style.backgroundColor, "rgb(0, 0, 0)", "The color swatch's background was updated"); @@ -47,9 +39,10 @@ function* testPressingEscapeRevertsChanges(view) { info("Pressing ESCAPE to close the tooltip"); let onHidden = cPicker.tooltip.once("hidden"); + let onModifications = view.once("ruleview-changed"); EventUtils.sendKey("ESCAPE", spectrum.element.ownerDocument.defaultView); yield onHidden; - yield ruleEditor.rule._applyingModifications; + yield onModifications; yield waitForComputedStyleProperty("body", null, "background-color", "rgb(237, 237, 237)"); @@ -59,56 +52,50 @@ function* testPressingEscapeRevertsChanges(view) { function* testPressingEscapeRevertsChangesAndDisables(view) { let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; - let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch"); - let cPicker = view.tooltips.colorPicker; info("Disabling background-color property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + let textProp = ruleEditor.rule.textProps[0]; + yield togglePropStatus(view, textProp); - ok(propEditor.element.classList.contains("ruleview-overridden"), + ok(textProp.editor.element.classList.contains("ruleview-overridden"), "property is overridden."); - is(propEditor.enable.style.visibility, "visible", + is(textProp.editor.enable.style.visibility, "visible", "property enable checkbox is visible."); - ok(!propEditor.enable.getAttribute("checked"), + ok(!textProp.editor.enable.getAttribute("checked"), "property enable checkbox is not checked."); - ok(!propEditor.prop.enabled, + ok(!textProp.editor.prop.enabled, "background-color property is disabled."); let newValue = yield getRulePropertyValue("background-color"); is(newValue, "", "background-color should have been unset."); - let onShown = cPicker.tooltip.once("shown"); - swatch.click(); - yield onShown; + let {cPicker} = yield openColorPickerAndSelectColor(view, + 1, 0, [0, 0, 0, 1]); - ok(!propEditor.element.classList.contains("ruleview-overridden"), + ok(!textProp.editor.element.classList.contains("ruleview-overridden"), "property overridden is not displayed."); - is(propEditor.enable.style.visibility, "hidden", + is(textProp.editor.enable.style.visibility, "hidden", "property enable checkbox is hidden."); let spectrum = yield cPicker.spectrum; - info("Simulating a color picker change in the widget"); - spectrum.rgb = [0, 0, 0, 1]; - yield ruleEditor.rule._applyingModifications; info("Pressing ESCAPE to close the tooltip"); let onHidden = cPicker.tooltip.once("hidden"); + let onModifications = view.once("ruleview-changed"); EventUtils.sendKey("ESCAPE", spectrum.element.ownerDocument.defaultView); yield onHidden; - yield ruleEditor.rule._applyingModifications; + yield onModifications; - ok(propEditor.element.classList.contains("ruleview-overridden"), + ok(textProp.editor.element.classList.contains("ruleview-overridden"), "property is overridden."); - is(propEditor.enable.style.visibility, "visible", + is(textProp.editor.enable.style.visibility, "visible", "property enable checkbox is visible."); - ok(!propEditor.enable.getAttribute("checked"), + ok(!textProp.editor.enable.getAttribute("checked"), "property enable checkbox is not checked."); - ok(!propEditor.prop.enabled, + ok(!textProp.editor.prop.enabled, "background-color property is disabled."); newValue = yield getRulePropertyValue("background-color"); is(newValue, "", "background-color should have been unset."); - is(propEditor.valueSpan.textContent, "#EDEDED", + is(textProp.editor.valueSpan.textContent, "#EDEDED", "Got expected property value."); } diff --git a/devtools/client/inspector/rules/test/browser_rules_colorpicker-swatch-displayed.js b/devtools/client/inspector/rules/test/browser_rules_colorpicker-swatch-displayed.js index 98296ad335..d05ddd46eb 100644 --- a/devtools/client/inspector/rules/test/browser_rules_colorpicker-swatch-displayed.js +++ b/devtools/client/inspector/rules/test/browser_rules_colorpicker-swatch-displayed.js @@ -37,7 +37,7 @@ const TESTS = [ {selector: "*", propertyName: "box-shadow", nb: 2}, ]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js index 1b11ba9346..c650c57603 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_01.js @@ -55,7 +55,7 @@ var testData = [ const TEST_URI = "

Header

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view, testActor} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js index 776bbf2c0f..bbcf461fd3 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-existing-property_02.js @@ -37,7 +37,7 @@ var testData = [ const TEST_URI = "

Header

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view, testActor} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js index 2c86241b1d..59feb9f4a6 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_01.js @@ -38,7 +38,7 @@ var testData = [ const TEST_URI = "

Header

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view, testActor} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js index 6eb1f24b6d..2b4193bd97 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_02.js @@ -48,7 +48,7 @@ const TEST_URI = `

Test element

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view, testActor} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_03.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_03.js index 678f13d295..77d72e16d4 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_03.js @@ -9,7 +9,7 @@ const TEST_URI = "

Header

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_04.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_04.js index 76a8d61497..5f283ae53b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_04.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_04.js @@ -13,7 +13,7 @@ const TEST_URI = "" + "

Header

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let { inspector, view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js new file mode 100644 index 0000000000..8b71f31a60 --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_completion-new-property_multiline.js @@ -0,0 +1,119 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the behaviour of the CSS autocomplete for CSS value displayed on +// multiple lines. Expected behavior is: +// - UP/DOWN should navigate in the input and not increment/decrement numbers +// - typing a new value should still trigger the autocomplete +// - UP/DOWN when the autocomplete popup is displayed should cycle through +// suggestions + +const LONG_CSS_VALUE = + "transparent linear-gradient(0deg, blue 0%, white 5%, red 10%, blue 15%, " + + "white 20%, red 25%, blue 30%, white 35%, red 40%, blue 45%, white 50%, " + + "red 55%, blue 60%, white 65%, red 70%, blue 75%, white 80%, red 85%, " + + "blue 90%, white 95% ) repeat scroll 0% 0%"; + +const EXPECTED_CSS_VALUE = LONG_CSS_VALUE.replace("95%", "95%, red"); + +const TEST_URI = + ` +

Header

`; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let { inspector, view} = yield openRuleView(); + + info("Selecting the test node"); + yield selectNode("h1", inspector); + + info("Focusing the property editable field"); + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; + + info("Focusing the css property editable value"); + let rect = prop.editor.valueSpan.getBoundingClientRect(); + let editor = yield focusEditableField(view, prop.editor.valueSpan, + rect.width / 2, rect.height / 2); + + info("Moving the caret next to a number"); + let pos = editor.input.value.indexOf("0deg") + 1; + editor.input.setSelectionRange(pos, pos); + is(editor.input.value[editor.input.selectionStart - 1], "0", + "Input caret is after a 0"); + + info("Check that UP/DOWN navigates in the input, even when next to a number"); + EventUtils.synthesizeKey("VK_DOWN", {}, view.styleWindow); + ok(editor.input.selectionStart != pos, "Input caret moved"); + is(editor.input.value, LONG_CSS_VALUE, "Input value was not decremented."); + + info("Move the caret to the end of the gradient definition."); + pos = editor.input.value.indexOf("95%") + 3; + editor.input.setSelectionRange(pos, pos); + + info("Sending \", re\" to the editable field."); + for (let key of ", re") { + yield synthesizeKeyForAutocomplete(key, editor, view.styleWindow); + } + + info("Check the autocomplete can still be displayed."); + ok(editor.popup && editor.popup.isOpen, "Autocomplete popup is displayed."); + is(editor.popup.selectedIndex, 0, + "Autocomplete has an item selected by default"); + + let item = editor.popup.getItemAtIndex(editor.popup.selectedIndex); + is(item.label, "rebeccapurple", + "Check autocomplete displays expected value."); + + info("Check autocomplete suggestions can be cycled using UP/DOWN arrows."); + + yield synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow); + ok(editor.popup.selectedIndex, 1, "Using DOWN cycles autocomplete values."); + yield synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow); + ok(editor.popup.selectedIndex, 2, "Using DOWN cycles autocomplete values."); + yield synthesizeKeyForAutocomplete("VK_UP", editor, view.styleWindow); + is(editor.popup.selectedIndex, 1, "Using UP cycles autocomplete values."); + item = editor.popup.getItemAtIndex(editor.popup.selectedIndex); + is(item.label, "red", "Check autocomplete displays expected value."); + + info("Select the background-color suggestion with a mouse click."); + let onRuleviewChanged = view.once("ruleview-changed"); + let onInputFocus = once(editor.input, "focus", true); + let node = editor.popup._list.childNodes[editor.popup.selectedIndex]; + EventUtils.synthesizeMouseAtCenter(node, {}, view.styleWindow); + yield onInputFocus; + yield onRuleviewChanged; + + is(editor.input.value, EXPECTED_CSS_VALUE, + "Input value correctly autocompleted"); + + info("Press ESCAPE to leave the input."); + onRuleviewChanged = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); + yield onRuleviewChanged; +}); + +/** + * Send the provided key to the currently focused input of the provided window. + * Wait for the editor to emit "after-suggest" to make sure the autocompletion + * process is finished. + * + * @param {String} key + * The key to send to the input. + * @param {InplaceEditor} editor + * The inplace editor which owns the focused input. + * @param {Window} win + * Window in which the key event will be dispatched. + */ +function* synthesizeKeyForAutocomplete(key, editor, win) { + let onSuggest = editor.once("after-suggest"); + EventUtils.synthesizeKey(key, {}, win); + yield onSuggest; +} diff --git a/devtools/client/inspector/rules/test/browser_rules_completion-popup-hidden-after-navigation.js b/devtools/client/inspector/rules/test/browser_rules_completion-popup-hidden-after-navigation.js index 548e827f95..6e24983745 100644 --- a/devtools/client/inspector/rules/test/browser_rules_completion-popup-hidden-after-navigation.js +++ b/devtools/client/inspector/rules/test/browser_rules_completion-popup-hidden-after-navigation.js @@ -8,7 +8,7 @@ const TEST_URI = "

"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view, testActor} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_computed-lists_01.js b/devtools/client/inspector/rules/test/browser_rules_computed-lists_01.js index 6214e665d4..5acebd562f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_computed-lists_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_computed-lists_01.js @@ -16,7 +16,7 @@ var TEST_URI = `

Styled Node

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_computed-lists_02.js b/devtools/client/inspector/rules/test/browser_rules_computed-lists_02.js index fd22e09765..d6dc82d5fb 100644 --- a/devtools/client/inspector/rules/test/browser_rules_computed-lists_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_computed-lists_02.js @@ -17,7 +17,7 @@ var TEST_URI = `

Styled Node

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); @@ -31,7 +31,7 @@ function* testComputedList(inspector, view) { ok(!expander.hasAttribute("open"), "margin computed list is closed"); - info("Opening the computed list of margin property") + info("Opening the computed list of margin property"); expander.click(); ok(expander.hasAttribute("open"), "margin computed list is open"); @@ -45,22 +45,28 @@ function* testComputedList(inspector, view) { ]; is(computed.length, propNames.length, "There should be 4 computed values"); - is(computedDom.children.length, propNames.length, "There should be 4 nodes in the DOM"); + is(computedDom.children.length, propNames.length, + "There should be 4 nodes in the DOM"); + propNames.forEach((propName, i) => { let propValue = i + "px"; - is(computed[i].name, propName, "Computed property #" + i + " has name " + propName); - is(computed[i].value, propValue, "Computed property #" + i + " has value " + propValue); - is(computedDom.getElementsByClassName("ruleview-propertyname")[i].textContent, propName, - "Computed property #" + i + " in DOM has correct name"); - is(computedDom.getElementsByClassName("ruleview-propertyvalue")[i].textContent, propValue, - "Computed property #" + i + " in DOM has correct value"); + is(computed[i].name, propName, + "Computed property #" + i + " has name " + propName); + is(computed[i].value, propValue, + "Computed property #" + i + " has value " + propValue); + is(computedDom.querySelectorAll(".ruleview-propertyname")[i].textContent, + propName, + "Computed property #" + i + " in DOM has correct name"); + is(computedDom.querySelectorAll(".ruleview-propertyvalue")[i].textContent, + propValue, + "Computed property #" + i + " in DOM has correct value"); }); - info("Closing the computed list of margin property") + info("Closing the computed list of margin property"); expander.click(); ok(!expander.hasAttribute("open"), "margin computed list is closed"); - info("Opening the computed list of margin property") + info("Opening the computed list of margin property"); expander.click(); ok(expander.hasAttribute("open"), "margin computed list is open"); is(computed.length, propNames.length, "Still 4 computed values"); diff --git a/devtools/client/inspector/rules/test/browser_rules_content_01.js b/devtools/client/inspector/rules/test/browser_rules_content_01.js index 85d58668f4..305c680cf7 100644 --- a/devtools/client/inspector/rules/test/browser_rules_content_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_content_01.js @@ -6,49 +6,46 @@ // Test that the rule-view content is correct -add_task(function*() { - yield addTab("data:text/html;charset=utf-8,browser_ruleview_content.js"); - let {toolbox, inspector, view} = yield openRuleView(); +const TEST_URI = ` + +
Styled Node
+
Styled Node
+`; - info("Creating the test document"); - let style = "" + - "@media screen and (min-width: 10px) {" + - " #testid {" + - " background-color: blue;" + - " }" + - "}" + - ".testclass, .unmatched {" + - " background-color: green;" + - "}"; - let styleNode = addStyle(content.document, style); - content.document.body.innerHTML = "
Styled Node
" + - "
Styled Node
"; +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view} = yield openRuleView(); - yield testContentAfterNodeSelection(inspector, view); -}); - -function* testContentAfterNodeSelection(inspector, ruleView) { yield selectNode("#testid", inspector); - is(ruleView.element.querySelectorAll("#noResults").length, 0, + is(view.element.querySelectorAll("#noResults").length, 0, "After a highlight, no longer has a no-results element."); - yield clearCurrentNodeSelection(inspector) - is(ruleView.element.querySelectorAll("#noResults").length, 1, + yield clearCurrentNodeSelection(inspector); + is(view.element.querySelectorAll("#noResults").length, 1, "After highlighting null, has a no-results element again."); yield selectNode("#testid", inspector); - let linkText = getRuleViewLinkTextByIndex(ruleView, 1); - is(linkText, "inline:1 @screen and (min-width: 10px)", + let linkText = getRuleViewLinkTextByIndex(view, 1); + is(linkText, "inline:3 @screen and (min-width: 10px)", "link text at index 1 contains media query text."); - linkText = getRuleViewLinkTextByIndex(ruleView, 2); - is(linkText, "inline:1", + linkText = getRuleViewLinkTextByIndex(view, 2); + is(linkText, "inline:7", "link text at index 2 contains no media query text."); - let classEditor = getRuleViewRuleEditor(ruleView, 2); - is(classEditor.selectorText.querySelector(".ruleview-selector-matched").textContent, + let selector = getRuleViewRuleEditor(view, 2).selectorText; + is(selector.querySelector(".ruleview-selector-matched").textContent, ".testclass", ".textclass should be matched."); - is(classEditor.selectorText.querySelector(".ruleview-selector-unmatched").textContent, + is(selector.querySelector(".ruleview-selector-unmatched").textContent, ".unmatched", ".unmatched should not be matched."); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_content_02.js b/devtools/client/inspector/rules/test/browser_rules_content_02.js index 5c9d31409f..920c7709c1 100644 --- a/devtools/client/inspector/rules/test/browser_rules_content_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_content_02.js @@ -1,24 +1,26 @@ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ - +/* globals getTestActorWithoutToolbox */ "use strict"; // Test the rule-view content when the inspector gets opened via the page // ctx-menu "inspect element" -const CONTENT = '\ -
\ -

\ - test element\ -

\ -
\ - '; +const CONTENT = ` + +
+

+ test element +

+
+ +`; const STRINGS = Services.strings .createBundle("chrome://devtools-shared/locale/styleinspector.properties"); -add_task(function*() { +add_task(function* () { let tab = yield addTab("data:text/html;charset=utf-8," + CONTENT); let testActor = yield getTestActorWithoutToolbox(tab); @@ -53,10 +55,12 @@ function checkRuleViewContent({styleDocument}) { "The rule's selector is correct"); let propertyNames = [...rule.querySelectorAll(".ruleview-propertyname")]; - is(propertyNames.length, 1, "There's only one property name, as expected"); + is(propertyNames.length, 1, + "There's only one property name, as expected"); let propertyValues = [...rule.querySelectorAll(".ruleview-propertyvalue")]; - is(propertyValues.length, 1, "There's only one property value, as expected"); + is(propertyValues.length, 1, + "There's only one property value, as expected"); } } diff --git a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js index ba552e03b1..5e3890e174 100644 --- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js +++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-01.js @@ -16,8 +16,6 @@ "use strict"; -const {setBaseCssDocsUrl} = require("devtools/client/shared/widgets/MdnDocsWidget"); - /** * The test document tries to confuse the context menu * code by having a tag called "padding" and a property diff --git a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js index 24d7b28f0d..6963b0dd5e 100644 --- a/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js +++ b/devtools/client/inspector/rules/test/browser_rules_context-menu-show-mdn-docs-02.js @@ -17,7 +17,8 @@ "use strict"; -const {setBaseCssDocsUrl} = require("devtools/client/shared/widgets/MdnDocsWidget"); +const {setBaseCssDocsUrl} = + require("devtools/client/shared/widgets/MdnDocsWidget"); const PROPERTYNAME = "color"; @@ -70,6 +71,8 @@ function* testShowAndHideMdnTooltip(view) { info("Quick check that the tooltip contents are set"); let cssDocs = view.tooltips.cssDocs; + // FIXME: Remove the comment below when bug 1246896 is fixed. + /* eslint-disable mozilla/no-cpows-in-tests */ let tooltipDocument = cssDocs.tooltip.content.contentDocument; let h1 = tooltipDocument.getElementById("property-name"); is(h1.textContent, PROPERTYNAME, "The MDN docs tooltip h1 is correct"); @@ -80,8 +83,3 @@ function* testShowAndHideMdnTooltip(view) { yield onHidden; ok(true, "The MDN docs tooltip was hidden on pressing 'escape'"); } - -/** - * Returns the root element for the rule view. - */ -var rootElement = view => (view.element) ? view.element : view.styleDocument; diff --git a/devtools/client/inspector/rules/test/browser_rules_copy_styles.js b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js index 835f7bb612..150c99ffd0 100644 --- a/devtools/client/inspector/rules/test/browser_rules_copy_styles.js +++ b/devtools/client/inspector/rules/test/browser_rules_copy_styles.js @@ -15,7 +15,7 @@ XPCOMUtils.defineLazyGetter(this, "osString", function() { const TEST_URI = URL_ROOT + "doc_copystyles.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URI); let { inspector, view } = yield openRuleView(); let contextmenu = view._contextmenu; @@ -103,6 +103,7 @@ add_task(function*() { "\tbackground-color: #00F;[\\r\\n]+" + "\tfont-size: 12px;[\\r\\n]+" + "\tborder-color: #00F !important;[\\r\\n]+" + + "\t--var: \"\\*/\";[\\r\\n]+" + "}", hidden: { copyLocation: true, @@ -143,8 +144,8 @@ add_task(function*() { } }, { - setup: function*() { - yield disableProperty(view); + setup: function* () { + yield disableProperty(view, 0); }, desc: "Test Copy Rule with Disabled Property", node: ruleEditor.rule.textProps[2].editor.nameSpan, @@ -154,6 +155,30 @@ add_task(function*() { "\tbackground-color: #00F;[\\r\\n]+" + "\tfont-size: 12px;[\\r\\n]+" + "\tborder-color: #00F !important;[\\r\\n]+" + + "\t--var: \"\\*/\";[\\r\\n]+" + + "}", + hidden: { + copyLocation: true, + copyPropertyDeclaration: false, + copyPropertyName: false, + copyPropertyValue: true, + copySelector: true, + copyRule: false + } + }, + { + setup: function* () { + yield disableProperty(view, 4); + }, + desc: "Test Copy Rule with Disabled Property with Comment", + node: ruleEditor.rule.textProps[2].editor.nameSpan, + menuItem: contextmenu.menuitemCopyRule, + expectedPattern: "#testid {[\\r\\n]+" + + "\t\/\\* color: #F00; \\*\/[\\r\\n]+" + + "\tbackground-color: #00F;[\\r\\n]+" + + "\tfont-size: 12px;[\\r\\n]+" + + "\tborder-color: #00F !important;[\\r\\n]+" + + "\t/\\* --var: \"\\*\\\\\/\"; \\*\/[\\r\\n]+" + "}", hidden: { copyLocation: true, @@ -234,20 +259,17 @@ function* checkCopyStyle(view, node, menuItem, expectedPattern, hidden) { try { yield waitForClipboard(() => menuItem.click(), () => checkClipboardData(expectedPattern)); - } catch(e) { + } catch (e) { failedClipboard(expectedPattern); } view._contextmenu._menupopup.hidePopup(); } -function* disableProperty(view) { +function* disableProperty(view, index) { let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; - - info("Disabling a property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + let textProp = ruleEditor.rule.textProps[index]; + yield togglePropStatus(view, textProp); } function checkClipboardData(expectedPattern) { diff --git a/devtools/client/inspector/rules/test/browser_rules_cssom.js b/devtools/client/inspector/rules/test/browser_rules_cssom.js index 004ba89763..d20e851927 100644 --- a/devtools/client/inspector/rules/test/browser_rules_cssom.js +++ b/devtools/client/inspector/rules/test/browser_rules_cssom.js @@ -9,7 +9,7 @@ const TEST_URI = URL_ROOT + "doc_cssom.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URI); let {inspector, view} = yield openRuleView(); yield selectNode("#target", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js index f9966dcf39..36113f8eb9 100644 --- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js +++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-appears-on-swatch-click.js @@ -21,7 +21,7 @@ const TEST_URI = `
Testing the cubic-bezier tooltip!
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("div", inspector); @@ -66,5 +66,5 @@ function* testAppears(view, swatch) { ok(true, "The cubic-bezier tooltip was shown on click of the cibuc swatch"); ok(!inplaceEditor(swatch.parentNode), "The inplace editor wasn't shown as a result of the cibuc swatch click"); - bezier.hide(); + yield hideTooltipAndWaitForRuleViewChanged(bezier, view); } diff --git a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js index dea4acc799..a5cc5c9f9d 100644 --- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js +++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-commit-on-ENTER.js @@ -15,7 +15,7 @@ const TEST_URI = ` `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); @@ -39,9 +39,10 @@ function* testPressingEnterCommitsChanges(swatch, ruleView) { widget.coordinates = [0.1, 2, 0.9, -1]; let expected = "cubic-bezier(0.1, 2, 0.9, -1)"; - yield waitForSuccess(() => { - return content.getComputedStyle(content.document.body) - .transitionTimingFunction === expected; + yield waitForSuccess(function* () { + let func = yield getComputedStyleProperty("body", null, + "transition-timing-function"); + return func === expected; }, "Waiting for the change to be previewed on the element"); ok(getRuleViewProperty(ruleView, "body", "transition").valueSpan.textContent @@ -49,13 +50,17 @@ function* testPressingEnterCommitsChanges(swatch, ruleView) { "The text of the timing-function was updated"); info("Sending RETURN key within the tooltip document"); - let onHidden = bezierTooltip.tooltip.once("hidden"); + // Pressing RETURN ends up doing 2 rule-view updates, one for the preview and + // one for the commit when the tooltip closes. + let onRuleViewChanged = waitForNEvents(ruleView, "ruleview-changed", 2); EventUtils.sendKey("RETURN", widget.parent.ownerDocument.defaultView); - yield onHidden; + yield onRuleViewChanged; - is(content.getComputedStyle(content.document.body).transitionTimingFunction, - expected, "The element's timing-function was kept after RETURN"); - ok(getRuleViewProperty(ruleView, "body", "transition").valueSpan.textContent - .indexOf("cubic-bezier(") !== -1, - "The text of the timing-function was kept after RETURN"); + let style = yield getComputedStyleProperty("body", null, + "transition-timing-function"); + is(style, expected, "The element's timing-function was kept after RETURN"); + + let ruleViewStyle = getRuleViewProperty(ruleView, "body", "transition") + .valueSpan.textContent.indexOf("cubic-bezier(") !== -1; + ok(ruleViewStyle, "The text of the timing-function was kept after RETURN"); } diff --git a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js index 932e3e143b..48726265d1 100644 --- a/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js +++ b/devtools/client/inspector/rules/test/browser_rules_cubicbezier-revert-on-ESC.js @@ -15,7 +15,7 @@ const TEST_URI = ` `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {view} = yield openRuleView(); yield testPressingEscapeRevertsChanges(view); @@ -23,30 +23,17 @@ add_task(function*() { }); function* testPressingEscapeRevertsChanges(view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; - let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch"); - let bezierTooltip = view.tooltips.cubicBezier; + let {propEditor} = yield openCubicBezierAndChangeCoords(view, 1, 0, + [0.1, 2, 0.9, -1], { + selector: "body", + name: "animation-timing-function", + value: "cubic-bezier(0.1, 2, 0.9, -1)" + }); - let onShown = bezierTooltip.tooltip.once("shown"); - swatch.click(); - yield onShown; - - let widget = yield bezierTooltip.widget; - info("Simulating a change of curve in the widget"); - widget.coordinates = [0.1, 2, 0.9, -1]; - yield ruleEditor.rule._applyingModifications; - - yield waitForComputedStyleProperty("body", null, "animation-timing-function", - "cubic-bezier(0.1, 2, 0.9, -1)"); is(propEditor.valueSpan.textContent, "cubic-bezier(.1,2,.9,-1)", "Got expected property value."); - info("Pressing ESCAPE to close the tooltip"); - let onHidden = bezierTooltip.tooltip.once("hidden"); - EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView); - yield onHidden; - yield ruleEditor.rule._applyingModifications; + yield escapeTooltip(view); yield waitForComputedStyleProperty("body", null, "animation-timing-function", "linear"); @@ -56,13 +43,11 @@ function* testPressingEscapeRevertsChanges(view) { function* testPressingEscapeRevertsChangesAndDisables(view) { let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; - let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch"); - let bezierTooltip = view.tooltips.cubicBezier; + let textProp = ruleEditor.rule.textProps[0]; + let propEditor = textProp.editor; info("Disabling animation-timing-function property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, textProp); ok(propEditor.element.classList.contains("ruleview-overridden"), "property is overridden."); @@ -75,25 +60,9 @@ function* testPressingEscapeRevertsChangesAndDisables(view) { let newValue = yield getRulePropertyValue("animation-timing-function"); is(newValue, "", "animation-timing-function should have been unset."); - let onShown = bezierTooltip.tooltip.once("shown"); - swatch.click(); - yield onShown; + yield openCubicBezierAndChangeCoords(view, 1, 0, [0.1, 2, 0.9, -1]); - ok(!propEditor.element.classList.contains("ruleview-overridden"), - "property overridden is not displayed."); - is(propEditor.enable.style.visibility, "hidden", - "property enable checkbox is hidden."); - - let widget = yield bezierTooltip.widget; - info("Simulating a change of curve in the widget"); - widget.coordinates = [0.1, 2, 0.9, -1]; - yield ruleEditor.rule._applyingModifications; - - info("Pressing ESCAPE to close the tooltip"); - let onHidden = bezierTooltip.tooltip.once("hidden"); - EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView); - yield onHidden; - yield ruleEditor.rule._applyingModifications; + yield escapeTooltip(view); ok(propEditor.element.classList.contains("ruleview-overridden"), "property is overridden."); @@ -117,3 +86,15 @@ function* getRulePropertyValue(name) { }); return propValue; } + +function* escapeTooltip(view) { + info("Pressing ESCAPE to close the tooltip"); + + let bezierTooltip = view.tooltips.cubicBezier; + let widget = yield bezierTooltip.widget; + let onHidden = bezierTooltip.tooltip.once("hidden"); + let onModifications = view.once("ruleview-changed"); + EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView); + yield onHidden; + yield onModifications; +} diff --git a/devtools/client/inspector/rules/test/browser_rules_custom.js b/devtools/client/inspector/rules/test/browser_rules_custom.js index 4c6704673c..7c941af6f4 100644 --- a/devtools/client/inspector/rules/test/browser_rules_custom.js +++ b/devtools/client/inspector/rules/test/browser_rules_custom.js @@ -8,7 +8,7 @@ const TEST_URI = URL_ROOT + "doc_custom.html"; // Tests the display of custom declarations in the rule-view. -add_task(function*() { +add_task(function* () { yield addTab(TEST_URI); let {inspector, view} = yield openRuleView(); @@ -20,61 +20,53 @@ add_task(function*() { function* simpleCustomOverride(inspector, view) { yield selectNode("#testidSimple", inspector); - let elementStyle = view._elementStyle; + let idRule = getRuleViewRuleEditor(view, 1).rule; + let idRuleProp = idRule.textProps[0]; - let idRule = elementStyle.rules[1]; - let idProp = idRule.textProps[0]; - is(idProp.name, "--background-color", + is(idRuleProp.name, "--background-color", "First ID prop should be --background-color"); - ok(!idProp.overridden, "ID prop should not be overridden."); + ok(!idRuleProp.overridden, "ID prop should not be overridden."); - let classRule = elementStyle.rules[2]; - let classProp = classRule.textProps[0]; - is(classProp.name, "--background-color", + let classRule = getRuleViewRuleEditor(view, 2).rule; + let classRuleProp = classRule.textProps[0]; + + is(classRuleProp.name, "--background-color", "First class prop should be --background-color"); - ok(classProp.overridden, "Class property should be overridden."); + ok(classRuleProp.overridden, "Class property should be overridden."); // Override --background-color by changing the element style. - let elementRule = elementStyle.rules[0]; - elementRule.createProperty("--background-color", "purple", ""); - yield elementRule._applyingModifications; + let elementProp = yield addProperty(view, 0, "--background-color", "purple"); - let elementProp = elementRule.textProps[0]; - is(classProp.name, "--background-color", + is(classRuleProp.name, "--background-color", "First element prop should now be --background-color"); ok(!elementProp.overridden, "Element style property should not be overridden"); - ok(idProp.overridden, "ID property should be overridden"); - ok(classProp.overridden, "Class property should be overridden"); + ok(idRuleProp.overridden, "ID property should be overridden"); + ok(classRuleProp.overridden, "Class property should be overridden"); } function* importantCustomOverride(inspector, view) { yield selectNode("#testidImportant", inspector); - let elementStyle = view._elementStyle; + let idRule = getRuleViewRuleEditor(view, 1).rule; + let idRuleProp = idRule.textProps[0]; + ok(idRuleProp.overridden, "Not-important rule should be overridden."); - let idRule = elementStyle.rules[1]; - let idProp = idRule.textProps[0]; - ok(idProp.overridden, "Not-important rule should be overridden."); - - let classRule = elementStyle.rules[2]; - let classProp = classRule.textProps[0]; - ok(!classProp.overridden, "Important rule should not be overridden."); + let classRule = getRuleViewRuleEditor(view, 2).rule; + let classRuleProp = classRule.textProps[0]; + ok(!classRuleProp.overridden, "Important rule should not be overridden."); } function* disableCustomOverride(inspector, view) { yield selectNode("#testidDisable", inspector); - let elementStyle = view._elementStyle; + let idRule = getRuleViewRuleEditor(view, 1).rule; + let idRuleProp = idRule.textProps[0]; - let idRule = elementStyle.rules[1]; - let idProp = idRule.textProps[0]; + yield togglePropStatus(view, idRuleProp); - idProp.setEnabled(false); - yield idRule._applyingModifications; - - let classRule = elementStyle.rules[2]; - let classProp = classRule.textProps[0]; - ok(!classProp.overridden, + let classRule = getRuleViewRuleEditor(view, 2).rule; + let classRuleProp = classRule.textProps[0]; + ok(!classRuleProp.overridden, "Class prop should not be overridden after id prop was disabled."); } diff --git a/devtools/client/inspector/rules/test/browser_rules_cycle-angle.js b/devtools/client/inspector/rules/test/browser_rules_cycle-angle.js new file mode 100644 index 0000000000..fa135f937e --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_cycle-angle.js @@ -0,0 +1,93 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test cycling angle units in the rule view. + +const TEST_URI = ` + +
Test
cycling angle units in the rule view! +`; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view} = yield openRuleView(); + let container = getRuleViewProperty( + view, "body", "image-orientation").valueSpan; + yield checkAngleCycling(container, view); + yield checkAngleCyclingPersist(inspector, view); +}); + +function* checkAngleCycling(container, view) { + let valueNode = container.querySelector(".ruleview-angle"); + let win = view.styleWindow; + + // turn + is(valueNode.textContent, "1turn", "Angle displayed as a turn value."); + + let tests = [{ + value: "360deg", + comment: "Angle displayed as a degree value." + }, { + value: `${Math.round(Math.PI * 2 * 10000) / 10000}rad`, + comment: "Angle displayed as a radian value." + }, { + value: "400grad", + comment: "Angle displayed as a gradian value." + }, { + value: "1turn", + comment: "Angle displayed as a turn value again." + }]; + + for (let test of tests) { + yield checkSwatchShiftClick(container, win, test.value, test.comment); + } +} + +function* checkAngleCyclingPersist(inspector, view) { + yield selectNode("div", inspector); + let container = getRuleViewProperty( + view, "div", "image-orientation").valueSpan; + let valueNode = container.querySelector(".ruleview-angle"); + let win = view.styleWindow; + + is(valueNode.textContent, "180deg", "Angle displayed as a degree value."); + + yield checkSwatchShiftClick(container, win, + `${Math.round(Math.PI * 10000) / 10000}rad`, + "Angle displayed as a radian value."); + + // Select the body and reselect the div to see + // if the new angle unit persisted + yield selectNode("body", inspector); + yield selectNode("div", inspector); + + // We have to query for the container and the swatch because + // they've been re-generated + container = getRuleViewProperty(view, "div", "image-orientation").valueSpan; + valueNode = container.querySelector(".ruleview-angle"); + is(valueNode.textContent, `${Math.round(Math.PI * 10000) / 10000}rad`, + "Angle still displayed as a radian value."); +} + +function* checkSwatchShiftClick(container, win, expectedValue, comment) { + let swatch = container.querySelector(".ruleview-angleswatch"); + let valueNode = container.querySelector(".ruleview-angle"); + + let onUnitChange = swatch.once("unit-change"); + EventUtils.synthesizeMouseAtCenter(swatch, { + type: "mousedown", + shiftKey: true + }, win); + yield onUnitChange; + is(valueNode.textContent, expectedValue, comment); +} diff --git a/devtools/client/inspector/rules/test/browser_rules_cycle-color.js b/devtools/client/inspector/rules/test/browser_rules_cycle-color.js index a022a625d5..09bd7ed4ac 100644 --- a/devtools/client/inspector/rules/test/browser_rules_cycle-color.js +++ b/devtools/client/inspector/rules/test/browser_rules_cycle-color.js @@ -11,53 +11,83 @@ const TEST_URI = ` body { color: #f00; } + span { + color: blue; + } - Test cycling color types in the rule view! + Test cycling color types in the rule view! `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); - let {view} = yield openRuleView(); + let {inspector, view} = yield openRuleView(); let container = getRuleViewProperty(view, "body", "color").valueSpan; - checkColorCycling(container, view); + yield checkColorCycling(container, view); + yield checkColorCyclingPersist(inspector, view); }); -function checkColorCycling(container, view) { - let swatch = container.querySelector(".ruleview-colorswatch"); +function* checkColorCycling(container, view) { let valueNode = container.querySelector(".ruleview-color"); let win = view.styleWindow; // Hex is(valueNode.textContent, "#f00", "Color displayed as a hex value."); - // HSL - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "hsl(0, 100%, 50%)", - "Color displayed as an HSL value."); + let tests = [{ + value: "hsl(0, 100%, 50%)", + comment: "Color displayed as an HSL value." + }, { + value: "rgb(255, 0, 0)", + comment: "Color displayed as an RGB value." + }, { + value: "red", + comment: "Color displayed as a color name." + }, { + value: "#f00", + comment: "Color displayed as an authored value." + }, { + value: "hsl(0, 100%, 50%)", + comment: "Color displayed as an HSL value again." + }]; - // RGB - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "rgb(255, 0, 0)", - "Color displayed as an RGB value."); - - // Color name - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "red", - "Color displayed as a color name."); - - // "Authored" - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "#f00", - "Color displayed as an authored value."); - - // One more click skips hex, because it is the same as authored, and - // instead goes back to HSL. - EventUtils.synthesizeMouseAtCenter(swatch, - {type: "mousedown", shiftKey: true}, win); - is(valueNode.textContent, "hsl(0, 100%, 50%)", - "Color displayed as an HSL value again."); + for (let test of tests) { + yield checkSwatchShiftClick(container, win, test.value, test.comment); + } +} + +function* checkColorCyclingPersist(inspector, view) { + yield selectNode("span", inspector); + let container = getRuleViewProperty(view, "span", "color").valueSpan; + let valueNode = container.querySelector(".ruleview-color"); + let win = view.styleWindow; + + is(valueNode.textContent, "blue", "Color displayed as a color name."); + + yield checkSwatchShiftClick(container, win, "#00f", + "Color displayed as a hex value."); + + // Select the body and reselect the span to see + // if the new color unit persisted + yield selectNode("body", inspector); + yield selectNode("span", inspector); + + // We have to query for the container and the swatch because + // they've been re-generated + container = getRuleViewProperty(view, "span", "color").valueSpan; + valueNode = container.querySelector(".ruleview-color"); + is(valueNode.textContent, "#00f", + "Color is still displayed as a hex value."); +} + +function* checkSwatchShiftClick(container, win, expectedValue, comment) { + let swatch = container.querySelector(".ruleview-colorswatch"); + let valueNode = container.querySelector(".ruleview-color"); + + let onUnitChange = swatch.once("unit-change"); + EventUtils.synthesizeMouseAtCenter(swatch, { + type: "mousedown", + shiftKey: true + }, win); + yield onUnitChange; + is(valueNode.textContent, expectedValue, comment); } diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js index 91fa3885ef..af1a6fbc07 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-cancel.js @@ -16,21 +16,17 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditPropertyAndCancel(inspector, view); -}); -function* testEditPropertyAndCancel(inspector, view) { let ruleEditor = getRuleViewRuleEditor(view, 1); let propEditor = ruleEditor.rule.textProps[0].editor; yield focusEditableField(view, propEditor.nameSpan); - yield sendCharsAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_ESCAPE"]); - yield ruleEditor.rule._applyingModifications; + yield sendKeysAndWaitForFocus(view, ruleEditor.element, + ["DELETE", "ESCAPE"]); is(propEditor.nameSpan.textContent, "background-color", "'background-color' property name is correctly set."); @@ -38,20 +34,13 @@ function* testEditPropertyAndCancel(inspector, view) { "rgb(0, 0, 255)", "#00F background color is set."); yield focusEditableField(view, propEditor.valueSpan); - yield sendCharsAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_ESCAPE"]); - yield ruleEditor.rule._applyingModifications; + let onValueDeleted = view.once("ruleview-changed"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, + ["DELETE", "ESCAPE"]); + yield onValueDeleted; is(propEditor.valueSpan.textContent, "#00F", "'#00F' property value is correctly set."); is((yield getComputedStyleProperty("#testid", null, "background-color")), "rgb(0, 0, 255)", "#00F background color is set."); -} - -function* sendCharsAndWaitForFocus(view, element, chars) { - let onFocus = once(element, "focus", true); - for (let ch of chars) { - EventUtils.sendChar(ch, view.styleWindow); - } - yield onFocus; -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-click.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-click.js new file mode 100644 index 0000000000..08a5ee786b --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-click.js @@ -0,0 +1,61 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the property name and value editors can be triggered when +// clicking on the property-name, the property-value, the colon or semicolon. + +const TEST_URI = ` + +
Styled Node
+`; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view} = yield openRuleView(); + yield selectNode("#testid", inspector); + yield testEditPropertyAndCancel(inspector, view); +}); + +function* testEditPropertyAndCancel(inspector, view) { + let ruleEditor = getRuleViewRuleEditor(view, 1); + let propEditor = ruleEditor.rule.textProps[0].editor; + + info("Test editor is created when clicking on property name"); + yield focusEditableField(view, propEditor.nameSpan); + ok(propEditor.nameSpan.inplaceEditor, "Editor created for property name"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["ESCAPE"]); + + info("Test editor is created when clicking on ':' next to property name"); + let nameRect = propEditor.nameSpan.getBoundingClientRect(); + yield focusEditableField(view, propEditor.nameSpan, nameRect.width + 1); + ok(propEditor.nameSpan.inplaceEditor, "Editor created for property name"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["ESCAPE"]); + + info("Test editor is created when clicking on property value"); + yield focusEditableField(view, propEditor.valueSpan); + ok(propEditor.valueSpan.inplaceEditor, "Editor created for property value"); + // When cancelling a value edition, the text-property-editor will trigger + // a modification to make sure the property is back to its original value + // => need to wait on "ruleview-changed" to avoid unhandled promises + let onRuleviewChanged = view.once("ruleview-changed"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["ESCAPE"]); + yield onRuleviewChanged; + + info("Test editor is created when clicking on ';' next to property value"); + let valueRect = propEditor.valueSpan.getBoundingClientRect(); + yield focusEditableField(view, propEditor.valueSpan, valueRect.width + 1); + ok(propEditor.valueSpan.inplaceEditor, "Editor created for property value"); + // When cancelling a value edition, the text-property-editor will trigger + // a modification to make sure the property is back to its original value + // => need to wait on "ruleview-changed" to avoid unhandled promises + onRuleviewChanged = view.once("ruleview-changed"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["ESCAPE"]); + yield onRuleviewChanged; +} diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-commit.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-commit.js index c20f8b3898..d868e8cbe4 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-commit.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-commit.js @@ -49,7 +49,7 @@ const testData = [ } ]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-computed.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-computed.js index f37d1f46ff..6bdeed5419 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-computed.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-computed.js @@ -16,7 +16,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js index b40b79e4ed..0b512dedb8 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-increments.js @@ -7,11 +7,25 @@ // Test that increasing/decreasing values in rule view using // arrow keys works correctly. -add_task(function*() { - yield addTab("data:text/html;charset=utf-8,sample document for bug 722691"); - createDocument(); - let {toolbox, inspector, view} = yield openRuleView(); +const TEST_URI = ` + +
+`; +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + + let {inspector, view} = yield openRuleView(); yield selectNode("#test", inspector); yield testMarginIncrements(view); @@ -20,21 +34,9 @@ add_task(function*() { yield testRgbIncrements(view); yield testShorthandIncrements(view); yield testOddCases(view); + yield testZeroValueIncrements(view); }); -function createDocument() { - content.document.body.innerHTML = '' + - '' + - '
'; -} - function* testMarginIncrements(view) { info("Testing keyboard increments on the margin property"); @@ -49,7 +51,10 @@ function* testMarginIncrements(view) { 5: {down: true, start: "0px", end: "-1px", selectAll: true}, 6: {down: true, shift: true, start: "0px", end: "-10px", selectAll: true}, 7: {pageUp: true, shift: true, start: "0px", end: "100px", selectAll: true}, - 8: {pageDown: true, shift: true, start: "0px", end: "-100px", selectAll: true} + 8: {pageDown: true, shift: true, start: "0px", end: "-100px", + selectAll: true}, + 9: {start: "0", end: "1px", selectAll: true}, + 10: {down: true, start: "0", end: "-1px", selectAll: true}, }); } @@ -64,13 +69,15 @@ function* testVariousUnitIncrements(view) { 2: {start: "0pt", end: "1pt", selectAll: true}, 3: {start: "0pc", end: "1pc", selectAll: true}, 4: {start: "0em", end: "1em", selectAll: true}, - 5: {start: "0%", end: "1%", selectAll: true}, + 5: {start: "0%", end: "1%", selectAll: true}, 6: {start: "0in", end: "1in", selectAll: true}, 7: {start: "0cm", end: "1cm", selectAll: true}, 8: {start: "0mm", end: "1mm", selectAll: true}, - 9: {start: "0ex", end: "1ex", selectAll: true} + 9: {start: "0ex", end: "1ex", selectAll: true}, + 10: {start: "0", end: "1px", selectAll: true}, + 11: {down: true, start: "0", end: "-1px", selectAll: true}, }); -}; +} function* testHexIncrements(view) { info("Testing keyboard increments with hex colors"); @@ -81,12 +88,13 @@ function* testHexIncrements(view) { yield runIncrementTest(hexColorPropEditor, view, { 1: {start: "#CCCCCC", end: "#CDCDCD", selectAll: true}, 2: {shift: true, start: "#CCCCCC", end: "#DCDCDC", selectAll: true}, - 3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1,3]}, - 4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1,3]}, + 3: {start: "#CCCCCC", end: "#CDCCCC", selection: [1, 3]}, + 4: {shift: true, start: "#CCCCCC", end: "#DCCCCC", selection: [1, 3]}, 5: {start: "#FFFFFF", end: "#FFFFFF", selectAll: true}, - 6: {down: true, shift: true, start: "#000000", end: "#000000", selectAll: true} + 6: {down: true, shift: true, start: "#000000", end: "#000000", + selectAll: true} }); -}; +} function* testRgbIncrements(view) { info("Testing keyboard increments with rgb colors"); @@ -95,14 +103,17 @@ function* testRgbIncrements(view) { let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor; yield runIncrementTest(rgbColorPropEditor, view, { - 1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6,7]}, - 2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)", selection: [6,7]}, - 3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6,9]}, - 4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)", selection: [6,9]}, - 5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6,7]}, - 6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)", selection: [6,7]} + 1: {start: "rgb(0,0,0)", end: "rgb(0,1,0)", selection: [6, 7]}, + 2: {shift: true, start: "rgb(0,0,0)", end: "rgb(0,10,0)", + selection: [6, 7]}, + 3: {start: "rgb(0,255,0)", end: "rgb(0,255,0)", selection: [6, 9]}, + 4: {shift: true, start: "rgb(0,250,0)", end: "rgb(0,255,0)", + selection: [6, 9]}, + 5: {down: true, start: "rgb(0,0,0)", end: "rgb(0,0,0)", selection: [6, 7]}, + 6: {down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)", + selection: [6, 7]} }); -}; +} function* testShorthandIncrements(view) { info("Testing keyboard increments within shorthand values"); @@ -111,17 +122,24 @@ function* testShorthandIncrements(view) { let paddingPropEditor = idRuleEditor.rule.textProps[1].editor; yield runIncrementTest(paddingPropEditor, view, { - 1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4,7]}, - 2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px", selection: [4,7]}, + 1: {start: "0px 0px 0px 0px", end: "0px 1px 0px 0px", selection: [4, 7]}, + 2: {shift: true, start: "0px 0px 0px 0px", end: "0px 10px 0px 0px", + selection: [4, 7]}, 3: {start: "0px 0px 0px 0px", end: "1px 0px 0px 0px", selectAll: true}, - 4: {shift: true, start: "0px 0px 0px 0px", end: "10px 0px 0px 0px", selectAll: true}, - 5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px", selection: [8,11]}, - 6: {down: true, shift: true, start: "0px 0px 0px 0px", end: "-10px 0px 0px 0px", selectAll: true}, - 7: {up: true, start: "0.1em .1em 0em 0em", end: "0.1em 1.1em 0em 0em", selection: [6, 9]}, - 8: {up: true, alt: true, start: "0.1em .9em 0em 0em", end: "0.1em 1em 0em 0em", selection: [6, 9]}, - 9: {up: true, shift: true, start: "0.2em .2em 0em 0em", end: "0.2em 10.2em 0em 0em", selection: [6, 9]} + 4: {shift: true, start: "0px 0px 0px 0px", end: "10px 0px 0px 0px", + selectAll: true}, + 5: {down: true, start: "0px 0px 0px 0px", end: "0px 0px -1px 0px", + selection: [8, 11]}, + 6: {down: true, shift: true, start: "0px 0px 0px 0px", + end: "-10px 0px 0px 0px", selectAll: true}, + 7: {up: true, start: "0.1em .1em 0em 0em", end: "0.1em 1.1em 0em 0em", + selection: [6, 9]}, + 8: {up: true, alt: true, start: "0.1em .9em 0em 0em", + end: "0.1em 1em 0em 0em", selection: [6, 9]}, + 9: {up: true, shift: true, start: "0.2em .2em 0em 0em", + end: "0.2em 10.2em 0em 0em", selection: [6, 9]} }); -}; +} function* testOddCases(view) { info("Testing some more odd cases"); @@ -130,32 +148,79 @@ function* testOddCases(view) { let marginPropEditor = idRuleEditor.rule.textProps[0].editor; yield runIncrementTest(marginPropEditor, view, { - 1: {start: "98.7%", end: "99.7%", selection: [3,3]}, - 2: {alt: true, start: "98.7%", end: "98.8%", selection: [3,3]}, - 3: {start: "0", end: "1"}, - 4: {down: true, start: "0", end: "-1"}, - 5: {start: "'a=-1'", end: "'a=0'", selection: [4,4]}, - 6: {start: "0 -1px", end: "0 0px", selection: [2,2]}, - 7: {start: "url(-1)", end: "url(-1)", selection: [4,4]}, - 8: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11,11]}, - 9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9,9]}, - 10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')", selection: [9,9]}, - 11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')", selection: [9,11]}, - 12: {start: "url('test1.1.png')", end: "url('test1.2.png')", selection: [11,12]}, - 13: {down: true, alt: true, start: "url('test-0.png')", end: "url('test--0.1.png')", selection: [10,11]}, - 14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')", selection: [10,14]} + 1: {start: "98.7%", end: "99.7%", selection: [3, 3]}, + 2: {alt: true, start: "98.7%", end: "98.8%", selection: [3, 3]}, + 3: {start: "0", end: "1px"}, + 4: {down: true, start: "0", end: "-1px"}, + 5: {start: "'a=-1'", end: "'a=0'", selection: [4, 4]}, + 6: {start: "0 -1px", end: "0 0px", selection: [2, 2]}, + 7: {start: "url(-1)", end: "url(-1)", selection: [4, 4]}, + 8: {start: "url('test1.1.png')", end: "url('test1.2.png')", + selection: [11, 11]}, + 9: {start: "url('test1.png')", end: "url('test2.png')", selection: [9, 9]}, + 10: {shift: true, start: "url('test1.1.png')", end: "url('test11.1.png')", + selection: [9, 9]}, + 11: {down: true, start: "url('test-1.png')", end: "url('test-2.png')", + selection: [9, 11]}, + 12: {start: "url('test1.1.png')", end: "url('test1.2.png')", + selection: [11, 12]}, + 13: {down: true, alt: true, start: "url('test-0.png')", + end: "url('test--0.1.png')", selection: [10, 11]}, + 14: {alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')", + selection: [10, 14]} }); -}; +} + +function* testZeroValueIncrements(view) { + info("Testing a valid unit is added when incrementing from 0"); + + let idRuleEditor = getRuleViewRuleEditor(view, 1); + let backgroundPropEditor = idRuleEditor.rule.textProps[4].editor; + yield runIncrementTest(backgroundPropEditor, view, { + 1: { start: "url(test-0.png) no-repeat 0 0", + end: "url(test-0.png) no-repeat 1px 0", selection: [26, 26] }, + 2: { start: "url(test-0.png) no-repeat 0 0", + end: "url(test-0.png) no-repeat 0 1px", selection: [28, 28] }, + 3: { start: "url(test-0.png) no-repeat center/0", + end: "url(test-0.png) no-repeat center/1px", selection: [34, 34] }, + 4: { start: "url(test-0.png) no-repeat 0 0", + end: "url(test-1.png) no-repeat 0 0", selection: [10, 10] }, + 5: { start: "linear-gradient(0, red 0, blue 0)", + end: "linear-gradient(1deg, red 0, blue 0)", selection: [17, 17] }, + 6: { start: "linear-gradient(1deg, red 0, blue 0)", + end: "linear-gradient(1deg, red 1px, blue 0)", selection: [27, 27] }, + 7: { start: "linear-gradient(1deg, red 0, blue 0)", + end: "linear-gradient(1deg, red 0, blue 1px)", selection: [35, 35] }, + }); + + let transitionPropEditor = idRuleEditor.rule.textProps[5].editor; + yield runIncrementTest(transitionPropEditor, view, { + 1: { start: "all 0 ease-out", end: "all 1s ease-out", selection: [5, 5] }, + 2: { start: "margin 4s, color 0", + end: "margin 4s, color 1s", selection: [18, 18] }, + }); + + let zIndexPropEditor = idRuleEditor.rule.textProps[6].editor; + yield runIncrementTest(zIndexPropEditor, view, { + 1: {start: "0", end: "1", selection: [1, 1]}, + }); +} function* runIncrementTest(propertyEditor, view, tests) { let editor = yield focusEditableField(view, propertyEditor.valueSpan); - for(let test in tests) { + for (let test in tests) { yield testIncrement(editor, tests[test], view, propertyEditor); } + + // Blur the field to put back the UI in its initial state (and avoid pending + // requests when the test ends). + let onRuleViewChanged = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); + yield onRuleViewChanged; } -function* testIncrement(editor, options, view, {ruleEditor}) { +function* testIncrement(editor, options, view) { editor.input.value = options.start; let input = editor.input; @@ -169,9 +234,15 @@ function* testIncrement(editor, options, view, {ruleEditor}) { let onRuleViewChanged = view.once("ruleview-changed"); let onKeyUp = once(input, "keyup"); + let key; key = options.down ? "VK_DOWN" : "VK_UP"; - key = options.pageDown ? "VK_PAGE_DOWN" : options.pageUp ? "VK_PAGE_UP" : key; + if (options.pageDown) { + key = "VK_PAGE_DOWN"; + } else if (options.pageUp) { + key = "VK_PAGE_UP"; + } + EventUtils.synthesizeKey(key, {altKey: options.alt, shiftKey: options.shift}, view.styleWindow); yield onKeyUp; diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-order.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-order.js index 0c088c9d21..b4a86c1941 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-order.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-order.js @@ -6,77 +6,84 @@ // Checking properties orders and overrides in the rule-view. -const TEST_URI = "
Styled Node
"; +const TEST_URI = "
Styled Node
"; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - let element = getNode("#testid"); let elementStyle = view._elementStyle; - let elementRule = elementStyle.rules[0]; + let elementRule = elementStyle.rules[1]; info("Checking rules insertion order and checking the applied style"); - let firstProp = elementRule.createProperty("background-color", "green", ""); - let secondProp = elementRule.createProperty("background-color", "blue", ""); - is(elementRule.textProps[0], firstProp, "Rules should be in addition order."); + let firstProp = yield addProperty(view, 1, "background-color", "green"); + let secondProp = yield addProperty(view, 1, "background-color", "blue"); + + is(elementRule.textProps[0], firstProp, + "Rules should be in addition order."); is(elementRule.textProps[1], secondProp, - "Rules should be in addition order."); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "blue", - "Second property should have been used."); + "Rules should be in addition order."); + + // rgb(0, 0, 255) = blue + is((yield getValue("#testid", "background-color")), "rgb(0, 0, 255)", + "Second property should have been used."); info("Removing the second property and checking the applied style again"); - secondProp.remove(); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "green", - "After deleting second property, first should be used."); + yield removeProperty(view, secondProp); + // rgb(0, 128, 0) = green + is((yield getValue("#testid", "background-color")), "rgb(0, 128, 0)", + "After deleting second property, first should be used."); info("Creating a new second property and checking that the insertion order " + - "is still the same"); - secondProp = elementRule.createProperty("background-color", "blue", ""); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "blue", - "New property should be used."); + "is still the same"); + + secondProp = yield addProperty(view, 1, "background-color", "blue"); + + is((yield getValue("#testid", "background-color")), "rgb(0, 0, 255)", + "New property should be used."); is(elementRule.textProps[0], firstProp, - "Rules shouldn't have switched places."); + "Rules shouldn't have switched places."); is(elementRule.textProps[1], secondProp, - "Rules shouldn't have switched places."); + "Rules shouldn't have switched places."); info("Disabling the second property and checking the applied style"); - secondProp.setEnabled(false); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "green", - "After disabling second property, first value should be used"); + yield togglePropStatus(view, secondProp); + + is((yield getValue("#testid", "background-color")), "rgb(0, 128, 0)", + "After disabling second property, first value should be used"); info("Disabling the first property too and checking the applied style"); - firstProp.setEnabled(false); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "", - "After disabling both properties, value should be empty."); + yield togglePropStatus(view, firstProp); + + is((yield getValue("#testid", "background-color")), "transparent", + "After disabling both properties, value should be empty."); info("Re-enabling the second propertyt and checking the applied style"); - secondProp.setEnabled(true); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "blue", - "Value should be set correctly after re-enabling"); + yield togglePropStatus(view, secondProp); + + is((yield getValue("#testid", "background-color")), "rgb(0, 0, 255)", + "Value should be set correctly after re-enabling"); info("Re-enabling the first property and checking the insertion order " + - "is still respected"); - firstProp.setEnabled(true); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "blue", - "Re-enabling an earlier property shouldn't make it override " + - "a later property."); - is(elementRule.textProps[0], firstProp, - "Rules shouldn't have switched places."); - is(elementRule.textProps[1], secondProp, - "Rules shouldn't have switched places."); + "is still respected"); + yield togglePropStatus(view, firstProp); + is((yield getValue("#testid", "background-color")), "rgb(0, 0, 255)", + "Re-enabling an earlier property shouldn't make it override " + + "a later property."); + is(elementRule.textProps[0], firstProp, + "Rules shouldn't have switched places."); + is(elementRule.textProps[1], secondProp, + "Rules shouldn't have switched places."); info("Modifying the first property and checking the applied style"); - firstProp.setValue("purple", ""); - yield elementRule._applyingModifications; - is(element.style.getPropertyValue("background-color"), "blue", - "Modifying an earlier property shouldn't override a later property."); + yield setProperty(view, firstProp, "purple"); + + is((yield getValue("#testid", "background-color")), "rgb(0, 0, 255)", + "Modifying an earlier property shouldn't override a later property."); }); + +function* getValue(selector, propName) { + let value = yield getComputedStyleProperty(selector, null, propName); + return value; +} diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js index 2fdf803131..0aed2f5c8e 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_01.js @@ -18,21 +18,17 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditPropertyAndRemove(inspector, view); -}); -function* testEditPropertyAndRemove(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + info("Getting the first property in the #testid rule"); + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; - yield focusEditableField(view, propEditor.nameSpan); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_RETURN"]); - yield ruleEditor.rule._applyingModifications; + info("Deleting the name of that property to remove the property"); + yield removeProperty(view, prop, false); let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -41,15 +37,16 @@ function* testEditPropertyAndRemove(inspector, view) { }); is(newValue, "", "background-color should have been unset."); - propEditor = ruleEditor.rule.textProps[0].editor; + info("Getting the new first property in the rule"); + prop = rule.textProps[0]; let editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(propEditor.nameSpan), editor, + is(inplaceEditor(prop.editor.nameSpan), editor, "Focus should have moved to the next property name"); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_RETURN"]); - yield ruleEditor.rule._applyingModifications; + info("Deleting the name of that property to remove the property"); + view.styleDocument.activeElement.blur(); + yield removeProperty(view, prop, false); newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -59,18 +56,12 @@ function* testEditPropertyAndRemove(inspector, view) { is(newValue, "", "color should have been unset."); editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(ruleEditor.newPropSpan), editor, + is(inplaceEditor(rule.editor.newPropSpan), editor, "Focus should have moved to the new property span"); - is(ruleEditor.rule.textProps.length, 0, + is(rule.textProps.length, 0, "All properties should have been removed."); - is(ruleEditor.propertyList.children.length, 1, + is(rule.editor.propertyList.children.length, 1, "Should have the new property span."); -} -function* sendKeysAndWaitForFocus(view, element, keys) { - let onFocus = once(element, "focus", true); - for (let key of keys) { - EventUtils.synthesizeKey(key, {}, view.styleWindow); - } - yield onFocus; -} + view.styleDocument.activeElement.blur(); +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js index 5414d03ff1..5690e7c2d3 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_02.js @@ -18,21 +18,17 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditPropertyAndRemove(inspector, view); -}); -function* testEditPropertyAndRemove(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + info("Getting the first property in the rule"); + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; - yield focusEditableField(view, propEditor.valueSpan); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_RETURN"]); - yield ruleEditor.rule._applyingModifications; + info("Clearing the property value"); + yield setProperty(view, prop, null, false); let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -41,17 +37,16 @@ function* testEditPropertyAndRemove(inspector, view) { }); is(newValue, "", "background-color should have been unset."); - propEditor = ruleEditor.rule.textProps[0].editor; + info("Getting the new first property in the rule"); + prop = rule.textProps[0]; let editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(propEditor.nameSpan), editor, + is(inplaceEditor(prop.editor.nameSpan), editor, "Focus should have moved to the next property name"); + view.styleDocument.activeElement.blur(); - info("Focus the property value and remove the property"); - let onChanged = view.once("ruleview-changed"); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, - ["VK_TAB", "VK_DELETE", "VK_RETURN"]); - yield onChanged; + info("Clearing the property value"); + yield setProperty(view, prop, null, false); newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -61,18 +56,12 @@ function* testEditPropertyAndRemove(inspector, view) { is(newValue, "", "color should have been unset."); editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(ruleEditor.newPropSpan), editor, + is(inplaceEditor(rule.editor.newPropSpan), editor, "Focus should have moved to the new property span"); - is(ruleEditor.rule.textProps.length, 0, + is(rule.textProps.length, 0, "All properties should have been removed."); - is(ruleEditor.propertyList.children.length, 1, + is(rule.editor.propertyList.children.length, 1, "Should have the new property span."); -} -function* sendKeysAndWaitForFocus(view, element, keys) { - let onFocus = once(element, "focus", true); - for (let key of keys) { - EventUtils.synthesizeKey(key, {}, view.styleWindow); - } - yield onFocus; -} + view.styleDocument.activeElement.blur(); +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js index 53ad3c4ec4..21a1063c2b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property-remove_03.js @@ -18,23 +18,21 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditPropertyAndRemove(inspector, view); -}); -function* testEditPropertyAndRemove(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[1].editor; + info("Getting the second property in the rule"); + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[1]; - yield focusEditableField(view, propEditor.valueSpan); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, [ - { key: "VK_DELETE", modifiers: {} }, - { key: "VK_TAB", modifiers: { shiftKey: true } } - ]); - yield ruleEditor.rule._applyingModifications; + info("Clearing the property value and pressing shift-tab"); + let editor = yield focusEditableField(view, prop.editor.valueSpan); + let onValueDone = view.once("ruleview-changed"); + editor.input.value = ""; + EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow); + yield onValueDone; let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -42,28 +40,31 @@ function* testEditPropertyAndRemove(inspector, view) { name: "color" }); is(newValue, "", "color should have been unset."); - is(propEditor.valueSpan.textContent, "", + is(prop.editor.valueSpan.textContent, "", "'' property value is correctly set."); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, [ - { key: "VK_TAB", modifiers: { shiftKey: true } } - ]); - yield ruleEditor.rule._applyingModifications; + info("Pressing shift-tab again to focus the previous property value"); + let onValueFocused = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow); + yield onValueFocused; - propEditor = ruleEditor.rule.textProps[0].editor; + info("Getting the first property in the rule"); + prop = rule.textProps[0]; - let editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(propEditor.valueSpan), editor, + editor = inplaceEditor(view.styleDocument.activeElement); + is(inplaceEditor(prop.editor.valueSpan), editor, "Focus should have moved to the previous property value"); - info("Focus the property name and remove the property"); - yield sendKeysAndWaitForFocus(view, ruleEditor.element, [ - { key: "VK_TAB", modifiers: { shiftKey: true } }, - { key: "VK_DELETE", modifiers: {} }, - { key: "VK_TAB", modifiers: { shiftKey: true } } - ]); + info("Pressing shift-tab again to focus the property name"); + let onNameFocused = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow); + yield onNameFocused; - yield ruleEditor.rule._applyingModifications; + info("Removing the name and pressing shift-tab to focus the selector"); + let onNameDeleted = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_DELETE", {}, view.styleWindow); + EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}, view.styleWindow); + yield onNameDeleted; newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -73,18 +74,10 @@ function* testEditPropertyAndRemove(inspector, view) { is(newValue, "", "background-color should have been unset."); editor = inplaceEditor(view.styleDocument.activeElement); - is(inplaceEditor(ruleEditor.selectorText), editor, + is(inplaceEditor(rule.editor.selectorText), editor, "Focus should have moved to the selector text."); - is(ruleEditor.rule.textProps.length, 0, + is(rule.textProps.length, 0, "All properties should have been removed."); - ok(!ruleEditor.propertyList.hasChildNodes(), + ok(!rule.editor.propertyList.hasChildNodes(), "Should not have any properties."); -} - -function* sendKeysAndWaitForFocus(view, element, keys) { - let onFocus = once(element, "focus", true); - for (let {key, modifiers} of keys) { - EventUtils.synthesizeKey(key, modifiers, view.styleWindow); - } - yield onFocus; -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js index e053cb315c..6f4c49e20a 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_01.js @@ -31,51 +31,51 @@ var TEST_DATA = [ { name: "border", value: "solid 1px foo", isValid: false }, ]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - let ruleEditor = getRuleViewRuleEditor(view, 1); + let rule = getRuleViewRuleEditor(view, 1).rule; for (let {name, value, isValid} of TEST_DATA) { - yield testEditProperty(ruleEditor, name, value, isValid); + yield testEditProperty(view, rule, name, value, isValid); } }); -function* testEditProperty(ruleEditor, name, value, isValid) { +function* testEditProperty(view, rule, name, value, isValid) { info("Test editing existing property name/value fields"); - let doc = ruleEditor.doc; - let propEditor = ruleEditor.rule.textProps[0].editor; + let doc = rule.editor.doc; + let prop = rule.textProps[0]; info("Focusing an existing property name in the rule-view"); - let editor = yield focusEditableField(ruleEditor.ruleView, - propEditor.nameSpan, 32, 1); + let editor = yield focusEditableField(view, prop.editor.nameSpan, 32, 1); - is(inplaceEditor(propEditor.nameSpan), editor, + is(inplaceEditor(prop.editor.nameSpan), editor, "The property name editor got focused"); let input = editor.input; info("Entering a new property name, including : to commit and " + "focus the value"); - let onValueFocus = once(ruleEditor.element, "focus", true); - let onModifications = ruleEditor.ruleView.once("ruleview-changed"); + let onValueFocus = once(rule.editor.element, "focus", true); + let onNameDone = view.once("ruleview-changed"); EventUtils.sendString(name + ":", doc.defaultView); yield onValueFocus; - yield onModifications; + yield onNameDone; // Getting the value editor after focus editor = inplaceEditor(doc.activeElement); input = editor.input; - is(inplaceEditor(propEditor.valueSpan), editor, "Focus moved to the value."); + is(inplaceEditor(prop.editor.valueSpan), editor, "Focus moved to the value."); info("Entering a new value, including ; to commit and blur the value"); + let onValueDone = view.once("ruleview-changed"); let onBlur = once(input, "blur"); EventUtils.sendString(value + ";", doc.defaultView); yield onBlur; - yield ruleEditor.rule._applyingModifications; + yield onValueDone; - is(propEditor.isValid(), isValid, + is(prop.editor.isValid(), isValid, value + " is " + isValid ? "valid" : "invalid"); info("Checking that the style property was changed on the content page"); @@ -90,10 +90,4 @@ function* testEditProperty(ruleEditor, name, value, isValid) { } else { isnot(propValue, value, name + " shouldn't have been set."); } - - info("Wait for remaining modifications to be applied"); - yield ruleEditor.rule._applyingModifications; - - is(ruleEditor.rule._applyingModifications, null, - "Reference to rule modification promise was removed after completion"); } diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js index 6e7f1361ac..b45221cfd8 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_02.js @@ -19,7 +19,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); @@ -30,12 +30,12 @@ add_task(function*() { }); function* testEditProperty(inspector, ruleView) { - let idRuleEditor = getRuleViewRuleEditor(ruleView, 1); - let propEditor = idRuleEditor.rule.textProps[0].editor; + let idRule = getRuleViewRuleEditor(ruleView, 1).rule; + let prop = idRule.textProps[0]; - let editor = yield focusEditableField(ruleView, propEditor.nameSpan); + let editor = yield focusEditableField(ruleView, prop.editor.nameSpan); let input = editor.input; - is(inplaceEditor(propEditor.nameSpan), editor, + is(inplaceEditor(prop.editor.nameSpan), editor, "Next focused editor should be the name editor."); ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, @@ -48,15 +48,16 @@ function* testEditProperty(inspector, ruleView) { info("Entering property name \"border-color\" followed by a colon to " + "focus the value"); - let onFocus = once(idRuleEditor.element, "focus", true); + let onNameDone = ruleView.once("ruleview-changed"); + let onFocus = once(idRule.editor.element, "focus", true); EventUtils.sendString("border-color:", ruleView.styleWindow); yield onFocus; - yield idRuleEditor.rule._applyingModifications; + yield onNameDone; info("Verifying that the focused field is the valueSpan"); editor = inplaceEditor(ruleView.styleDocument.activeElement); input = editor.input; - is(inplaceEditor(propEditor.valueSpan), editor, + is(inplaceEditor(prop.editor.valueSpan), editor, "Focus should have moved to the value."); ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, "Editor contents are selected."); @@ -64,14 +65,15 @@ function* testEditProperty(inspector, ruleView) { info("Entering a value following by a semi-colon to commit it"); let onBlur = once(editor.input, "blur"); // Use sendChar() to pass each character as a string so that we can test - // propEditor.warning.hidden after each character. + // prop.editor.warning.hidden after each character. for (let ch of "red;") { + let onPreviewDone = ruleView.once("ruleview-changed"); EventUtils.sendChar(ch, ruleView.styleWindow); - is(propEditor.warning.hidden, true, + yield onPreviewDone; + is(prop.editor.warning.hidden, true, "warning triangle is hidden or shown as appropriate"); } yield onBlur; - yield idRuleEditor.rule._applyingModifications; let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -80,20 +82,8 @@ function* testEditProperty(inspector, ruleView) { }); is(newValue, "red", "border-color should have been set."); - info("Entering property name \"color\" followed by a colon to " + - "focus the value"); - onFocus = once(idRuleEditor.element, "focus", true); - EventUtils.sendString("color:", ruleView.styleWindow); - yield onFocus; - - info("Verifying that the focused field is the valueSpan"); - editor = inplaceEditor(ruleView.styleDocument.activeElement); - - info("Entering a value following by a semi-colon to commit it"); - onBlur = once(editor.input, "blur"); - EventUtils.sendString("red;", ruleView.styleWindow); - yield onBlur; - yield idRuleEditor.rule._applyingModifications; + ruleView.styleDocument.activeElement.blur(); + yield addProperty(ruleView, 1, "color", "red", ";"); let props = ruleView.element.querySelectorAll(".ruleview-property"); for (let i = 0; i < props.length; i++) { @@ -103,12 +93,11 @@ function* testEditProperty(inspector, ruleView) { } function* testDisableProperty(inspector, ruleView) { - let idRuleEditor = getRuleViewRuleEditor(ruleView, 1); - let propEditor = idRuleEditor.rule.textProps[0].editor; + let idRule = getRuleViewRuleEditor(ruleView, 1).rule; + let prop = idRule.textProps[0]; info("Disabling a property"); - propEditor.enable.click(); - yield idRuleEditor.rule._applyingModifications; + yield togglePropStatus(ruleView, prop); let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -118,8 +107,7 @@ function* testDisableProperty(inspector, ruleView) { is(newValue, "", "Border-color should have been unset."); info("Enabling the property again"); - propEditor.enable.click(); - yield idRuleEditor.rule._applyingModifications; + yield togglePropStatus(ruleView, prop); newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_03.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_03.js index b9ba3fe629..a5771b41e2 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_03.js @@ -22,7 +22,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); @@ -33,24 +33,18 @@ add_task(function*() { yield focusEditableField(view, propEditor.valueSpan); info("Deleting all the text out of a value field"); - let waitForUpdates = view.once("ruleview-changed"); - yield sendCharsAndWaitForFocus(view, ruleEditor.element, - ["VK_DELETE", "VK_RETURN"]); - yield waitForUpdates; + let onRuleViewChanged = view.once("ruleview-changed"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, + ["DELETE", "RETURN"]); + yield onRuleViewChanged; info("Pressing enter a couple times to cycle through editors"); - yield sendCharsAndWaitForFocus(view, ruleEditor.element, ["VK_RETURN"]); - yield sendCharsAndWaitForFocus(view, ruleEditor.element, ["VK_RETURN"]); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["RETURN"]); + onRuleViewChanged = view.once("ruleview-changed"); + yield sendKeysAndWaitForFocus(view, ruleEditor.element, ["RETURN"]); + yield onRuleViewChanged; isnot(ruleEditor.rule.textProps[1].editor.nameSpan.style.display, "none", "The name span is visible"); is(ruleEditor.rule.textProps.length, 2, "Correct number of props"); }); - -function* sendCharsAndWaitForFocus(view, element, chars) { - let onFocus = once(element, "focus", true); - for (let ch of chars) { - EventUtils.sendChar(ch, element.ownerDocument.defaultView); - } - yield onFocus; -} diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js index 880a1c70d1..7460db4cd3 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_04.js @@ -16,20 +16,16 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testDisableProperty(inspector, view); -}); -function* testDisableProperty(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; info("Disabling a property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, prop); let newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, @@ -38,23 +34,21 @@ function* testDisableProperty(inspector, view) { }); is(newValue, "", "background-color should have been unset."); - yield testEditDisableProperty(view, ruleEditor, propEditor, - propEditor.nameSpan, "VK_ESCAPE"); - yield testEditDisableProperty(view, ruleEditor, propEditor, - propEditor.valueSpan, "VK_ESCAPE"); - yield testEditDisableProperty(view, ruleEditor, propEditor, - propEditor.valueSpan, "VK_TAB"); - yield testEditDisableProperty(view, ruleEditor, propEditor, - propEditor.valueSpan, "VK_RETURN"); -} + yield testEditDisableProperty(view, rule, prop, "name", "VK_ESCAPE"); + yield testEditDisableProperty(view, rule, prop, "value", "VK_ESCAPE"); + yield testEditDisableProperty(view, rule, prop, "value", "VK_TAB"); + yield testEditDisableProperty(view, rule, prop, "value", "VK_RETURN"); +}); -function* testEditDisableProperty(view, ruleEditor, propEditor, - editableField, commitKey) { - let editor = yield focusEditableField(view, editableField); +function* testEditDisableProperty(view, rule, prop, fieldType, commitKey) { + let field = fieldType === "name" ? prop.editor.nameSpan + : prop.editor.valueSpan; - ok(!propEditor.element.classList.contains("ruleview-overridden"), + let editor = yield focusEditableField(view, field); + + ok(!prop.editor.element.classList.contains("ruleview-overridden"), "property is not overridden."); - is(propEditor.enable.style.visibility, "hidden", + is(prop.editor.enable.style.visibility, "hidden", "property enable checkbox is hidden."); let newValue = yield executeInContent("Test:GetRulePropertyValue", { @@ -64,17 +58,22 @@ function* testEditDisableProperty(view, ruleEditor, propEditor, }); is(newValue, "", "background-color should remain unset."); + let onChangeDone; + if (fieldType === "value") { + onChangeDone = view.once("ruleview-changed"); + } + let onBlur = once(editor.input, "blur"); EventUtils.synthesizeKey(commitKey, {}, view.styleWindow); yield onBlur; - yield ruleEditor.rule._applyingModifications; + yield onChangeDone; - ok(!propEditor.prop.enabled, "property is disabled."); - ok(propEditor.element.classList.contains("ruleview-overridden"), + ok(!prop.enabled, "property is disabled."); + ok(prop.editor.element.classList.contains("ruleview-overridden"), "property is overridden."); - is(propEditor.enable.style.visibility, "visible", + is(prop.editor.enable.style.visibility, "visible", "property enable checkbox is visible."); - ok(!propEditor.enable.getAttribute("checked"), + ok(!prop.editor.enable.getAttribute("checked"), "property enable checkbox is not checked."); newValue = yield executeInContent("Test:GetRulePropertyValue", { diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js index a346b27559..3d37c81d58 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_05.js @@ -16,65 +16,56 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditingDisableProperty(inspector, view); -}); -function* testEditingDisableProperty(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; info("Disabling background-color property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, prop); let newValue = yield getRulePropertyValue("background-color"); is(newValue, "", "background-color should have been unset."); - yield focusEditableField(view, propEditor.nameSpan); - info("Entering a new property name, including : to commit and " + "focus the value"); - let onValueFocus = once(ruleEditor.element, "focus", true); + + yield focusEditableField(view, prop.editor.nameSpan); + let onNameDone = view.once("ruleview-changed"); EventUtils.sendString("border-color:", view.styleWindow); - yield onValueFocus; - yield ruleEditor.rule._applyingModifications; + yield onNameDone; info("Escape editing the property value"); + let onValueDone = view.once("ruleview-changed"); EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); - yield ruleEditor.rule._applyingModifications; + yield onValueDone; newValue = yield getRulePropertyValue("border-color"); is(newValue, "blue", "border-color should have been set."); - ok(propEditor.prop.enabled, "border-color property is enabled."); - ok(!propEditor.element.classList.contains("ruleview-overridden"), + ok(prop.enabled, "border-color property is enabled."); + ok(!prop.editor.element.classList.contains("ruleview-overridden"), "border-color is not overridden"); info("Disabling border-color property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, prop); newValue = yield getRulePropertyValue("border-color"); is(newValue, "", "border-color should have been unset."); info("Enter a new property value for the border-color property"); - let editor = yield focusEditableField(view, propEditor.valueSpan); - let onBlur = once(editor.input, "blur"); - EventUtils.sendString("red;", view.styleWindow); - yield onBlur; - yield ruleEditor.rule._applyingModifications; + yield setProperty(view, prop, "red"); newValue = yield getRulePropertyValue("border-color"); is(newValue, "red", "new border-color should have been set."); - ok(propEditor.prop.enabled, "border-color property is enabled."); - ok(!propEditor.element.classList.contains("ruleview-overridden"), + ok(prop.enabled, "border-color property is enabled."); + ok(!prop.editor.element.classList.contains("ruleview-overridden"), "border-color is not overridden"); -} +}); function* getRulePropertyValue(name) { let propValue = yield executeInContent("Test:GetRulePropertyValue", { diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js index 1025292d2a..95211f1d0b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_06.js @@ -18,47 +18,35 @@ const TEST_URI = ` `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("body", inspector); - yield testEditPropertyPriorityAndDisable(inspector, view); -}); -function* testEditPropertyPriorityAndDisable(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; is((yield getComputedStyleProperty("body", null, "background-color")), "rgb(0, 128, 0)", "green background color is set."); - let editor = yield focusEditableField(view, propEditor.valueSpan); - let onBlur = once(editor.input, "blur"); - EventUtils.sendString("red !important;", view.styleWindow); - yield onBlur; - yield ruleEditor.rule._applyingModifications; + yield setProperty(view, prop, "red !important"); - is(propEditor.valueSpan.textContent, "red !important", + is(prop.editor.valueSpan.textContent, "red !important", "'red !important' property value is correctly set."); is((yield getComputedStyleProperty("body", null, "background-color")), "rgb(255, 0, 0)", "red background color is set."); info("Disabling red background color property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, prop); is((yield getComputedStyleProperty("body", null, "background-color")), "rgb(0, 128, 0)", "green background color is set."); - editor = yield focusEditableField(view, propEditor.valueSpan); - onBlur = once(editor.input, "blur"); - EventUtils.sendString("red;", view.styleWindow); - yield onBlur; - yield ruleEditor.rule._applyingModifications; + yield setProperty(view, prop, "red"); - is(propEditor.valueSpan.textContent, "red", + is(prop.editor.valueSpan.textContent, "red", "'red' property value is correctly set."); - ok(propEditor.prop.enabled, "red background-color property is enabled."); + ok(prop.enabled, "red background-color property is enabled."); is((yield getComputedStyleProperty("body", null, "background-color")), "rgb(0, 128, 0)", "green background color is set."); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js index 2b08b400c9..40314819f5 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_07.js @@ -16,40 +16,35 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testEditDisableProperty(inspector, view); -}); -function* testEditDisableProperty(inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 1); - let propEditor = ruleEditor.rule.textProps[0].editor; + let rule = getRuleViewRuleEditor(view, 1).rule; + let prop = rule.textProps[0]; info("Disabling red background color property"); - propEditor.enable.click(); - yield ruleEditor.rule._applyingModifications; + yield togglePropStatus(view, prop); + ok(!prop.enabled, "red background-color property is disabled."); - ok(!propEditor.prop.enabled, "red background-color property is disabled."); + let editor = yield focusEditableField(view, prop.editor.valueSpan); + let onDone = view.once("ruleview-changed"); + editor.input.value = "red; color: red;"; + EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow); + yield onDone; - let editor = yield focusEditableField(view, propEditor.valueSpan); - let onBlur = once(editor.input, "blur"); - EventUtils.sendString("red; color: red;", view.styleWindow); - yield onBlur; - yield ruleEditor.rule._applyingModifications; - - is(propEditor.valueSpan.textContent, "red", + is(prop.editor.valueSpan.textContent, "red", "'red' property value is correctly set."); - ok(propEditor.prop.enabled, "red background-color property is enabled."); + ok(prop.enabled, "red background-color property is enabled."); is((yield getComputedStyleProperty("#testid", null, "background-color")), "rgb(255, 0, 0)", "red background color is set."); - propEditor = ruleEditor.rule.textProps[1].editor; + let propEditor = rule.textProps[1].editor; is(propEditor.nameSpan.textContent, "color", "new 'color' property name is correctly set."); is(propEditor.valueSpan.textContent, "red", "new 'red' property value is correctly set."); is((yield getComputedStyleProperty("#testid", null, "color")), "rgb(255, 0, 0)", "red color is set."); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_08.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_08.js index 5cd0515f80..1becd40d9c 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_08.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_08.js @@ -15,29 +15,31 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testRenameProperty(inspector, view); -}); -function* testRenameProperty(inspector, view) { + info("Get the color property editor"); let ruleEditor = getRuleViewRuleEditor(view, 0); let propEditor = ruleEditor.rule.textProps[0].editor; - is(ruleEditor.rule.textProps[0].name, "color"); - info("Focus on property name"); - let editor = yield focusEditableField(ruleEditor.ruleView, - propEditor.nameSpan, 32, 1); + info("Focus the property name field"); + yield focusEditableField(ruleEditor.ruleView, propEditor.nameSpan, 32, 1); - info("Renaming the property"); + info("Rename the property to background-color"); + // Expect 3 events: the value editor being focused, the ruleview-changed event + // which signals that the new value has been previewed (fires once when the + // value gets focused), and the markupmutation event since we're modifying an + // inline style. let onValueFocus = once(ruleEditor.element, "focus", true); - let onModifications = ruleEditor.ruleView.once("ruleview-changed"); + let onRuleViewChanged = ruleEditor.ruleView.once("ruleview-changed"); + let onMutation = inspector.once("markupmutation"); EventUtils.sendString("background-color:", ruleEditor.doc.defaultView); yield onValueFocus; - yield onModifications; + yield onRuleViewChanged; + yield onMutation; is(ruleEditor.rule.textProps[0].name, "background-color"); yield waitForComputedStyleProperty("#testid", null, "background-color", @@ -45,4 +47,11 @@ function* testRenameProperty(inspector, view) { is((yield getComputedStyleProperty("#testid", null, "color")), "rgb(255, 255, 255)", "color is white"); -} + + // The value field is still focused. Blur it now and wait for the + // ruleview-changed event to avoid pending requests. + onRuleViewChanged = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_ESCAPE", {}); + yield onRuleViewChanged; +}); + diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-property_09.js b/devtools/client/inspector/rules/test/browser_rules_edit-property_09.js index aa10bd1143..51f714021c 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-property_09.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-property_09.js @@ -16,7 +16,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector-click-on-scrollbar.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector-click-on-scrollbar.js new file mode 100644 index 0000000000..2e0ed69377 --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector-click-on-scrollbar.js @@ -0,0 +1,88 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Testing ruleview inplace-editor is not blurred when clicking on the ruleview +// container scrollbar. + +const TEST_URI = ` + +
Styled Node
+`; + +add_task(function* () { + info("Toolbox height should be small enough to force scrollbars to appear"); + yield new Promise(done => { + let options = {"set": [ + ["devtools.toolbox.footer.height", 200], + ]}; + SpecialPowers.pushPrefEnv(options, done); + }); + + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let {inspector, view} = yield openRuleView(); + yield selectNode(".testclass", inspector); + + info("Check we have an overflow on the ruleview container."); + let container = view.element; + let hasScrollbar = container.offsetHeight < container.scrollHeight; + ok(hasScrollbar, "The rule view container should have a vertical scrollbar."); + + info("Focusing an existing selector name in the rule-view."); + let ruleEditor = getRuleViewRuleEditor(view, 1); + let editor = yield focusEditableField(view, ruleEditor.selectorText); + is(inplaceEditor(ruleEditor.selectorText), editor, + "The selector editor is focused."); + + info("Click on the scrollbar element."); + yield clickOnRuleviewScrollbar(view); + + is(editor.input, view.styleDocument.activeElement, + "The editor input should still be focused."); + + info("Check a new value can still be committed in the editable field"); + let newValue = ".testclass.a.b.c.d.e.f"; + let onRuleViewChanged = once(view, "ruleview-changed"); + + info("Enter new value and commit."); + editor.input.value = newValue; + EventUtils.synthesizeKey("VK_RETURN", {}); + yield onRuleViewChanged; + ok(getRuleViewRule(view, newValue), "Rule with '" + newValue + " 'exists."); +}); + +function* clickOnRuleviewScrollbar(view) { + let container = view.element; + let onScroll = once(container, "scroll"); + let rect = container.getBoundingClientRect(); + // click 5 pixels before the bottom-right corner should hit the scrollbar + EventUtils.synthesizeMouse(container, rect.width - 5, rect.height - 5, + {}, view.styleWindow); + yield onScroll; + + ok(true, "The rule view container scrolled after clicking on the scrollbar."); +} diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js index f8e08fc487..7a3b6d4675 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector-click.js @@ -16,7 +16,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode(".testclass", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector-commit.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector-commit.js index 7055d7f299..f7058371fd 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector-commit.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector-commit.js @@ -55,7 +55,7 @@ const TEST_DATA = [ } ]; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let { inspector, view } = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_01.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_01.js index d1aef87dc3..af228094bd 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_01.js @@ -16,7 +16,7 @@ const TEST_URI = ` This is a span `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_02.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_02.js index 600d475b5f..503f91efaf 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_02.js @@ -24,7 +24,7 @@ const TEST_URI = ` const PSEUDO_PREF = "devtools.inspector.show_pseudo_elements"; -add_task(function*() { +add_task(function* () { // Expand the pseudo-elements section by default. Services.prefs.setBoolPref(PSEUDO_PREF, true); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_03.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_03.js index 57f85c30b7..c6834f6ee6 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_03.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_03.js @@ -16,7 +16,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode(".testclass", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js index 01f2933c03..59f7ba9a47 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_04.js @@ -16,7 +16,7 @@ const TEST_URI = `

Test the selector highlighter

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("p", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_05.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_05.js index 60591238b4..1a048dcd5d 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_05.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_05.js @@ -18,7 +18,7 @@ const TEST_URI = ` This is a span `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); @@ -71,42 +71,7 @@ function* checkModifiedElement(view, name) { function* testAddProperty(view) { info("Test creating a new property"); - - let ruleEditor = getRuleViewRuleEditor(view, 1); - - info("Focusing a new property name in the rule-view"); - let editor = yield focusEditableField(view, ruleEditor.closeBrace); - - is(inplaceEditor(ruleEditor.newPropSpan), editor, - "The new property editor got focused"); - let input = editor.input; - - info("Entering text-align in the property name editor"); - input.value = "text-align"; - - info("Pressing return to commit and focus the new value field"); - let onValueFocus = once(ruleEditor.element, "focus", true); - let onRuleViewChanged = view.once("ruleview-changed"); - EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow); - yield onValueFocus; - yield onRuleViewChanged; - - // Getting the new value editor after focus - editor = inplaceEditor(view.styleDocument.activeElement); - let textProp = ruleEditor.rule.textProps[0]; - - is(ruleEditor.rule.textProps.length, 1, "Created a new text property."); - is(ruleEditor.propertyList.children.length, 1, "Created a property editor."); - is(editor, inplaceEditor(textProp.editor.valueSpan), - "Editing the value span now."); - - info("Entering a value and bluring the field to expect a rule change"); - editor.input.value = "center"; - let onBlur = once(editor.input, "blur"); - onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); - editor.input.blur(); - yield onBlur; - yield onRuleViewChanged; + let textProp = yield addProperty(view, 1, "text-align", "center"); is(textProp.value, "center", "Text prop should have been changed."); is(textProp.overridden, false, "Property should not be overridden"); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_06.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_06.js index 8fc6f82abc..7d782a309f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_06.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_06.js @@ -18,7 +18,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode(".testclass", inspector); diff --git a/devtools/client/inspector/rules/test/browser_rules_edit-selector_07.js b/devtools/client/inspector/rules/test/browser_rules_edit-selector_07.js index 05b9d07209..81c7aad720 100644 --- a/devtools/client/inspector/rules/test/browser_rules_edit-selector_07.js +++ b/devtools/client/inspector/rules/test/browser_rules_edit-selector_07.js @@ -22,7 +22,7 @@ const TEST_URI = ` This is a span `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); diff --git a/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_01.js b/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_01.js index 9981b1233e..c9c7cd3d24 100644 --- a/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_01.js @@ -22,7 +22,7 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); @@ -30,51 +30,65 @@ add_task(function*() { yield testEditableFieldFocus(inspector, view, "VK_TAB"); }); -function* testEditableFieldFocus(inspector, view, commitKey, options={}) { +function* testEditableFieldFocus(inspector, view, commitKey) { + info("Click on the selector of the inline style ('element')"); let ruleEditor = getRuleViewRuleEditor(view, 0); - let onFocus = once(ruleEditor.element, "focus", true); ruleEditor.selectorText.click(); yield onFocus; assertEditor(view, ruleEditor.newPropSpan, "Focus should be in the element property span"); + info("Focus the next field with " + commitKey); ruleEditor = getRuleViewRuleEditor(view, 1); - - yield focusNextEditableField(view, ruleEditor, commitKey, options); - yield assertEditor(view, ruleEditor.selectorText, + yield focusNextEditableField(view, ruleEditor, commitKey); + assertEditor(view, ruleEditor.selectorText, "Focus should have moved to the next rule selector"); - for (let textProp of ruleEditor.rule.textProps) { + for (let i = 0; i < ruleEditor.rule.textProps.length; i++) { + let textProp = ruleEditor.rule.textProps[i]; let propEditor = textProp.editor; - yield focusNextEditableField(view, ruleEditor, commitKey, options); - yield assertEditor(view, propEditor.nameSpan, + info("Focus the next field with " + commitKey); + // Expect a ruleview-changed event if we are moving from a property value + // to the next property name (which occurs after the first iteration, as for + // i=0, the previous field is the selector). + let onRuleViewChanged = i > 0 ? view.once("ruleview-changed") : null; + yield focusNextEditableField(view, ruleEditor, commitKey); + yield onRuleViewChanged; + assertEditor(view, propEditor.nameSpan, "Focus should have moved to the property name"); - yield focusNextEditableField(view, ruleEditor, commitKey, options); - yield assertEditor(view, propEditor.valueSpan, + info("Focus the next field with " + commitKey); + yield focusNextEditableField(view, ruleEditor, commitKey); + assertEditor(view, propEditor.valueSpan, "Focus should have moved to the property value"); } - yield focusNextEditableField(view, ruleEditor, commitKey, options); - yield assertEditor(view, ruleEditor.newPropSpan, + // Expect a ruleview-changed event again as we're bluring a property value. + let onRuleViewChanged = view.once("ruleview-changed"); + yield focusNextEditableField(view, ruleEditor, commitKey); + yield onRuleViewChanged; + assertEditor(view, ruleEditor.newPropSpan, "Focus should have moved to the new property span"); ruleEditor = getRuleViewRuleEditor(view, 2); - yield focusNextEditableField(view, ruleEditor, commitKey, options); - yield assertEditor(view, ruleEditor.selectorText, + yield focusNextEditableField(view, ruleEditor, commitKey); + assertEditor(view, ruleEditor.selectorText, "Focus should have moved to the next rule selector"); + + info("Blur the selector field"); + EventUtils.synthesizeKey("VK_ESCAPE", {}); } -function* focusNextEditableField(view, ruleEditor, commitKey, options) { +function* focusNextEditableField(view, ruleEditor, commitKey) { let onFocus = once(ruleEditor.element, "focus", true); - EventUtils.synthesizeKey(commitKey, options, view.styleWindow); + EventUtils.synthesizeKey(commitKey, {}, view.styleWindow); yield onFocus; } -function* assertEditor(view, element, message) { +function assertEditor(view, element, message) { let editor = inplaceEditor(view.styleDocument.activeElement); is(inplaceEditor(element), editor, message); } diff --git a/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_02.js b/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_02.js index af5e2b9bc6..13ad221f02 100644 --- a/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_editable-field-focus_02.js @@ -22,14 +22,14 @@ const TEST_URI = `
Styled Node
`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); yield testEditableFieldFocus(inspector, view, "VK_TAB", { shiftKey: true }); }); -function* testEditableFieldFocus(inspector, view, commitKey, options={}) { +function* testEditableFieldFocus(inspector, view, commitKey, options = {}) { let ruleEditor = getRuleViewRuleEditor(view, 2); let editor = yield focusEditableField(view, ruleEditor.selectorText); is(inplaceEditor(ruleEditor.selectorText), editor, @@ -37,36 +37,42 @@ function* testEditableFieldFocus(inspector, view, commitKey, options={}) { ruleEditor = getRuleViewRuleEditor(view, 1); - yield focusNextEditableField(view, ruleEditor, commitKey, options); + yield focusNextField(view, ruleEditor, commitKey, options); assertEditor(view, ruleEditor.newPropSpan, "Focus should have moved to the new property span"); for (let textProp of ruleEditor.rule.textProps.slice(0).reverse()) { let propEditor = textProp.editor; - yield focusNextEditableField(view, ruleEditor, commitKey, options); + yield focusNextField(view, ruleEditor, commitKey, options); yield assertEditor(view, propEditor.valueSpan, "Focus should have moved to the property value"); - yield focusNextEditableField(view, ruleEditor, commitKey, options); + yield focusNextFieldAndExpectChange(view, ruleEditor, commitKey, options); yield assertEditor(view, propEditor.nameSpan, "Focus should have moved to the property name"); } ruleEditor = getRuleViewRuleEditor(view, 1); - yield focusNextEditableField(view, ruleEditor, commitKey, options); + yield focusNextField(view, ruleEditor, commitKey, options); yield assertEditor(view, ruleEditor.selectorText, "Focus should have moved to the '#testid' rule selector"); ruleEditor = getRuleViewRuleEditor(view, 0); - yield focusNextEditableField(view, ruleEditor, commitKey, options); + yield focusNextField(view, ruleEditor, commitKey, options); assertEditor(view, ruleEditor.newPropSpan, "Focus should have moved to the new property span"); } -function* focusNextEditableField(view, ruleEditor, commitKey, options) { +function* focusNextFieldAndExpectChange(view, ruleEditor, commitKey, options) { + let onRuleViewChanged = view.once("ruleview-changed"); + yield focusNextField(view, ruleEditor, commitKey, options); + yield onRuleViewChanged; +} + +function* focusNextField(view, ruleEditor, commitKey, options) { let onFocus = once(ruleEditor.element, "focus", true); EventUtils.synthesizeKey(commitKey, options, view.styleWindow); yield onFocus; diff --git a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js index 55a46f913c..c3c35b9e76 100644 --- a/devtools/client/inspector/rules/test/browser_rules_eyedropper.js +++ b/devtools/client/inspector/rules/test/browser_rules_eyedropper.js @@ -10,8 +10,6 @@ Services.telemetry.canRecordExtended = true; registerCleanupFunction(function() { Services.telemetry.canRecordExtended = oldCanRecord; }); -const HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT"; -const FLAG_HISTOGRAM_ID = "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG"; const EXPECTED_TELEMETRY = { "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT": 2, "DEVTOOLS_PICKER_EYEDROPPER_OPENED_PER_USER_FLAG": 1 @@ -40,13 +38,15 @@ const TEST_URI = `
`; -const ORIGINAL_COLOR = "rgb(255, 0, 153)"; // #f09 -const EXPECTED_COLOR = "rgb(255, 255, 85)"; // #ff5 +// #f09 +const ORIGINAL_COLOR = "rgb(255, 0, 153)"; +// #ff5 +const EXPECTED_COLOR = "rgb(255, 255, 85)"; // Test opening the eyedropper from the color picker. Pressing escape // to close it, and clicking the page to select a color. -add_task(function*() { +add_task(function* () { // clear telemetry so we can get accurate counts clearTelemetry(); @@ -103,8 +103,7 @@ function* testSelect(view, swatch, dropper) { let color = swatch.style.backgroundColor; is(color, EXPECTED_COLOR, "swatch changed colors"); - let element = content.document.querySelector("div"); - is(content.window.getComputedStyle(element).backgroundColor, + is((yield getComputedStyleProperty("div", null, "background-color")), EXPECTED_COLOR, "div's color set to body color after dropper"); } @@ -148,7 +147,7 @@ function openEyedropper(view, swatch) { return deferred.promise; } -function inspectPage(dropper, click=true) { +function inspectPage(dropper, click = true) { let target = document.documentElement; let win = window; diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js index c959079ccb..d15a842216 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-appears-on-swatch-click.js @@ -7,7 +7,7 @@ const TEST_URL = URL_ROOT + "doc_filter.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URL); let {view} = yield openRuleView(); @@ -17,12 +17,11 @@ add_task(function*() { .querySelector(".ruleview-filterswatch"); let filterTooltip = view.tooltips.filterEditor; - let onShow = filterTooltip.tooltip.once("shown"); + // Clicking on a cssfilter swatch sets the current filter value in the tooltip + // which, in turn, makes the FilterWidget emit an "updated" event that causes + // the rule-view to refresh. So we must wait for the ruleview-changed event. let onRuleViewChanged = view.once("ruleview-changed"); swatch.click(); - yield onShow; - // Clicking on swatch runs a preview of the current value - // and updates the rule-view yield onRuleViewChanged; ok(true, "The shown event was emitted after clicking on swatch"); @@ -30,5 +29,5 @@ add_task(function*() { "The inplace editor wasn't shown as a result of the filter swatch click"); yield filterTooltip.widget; - filterTooltip.hide(); + yield hideTooltipAndWaitForRuleViewChanged(filterTooltip, view); }); diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js index d708f1ae23..ef2e4bf457 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-commit-on-ENTER.js @@ -7,30 +7,39 @@ const TEST_URL = URL_ROOT + "doc_filter.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URL); let {view} = yield openRuleView(); - info("Getting the filter swatch element"); + info("Get the filter swatch element"); let swatch = getRuleViewProperty(view, "body", "filter").valueSpan .querySelector(".ruleview-filterswatch"); - let filterTooltip = view.tooltips.filterEditor; - let onShow = filterTooltip.tooltip.once("shown"); + info("Click on the filter swatch element"); + // Clicking on a cssfilter swatch sets the current filter value in the tooltip + // which, in turn, makes the FilterWidget emit an "updated" event that causes + // the rule-view to refresh. So we must wait for the ruleview-changed event. + let onRuleViewChanged = view.once("ruleview-changed"); swatch.click(); - yield onShow; + yield onRuleViewChanged; + info("Get the cssfilter widget instance"); + let filterTooltip = view.tooltips.filterEditor; let widget = yield filterTooltip.widget; + info("Set a new value in the cssfilter widget"); + onRuleViewChanged = view.once("ruleview-changed"); widget.setCssValue("blur(2px)"); yield waitForComputedStyleProperty("body", null, "filter", "blur(2px)"); - + yield onRuleViewChanged; ok(true, "Changes previewed on the element"); - info("Pressing RETURN to commit changes"); + info("Press RETURN to commit changes"); + // Pressing return in the cssfilter tooltip triggeres 2 ruleview-changed + onRuleViewChanged = waitForNEvents(view, "ruleview-changed", 2); EventUtils.sendKey("RETURN", widget.styleWindow); + yield onRuleViewChanged; - const computed = content.getComputedStyle(content.document.body); - is(computed.filter, "blur(2px)", + is((yield getComputedStyleProperty("body", null, "filter")), "blur(2px)", "The elemenet's filter was kept after RETURN"); }); diff --git a/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js b/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js index 22c5256256..048bafaded 100644 --- a/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js +++ b/devtools/client/inspector/rules/test/browser_rules_filtereditor-revert-on-ESC.js @@ -8,7 +8,7 @@ const TEST_URL = URL_ROOT + "doc_filter.html"; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URL); let {view} = yield openRuleView(); yield testPressingEscapeRevertsChanges(view); diff --git a/devtools/client/inspector/rules/test/browser_rules_guessIndentation.js b/devtools/client/inspector/rules/test/browser_rules_guessIndentation.js index d7bcdc7287..ba2a1d7fb4 100644 --- a/devtools/client/inspector/rules/test/browser_rules_guessIndentation.js +++ b/devtools/client/inspector/rules/test/browser_rules_guessIndentation.js @@ -30,44 +30,18 @@ div { } `; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {toolbox, inspector, view} = yield openRuleView(); yield selectNode("#testid", inspector); - yield testIndentation(toolbox, inspector, view); -}); -function* testIndentation(toolbox, inspector, view) { - let ruleEditor = getRuleViewRuleEditor(view, 2); - - info("Focusing a new property name in the rule-view"); - let editor = yield focusEditableField(view, ruleEditor.closeBrace); - - let input = editor.input; - - info("Entering color in the property name editor"); - input.value = "color"; - - info("Pressing return to commit and focus the new value field"); - let onValueFocus = once(ruleEditor.element, "focus", true); - let onModifications = ruleEditor.rule._applyingModifications; - EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow); - yield onValueFocus; - yield onModifications; - - // Getting the new value editor after focus - editor = inplaceEditor(view.styleDocument.activeElement); - info("Entering a value and bluring the field to expect a rule change"); - editor.input.value = "chartreuse"; - let onBlur = once(editor.input, "blur"); - onModifications = ruleEditor.rule._applyingModifications; - editor.input.blur(); - yield onBlur; - yield onModifications; + info("Add a new property in the rule-view"); + yield addProperty(view, 2, "color", "chartreuse"); + info("Switch to the style-editor"); let { UI } = yield toolbox.selectTool("styleeditor"); let styleEditor = yield UI.editors[0].getSourceEditor(); let text = styleEditor.sourceEditor.getText(); is(text, expectedText, "style inspector changes are synced"); -} +}); diff --git a/devtools/client/inspector/rules/test/browser_rules_inherited-properties_01.js b/devtools/client/inspector/rules/test/browser_rules_inherited-properties_01.js index eee5718642..d1f6d7f45b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_inherited-properties_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_inherited-properties_01.js @@ -7,8 +7,6 @@ // Check that inherited properties appear for a nested element in the // rule view. -var {ELEMENT_STYLE} = require("devtools/server/actors/styles"); - const TEST_URI = `
', - '', - '', - '', - '', - '', - '', - '

Some header text

', - '

hi.

', - '

I am a test-case. This text exists ', - 'solely to provide some things to ', - '', - 'highlight and count ', - 'style list-items in the box at right. If you are reading this, ', - 'you should go do something else instead. Maybe read a book. Or better ', - 'yet, write some test-cases for another bit of code. ', - 'some text

', - '

more text

', - '

even more text

', - '
', - '', - ''].join("\n")); +const DOCUMENT_URL = "data:text/html;charset=utf-8," + encodeURIComponent(` + + + Rule view style editor link test +
+ + + + + + +

Some header text

+

hi.

+

I am a test-case. This text exists + solely to provide some things to + + highlight and count + style list-items in the box at right. If you are reading this, + you should go do something else instead. Maybe read a book. Or better + yet, write some test-cases for another bit of code. + some text

+

more text

+

even more text

+
+ + +`); -add_task(function*() { +add_task(function* () { yield addTab(DOCUMENT_URL); - let {toolbox, inspector, view} = yield openRuleView(); + let {toolbox, inspector, view, testActor} = yield openRuleView(); yield selectNode("div", inspector); yield testInlineStyle(view); - yield testFirstInlineStyleSheet(view, toolbox); - yield testSecondInlineStyleSheet(view, toolbox); - yield testExternalStyleSheet(view, toolbox); + yield testFirstInlineStyleSheet(view, toolbox, testActor); + yield testSecondInlineStyleSheet(view, toolbox, testActor); + yield testExternalStyleSheet(view, toolbox, testActor); }); function* testInlineStyle(view) { @@ -80,7 +78,7 @@ function* testInlineStyle(view) { gBrowser.removeTab(tab); } -function* testFirstInlineStyleSheet(view, toolbox) { +function* testFirstInlineStyleSheet(view, toolbox, testActor) { info("Testing inline stylesheet"); info("Listening for toolbox switch to the styleeditor"); @@ -92,10 +90,10 @@ function* testFirstInlineStyleSheet(view, toolbox) { ok(true, "Switched to the style-editor panel in the toolbox"); - validateStyleEditorSheet(editor, 0); + yield validateStyleEditorSheet(editor, 0, testActor); } -function* testSecondInlineStyleSheet(view, toolbox) { +function* testSecondInlineStyleSheet(view, toolbox, testActor) { info("Testing second inline stylesheet"); info("Waiting for the stylesheet editor to be selected"); @@ -112,10 +110,10 @@ function* testSecondInlineStyleSheet(view, toolbox) { is(toolbox.currentToolId, "styleeditor", "The style editor is selected again"); - validateStyleEditorSheet(editor, 1); + yield validateStyleEditorSheet(editor, 1, testActor); } -function* testExternalStyleSheet(view, toolbox) { +function* testExternalStyleSheet(view, toolbox, testActor) { info("Testing external stylesheet"); info("Waiting for the stylesheet editor to be selected"); @@ -132,17 +130,21 @@ function* testExternalStyleSheet(view, toolbox) { is(toolbox.currentToolId, "styleeditor", "The style editor is selected again"); - validateStyleEditorSheet(editor, 2); + yield validateStyleEditorSheet(editor, 2, testActor); } -function validateStyleEditorSheet(editor, expectedSheetIndex) { +function* validateStyleEditorSheet(editor, expectedSheetIndex, testActor) { info("validating style editor stylesheet"); is(editor.styleSheet.styleSheetIndex, expectedSheetIndex, "loaded stylesheet index matches document stylesheet"); - let sheet = content.document.styleSheets[expectedSheetIndex]; - is(editor.styleSheet.href, sheet.href, - "loaded stylesheet href matches document stylesheet"); + let href = editor.styleSheet.href || editor.styleSheet.nodeHref; + + let expectedHref = yield testActor.eval( + `content.document.styleSheets[${expectedSheetIndex}].href || + content.document.location.href`); + + is(href, expectedHref, "loaded stylesheet href matches document stylesheet"); } function testRuleViewLinkLabel(view) { diff --git a/devtools/client/inspector/rules/test/browser_rules_urls-clickable.js b/devtools/client/inspector/rules/test/browser_rules_urls-clickable.js index c59e89fcca..fb1211e3c8 100644 --- a/devtools/client/inspector/rules/test/browser_rules_urls-clickable.js +++ b/devtools/client/inspector/rules/test/browser_rules_urls-clickable.js @@ -12,7 +12,7 @@ const BASE_64_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAA" + "FCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAA" + "BJRU5ErkJggg=="; -add_task(function*() { +add_task(function* () { yield addTab(TEST_URI); let {inspector, view} = yield openRuleView(); yield selectNodes(inspector, view); diff --git a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js index c5e91bdfb8..e1bafff9b2 100644 --- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js +++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles-uneditable.js @@ -17,7 +17,7 @@ const TEST_URI = ` var PREF_UA_STYLES = "devtools.inspector.showUserAgentStyles"; -add_task(function*() { +add_task(function* () { info("Starting the test with the pref set to true before toolbox is opened"); Services.prefs.setBoolPref(PREF_UA_STYLES, true); diff --git a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js index a9bb24031b..eccbf4fe1b 100644 --- a/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js +++ b/devtools/client/inspector/rules/test/browser_rules_user-agent-styles.js @@ -48,6 +48,8 @@ const TEST_DATA = [ numUserRules: 1, numUARules: 0 }, + // Note that some tests below assume that the "a" selector is the + // last test in TEST_DATA. { selector: "a", numUserRules: 3, @@ -55,7 +57,7 @@ const TEST_DATA = [ } ]; -add_task(function*() { +add_task(function* () { requestLongerTimeout(2); info("Starting the test with the pref set to true before toolbox is opened"); @@ -108,15 +110,20 @@ function* userAgentStylesVisible(inspector, view) { ok(uaRules.length > data.numUARules, "Has UA rules"); } - ok(userRules.some(rule=> rule.matchedSelectors.length === 1), + ok(userRules.some(rule => rule.matchedSelectors.length === 1), "There is an inline style for element in user styles"); - ok(uaRules.some(rule=> rule.matchedSelectors.indexOf(":-moz-any-link")), - "There is a rule for :-moz-any-link"); - ok(uaRules.some(rule=> rule.matchedSelectors.indexOf("*|*:link")), - "There is a rule for *|*:link"); - ok(uaRules.some(rule=> rule.matchedSelectors.length === 1), - "Inline styles for ua styles"); + // These tests rely on the "a" selector being the last test in + // TEST_DATA. + ok(uaRules.some(rule => { + return rule.matchedSelectors.indexOf(":-moz-any-link") !== -1; + }), "There is a rule for :-moz-any-link"); + ok(uaRules.some(rule => { + return rule.matchedSelectors.indexOf("*|*:link") !== -1; + }), "There is a rule for *|*:link"); + ok(uaRules.some(rule => { + return rule.matchedSelectors.length === 1; + }), "Inline styles for ua styles"); } function* userAgentStylesNotVisible(inspector, view) { @@ -140,11 +147,13 @@ function* compareAppliedStylesWithUI(inspector, view, filter) { info("Making sure that UI is consistent with pageStyle.getApplied"); let entries = yield inspector.pageStyle.getApplied( - inspector.selection.nodeFront, { - inherited: true, - matchedSelectors: true, - filter: filter - }); + inspector.selection.nodeFront, + { + inherited: true, + matchedSelectors: true, + filter: filter + } + ); // We may see multiple entries that map to a given rule; filter the // duplicates here to match what the UI does. diff --git a/devtools/client/inspector/rules/test/browser_rules_user-property-reset.js b/devtools/client/inspector/rules/test/browser_rules_user-property-reset.js index 45def46ca1..dcfb1dd28f 100644 --- a/devtools/client/inspector/rules/test/browser_rules_user-property-reset.js +++ b/devtools/client/inspector/rules/test/browser_rules_user-property-reset.js @@ -12,7 +12,7 @@ const TEST_URI = `

element 2

`; -add_task(function*() { +add_task(function* () { yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); let {inspector, view, testActor} = yield openRuleView(); @@ -75,6 +75,7 @@ function* getContainerStyleAttrValue(id, {walker, markup}) { } attrIndex++; } + return undefined; } function* assertRuleAndMarkupViewWidth(id, value, ruleView, inspector) { diff --git a/devtools/client/inspector/rules/test/doc_author-sheet.html b/devtools/client/inspector/rules/test/doc_author-sheet.html index a4d0959789..f8c2eadd53 100644 --- a/devtools/client/inspector/rules/test/doc_author-sheet.html +++ b/devtools/client/inspector/rules/test/doc_author-sheet.html @@ -11,16 +11,16 @@ diff --git a/devtools/client/inspector/rules/test/doc_content_stylesheet.html b/devtools/client/inspector/rules/test/doc_content_stylesheet.html index 3d3b132d61..3ea65f6065 100644 --- a/devtools/client/inspector/rules/test/doc_content_stylesheet.html +++ b/devtools/client/inspector/rules/test/doc_content_stylesheet.html @@ -5,13 +5,15 @@ diff --git a/devtools/client/inspector/rules/test/doc_cssom.html b/devtools/client/inspector/rules/test/doc_cssom.html index 4a2dad60f5..65d4dfb7d2 100644 --- a/devtools/client/inspector/rules/test/doc_cssom.html +++ b/devtools/client/inspector/rules/test/doc_cssom.html @@ -5,6 +5,7 @@ CSSOM test diff --git a/dom/network/tests/test_tcpsocket_legacy.html b/dom/network/tests/test_tcpsocket_legacy.html index 9efcf72a4c..a75cbe3d79 100644 --- a/dom/network/tests/test_tcpsocket_legacy.html +++ b/dom/network/tests/test_tcpsocket_legacy.html @@ -40,6 +40,8 @@ Test of legacy navigator interface for opening TCPSocket/TCPServerSocket. -1); listeningServer.onconnect = function(ev) { ok(true, "got server connect"); + listeningServer.close(); + listeningServer = null; ev.socket.close() } @@ -48,7 +50,14 @@ Test of legacy navigator interface for opening TCPSocket/TCPServerSocket. clientSocket.onopen = function() { ok(true, "got client open"); } clientSocket.onclose = function() { ok(true, "got client close"); - SimpleTest.finish(); + clientSocket.close(); + clientSocket = null; + setTimeout(function() { + // This just helps the test harness clean up quickly + SpecialPowers.forceCC(); + SpecialPowers.forceGC(); + SimpleTest.finish(); + }, 0); } } diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 5a5862df65..01301eac7c 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -289,7 +289,8 @@ class GetPermissionRunnable final : public WorkerMainThreadRunnable public: explicit GetPermissionRunnable(WorkerPrivate* aWorker) - : WorkerMainThreadRunnable(aWorker) + : WorkerMainThreadRunnable(aWorker, + NS_LITERAL_CSTRING("Notification :: Get Permission")) , mPermission(NotificationPermission::Denied) { } @@ -2446,7 +2447,8 @@ class CloseNotificationRunnable final public: explicit CloseNotificationRunnable(Notification* aNotification) - : WorkerMainThreadRunnable(aNotification->mWorkerPrivate) + : WorkerMainThreadRunnable(aNotification->mWorkerPrivate, + NS_LITERAL_CSTRING("Notification :: Close Notification")) , mNotification(aNotification) , mHadObserver(false) {} @@ -2553,7 +2555,8 @@ class CheckLoadRunnable final : public WorkerMainThreadRunnable public: explicit CheckLoadRunnable(WorkerPrivate* aWorker, const nsACString& aScope) - : WorkerMainThreadRunnable(aWorker) + : WorkerMainThreadRunnable(aWorker, + NS_LITERAL_CSTRING("Notification :: Check Load")) , mRv(NS_ERROR_DOM_SECURITY_ERR) , mScope(aScope) { } diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index a7d771f43f..c9c5b6abb2 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -8,6 +8,7 @@ #include "nsContentPolicyUtils.h" #include "nsIDOMElement.h" #include "nsIStreamConverterService.h" +#include "nsIStreamLoader.h" #include "nsIHttpChannel.h" #include "nsIHttpChannelInternal.h" #include "nsIFileChannel.h" @@ -34,7 +35,7 @@ #include "nsDataHashtable.h" #include "nsNullPrincipal.h" -#define MAGIC_REQUEST_CONTEXT 0x01020304 +#define BYTERANGE_REQUEST_CONTEXT 0x01020304 // nsPluginByteRangeStreamListener @@ -55,7 +56,7 @@ private: nsCOMPtr mStreamConverter; nsWeakPtr mWeakPtrPluginStreamListenerPeer; - bool mRemoveMagicNumber; + bool mRemoveByteRangeRequest; }; NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener, @@ -66,7 +67,7 @@ NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener, nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr) { mWeakPtrPluginStreamListenerPeer = aWeakPtr; - mRemoveMagicNumber = false; + mRemoveByteRangeRequest = false; } nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener() @@ -152,7 +153,7 @@ nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports // if server cannot continue with byte range (206 status) and sending us whole object (200 status) // reset this seekable stream & try serve it to plugin instance as a file mStreamConverter = finalStreamListener; - mRemoveMagicNumber = true; + mRemoveByteRangeRequest = true; rv = pslp->ServeStreamAsFile(request, ctxt); return rv; @@ -176,15 +177,15 @@ nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports NS_ERROR("OnStopRequest received for untracked byte-range request!"); } - if (mRemoveMagicNumber) { - // remove magic number from container + if (mRemoveByteRangeRequest) { + // remove byte range request from container nsCOMPtr container = do_QueryInterface(ctxt); if (container) { - uint32_t magicNumber = 0; - container->GetData(&magicNumber); - if (magicNumber == MAGIC_REQUEST_CONTEXT) { + uint32_t byteRangeRequest = 0; + container->GetData(&byteRangeRequest); + if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) { // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest() - // set it to something that is not the magic number. + // set it to something that is not the byte range request. container->SetData(0); } } else { @@ -664,6 +665,63 @@ nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACStr return; } +// XXX: Converting the channel within nsPluginStreamListenerPeer +// to use asyncOpen2() and do not want to touch the fragile logic +// of byte range requests. Hence we just introduce this lightweight +// wrapper to proxy the context. +class PluginContextProxy final : public nsIStreamListener +{ +public: + NS_DECL_ISUPPORTS + + PluginContextProxy(nsIStreamListener *aListener, nsISupports* aContext) + : mListener(aListener) + , mContext(aContext) + { + MOZ_ASSERT(aListener); + MOZ_ASSERT(aContext); + } + + NS_IMETHOD + OnDataAvailable(nsIRequest* aRequest, + nsISupports* aContext, + nsIInputStream *aIStream, + uint64_t aSourceOffset, + uint32_t aLength) override + { + // Proxy OnDataAvailable using the internal context + return mListener->OnDataAvailable(aRequest, + mContext, + aIStream, + aSourceOffset, + aLength); + } + + NS_IMETHOD + OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) override + { + // Proxy OnStartRequest using the internal context + return mListener->OnStartRequest(aRequest, mContext); + } + + NS_IMETHOD + OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, + nsresult aStatusCode) override + { + // Proxy OnStopRequest using the inernal context + return mListener->OnStopRequest(aRequest, + mContext, + aStatusCode); + } + +private: + ~PluginContextProxy() {} + nsCOMPtr mListener; + nsCOMPtr mContext; +}; + +NS_IMPL_ISUPPORTS(PluginContextProxy, nsIStreamListener) + nsresult nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) { @@ -696,22 +754,19 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) rv = NS_NewChannel(getter_AddRefs(channel), mURL, requestingNode, - nsILoadInfo::SEC_NORMAL, + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, loadGroup, callbacks, nsIChannel::LOAD_BYPASS_SERVICE_WORKER); } else { - // in this else branch we really don't know where the load is coming - // from and in fact should use something better than just using - // a nullPrincipal as the loadingPrincipal. - nsCOMPtr principal = nsNullPrincipal::Create(); - NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE); + // In this else branch we really don't know where the load is coming + // from. Let's fall back to using the SystemPrincipal for such Plugins. rv = NS_NewChannel(getter_AddRefs(channel), mURL, - principal, - nsILoadInfo::SEC_NORMAL, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER, loadGroup, callbacks, @@ -747,16 +802,16 @@ nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList) mPendingRequests += numRequests; nsCOMPtr container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv); - if (NS_FAILED(rv)) - return rv; - rv = container->SetData(MAGIC_REQUEST_CONTEXT); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv, rv); + rv = container->SetData(BYTERANGE_REQUEST_CONTEXT); + NS_ENSURE_SUCCESS(rv, rv); - rv = channel->AsyncOpen(converter, container); - if (NS_SUCCEEDED(rv)) - TrackRequest(channel); - return rv; + RefPtr pluginContextProxy = + new PluginContextProxy(converter, container); + rv = channel->AsyncOpen2(pluginContextProxy); + NS_ENSURE_SUCCESS(rv, rv); + TrackRequest(channel); + return NS_OK; } nsresult @@ -847,12 +902,12 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, return NS_ERROR_FAILURE; if (mAbort) { - uint32_t magicNumber = 0; // set it to something that is not the magic number. + uint32_t byteRangeRequest = 0; // set it to something that is not the byte range request. nsCOMPtr container = do_QueryInterface(aContext); if (container) - container->GetData(&magicNumber); + container->GetData(&byteRangeRequest); - if (magicNumber != MAGIC_REQUEST_CONTEXT) { + if (byteRangeRequest != BYTERANGE_REQUEST_CONTEXT) { // this is not one of our range requests mAbort = false; return NS_BINDING_ABORTED; @@ -985,9 +1040,9 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request, // we keep our connections around... nsCOMPtr container = do_QueryInterface(aContext); if (container) { - uint32_t magicNumber = 0; // set it to something that is not the magic number. - container->GetData(&magicNumber); - if (magicNumber == MAGIC_REQUEST_CONTEXT) { + uint32_t byteRangeRequest = 0; // something other than the byte range request. + container->GetData(&byteRangeRequest); + if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) { // this is one of our range requests return NS_OK; } diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index d9e9bfd02b..1d5d159890 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -266,6 +266,7 @@ nsPluginTag::nsPluginTag(const char* aName, : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion), mId(sNextId++), mContentProcessRunningCount(0), + mHadLocalInstance(false), mLibrary(nullptr), mIsJavaPlugin(false), mIsFlashPlugin(false), diff --git a/dom/plugins/base/nsPluginsDirWin.cpp b/dom/plugins/base/nsPluginsDirWin.cpp index 8d3c0b76ea..eb771af5cf 100644 --- a/dom/plugins/base/nsPluginsDirWin.cpp +++ b/dom/plugins/base/nsPluginsDirWin.cpp @@ -71,7 +71,7 @@ static char* GetKeyValue(void* verbuf, const WCHAR* key, { WCHAR keybuf[64]; // plenty for the template below, with the longest key // we use (currently "FileDescription") - const WCHAR keyFormat[] = L"\\StringFileInfo\\%04X%04X\\%s"; + const WCHAR keyFormat[] = L"\\StringFileInfo\\%04X%04X\\%ls"; WCHAR *buf = nullptr; UINT blen; diff --git a/dom/workers/ServiceWorkerRegistration.cpp b/dom/workers/ServiceWorkerRegistration.cpp index 1981c66804..76d666c36d 100644 --- a/dom/workers/ServiceWorkerRegistration.cpp +++ b/dom/workers/ServiceWorkerRegistration.cpp @@ -1071,7 +1071,8 @@ class SyncStopListeningRunnable final : public WorkerMainThreadRunnable public: SyncStopListeningRunnable(WorkerPrivate* aWorkerPrivate, WorkerListener* aListener) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("ServiceWorkerRegistration :: StopListening")) , mListener(aListener) {} diff --git a/dom/workers/URL.cpp b/dom/workers/URL.cpp index 13f2f481ed..8c2b05f206 100644 --- a/dom/workers/URL.cpp +++ b/dom/workers/URL.cpp @@ -77,7 +77,8 @@ public: CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl, const mozilla::dom::objectURLOptions& aOptions, nsAString& aURL) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: CreateURL")) , mBlobImpl(aBlobImpl) , mURL(aURL) { @@ -168,7 +169,8 @@ private: public: RevokeURLRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: RevokeURL")) , mURL(aURL) {} @@ -229,7 +231,8 @@ public: ConstructorRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL, const Optional& aBase, mozilla::ErrorResult& aRv) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: Constructor")) , mURL(aURL) , mRv(aRv) { @@ -244,7 +247,8 @@ public: ConstructorRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL, URLProxy* aBaseProxy, mozilla::ErrorResult& aRv) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("URL :: Constructor with BaseURL")) , mURL(aURL) , mBaseProxy(aBaseProxy) , mRv(aRv) @@ -326,7 +330,10 @@ public: GetterRunnable(WorkerPrivate* aWorkerPrivate, GetterType aType, nsAString& aValue, URLProxy* aURLProxy) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + // We can have telemetry keys for each getter when + // needed. + NS_LITERAL_CSTRING("URL :: getter")) , mValue(aValue) , mType(aType) , mURLProxy(aURLProxy) @@ -414,7 +421,10 @@ public: SetterRunnable(WorkerPrivate* aWorkerPrivate, SetterType aType, const nsAString& aValue, URLProxy* aURLProxy) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + // We can have telemetry keys for each setter when + // needed. + NS_LITERAL_CSTRING("URL :: setter")) , mValue(aValue) , mType(aType) , mURLProxy(aURLProxy) diff --git a/dom/workers/WorkerNavigator.cpp b/dom/workers/WorkerNavigator.cpp index 102de09c20..08d7fc656a 100644 --- a/dom/workers/WorkerNavigator.cpp +++ b/dom/workers/WorkerNavigator.cpp @@ -109,7 +109,8 @@ class GetUserAgentRunnable final : public WorkerMainThreadRunnable public: GetUserAgentRunnable(WorkerPrivate* aWorkerPrivate, nsString& aUA) - : WorkerMainThreadRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("UserAgent getter")) , mUA(aUA) { MOZ_ASSERT(aWorkerPrivate); diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index 0c21f0b706..f70cb05c40 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -15,6 +15,7 @@ #include "mozilla/DebugOnly.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/Telemetry.h" #include "js/RootingAPI.h" #include "js/Value.h" @@ -466,19 +467,20 @@ MainThreadWorkerSyncRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate, { } -StopSyncLoopRunnable::StopSyncLoopRunnable( +MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable( WorkerPrivate* aWorkerPrivate, already_AddRefed&& aSyncLoopTarget, bool aResult) : WorkerSyncRunnable(aWorkerPrivate, Move(aSyncLoopTarget)), mResult(aResult) { + AssertIsOnMainThread(); #ifdef DEBUG mWorkerPrivate->AssertValidSyncLoop(mSyncLoopTarget); #endif } nsresult -StopSyncLoopRunnable::Cancel() +MainThreadStopSyncLoopRunnable::Cancel() { nsresult rv = Run(); NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Run() failed"); @@ -490,8 +492,8 @@ StopSyncLoopRunnable::Cancel() } bool -StopSyncLoopRunnable::WorkerRun(JSContext* aCx, - WorkerPrivate* aWorkerPrivate) +MainThreadStopSyncLoopRunnable::WorkerRun(JSContext* aCx, + WorkerPrivate* aWorkerPrivate) { aWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(mSyncLoopTarget); @@ -508,11 +510,11 @@ StopSyncLoopRunnable::WorkerRun(JSContext* aCx, } bool -StopSyncLoopRunnable::DispatchInternal() +MainThreadStopSyncLoopRunnable::DispatchInternal() { MOZ_ASSERT(mSyncLoopTarget); - RefPtr runnable(this); + RefPtr runnable(this); return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL)); } @@ -572,8 +574,10 @@ MainThreadWorkerControlRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate, NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable) -WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate) +WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, + const nsACString& aTelemetryKey) : mWorkerPrivate(aWorkerPrivate) +, mTelemetryKey(aTelemetryKey) { mWorkerPrivate->AssertIsOnWorkerThread(); } @@ -583,6 +587,8 @@ WorkerMainThreadRunnable::Dispatch(ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); + TimeStamp startTime = TimeStamp::NowLoRes(); + AutoSyncLoopHolder syncLoop(mWorkerPrivate); mSyncLoopTarget = syncLoop.EventTarget(); @@ -596,6 +602,10 @@ WorkerMainThreadRunnable::Dispatch(ErrorResult& aRv) if (!syncLoop.Run()) { aRv.ThrowUncatchableException(); } + + Telemetry::Accumulate(Telemetry::SYNC_WORKER_OPERATION, mTelemetryKey, + static_cast((TimeStamp::NowLoRes() - startTime) + .ToMilliseconds())); } NS_IMETHODIMP @@ -615,6 +625,14 @@ WorkerMainThreadRunnable::Run() return NS_OK; } +WorkerCheckAPIExposureOnMainThreadRunnable::WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate): + WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("WorkerCheckAPIExposureOnMainThread")) +{} + +WorkerCheckAPIExposureOnMainThreadRunnable::~WorkerCheckAPIExposureOnMainThreadRunnable() +{} + bool WorkerCheckAPIExposureOnMainThreadRunnable::Dispatch() { diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index 412aeb4b2a..17699cc42f 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -264,18 +264,20 @@ private: PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override; }; -// This runnable is used to stop a sync loop . As sync loops keep the busy count -// incremented as long as they run this runnable does not modify the busy count +// This runnable is used to stop a sync loop and it's meant to be used on the +// main-thread only. As sync loops keep the busy count incremented as long as +// they run this runnable does not modify the busy count // in any way. -class StopSyncLoopRunnable : public WorkerSyncRunnable +class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable { bool mResult; public: // Passing null for aSyncLoopTarget is not allowed. - StopSyncLoopRunnable(WorkerPrivate* aWorkerPrivate, - already_AddRefed&& aSyncLoopTarget, - bool aResult); + MainThreadStopSyncLoopRunnable( + WorkerPrivate* aWorkerPrivate, + already_AddRefed&& aSyncLoopTarget, + bool aResult); // By default StopSyncLoopRunnables cannot be canceled since they could leave // a sync loop spinning forever. @@ -283,7 +285,7 @@ public: Cancel() override; protected: - virtual ~StopSyncLoopRunnable() + virtual ~MainThreadStopSyncLoopRunnable() { } // Called on the worker thread, in WorkerRun, right before stopping the @@ -296,33 +298,6 @@ protected: MaybeSetException() { } -private: - virtual bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; - - virtual bool - DispatchInternal() override final; -}; - -// This runnable is identical to StopSyncLoopRunnable except it is meant to be -// used on the main thread only. -class MainThreadStopSyncLoopRunnable : public StopSyncLoopRunnable -{ -public: - // Passing null for aSyncLoopTarget is not allowed. - MainThreadStopSyncLoopRunnable( - WorkerPrivate* aWorkerPrivate, - already_AddRefed&& aSyncLoopTarget, - bool aResult) - : StopSyncLoopRunnable(aWorkerPrivate, Move(aSyncLoopTarget), aResult) - { - AssertIsOnMainThread(); - } - -protected: - virtual ~MainThreadStopSyncLoopRunnable() - { } - private: virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override final @@ -333,6 +308,12 @@ private: virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override; + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; + + virtual bool + DispatchInternal() override final; }; // This runnable is processed as soon as it is received by the worker, @@ -429,8 +410,10 @@ class WorkerMainThreadRunnable : public Runnable protected: WorkerPrivate* mWorkerPrivate; nsCOMPtr mSyncLoopTarget; + const nsCString mTelemetryKey; - explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate); + explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, + const nsACString& aTelemetryKey); ~WorkerMainThreadRunnable() {} virtual bool MainThreadRun() = 0; @@ -452,13 +435,14 @@ private: // them happen while a worker is shutting down. // // Do NOT copy what this class is doing elsewhere. Just don't. -class WorkerCheckAPIExposureOnMainThreadRunnable : public WorkerMainThreadRunnable +class WorkerCheckAPIExposureOnMainThreadRunnable + : public WorkerMainThreadRunnable { public: - explicit WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate): - WorkerMainThreadRunnable(aWorkerPrivate) - {} - ~WorkerCheckAPIExposureOnMainThreadRunnable() {} + explicit + WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate); + virtual + ~WorkerCheckAPIExposureOnMainThreadRunnable(); // Returns whether the dispatch succeeded. If this returns false, the API // should not be exposed. diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index 09531ee1d1..6e6262d912 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -914,6 +914,11 @@ static bool ShouldPersistAttribute(Element* aElement, nsIAtom* aAttribute) { if (aElement->IsXULElement(nsGkAtoms::window)) { + // This is not an element of the top document, its owner is + // not an nsXULWindow. Persist it. + if (aElement->OwnerDoc()->GetParentDocument()) { + return true; + } // The following attributes of xul:window should be handled in // nsXULWindow::SavePersistentAttributes instead of here. if (aAttribute == nsGkAtoms::screenX || diff --git a/dom/xul/nsXULPrototypeCache.cpp b/dom/xul/nsXULPrototypeCache.cpp index 20522a044d..36438be092 100644 --- a/dom/xul/nsXULPrototypeCache.cpp +++ b/dom/xul/nsXULPrototypeCache.cpp @@ -212,7 +212,7 @@ nsXULPrototypeCache::PutScript(nsIURI* aURI, { MOZ_ASSERT(aScriptObject, "Need a non-NULL script"); -#ifdef DEBUG +#ifdef DEBUG_BUG_392650 if (mScriptTable.Get(aURI)) { nsAutoCString scriptName; aURI->GetSpec(scriptName); diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index ec65febd5f..e72c053b99 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -1502,7 +1502,8 @@ public: int32_t feature, nsACString& failureId, int32_t* status) - : WorkerMainThreadRunnable(workerPrivate) + : WorkerMainThreadRunnable(workerPrivate, + NS_LITERAL_CSTRING("GFX :: GetFeatureStatus")) , mGfxInfo(gfxInfo) , mFeature(feature) , mStatus(status) diff --git a/js/src/jit-test/tests/debug/bug1251919.js b/js/src/jit-test/tests/debug/bug1251919.js new file mode 100644 index 0000000000..188bfa3932 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1251919.js @@ -0,0 +1,13 @@ +// |jit-test| error: out of memory + +if (!('oomTest' in this)) + throw new Error("out of memory"); + +// jsfunfuzz-generated +fullcompartmentchecks(true); +// Adapted from randomly chosen test: js/src/jit-test/tests/debug/bug-1248162.js +var dbg = new Debugger; +dbg.onNewGlobalObject = function() {}; +oomTest(function() { + newGlobal(); +}) diff --git a/js/src/jit-test/tests/debug/bug1254123.js b/js/src/jit-test/tests/debug/bug1254123.js new file mode 100644 index 0000000000..51b2c8940d --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1254123.js @@ -0,0 +1,17 @@ +// |jit-test| error: boom + +if (!('oomTest' in this)) + throw new Error("boom"); + +evaluate(` +function ERROR(msg) { + throw new Error("boom"); +} +for (var i = 0; i < 9; ++ i) { + var dbg = new Debugger; + dbg.onNewGlobalObject = ERROR; +} +oomTest(function() { + newGlobal(); +}) +`); diff --git a/js/src/jit-test/tests/debug/bug1254190.js b/js/src/jit-test/tests/debug/bug1254190.js new file mode 100644 index 0000000000..d4bd11758d --- /dev/null +++ b/js/src/jit-test/tests/debug/bug1254190.js @@ -0,0 +1,15 @@ +// |jit-test| error: out of memory + +if (!('oomTest' in this)) + throw new Error("out of memory"); + +var g = newGlobal(); +var dbg = new Debugger(g); +dbg.onNewScript = function (s) { + log += dbg.findScripts({ source: s.source }).length; +} +log = ""; +oomTest(() => { + var static = newGlobal(); + g.eval("(function() {})()"); +}); diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 2180d92543..767350705a 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -84,6 +84,7 @@ UNIFIED_SOURCES += [ 'testStringBuffer.cpp', 'testStructuredClone.cpp', 'testSymbol.cpp', + 'testThreadingConditionVariable.cpp', 'testThreadingExclusiveData.cpp', 'testThreadingMutex.cpp', 'testToIntWidth.cpp', diff --git a/js/src/jsapi-tests/testThreadingConditionVariable.cpp b/js/src/jsapi-tests/testThreadingConditionVariable.cpp new file mode 100644 index 0000000000..34b599be34 --- /dev/null +++ b/js/src/jsapi-tests/testThreadingConditionVariable.cpp @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +* vim: set ts=8 sts=4 et sw=4 tw=99: +*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jsapi-tests/tests.h" +#include "threading/ConditionVariable.h" +#include "threading/Mutex.h" + +struct TestState { + js::Mutex mutex; + js::ConditionVariable condition; + bool flag; + PRThread* testThread; + + explicit TestState(bool createThread = true) + : flag(false), testThread(nullptr) + { + if (createThread) { + testThread = PR_CreateThread(PR_USER_THREAD, + setFlag, + (void *)this, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, + 0); + MOZ_RELEASE_ASSERT(testThread); + } + } + + static void setFlag(void* arg) { + auto& state = *static_cast(arg); + js::UniqueLock lock(state.mutex); + state.flag = true; + state.condition.notify_one(); + } + + void join() { + MOZ_RELEASE_ASSERT(testThread != nullptr); + PR_JoinThread(testThread); + testThread = nullptr; + } +}; + +BEGIN_TEST(testThreadingConditionVariable) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + while (!state->flag) + state->condition.wait(lock); + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariable) + +BEGIN_TEST(testThreadingConditionVariablePredicate) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + state->condition.wait(lock, [&state]() {return state->flag;}); + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariablePredicate) + +BEGIN_TEST(testThreadingConditionVariableUntilOkay) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + while (!state->flag) { + auto to = mozilla::TimeStamp::Now() + mozilla::TimeDuration::FromSeconds(600); + js::CVStatus res = state->condition.wait_until(lock, to); + CHECK(res == js::CVStatus::NoTimeout); + } + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableUntilOkay) + +BEGIN_TEST(testThreadingConditionVariableUntilTimeout) +{ + auto state = MakeUnique(false); + { + js::UniqueLock lock(state->mutex); + while (!state->flag) { + auto to = mozilla::TimeStamp::Now() + mozilla::TimeDuration::FromMilliseconds(10); + js::CVStatus res = state->condition.wait_until(lock, to); + if (res == js::CVStatus::Timeout) + break; + } + } + CHECK(!state->flag); + + // Timeout in the past should return with timeout immediately. + { + js::UniqueLock lock(state->mutex); + auto to = mozilla::TimeStamp::Now() - mozilla::TimeDuration::FromMilliseconds(10); + js::CVStatus res = state->condition.wait_until(lock, to); + CHECK(res == js::CVStatus::Timeout); + } + + return true; +} +END_TEST(testThreadingConditionVariableUntilTimeout) + +BEGIN_TEST(testThreadingConditionVariableUntilOkayPredicate) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + auto to = mozilla::TimeStamp::Now() + mozilla::TimeDuration::FromSeconds(600); + bool res = state->condition.wait_until(lock, to, [&state](){return state->flag;}); + CHECK(res); + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableUntilOkayPredicate) + +BEGIN_TEST(testThreadingConditionVariableUntilTimeoutPredicate) +{ + auto state = MakeUnique(false); + { + js::UniqueLock lock(state->mutex); + auto to = mozilla::TimeStamp::Now() + mozilla::TimeDuration::FromMilliseconds(10); + bool res = state->condition.wait_until(lock, to, [&state](){return state->flag;}); + CHECK(!res); + } + CHECK(!state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableUntilTimeoutPredicate) + +BEGIN_TEST(testThreadingConditionVariableForOkay) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + while (!state->flag) { + auto duration = mozilla::TimeDuration::FromSeconds(600); + js::CVStatus res = state->condition.wait_for(lock, duration); + CHECK(res == js::CVStatus::NoTimeout); + } + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableForOkay) + +BEGIN_TEST(testThreadingConditionVariableForTimeout) +{ + auto state = MakeUnique(false); + { + js::UniqueLock lock(state->mutex); + while (!state->flag) { + auto duration = mozilla::TimeDuration::FromMilliseconds(10); + js::CVStatus res = state->condition.wait_for(lock, duration); + if (res == js::CVStatus::Timeout) + break; + } + } + CHECK(!state->flag); + + // Timeout in the past should return with timeout immediately. + { + js::UniqueLock lock(state->mutex); + auto duration = mozilla::TimeDuration::FromMilliseconds(-10); + js::CVStatus res = state->condition.wait_for(lock, duration); + CHECK(res == js::CVStatus::Timeout); + } + + return true; +} +END_TEST(testThreadingConditionVariableForTimeout) + +BEGIN_TEST(testThreadingConditionVariableForOkayPredicate) +{ + auto state = MakeUnique(); + { + js::UniqueLock lock(state->mutex); + auto duration = mozilla::TimeDuration::FromSeconds(600); + bool res = state->condition.wait_for(lock, duration, [&state](){return state->flag;}); + CHECK(res); + } + state->join(); + + CHECK(state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableForOkayPredicate) + +BEGIN_TEST(testThreadingConditionVariableForTimeoutPredicate) +{ + auto state = MakeUnique(false); + { + js::UniqueLock lock(state->mutex); + auto duration = mozilla::TimeDuration::FromMilliseconds(10); + bool res = state->condition.wait_for(lock, duration, [&state](){return state->flag;}); + CHECK(!res); + } + CHECK(!state->flag); + + return true; +} +END_TEST(testThreadingConditionVariableForTimeoutPredicate) diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index a8b8af2677..b8b42382f3 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -305,7 +305,13 @@ js::ErrorFromException(JSContext* cx, HandleObject objArg) if (!obj->is()) return nullptr; - return obj->as().getOrCreateErrorReport(cx); + JSErrorReport* report = obj->as().getOrCreateErrorReport(cx); + if (!report) { + MOZ_ASSERT(cx->isThrowingOutOfMemory()); + cx->recoverFromOutOfMemory(); + } + + return report; } JS_PUBLIC_API(JSObject*) diff --git a/js/src/jsnum.h b/js/src/jsnum.h index a6e078c192..710d0f289c 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -266,6 +266,19 @@ ToInteger(JSContext* cx, HandleValue v, double* dp) return true; } +/* ECMA-262 draft (2016 Mar 19) 7.1.15 ToLength ( argument ) */ +inline double +ToLength(double argument) +{ + const double MAX_SAFE_INTEGER = 9007199254740991; + double len = JS::ToInteger(argument); + if (len <= 0) + return 0; + if (len > MAX_SAFE_INTEGER) + return MAX_SAFE_INTEGER; + return len; +} + /* ES6 7.1.15 ToLength, but clamped to the [0,2^32-2] range. If the * return value is false then *overflow will be true iff the value was * not clampable to uint32_t range. diff --git a/js/src/moz.build b/js/src/moz.build index f4c4b50408..6b4e38c6d2 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -563,6 +563,7 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']: if CONFIG['OS_ARCH'] == 'WINNT': SOURCES += [ 'jit/ExecutableAllocatorWin.cpp', + 'threading/windows/ConditionVariable.cpp', 'threading/windows/Mutex.cpp', ] # _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s() @@ -570,6 +571,7 @@ if CONFIG['OS_ARCH'] == 'WINNT': else: SOURCES += [ 'jit/ExecutableAllocatorPosix.cpp', + 'threading/posix/ConditionVariable.cpp', 'threading/posix/Mutex.cpp', ] @@ -711,6 +713,8 @@ if CONFIG['OS_ARCH'] == 'SunOS': 'socket', ] +OS_LIBS += CONFIG['REALTIME_LIBS'] + CFLAGS += CONFIG['MOZ_ICU_CFLAGS'] CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS'] LOCAL_INCLUDES += CONFIG['MOZ_ICU_INCLUDES'] diff --git a/js/src/tests/ecma_6/ArrayBuffer/constructorTypeCheck.js b/js/src/tests/ecma_6/ArrayBuffer/constructorTypeCheck.js new file mode 100644 index 0000000000..10cccb4413 --- /dev/null +++ b/js/src/tests/ecma_6/ArrayBuffer/constructorTypeCheck.js @@ -0,0 +1,20 @@ +let badLengths = [ + -1, + 1.0001342, + 0x100000000, + 0x200000000, + 0x400000000, + Infinity, + NaN +]; + +for (let n of badLengths) + assertThrowsInstanceOf(() => new ArrayBuffer(n), RangeError); + +assertEq(new ArrayBuffer({valueOf: () => 123}).byteLength, 123); +assertEq(new ArrayBuffer(true).byteLength, 1); +assertEq(new ArrayBuffer([123]).byteLength, 123); +assertEq(new ArrayBuffer(["0x10"]).byteLength, 16); + +if (typeof reportCompare === 'function') + reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/DataView/detach-after-construction.js b/js/src/tests/ecma_6/DataView/detach-after-construction.js index a2c66a5808..d626281485 100644 --- a/js/src/tests/ecma_6/DataView/detach-after-construction.js +++ b/js/src/tests/ecma_6/DataView/detach-after-construction.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!xulRuntime.shell) -- needs detachArrayBuffer for (var detachArg of ['change-data', 'same-data']) { - var buf = new ArrayBuffer([1,2]); + var buf = new ArrayBuffer(2); var bufView = new DataView(buf); detachArrayBuffer(buf, detachArg); diff --git a/js/src/threading/ConditionVariable.h b/js/src/threading/ConditionVariable.h new file mode 100644 index 0000000000..8ffd88ac72 --- /dev/null +++ b/js/src/threading/ConditionVariable.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef threading_ConditionVariable_h +#define threading_ConditionVariable_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TimeStamp.h" + +#include +#ifndef XP_WIN +# include +#endif + +#include "threading/LockGuard.h" +#include "threading/Mutex.h" + +namespace js { + +template using UniqueLock = LockGuard; + +enum class CVStatus { + NoTimeout, + Timeout +}; + +// A poly-fill for std::condition_variable. +class ConditionVariable +{ +public: + struct PlatformData; + + ConditionVariable(); + ~ConditionVariable(); + + void notify_one(); + void notify_all(); + + void wait(UniqueLock& lock); + + template + void wait(UniqueLock& lock, Predicate pred) { + while (!pred()) { + wait(lock); + } + } + + CVStatus wait_until(UniqueLock& lock, + const mozilla::TimeStamp& abs_time); + + template + bool wait_until(UniqueLock& lock, const mozilla::TimeStamp& abs_time, + Predicate pred) { + while (!pred()) { + if (wait_until(lock, abs_time) == CVStatus::Timeout) { + return pred(); + } + } + return true; + } + + CVStatus wait_for(UniqueLock& lock, + const mozilla::TimeDuration& rel_time); + + template + bool wait_for(UniqueLock& lock, const mozilla::TimeDuration& rel_time, + Predicate pred) { + return wait_until(lock, mozilla::TimeStamp::Now() + rel_time, + mozilla::Move(pred)); + } + + +private: + ConditionVariable(const ConditionVariable&) = delete; + ConditionVariable& operator=(const ConditionVariable&) = delete; + + PlatformData* platformData(); + +#ifndef XP_WIN + void* platformData_[sizeof(pthread_cond_t) / sizeof(void*)]; + static_assert(sizeof(pthread_cond_t) / sizeof(void*) != 0 && + sizeof(pthread_cond_t) % sizeof(void*) == 0, + "pthread_cond_t must have pointer alignment"); +#else + void* platformData_[4]; +#endif +}; + +} // namespace js + +#endif // threading_ConditionVariable_h diff --git a/js/src/threading/LockGuard.h b/js/src/threading/LockGuard.h index 34ebfbccf0..45b023a90a 100644 --- a/js/src/threading/LockGuard.h +++ b/js/src/threading/LockGuard.h @@ -15,6 +15,7 @@ template class MOZ_RAII LockGuard { friend class UnlockGuard; + friend class ConditionVariable; Mutex& lock; public: diff --git a/js/src/threading/Mutex.h b/js/src/threading/Mutex.h index 8db25c060a..6cb4e0ea04 100644 --- a/js/src/threading/Mutex.h +++ b/js/src/threading/Mutex.h @@ -44,6 +44,7 @@ private: Mutex(const Mutex&) = delete; void operator=(const Mutex&) = delete; + friend class ConditionVariable; PlatformData* platformData() { MOZ_ASSERT(platformData_); return platformData_; diff --git a/js/src/threading/posix/ConditionVariable.cpp b/js/src/threading/posix/ConditionVariable.cpp new file mode 100644 index 0000000000..6a2e4a2467 --- /dev/null +++ b/js/src/threading/posix/ConditionVariable.cpp @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" +#include "mozilla/CheckedInt.h" + +#include +#include +#include +#include +#include + +#include "threading/ConditionVariable.h" +#include "threading/Mutex.h" +#include "threading/posix/MutexPlatformData.h" + +using mozilla::CheckedInt; +using mozilla::TimeDuration; +using mozilla::TimeStamp; + +static const long NanoSecPerSec = 1000000000; + +// Android has the clock functions, but not pthread_condattr_setclock. +#if defined(HAVE_CLOCK_MONOTONIC) && !defined(__ANDROID__) +# define USE_CLOCK_API +#endif + +#ifdef USE_CLOCK_API +// The C++ specification defines std::condition_variable::wait_for in terms of +// std::chrono::steady_clock, which is closest to CLOCK_MONOTONIC. +static const clockid_t WhichClock = CLOCK_MONOTONIC; + +// While timevaladd is widely available to work with timevals, the newer +// timespec structure is largely lacking such conveniences. Thankfully, the +// utilities available in MFBT make implementing our own quite easy. +static void +timespecadd(struct timespec* lhs, struct timespec* rhs, struct timespec* result) +{ + // Add nanoseconds. This may wrap, but not above 2 billion. + MOZ_RELEASE_ASSERT(lhs->tv_nsec < NanoSecPerSec); + MOZ_RELEASE_ASSERT(rhs->tv_nsec < NanoSecPerSec); + result->tv_nsec = lhs->tv_nsec + rhs->tv_nsec; + + // Add seconds, checking for overflow in the platform specific time_t type. + CheckedInt sec = CheckedInt(lhs->tv_sec) + rhs->tv_sec; + + // If nanoseconds overflowed, carry the result over into seconds. + if (result->tv_nsec >= NanoSecPerSec) { + MOZ_RELEASE_ASSERT(result->tv_nsec < 2 * NanoSecPerSec); + result->tv_nsec -= NanoSecPerSec; + sec += 1; + } + + // Extracting the value asserts that there was no overflow. + MOZ_RELEASE_ASSERT(sec.isValid()); + result->tv_sec = sec.value(); +} +#endif + +struct js::ConditionVariable::PlatformData +{ + pthread_cond_t ptCond; +}; + +js::ConditionVariable::ConditionVariable() +{ + pthread_cond_t* ptCond = &platformData()->ptCond; + +#ifdef USE_CLOCK_API + pthread_condattr_t attr; + int r0 = pthread_condattr_init(&attr); + MOZ_RELEASE_ASSERT(!r0); + + int r1 = pthread_condattr_setclock(&attr, WhichClock); + MOZ_RELEASE_ASSERT(!r1); + + int r2 = pthread_cond_init(ptCond, &attr); + MOZ_RELEASE_ASSERT(!r2); + + int r3 = pthread_condattr_destroy(&attr); + MOZ_RELEASE_ASSERT(!r3); +#else + int r = pthread_cond_init(ptCond, NULL); + MOZ_RELEASE_ASSERT(!r); +#endif +} + +js::ConditionVariable::~ConditionVariable() +{ + int r = pthread_cond_destroy(&platformData()->ptCond); + MOZ_RELEASE_ASSERT(r == 0); +} + +void +js::ConditionVariable::notify_one() +{ + int r = pthread_cond_signal(&platformData()->ptCond); + MOZ_RELEASE_ASSERT(r == 0); +} + +void +js::ConditionVariable::notify_all() +{ + int r = pthread_cond_broadcast(&platformData()->ptCond); + MOZ_RELEASE_ASSERT(r == 0); +} + +void +js::ConditionVariable::wait(UniqueLock& lock) +{ + pthread_cond_t* ptCond = &platformData()->ptCond; + pthread_mutex_t* ptMutex = &lock.lock.platformData()->ptMutex; + + int r = pthread_cond_wait(ptCond, ptMutex); + MOZ_RELEASE_ASSERT(r == 0); +} + +js::CVStatus +js::ConditionVariable::wait_until(UniqueLock& lock, + const TimeStamp& abs_time) +{ + return wait_for(lock, abs_time - TimeStamp::Now()); +} + +js::CVStatus +js::ConditionVariable::wait_for(UniqueLock& lock, + const TimeDuration& a_rel_time) +{ + pthread_cond_t* ptCond = &platformData()->ptCond; + pthread_mutex_t* ptMutex = &lock.lock.platformData()->ptMutex; + int r; + + // Clamp to 0, as time_t is unsigned. + TimeDuration rel_time = a_rel_time < TimeDuration::FromSeconds(0) + ? TimeDuration::FromSeconds(0) + : a_rel_time; + + // Convert the duration to a timespec. + struct timespec rel_ts; + rel_ts.tv_sec = static_cast(rel_time.ToSeconds()); + rel_ts.tv_nsec = static_cast(rel_time.ToMicroseconds() * 1000.0) % NanoSecPerSec; + +#ifdef USE_CLOCK_API + struct timespec now_ts; + r = clock_gettime(WhichClock, &now_ts); + MOZ_RELEASE_ASSERT(!r); + + struct timespec abs_ts; + timespecadd(&now_ts, &rel_ts, &abs_ts); + + r = pthread_cond_timedwait(ptCond, ptMutex, &abs_ts); +#else + // Our non-clock-supporting platforms, OS X and Android, do support waiting + // on a condition variable with a relative timeout. + r = pthread_cond_timedwait_relative_np(ptCond, ptMutex, &rel_ts); +#endif + + if (r == 0) { + return CVStatus::NoTimeout; + } + MOZ_RELEASE_ASSERT(r == ETIMEDOUT); + return CVStatus::Timeout; +} + +js::ConditionVariable::PlatformData* +js::ConditionVariable::platformData() +{ + static_assert(sizeof platformData_ >= sizeof(PlatformData), + "platformData_ is too small"); + return reinterpret_cast(platformData_); +} diff --git a/js/src/threading/windows/ConditionVariable.cpp b/js/src/threading/windows/ConditionVariable.cpp new file mode 100644 index 0000000000..2f62368ae8 --- /dev/null +++ b/js/src/threading/windows/ConditionVariable.cpp @@ -0,0 +1,416 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Assertions.h" + +#include +#include +#include +#include + +#include "threading/ConditionVariable.h" +#include "threading/Mutex.h" +#include "threading/windows/MutexPlatformData.h" + +// Some versions of the Windows SDK have a bug where some interlocked functions +// are not redefined as compiler intrinsics. Fix that for the interlocked +// functions that are used in this file. +#if defined(_MSC_VER) && !defined(InterlockedExchangeAdd) +#define InterlockedExchangeAdd(addend, value) \ + _InterlockedExchangeAdd((volatile long*)(addend), (long)(value)) +#endif + +#if defined(_MSC_VER) && !defined(InterlockedIncrement) +#define InterlockedIncrement(addend) \ + _InterlockedIncrement((volatile long*)(addend)) +#endif + +// Windows XP and Server 2003 don't support condition variables natively. The +// NativeImports class is responsible for detecting native support and +// retrieving the appropriate function pointers. It gets instantiated once, +// using a static initializer. +class ConditionVariableNativeImports +{ +public: + ConditionVariableNativeImports() { + HMODULE kernel32_dll = GetModuleHandle("kernel32.dll"); + MOZ_RELEASE_ASSERT(kernel32_dll != NULL); + +#define LOAD_SYMBOL(symbol) loadSymbol(kernel32_dll, #symbol, symbol) + supported_ = LOAD_SYMBOL(InitializeConditionVariable) && + LOAD_SYMBOL(WakeConditionVariable) && + LOAD_SYMBOL(WakeAllConditionVariable) && + LOAD_SYMBOL(SleepConditionVariableCS); +#undef LOAD_SYMBOL + } + + inline bool supported() const { + return supported_; + } + + void(WINAPI* InitializeConditionVariable)(CONDITION_VARIABLE* ConditionVariable); + void(WINAPI* WakeAllConditionVariable)(PCONDITION_VARIABLE ConditionVariable); + void(WINAPI* WakeConditionVariable)(CONDITION_VARIABLE* ConditionVariable); + BOOL(WINAPI* SleepConditionVariableCS)(CONDITION_VARIABLE* ConditionVariable, + CRITICAL_SECTION* CriticalSection, + DWORD dwMilliseconds); + +private: + template + inline bool loadSymbol(HMODULE module, const char* name, T& fn) { + void* ptr = GetProcAddress(module, name); + if (!ptr) + return false; + + fn = reinterpret_cast(ptr); + return true; + } + + bool supported_; +}; + +static ConditionVariableNativeImports sNativeImports; + +// Wrapper for native condition variable APIs. +struct ConditionVariableNative +{ + inline void initialize() { + sNativeImports.InitializeConditionVariable(&cv_); + } + + inline void destroy() { + // Native condition variables don't require cleanup. + } + + inline void notify_one() { sNativeImports.WakeConditionVariable(&cv_); } + + inline void notify_all() { sNativeImports.WakeAllConditionVariable(&cv_); } + + inline bool wait(CRITICAL_SECTION* cs, DWORD msec) { + return sNativeImports.SleepConditionVariableCS(&cv_, cs, msec); + } + +private: + CONDITION_VARIABLE cv_; +}; + +// Fallback condition variable support for Windows XP and Server 2003. Given the +// difficulty of testing on these antiquated platforms and their rapidly +// diminishing market share, this implementation trades performance for +// predictable behavior. +struct ConditionVariableFallback +{ + static const uint32_t WAKEUP_MODE_NONE = 0; + static const uint32_t WAKEUP_MODE_ONE = 0x40000000; + static const uint32_t WAKEUP_MODE_ALL = 0x80000000; + + static const uint32_t WAKEUP_MODE_MASK = WAKEUP_MODE_ONE | WAKEUP_MODE_ALL; + static const uint32_t SLEEPERS_COUNT_MASK = ~WAKEUP_MODE_MASK; + + void initialize() + { + // Initialize the state variable to 0 sleepers, no wakeup. + sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE; + + // Create a semaphore that prevents threads from entering sleep, + // or waking other threads while a wakeup is ongoing. + sleepWakeupSemaphore_ = CreateSemaphoreW(NULL, 1, 1, NULL); + MOZ_RELEASE_ASSERT(sleepWakeupSemaphore_); + + // Use an auto-reset event for waking up a single sleeper. + wakeOneEvent_ = CreateEventW(NULL, FALSE, FALSE, NULL); + MOZ_RELEASE_ASSERT(wakeOneEvent_); + + // Use a manual-reset event for waking up all sleepers. + wakeAllEvent_ = CreateEventW(NULL, TRUE, FALSE, NULL); + MOZ_RELEASE_ASSERT(wakeAllEvent_); + } + + void destroy() + { + BOOL r; + + MOZ_RELEASE_ASSERT(sleepersCountAndWakeupMode_ == (0 | WAKEUP_MODE_NONE)); + + r = CloseHandle(sleepWakeupSemaphore_); + MOZ_RELEASE_ASSERT(r); + + r = CloseHandle(wakeOneEvent_); + MOZ_RELEASE_ASSERT(r); + + r = CloseHandle(wakeAllEvent_); + MOZ_RELEASE_ASSERT(r); + } + +private: + void wakeup(uint32_t wakeupMode, HANDLE wakeEvent) + { + // Ensure that only one thread at a time can wake up others. + BOOL result = WaitForSingleObject(sleepWakeupSemaphore_, INFINITE); + MOZ_RELEASE_ASSERT(result == WAIT_OBJECT_0); + + // Atomically set the wakeup mode and retrieve the number of sleepers. + uint32_t wcwm = InterlockedExchangeAdd(&sleepersCountAndWakeupMode_, + wakeupMode); + uint32_t sleepersCount = wcwm & SLEEPERS_COUNT_MASK; + MOZ_RELEASE_ASSERT((wcwm & WAKEUP_MODE_MASK) == WAKEUP_MODE_NONE); + + if (sleepersCount > 0) { + // If there are any sleepers, set the wake event. The (last) woken + // up thread is responsible for releasing the semaphore. + BOOL success = SetEvent(wakeEvent); + MOZ_RELEASE_ASSERT(success); + + } else { + // If there are no sleepers, set the wakeup mode back to 'none' + // and release the semaphore ourselves. + sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE; + + BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL); + MOZ_RELEASE_ASSERT(success); + } + } + +public: + void notify_one() { wakeup(WAKEUP_MODE_ONE, wakeOneEvent_); } + + void notify_all() { wakeup(WAKEUP_MODE_ALL, wakeAllEvent_); } + + bool wait(CRITICAL_SECTION* userLock, DWORD msec) + { + // Make sure that we can't enter sleep when there are other threads + // that still need to wake up on either of the wake events being set. + DWORD result = WaitForSingleObject(sleepWakeupSemaphore_, INFINITE); + MOZ_RELEASE_ASSERT(result == WAIT_OBJECT_0); + + // Register ourselves as a sleeper. Use an atomic operation, because + // if another thread times out at the same time, it will decrement the + // sleepers count without acquiring the semaphore. + uint32_t wcwm = InterlockedIncrement(&sleepersCountAndWakeupMode_); + MOZ_RELEASE_ASSERT((wcwm & WAKEUP_MODE_MASK) == WAKEUP_MODE_NONE); + + // Now that that this thread has been enlisted as a sleeper, it is safe + // again for other threads to do a wakeup. + BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL); + MOZ_RELEASE_ASSERT(success); + + // Release the caller's mutex. + LeaveCriticalSection(userLock); + + // Wait for either event to become signaled, which happens when + // notify_one() or notify_all() is called, or for a timeout. + HANDLE handles[2] = { wakeOneEvent_, wakeAllEvent_ }; + DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, msec); + MOZ_RELEASE_ASSERT(waitResult == WAIT_OBJECT_0 || + waitResult == WAIT_OBJECT_0 + 1 || + (waitResult == WAIT_TIMEOUT && msec != INFINITE)); + + // Atomically decrease the sleepers count and retrieve the wakeup mode + // and new sleepers count. + // If the wait returned because wakeOneEvent_ was set, we are certain + // that the wakeup mode will be WAKEUP_MODE_ONE. In that case, + // atomically reset the wakeup mode to 'none', because if another + // thread's sleep times out at same time and it finds that it was the + // last sleeper, it decides whether or not to reset the wakeOneEvent_ + // based on the current wakeup mode. + uint32_t sub; + if (waitResult == WAIT_OBJECT_0) + sub = 1 | WAKEUP_MODE_ONE; + else + sub = 1; + // Note that InterlockedExchangeAdd returns the old value, but it's + // easier to work with the new value. + wcwm = InterlockedExchangeAdd(&sleepersCountAndWakeupMode_, -sub) - sub; + + uint32_t wakeupMode = wcwm & WAKEUP_MODE_MASK; + uint32_t sleepersCount = wcwm & SLEEPERS_COUNT_MASK; + + bool releaseSleepWakeupSemaphore = false; + + if (waitResult == WAIT_OBJECT_0) { + // The wake-one event is an auto-reset event so if we're woken by + // it, it should already have been reset. We also already removed + // the WAKEUP_MODE_ONE bit so the wakeup mode should now be 'none' + // again. + MOZ_RELEASE_ASSERT(wakeupMode == WAKEUP_MODE_NONE); + + // The signaling thread has acquired the enter-wakeup semaphore and + // expects the woken (this) thread to release it again. + releaseSleepWakeupSemaphore = true; + + } else if (waitResult == WAIT_TIMEOUT && wakeupMode == WAKEUP_MODE_ONE && + sleepersCount == 0) { + // In theory a race condition is possible where the last sleeper + // times out right at the moment that another thread signals it. + // If that just happened we now have a dangling signal event and + // mode, but no threads to be woken up by it, and we need to clean + // that up. + BOOL success = ResetEvent(wakeOneEvent_); + MOZ_RELEASE_ASSERT(success); + + // This is safe - we are certain there are no other sleepers that + // could wake up right now, and the semaphore ensures that no + // non-sleeping threads are messing with + // sleepersCountAndWakeupMode_. + sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE; + + // The signaling thread has acquired the sleep-wakeup semaphore and + // expects the woken thread to release it. But since there are no + // sleeping threads left this thread will do it instead. + releaseSleepWakeupSemaphore = true; + + } else if (wakeupMode == WAKEUP_MODE_ALL && sleepersCount == 0) { + // If this was the last thread waking up in response to a + // notify_all, clear the wakeup mode and reset the wake-all event. + // A race condition similar to the case described above could + // occur, so waitResult could be WAIT_TIMEOUT, but that doesn't + // matter for the actions that need to be taken. + MOZ_RELEASE_ASSERT(waitResult = WAIT_OBJECT_0 + 1 || + waitResult == WAIT_TIMEOUT); + + BOOL success = ResetEvent(wakeAllEvent_); + MOZ_RELEASE_ASSERT(success); + + sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE; + + // The broadcasting thread has acquired the enter-wakeup semaphore + // and expects the last thread that wakes up to release it. + releaseSleepWakeupSemaphore = true; + + } else if ((waitResult == WAIT_TIMEOUT && msec != INFINITE) || + (waitResult == WAIT_OBJECT_0 + 1 && + wakeupMode == WAKEUP_MODE_ALL)) { + // Either: + // * The wait timed out but found no active notify_one or notify_all + // the moment it decreased the wait count. + // * A notify_all woke up this thread but there are more threads + // that need to be woken up by the wake-all event. + // These are ordinary conditions in which we don't have to do + // anything. + + } else { + MOZ_CRASH("invalid wakeup condition"); + } + + // Release the enter-wakeup semaphore if the wakeup condition requires + // us to do it. + if (releaseSleepWakeupSemaphore) { + BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL); + MOZ_RELEASE_ASSERT(success); + } + + // Reacquire the user mutex. + EnterCriticalSection(userLock); + + // Return true if woken up, false when timed out. + if (waitResult == WAIT_TIMEOUT) { + SetLastError(ERROR_TIMEOUT); + return false; + } + return true; + } + +private: + uint32_t sleepersCountAndWakeupMode_; + HANDLE sleepWakeupSemaphore_; + HANDLE wakeOneEvent_; + HANDLE wakeAllEvent_; +}; + +struct js::ConditionVariable::PlatformData +{ + union + { + ConditionVariableNative native; + ConditionVariableFallback fallback; + }; +}; + +js::ConditionVariable::ConditionVariable() +{ + if (sNativeImports.supported()) + platformData()->native.initialize(); + else + platformData()->fallback.initialize(); +} + +void +js::ConditionVariable::notify_one() +{ + if (sNativeImports.supported()) + platformData()->native.notify_one(); + else + platformData()->fallback.notify_one(); +} + +void +js::ConditionVariable::notify_all() +{ + if (sNativeImports.supported()) + platformData()->native.notify_all(); + else + platformData()->fallback.notify_all(); +} + +void +js::ConditionVariable::wait(UniqueLock& lock) +{ + CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; + bool r; + if (sNativeImports.supported()) + r = platformData()->native.wait(cs, INFINITE); + else + r = platformData()->fallback.wait(cs, INFINITE); + MOZ_RELEASE_ASSERT(r); +} + +js::CVStatus +js::ConditionVariable::wait_until(UniqueLock& lock, + const mozilla::TimeStamp& abs_time) +{ + return wait_for(lock, abs_time - mozilla::TimeStamp::Now()); +} + +js::CVStatus +js::ConditionVariable::wait_for(UniqueLock& lock, + const mozilla::TimeDuration& rel_time) +{ + CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; + + // Note that DWORD is unsigned, so we have to be careful to clamp at 0. + double msecd = rel_time.ToMilliseconds(); + DWORD msec = msecd < 0.0 + ? 0 + : msecd > DBL_MAX + ? INFINITE + : static_cast(msecd); + + BOOL r; + if (sNativeImports.supported()) + r = platformData()->native.wait(cs, msec); + else + r = platformData()->fallback.wait(cs, msec); + if (r) + return CVStatus::NoTimeout; + MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT); + return CVStatus::Timeout; +} + +js::ConditionVariable::~ConditionVariable() +{ + if (sNativeImports.supported()) + platformData()->native.destroy(); + else + platformData()->fallback.destroy(); +} + +inline js::ConditionVariable::PlatformData* +js::ConditionVariable::platformData() +{ + static_assert(sizeof platformData_ >= sizeof(PlatformData), + "platformData_ is too small"); + return reinterpret_cast(platformData_); +} diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index b2b66e78d2..4a4d7f66b6 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -202,37 +202,39 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp) return true; } -/* - * new ArrayBuffer(byteLength) - */ +// new ArrayBuffer(byteLength) - ECMA-262 draft (2016 Mar 19) 24.1.2.1 bool ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + // Step 1. if (!ThrowIfNotConstructing(cx, args, "ArrayBuffer")) return false; - int32_t nbytes = 0; - if (argc > 0 && !ToInt32(cx, args[0], &nbytes)) - return false; + // Step 2. ES6 specifies that `new ArrayBuffer()` without arguments should + // throw, but it's a bug. + double length = 0; + if (args.hasDefined(0)) { + if (!ToNumber(cx, args[0], &length)) + return false; + } - if (nbytes < 0) { - /* - * We're just not going to support arrays that are bigger than what will fit - * as an integer value; if someone actually ever complains (validly), then we - * can fix. - */ + // Steps 3-4. Also refuse to allocate buffers 1GiB or larger. + double byteLength = ToLength(length); + const double SIZE_LIMIT = 1024.0 * 1024 * 1024; + if (length != byteLength || byteLength >= SIZE_LIMIT) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); return false; } + // Step 5. RootedObject proto(cx); RootedObject newTarget(cx, &args.newTarget().toObject()); if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) return false; - JSObject* bufobj = create(cx, uint32_t(nbytes), proto); + JSObject* bufobj = create(cx, uint32_t(byteLength), proto); if (!bufobj) return false; args.rval().setObject(*bufobj); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 1ca2cc9fdb..57d62caf18 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -398,6 +398,14 @@ Debugger::slowPathCheckNoExecute(JSContext* cx, HandleScript script) return EnterDebuggeeNoExecute::reportIfFoundInStack(cx, script); } +static inline void +NukeDebuggerWrapper(NativeObject *wrapper) +{ + // In some OOM failure cases, we need to destroy the edge to the referent, + // to avoid trying to trace it during untimely collections. + wrapper->setPrivate(nullptr); +} + /*** Breakpoints *********************************************************************************/ @@ -934,14 +942,19 @@ Debugger::wrapEnvironment(JSContext* cx, Handle env, MutableHandleValue rv return false; envobj->setPrivateGCThing(env); envobj->setReservedSlot(JSSLOT_DEBUGENV_OWNER, ObjectValue(*object)); - if (!p.add(cx, environments, env, envobj)) + + if (!p.add(cx, environments, env, envobj)) { + NukeDebuggerWrapper(envobj); return false; + } CrossCompartmentKey key(CrossCompartmentKey::DebuggerEnvironment, object, env); if (!object->compartment()->putWrapper(cx, key, ObjectValue(*envobj))) { + NukeDebuggerWrapper(envobj); environments.remove(env); return false; } + } rval.setObject(*envobj); return true; @@ -976,12 +989,15 @@ Debugger::wrapDebuggeeValue(JSContext* cx, MutableHandleValue vp) dobj->setPrivateGCThing(obj); dobj->setReservedSlot(JSSLOT_DEBUGOBJECT_OWNER, ObjectValue(*object)); - if (!p.add(cx, objects, obj, dobj)) + if (!p.add(cx, objects, obj, dobj)) { + NukeDebuggerWrapper(dobj); return false; + } if (obj->compartment() != object->compartment()) { CrossCompartmentKey key(CrossCompartmentKey::DebuggerObject, object, obj); if (!object->compartment()->putWrapper(cx, key, ObjectValue(*dobj))) { + NukeDebuggerWrapper(dobj); objects.remove(obj); ReportOutOfMemory(cx); return false; @@ -3856,7 +3872,8 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery if (!GetProperty(cx, query, query, cx->names().global, &global)) return false; if (global.isUndefined()) { - matchAllDebuggeeGlobals(); + if (!matchAllDebuggeeGlobals()) + return false; } else { GlobalObject* globalObject = debugger->unwrapDebuggeeArgument(cx, global); if (!globalObject) @@ -5028,7 +5045,7 @@ class DebuggerScriptSetPrivateMatcher ReturnType match(Handle module) { obj_->setPrivateGCThing(module); } }; -JSObject* +NativeObject* Debugger::newDebuggerScript(JSContext* cx, Handle referent) { assertSameCompartment(cx, object.get()); @@ -5058,19 +5075,23 @@ Debugger::wrapVariantReferent(JSContext* cx, Map& map, CrossCompartmentKey::Kind DependentAddPtr p(cx, map, untaggedReferent); if (!p) { - JSObject* wrapper = newVariantWrapper(cx, referent); + NativeObject* wrapper = newVariantWrapper(cx, referent); if (!wrapper) return nullptr; - if (!p.add(cx, map, untaggedReferent, wrapper)) + if (!p.add(cx, map, untaggedReferent, wrapper)) { + NukeDebuggerWrapper(wrapper); return nullptr; + } CrossCompartmentKey key(keyKind, object, untaggedReferent); if (!object->compartment()->putWrapper(cx, key, ObjectValue(*wrapper))) { + NukeDebuggerWrapper(wrapper); map.remove(untaggedReferent); ReportOutOfMemory(cx); return nullptr; } + } return p->value(); @@ -6300,7 +6321,7 @@ class SetDebuggerSourcePrivateMatcher ReturnType match(Handle module) { obj_->setPrivateGCThing(module); } }; -JSObject* +NativeObject* Debugger::newDebuggerSource(JSContext* cx, Handle referent) { assertSameCompartment(cx, object.get()); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index e833e084bb..bcc5e6742b 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -690,10 +690,10 @@ class Debugger : private mozilla::LinkedListElement JSTrapStatus fireNewGlobalObject(JSContext* cx, Handle global, MutableHandleValue vp); JSTrapStatus firePromiseHook(JSContext* cx, Hook hook, HandleObject promise, MutableHandleValue vp); - JSObject* newVariantWrapper(JSContext* cx, Handle referent) { + NativeObject* newVariantWrapper(JSContext* cx, Handle referent) { return newDebuggerScript(cx, referent); } - JSObject* newVariantWrapper(JSContext* cx, Handle referent) { + NativeObject* newVariantWrapper(JSContext* cx, Handle referent) { return newDebuggerSource(cx, referent); } @@ -715,13 +715,13 @@ class Debugger : private mozilla::LinkedListElement * Allocate and initialize a Debugger.Script instance whose referent is * |referent|. */ - JSObject* newDebuggerScript(JSContext* cx, Handle referent); + NativeObject* newDebuggerScript(JSContext* cx, Handle referent); /* * Allocate and initialize a Debugger.Source instance whose referent is * |referent|. */ - JSObject* newDebuggerSource(JSContext* cx, Handle referent); + NativeObject* newDebuggerSource(JSContext* cx, Handle referent); /* * Receive a "new script" event from the engine. A new script was compiled diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 374869aedc..bf6e492589 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -509,25 +509,31 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) if (!nativeGroup) return false; - // Propagate all property types from the old group to the new group. - if (layout.isArray()) { - if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup)) - return false; - } else { - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - jsid id = NameToId(property.name); - if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) + // No sense propagating if we don't know what we started with. + if (!group->unknownProperties()) { + // Propagate all property types from the old group to the new group. + if (layout.isArray()) { + if (!PropagatePropertyTypes(cx, JSID_VOID, group, nativeGroup)) return false; + } else { + for (size_t i = 0; i < layout.properties().length(); i++) { + const UnboxedLayout::Property& property = layout.properties()[i]; + jsid id = NameToId(property.name); + if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) + return false; - // If we are OOM we may not be able to propagate properties. - if (nativeGroup->unknownProperties()) - break; + // If we are OOM we may not be able to propagate properties. + if (nativeGroup->unknownProperties()) + break; - HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); - if (nativeProperty && nativeProperty->canSetDefinite(i)) - nativeProperty->setDefinite(i); + HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); + if (nativeProperty && nativeProperty->canSetDefinite(i)) + nativeProperty->setDefinite(i); + } } + } else { + // If we skip, though, the new group had better agree. + MOZ_ASSERT(nativeGroup->unknownProperties()); } layout.nativeGroup_ = nativeGroup; diff --git a/media/mtransport/nriceresolver.cpp b/media/mtransport/nriceresolver.cpp index 1ef619112f..2298d6fafc 100644 --- a/media/mtransport/nriceresolver.cpp +++ b/media/mtransport/nriceresolver.cpp @@ -199,7 +199,7 @@ nsresult NrIceResolver::PendingResolution::OnLookupComplete( ASSERT_ON_THREAD(thread_); // First check if we've been canceled. This is single-threaded on the STS // thread, but cancel() cannot guarantee this event isn't on the queue. - if (!canceled_) { + if (request_) { nr_transport_addr *cb_addr = nullptr; nr_transport_addr ta; // TODO(jib@mozilla.com): Revisit when we do TURN. @@ -212,6 +212,7 @@ nsresult NrIceResolver::PendingResolution::OnLookupComplete( } } cb_(cb_arg_, cb_addr); + request_ = nullptr; Release(); } return NS_OK; @@ -226,7 +227,7 @@ int NrIceResolver::cancel(void *obj, void *handle) { int NrIceResolver::PendingResolution::cancel() { request_->Cancel (NS_ERROR_ABORT); - canceled_ = true; // in case OnLookupComplete is already on event queue. + request_ = nullptr; Release(); return 0; } diff --git a/media/mtransport/nriceresolver.h b/media/mtransport/nriceresolver.h index c3a379e716..612c860ae2 100644 --- a/media/mtransport/nriceresolver.h +++ b/media/mtransport/nriceresolver.h @@ -95,8 +95,7 @@ class NrIceResolver thread_(thread), port_(port), transport_(transport), - cb_(cb), cb_arg_(cb_arg), - canceled_ (false) {} + cb_(cb), cb_arg_(cb_arg) {} NS_IMETHOD OnLookupComplete(nsICancelable *request, nsIDNSRecord *record, nsresult status) override; int cancel(); @@ -110,7 +109,6 @@ class NrIceResolver int transport_; int (*cb_)(void *cb_arg, nr_transport_addr *addr); void *cb_arg_; - bool canceled_; }; nr_resolver_vtbl* vtbl_; diff --git a/media/mtransport/test_nr_socket.cpp b/media/mtransport/test_nr_socket.cpp index 79d85f0ec5..ea61787c9a 100644 --- a/media/mtransport/test_nr_socket.cpp +++ b/media/mtransport/test_nr_socket.cpp @@ -386,8 +386,14 @@ int TestNrSocket::recvfrom(void *buf, size_t maxlen, if (!r) { PortMapping *port_mapping_used; ingress_allowed = allow_ingress(*from, &port_mapping_used); - if (ingress_allowed && nat_->refresh_on_ingress_ && port_mapping_used) { - port_mapping_used->last_used_ = PR_IntervalNow(); + if (ingress_allowed) { + r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s received from %s via %s", + internal_socket_->my_addr().as_string, + from->as_string, + port_mapping_used->external_socket_->my_addr().as_string); + if (nat_->refresh_on_ingress_) { + port_mapping_used->last_used_ = PR_IntervalNow(); + } } } } else { @@ -402,9 +408,13 @@ int TestNrSocket::recvfrom(void *buf, size_t maxlen, nat_->is_an_internal_tuple(*from)); if (!ingress_allowed) { r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: " - "Not behind the same NAT", - internal_socket_->my_addr().as_string, - from->as_string); + "Not behind the same NAT", + internal_socket_->my_addr().as_string, + from->as_string); + } else { + r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s received from %s", + internal_socket_->my_addr().as_string, + from->as_string); } } } @@ -425,12 +435,9 @@ int TestNrSocket::recvfrom(void *buf, size_t maxlen, bool TestNrSocket::allow_ingress(const nr_transport_addr &from, PortMapping **port_mapping_used) const { - *port_mapping_used = nullptr; - if (!nat_->enabled_) - return true; - - if (nat_->is_an_internal_tuple(from)) - return true; + // This is only called for traffic arriving at a port mapping + MOZ_ASSERT(nat_->enabled_); + MOZ_ASSERT(!nat_->is_an_internal_tuple(from)); *port_mapping_used = get_port_mapping(from, nat_->filtering_type_); if (!(*port_mapping_used)) { @@ -699,10 +706,6 @@ void TestNrSocket::on_socket_readable(NrSocketBase *real_socket) { void TestNrSocket::fire_readable_callback() { MOZ_ASSERT(poll_flags() & PR_POLL_READ); - // Stop listening on all real sockets; we will start listening again - // if the app starts listening to us again. - cancel_port_mapping_async_wait(NR_ASYNC_WAIT_READ); - internal_socket_->cancel(NR_ASYNC_WAIT_READ); r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s ready for read", internal_socket_->my_addr().as_string); fire_callback(NR_ASYNC_WAIT_READ); diff --git a/media/omx-plugin/OmxPlugin.cpp b/media/omx-plugin/OmxPlugin.cpp index 4dae18bc02..4b6641c46e 100644 --- a/media/omx-plugin/OmxPlugin.cpp +++ b/media/omx-plugin/OmxPlugin.cpp @@ -31,13 +31,7 @@ #undef LOG #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OmxPlugin" , ## args) -#if !defined(MOZ_ANDROID_GB) && !defined(MOZ_ANDROID_HC) -#define MOZ_ANDROID_V4_OR_ABOVE -#endif - -#if defined(MOZ_ANDROID_V4_OR_ABOVE) #include -#endif using namespace MPAPI; @@ -200,11 +194,9 @@ OmxDecoder::~OmxDecoder() mAudioSource->stop(); } -#ifndef MOZ_ANDROID_HC if (mColorConverter) { delete mColorConverter; } -#endif } class AutoStopMediaSource { @@ -268,14 +260,12 @@ static uint32_t GetVideoCreationFlags(PluginHost* aPluginHost) int32_t flags = 0; aPluginHost->GetIntPref("media.stagefright.omxcodec.flags", &flags); if (flags != 0) { -#if !defined(MOZ_ANDROID_GB) LOG("media.stagefright.omxcodec.flags=%d", flags); if ((flags & OMXCodec::kHardwareCodecsOnly) != 0) { LOG("FORCE HARDWARE DECODING"); } else if ((flags & OMXCodec::kSoftwareCodecsOnly) != 0) { LOG("FORCE SOFTWARE DECODING"); } -#endif } flags |= GetDefaultStagefrightFlags(aPluginHost); @@ -310,14 +300,11 @@ IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat) // These formats are okay if we can't find a better one; Android provides a // software conversion to a sane colour format. -#if !defined(MOZ_ANDROID_HC) if (ColorConverter(aColorFormat, OMX_COLOR_Format16bitRGB565).isValid()) { LOG("Colour format %#x supported by Android ColorConverter.", aColorFormat); return ColorFormatSupportOK; } -#endif -#if defined(MOZ_ANDROID_V4_OR_ABOVE) I420ColorConverter yuvConverter; if (yuvConverter.isLoaded() && @@ -325,7 +312,6 @@ IsColorFormatSupported(OMX_COLOR_FORMATTYPE aColorFormat) LOG("Colour format %#x supported by Android I420ColorConverter.", aColorFormat); return ColorFormatSupportOK; } -#endif return ColorFormatNotSupported; } @@ -433,11 +419,7 @@ static sp CreateVideoSource(PluginHost* aPluginHost, // Throw away the videoSource and try again with new flags. LOG("Falling back to software decoder"); videoSource.clear(); -#if defined(MOZ_ANDROID_GB) - flags = DEFAULT_STAGEFRIGHT_FLAGS | OMXCodec::kPreferSoftwareCodecs; -#else flags = DEFAULT_STAGEFRIGHT_FLAGS | OMXCodec::kSoftwareCodecsOnly; -#endif } MOZ_ASSERT(flags != DEFAULT_STAGEFRIGHT_FLAGS); @@ -633,18 +615,14 @@ bool OmxDecoder::SetVideoFormat() { } // Gingerbread does not support the kKeyCropRect key -#if !defined(MOZ_ANDROID_GB) if (!format->findRect(kKeyCropRect, &mVideoCropLeft, &mVideoCropTop, &mVideoCropRight, &mVideoCropBottom)) { -#endif mVideoCropLeft = 0; mVideoCropTop = 0; mVideoCropRight = mVideoStride - 1; mVideoCropBottom = mVideoSliceHeight - 1; LOG("crop rect not available, assuming no cropping"); -#if !defined(MOZ_ANDROID_GB) } -#endif if (mVideoCropLeft < 0 || mVideoCropLeft >= mVideoCropRight || mVideoCropRight >= mVideoStride || mVideoCropTop < 0 || mVideoCropTop >= mVideoCropBottom || mVideoCropBottom >= mVideoSliceHeight) { @@ -798,9 +776,6 @@ bool OmxDecoder::ToVideoFrame_RGB565(VideoFrame *aFrame, int64_t aTimeUs, void * } bool OmxDecoder::ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) { -#ifdef MOZ_ANDROID_HC - return false; -#else if (!mColorConverter) { mColorConverter = new ColorConverter((OMX_COLOR_FORMATTYPE)mVideoColorFormat, OMX_COLOR_Format16bitRGB565); @@ -820,26 +795,18 @@ bool OmxDecoder::ToVideoFrame_ColorConverter(VideoFrame *aFrame, int64_t aTimeUs aFrame->mSize = mVideoWidth * mVideoHeight * 2; -#if defined(MOZ_ANDROID_GB) - mColorConverter->convert(mVideoWidth, mVideoHeight, - aData, 0 /* srcSkip */, - buffer, mVideoWidth * 2); -#else mColorConverter->convert(aData, mVideoStride, mVideoSliceHeight, mVideoCropLeft, mVideoCropTop, mVideoCropLeft + mVideoWidth - 1, mVideoCropTop + mVideoHeight - 1, buffer, mVideoWidth, mVideoHeight, 0, 0, mVideoWidth - 1, mVideoHeight - 1); -#endif return true; -#endif } bool OmxDecoder::ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) { -#if defined(MOZ_ANDROID_V4_OR_ABOVE) I420ColorConverter yuvConverter; if (!yuvConverter.isLoaded()) { @@ -866,9 +833,6 @@ bool OmxDecoder::ToVideoFrame_I420ColorConverter(VideoFrame *aFrame, int64_t aTi } return result == OK; -#else - return false; -#endif } bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame, BufferCallback *aBufferCallback) { diff --git a/testing/eslint-plugin-mozilla/docs/components-imports.rst b/testing/eslint-plugin-mozilla/docs/components-imports.rst deleted file mode 100644 index b923f2a916..0000000000 --- a/testing/eslint-plugin-mozilla/docs/components-imports.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _components-imports: - -================== -components-imports -================== - -Rule Details ------------- - -Adds the filename of imported files e.g. -``Cu.import("some/path/Blah.jsm")`` adds Blah to the global scope. - -The following patterns are supported: - -- ``Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");`` -- ``loader.lazyImporter(this, "name1");`` -- ``loader.lazyRequireGetter(this, "name2"`` -- ``loader.lazyServiceGetter(this, "name3"`` -- ``XPCOMUtils.defineLazyModuleGetter(this, "setNamedTimeout", ...)`` -- ``loader.lazyGetter(this, "toolboxStrings"`` -- ``XPCOMUtils.defineLazyGetter(this, "clipboardHelper"`` diff --git a/testing/eslint-plugin-mozilla/docs/import-globals-from.rst b/testing/eslint-plugin-mozilla/docs/import-globals-from.rst deleted file mode 100644 index fcd32b301b..0000000000 --- a/testing/eslint-plugin-mozilla/docs/import-globals-from.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _import-globals-from: - -=================== -import-globals-from -=================== - -Rule Details ------------- - -When the "import-globals-from " comment is found in a file, then all -globals from the file at will be imported in the current scope. - -This is useful for tests that rely on globals defined in head.js files, or for -scripts that are loaded as