foobar
")}, + {"url": self.test_page}, + {"url": inline("foobar
")}, + ] + self.run_test(test_pages) + + def test_same_document_hash_change(self): + test_pages = [ + {"url": "{}#23".format(self.test_page)}, + {"url": self.test_page}, + {"url": "{}#42".format(self.test_page)}, + ] + self.run_test(test_pages) + + @skip("Causes crashes for JS GC (bug 1344863) and a11y (bug 1344868)") + def test_frameset(self): + test_pages = [ + {"url": self.marionette.absolute_url("frameset.html")}, + {"url": self.test_page}, + {"url": self.marionette.absolute_url("frameset.html")}, + ] + self.run_test(test_pages) + + def test_frameset_after_navigating_in_frame(self): + test_element_locator = (By.ID, "email") + + self.marionette.navigate(self.test_page) + self.assertEqual(self.marionette.get_url(), self.test_page) + self.assertEqual(self.history_length, 1) + page = self.marionette.absolute_url("frameset.html") + self.marionette.navigate(page) + self.assertEqual(self.marionette.get_url(), page) + self.assertEqual(self.history_length, 2) + frame = self.marionette.find_element(By.ID, "fifth") + self.marionette.switch_to_frame(frame) + link = self.marionette.find_element(By.ID, "linkId") + link.click() + + # We cannot use get_url() to wait until the target page has been loaded, + # because it will return the URL of the top browsing context and doesn't + # wait for the page load to be complete. + Wait(self.marionette, timeout=self.marionette.timeout.page_load).until( + expected.element_present(*test_element_locator), + message="Target element 'email' has not been found") + self.assertEqual(self.history_length, 3) + + # Go back to the frame the click navigated away from + self.marionette.go_back() + self.assertEqual(self.marionette.get_url(), page) + with self.assertRaises(errors.NoSuchElementException): + self.marionette.find_element(*test_element_locator) + + # Go back to the non-frameset page + self.marionette.switch_to_parent_frame() + self.marionette.go_back() + self.assertEqual(self.marionette.get_url(), self.test_page) + + # Go forward to the frameset page + self.marionette.go_forward() + self.assertEqual(self.marionette.get_url(), page) + + # Go forward to the frame the click navigated to + # TODO: See above for automatic browser context switches. Hard to do here + frame = self.marionette.find_element(By.ID, "fifth") + self.marionette.switch_to_frame(frame) + self.marionette.go_forward() + self.marionette.find_element(*test_element_locator) + self.assertEqual(self.marionette.get_url(), page) + + def test_image_document_to_html(self): + test_pages = [ + {"url": self.marionette.absolute_url('black.png')}, + {"url": self.test_page}, + {"url": self.marionette.absolute_url('white.png')}, + ] + self.run_test(test_pages) + + def test_image_document_to_image_document(self): + test_pages = [ + {"url": self.marionette.absolute_url('black.png')}, + {"url": self.marionette.absolute_url('white.png')}, + ] + self.run_test(test_pages) + + @run_if_e10s("Requires e10s mode enabled") + def test_remoteness_change(self): + # TODO: Verify that a remoteness change happened + # like: self.assertNotEqual(self.marionette.current_window_handle, self.new_tab) + + # about:robots is always a non-remote page for now + test_pages = [ + {"url": "about:robots"}, + {"url": self.test_page}, + {"url": "about:robots"}, + ] + self.run_test(test_pages) + + def test_navigate_to_requested_about_page_after_error_page(self): + test_pages = [ + {"url": "about:neterror"}, + {"url": self.marionette.absolute_url("test.html")}, + {"url": "about:blocked"}, + ] + self.run_test(test_pages) + + def test_timeout_error(self): + urls = [ + self.marionette.absolute_url('slow'), + self.test_page, + self.marionette.absolute_url('slow'), + ] + + # First, load all pages completely to get them added to the cache + for index, url in enumerate(urls): + self.marionette.navigate(url) + self.assertEqual(url, self.marionette.get_url()) + self.assertEqual(self.history_length, index + 1) + + self.marionette.go_back() + self.assertEqual(urls[1], self.marionette.get_url()) + + # Force triggering a timeout error + self.marionette.timeout.page_load = 0.1 + with self.assertRaises(errors.TimeoutException): + self.marionette.go_back() + self.assertEqual(urls[0], self.marionette.get_url()) + self.marionette.timeout.page_load = 300000 + + self.marionette.go_forward() + self.assertEqual(urls[1], self.marionette.get_url()) + + # Force triggering a timeout error + self.marionette.timeout.page_load = 0.1 + with self.assertRaises(errors.TimeoutException): + self.marionette.go_forward() + self.assertEqual(urls[2], self.marionette.get_url()) + self.marionette.timeout.page_load = 300000 + + def test_certificate_error(self): + test_pages = [ + {"url": self.fixtures.where_is("/test.html", on="https"), + "error": errors.InsecureCertificateException}, + {"url": self.test_page}, + {"url": self.fixtures.where_is("/test.html", on="https"), + "error": errors.InsecureCertificateException}, + ] + self.run_test(test_pages) + + class TestNavigate(WindowManagerMixin, MarionetteTestCase): def setUp(self): @@ -30,7 +241,8 @@ def setUp(self): self.iframe_doc = self.marionette.absolute_url("test_iframe.html") def tearDown(self): - self.close_all_windows() + self.marionette.timeout.reset() + self.close_all_tabs() super(TestNavigate, self).tearDown() @@ -52,11 +264,6 @@ def test_set_location_through_execute_script(self): lambda _: self.test_doc == self.location_href) self.assertEqual("Marionette Test", self.marionette.title) - def test_navigate(self): - self.marionette.navigate(self.test_doc) - self.assertNotEqual("about:", self.location_href) - self.assertEqual("Marionette Test", self.marionette.title) - def test_navigate_chrome_error(self): with self.marionette.using_context("chrome"): self.assertRaises(errors.UnsupportedOperationException, @@ -78,33 +285,6 @@ def test_get_current_url(self): self.marionette.navigate("about:blank") self.assertEqual("about:blank", self.marionette.get_url()) - # TODO(ato): Remove wait conditions when fixing bug 1330348 - def test_go_back(self): - self.marionette.navigate(self.test_doc) - self.assertNotEqual("about:blank", self.location_href) - self.assertEqual("Marionette Test", self.marionette.title) - self.marionette.navigate("about:blank") - self.assertEqual("about:blank", self.location_href) - self.marionette.go_back() - Wait(self.marionette).until(lambda m: self.location_href == self.test_doc) - self.assertNotEqual("about:blank", self.location_href) - self.assertEqual("Marionette Test", self.marionette.title) - - # TODO(ato): Remove wait conditions when fixing bug 1330348 - def test_go_forward(self): - self.marionette.navigate(self.test_doc) - self.assertNotEqual("about:blank", self.location_href) - self.assertEqual("Marionette Test", self.marionette.title) - self.marionette.navigate("about:blank") - self.assertEqual("about:blank", self.location_href) - self.marionette.go_back() - Wait(self.marionette).until(lambda m: self.location_href == self.test_doc) - self.assertEqual(self.test_doc, self.location_href) - self.assertEqual("Marionette Test", self.marionette.title) - self.marionette.go_forward() - Wait(self.marionette).until(lambda m: self.location_href == "about:blank") - self.assertEqual("about:blank", self.location_href) - def test_refresh(self): self.marionette.navigate(self.test_doc) self.assertEqual("Marionette Test", self.marionette.title) @@ -137,13 +317,6 @@ def test_invalid_protocol(self): with self.assertRaises(errors.MarionetteException): self.marionette.navigate("thisprotocoldoesnotexist://") - def test_should_navigate_to_requested_about_page(self): - self.marionette.navigate("about:neterror") - self.assertEqual(self.marionette.get_url(), "about:neterror") - self.marionette.navigate(self.marionette.absolute_url("test.html")) - self.marionette.navigate("about:blocked") - self.assertEqual(self.marionette.get_url(), "about:blocked") - def test_find_element_state_complete(self): self.marionette.navigate(self.test_doc) state = self.marionette.execute_script( @@ -152,21 +325,21 @@ def test_find_element_state_complete(self): self.assertTrue(self.marionette.find_element(By.ID, "mozLink")) def test_error_when_exceeding_page_load_timeout(self): + self.marionette.timeout.page_load = 0.1 with self.assertRaises(errors.TimeoutException): - self.marionette.timeout.page_load = 0.1 self.marionette.navigate(self.marionette.absolute_url("slow")) - self.marionette.find_element(By.TAG_NAME, "p") - def test_navigate_iframe(self): - self.marionette.navigate(self.iframe_doc) - self.assertTrue('test_iframe.html' in self.marionette.get_url()) - self.assertTrue(self.marionette.find_element(By.ID, "test_iframe")) + def test_navigate_to_same_image_document_twice(self): + self.marionette.navigate(self.fixtures.where_is("black.png")) + self.assertIn("black.png", self.marionette.title) + self.marionette.navigate(self.fixtures.where_is("black.png")) + self.assertIn("black.png", self.marionette.title) - def test_fragment(self): + def test_navigate_hash_change(self): doc = inline("") self.marionette.navigate(doc) self.marionette.execute_script("window.visited = true", sandbox=None) - self.marionette.navigate("%s#foo" % doc) + self.marionette.navigate("{}#foo".format(doc)) self.assertTrue(self.marionette.execute_script( "return window.visited", sandbox=None)) @@ -187,23 +360,6 @@ def open_with_link(): self.marionette.close() self.marionette.switch_to_window(self.start_window) - def test_error_on_tls_navigation(self): - self.assertRaises(errors.InsecureCertificateException, - self.marionette.navigate, self.fixtures.where_is("/test.html", on="https")) - - def test_html_document_to_image_document(self): - self.marionette.navigate(self.fixtures.where_is("test.html")) - self.marionette.navigate(self.fixtures.where_is("white.png")) - self.assertIn("white.png", self.marionette.title) - - def test_image_document_to_image_document(self): - self.marionette.navigate(self.fixtures.where_is("test.html")) - - self.marionette.navigate(self.fixtures.where_is("white.png")) - self.assertIn("white.png", self.marionette.title) - self.marionette.navigate(self.fixtures.where_is("black.png")) - self.assertIn("black.png", self.marionette.title) - @run_if_manage_instance("Only runnable if Marionette manages the instance") @skip_if_mobile("Bug 1322993 - Missing temporary folder") def test_focus_after_navigation(self): diff --git a/testing/marionette/harness/marionette_harness/www/frameset.html b/testing/marionette/harness/marionette_harness/www/frameset.html index 1136b35b3994..209d705b5ab6 100644 --- a/testing/marionette/harness/marionette_harness/www/frameset.html +++ b/testing/marionette/harness/marionette_harness/www/frameset.html @@ -8,7 +8,7 @@ - + \ No newline at end of file diff --git a/testing/marionette/harness/marionette_harness/www/xhtmlTest.html b/testing/marionette/harness/marionette_harness/www/xhtmlTest.html index e6e7926bdb99..146def33ad0e 100644 --- a/testing/marionette/harness/marionette_harness/www/xhtmlTest.html +++ b/testing/marionette/harness/marionette_harness/www/xhtmlTest.html @@ -10,7 +10,7 @@
diff --git a/testing/marionette/listener.js b/testing/marionette/listener.js index a051bccd3ba9..65c491100a57 100644 --- a/testing/marionette/listener.js +++ b/testing/marionette/listener.js @@ -222,7 +222,6 @@ var getTitleFn = dispatch(getTitle); var getPageSourceFn = dispatch(getPageSource); var getActiveElementFn = dispatch(getActiveElement); var clickElementFn = dispatch(clickElement); -var goBackFn = dispatch(goBack); var getElementAttributeFn = dispatch(getElementAttribute); var getElementPropertyFn = dispatch(getElementProperty); var getElementTextFn = dispatch(getElementText); @@ -271,7 +270,7 @@ function startListeners() { addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrlFn); addMessageListenerId("Marionette:getTitle", getTitleFn); addMessageListenerId("Marionette:getPageSource", getPageSourceFn); - addMessageListenerId("Marionette:goBack", goBackFn); + addMessageListenerId("Marionette:goBack", goBack); addMessageListenerId("Marionette:goForward", goForward); addMessageListenerId("Marionette:refresh", refresh); addMessageListenerId("Marionette:findElementContent", findElementContentFn); @@ -376,7 +375,7 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:getTitle", getTitleFn); removeMessageListenerId("Marionette:getPageSource", getPageSourceFn); removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrlFn); - removeMessageListenerId("Marionette:goBack", goBackFn); + removeMessageListenerId("Marionette:goBack", goBack); removeMessageListenerId("Marionette:goForward", goForward); removeMessageListenerId("Marionette:refresh", refresh); removeMessageListenerId("Marionette:findElementContent", findElementContentFn); @@ -685,9 +684,9 @@ function createATouch(el, corx, cory, touchId) { * Object with an |actions| attribute that is an Array of objects * each of which represents an action sequence. */ -function performActions(msg) { +function* performActions(msg) { let chain = action.Chain.fromJson(msg.actions); - action.dispatch(chain, seenEls, curContainer); + yield action.dispatch(chain, seenEls, curContainer); } /** @@ -696,8 +695,8 @@ function performActions(msg) { * the state was released by an explicit series of actions. It also clears all * the internal state of the virtual devices. */ -function releaseActions() { - action.dispatchTickActions(action.inputsToCancel.reverse(), 0, seenEls, curContainer); +function* releaseActions() { + yield action.dispatchTickActions(action.inputsToCancel.reverse(), 0, seenEls, curContainer); action.inputsToCancel.length = 0; action.inputStateMap.clear(); } @@ -886,46 +885,70 @@ function multiAction(args, maxLen) { setDispatch(concurrentEvent, pendingTouches); } -/* +/** * This implements the latter part of a get request (for the case we need to resume one * when a remoteness update happens in the middle of a navigate request). This is most of * of the work of a navigate request, but doesn't assume DOMContentLoaded is yet to fire. + * + * @param {function=} cleanupCallback + * Callback to execute when registered event handlers or observer notifications + * have to be cleaned-up. + * @param {number} command_id + * ID of the currently handled message between the driver and listener. + * @param {string=} lastSeenURL + * Last URL as seen before the navigation request got triggered. + * @param {number} pageTimeout + * Timeout in seconds the method has to wait for the page being finished loading. + * @param {number} startTime + * Unix timestap when the navitation request got triggred. */ -function pollForReadyState(msg, start = undefined, callback = undefined) { - let {pageTimeout, url, command_id} = msg.json; - if (!start) { - start = new Date().getTime(); +function pollForReadyState(msg) { + let {cleanupCallback, command_id, lastSeenURL, pageTimeout, startTime} = msg.json; + + if (typeof startTime == "undefined") { + startTime = new Date().getTime(); } - if (!callback) { - callback = () => {}; + + if (typeof cleanupCallback == "undefined") { + cleanupCallback = () => {}; } + let endTime = startTime + pageTimeout; + let checkLoad = function() { navTimer.cancel(); let doc = curContainer.frame.document; - let now = new Date().getTime(); - if (pageTimeout == null || (now - start) <= pageTimeout) { + + if (pageTimeout === null || new Date().getTime() <= endTime) { + // Under some conditions (eg. for error pages) the pagehide event is fired + // even with a readyState complete for the formerly loaded page. + // To prevent race conditition for goBack and goForward we have to wait + // until the last seen page has been fully unloaded. + // TODO: Bug 1333458 has to improve this. + if (!doc.location || lastSeenURL && doc.location.href === lastSeenURL) { + navTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT); + // document fully loaded - if (doc.readyState == "complete") { - callback(); + } else if (doc.readyState === "complete") { + cleanupCallback(); sendOk(command_id); // document with an insecure cert - } else if (doc.readyState == "interactive" && + } else if (doc.readyState === "interactive" && doc.baseURI.startsWith("about:certerror")) { - callback(); + cleanupCallback(); sendError(new InsecureCertificateError(), command_id); // we have reached an error url without requesting it - } else if (doc.readyState == "interactive" && + } else if (doc.readyState === "interactive" && /about:.+(error)\?/.exec(doc.baseURI)) { - callback(); + cleanupCallback(); sendError(new UnknownError("Reached error page: " + doc.baseURI), command_id); // return early for about: urls - } else if (doc.readyState == "interactive" && doc.baseURI.startsWith("about:")) { - callback(); + } else if (doc.readyState === "interactive" && doc.baseURI.startsWith("about:")) { + cleanupCallback(); sendOk(command_id); // document not fully loaded @@ -934,10 +957,11 @@ function pollForReadyState(msg, start = undefined, callback = undefined) { } } else { - callback(); + cleanupCallback(); sendError(new TimeoutError("Error loading page, timed out (checkLoad)"), command_id); } }; + checkLoad(); } @@ -948,9 +972,10 @@ function pollForReadyState(msg, start = undefined, callback = undefined) { * driver (in chrome space). */ function get(msg) { - let start = new Date().getTime(); let {pageTimeout, url, command_id} = msg.json; + let startTime = new Date().getTime(); + // We need to move to the top frame before navigating sendSyncMessage("Marionette:switchedToFrame", {frameValue: null}); curContainer.frame = content; @@ -1018,9 +1043,15 @@ function get(msg) { // not triggered, which is the case for image documents. else if (state & Ci.nsIWebProgressListener.STATE_STOP && content.document instanceof content.ImageDocument) { - pollForReadyState(msg, start, () => { - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - }); + pollForReadyState({json: { + command_id: command_id, + pageTimeout: pageTimeout, + startTime: startTime, + cleanupCallback: () => { + webProgress.removeProgressListener(loadListener); + removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); + } + }}); } }, @@ -1057,10 +1088,15 @@ function get(msg) { docShell.hasLoadedNonBlankURI; if (correctFrame && sawLoad && loadedRequestedURI) { - webProgress.removeProgressListener(loadListener); - pollForReadyState(msg, start, () => { - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - }); + pollForReadyState({json: { + command_id: command_id, + pageTimeout: pageTimeout, + startTime: startTime, + cleanupCallback: () => { + webProgress.removeProgressListener(loadListener); + removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); + } + }}); } }; @@ -1099,12 +1135,8 @@ function cancelRequest() { /** * Get URL of the top-level browsing context. */ -function getCurrentUrl(isB2G) { - if (isB2G) { - return curContainer.frame.location.href; - } else { - return content.location.href; - } +function getCurrentUrl() { + return content.location.href; } /** @@ -1121,20 +1153,115 @@ function getPageSource() { return curContainer.frame.document.documentElement.outerHTML; } +/** + * Wait for the current page to be unloaded after a navigation got triggered. + * + * @param {function} trigger + * Callback to execute which triggers a page navigation. + * @param {function} doneCallback + * Callback to execute when the current page has been unloaded. + * + * It receives a dictionary with the following items as argument: + * loading - Flag if a page load will follow. + * lastSeenURL - Last seen URL before the navigation request. + * startTime - Time when the navigation request has been triggered. + */ +function waitForPageUnloaded(trigger, doneCallback) { + let currentURL = curContainer.frame.location.href; + let start = new Date().getTime(); + + function handleEvent(event) { + // In case of a remoteness change it can happen that we are no longer able + // to access the document's location. In those cases ignore the event, + // but keep the code waiting, and assume in the driver that waiting for the + // page load is necessary. Bug 1333458 should improve things. + if (typeof event.originalTarget.location == "undefined") { + return; + } + + switch (event.type) { + case "hashchange": + removeEventListener("hashchange", handleEvent); + removeEventListener("pagehide", handleEvent); + removeEventListener("unload", handleEvent); + + doneCallback({loading: false, lastSeenURL: currentURL}); + break; + + case "pagehide": + case "unload": + if (event.originalTarget === curContainer.frame.document) { + removeEventListener("hashchange", handleEvent); + removeEventListener("pagehide", handleEvent); + removeEventListener("unload", handleEvent); + + doneCallback({loading: true, lastSeenURL: currentURL, startTime: start}); + } + break; + } + } + + addEventListener("hashchange", handleEvent, false); + addEventListener("pagehide", handleEvent, false); + addEventListener("unload", handleEvent, false); + + trigger(); +} + /** * Cause the browser to traverse one step backward in the joint history - * of the current top-level browsing context. + * of the current browsing context. + * + * @param {number} command_id + * ID of the currently handled message between the driver and listener. + * @param {number} pageTimeout + * Timeout in milliseconds the method has to wait for the page being finished loading. */ -function goBack() { - curContainer.frame.history.back(); +function goBack(msg) { + let {command_id, pageTimeout} = msg.json; + + waitForPageUnloaded(() => { + curContainer.frame.history.back(); + }, pageLoadStatus => { + if (pageLoadStatus.loading) { + pollForReadyState({json: { + command_id: command_id, + lastSeenURL: pageLoadStatus.lastSeenURL, + pageTimeout: pageTimeout, + startTime: pageLoadStatus.startTime, + }}); + } else { + sendOk(command_id); + } + }); } /** - * Go forward in history + * Cause the browser to traverse one step forward in the joint history + * of the current browsing context. + * + * @param {number} command_id + * ID of the currently handled message between the driver and listener. + * @param {number} pageTimeout + * Timeout in milliseconds the method has to wait for the page being finished loading. */ function goForward(msg) { - curContainer.frame.history.forward(); - sendOk(msg.json.command_id); + let {command_id, pageTimeout} = msg.json; + + waitForPageUnloaded(() => { + curContainer.frame.history.forward(); + }, pageLoadStatus => { + if (pageLoadStatus.loading) { + pollForReadyState({json: { + command_id: command_id, + lastSeenURL: pageLoadStatus.lastSeenURL, + pageTimeout: pageTimeout, + startTime: pageLoadStatus.startTime, + }}); + } else { + sendOk(command_id); + } + }); } /** diff --git a/testing/marionette/test_action.js b/testing/marionette/test_action.js index 74b0446b26a3..1c58ced766a2 100644 --- a/testing/marionette/test_action.js +++ b/testing/marionette/test_action.js @@ -25,7 +25,7 @@ add_test(function test_createAction() { }); add_test(function test_defaultPointerParameters() { - let defaultParameters = {pointerType: action.PointerType.Mouse, primary: true}; + let defaultParameters = {pointerType: action.PointerType.Mouse}; deepEqual(action.PointerParameters.fromJson(), defaultParameters); run_next_test(); @@ -34,16 +34,15 @@ add_test(function test_defaultPointerParameters() { add_test(function test_processPointerParameters() { let check = (regex, message, arg) => checkErrors( regex, action.PointerParameters.fromJson, [arg], message); - let parametersData = {pointerType: "foo", primary: undefined}; - let message = `parametersData: [pointerType: ${parametersData.pointerType}, ` + - `primary: ${parametersData.primary}]`; - check(/Unknown pointerType/, message, parametersData); - parametersData.pointerType = "pen"; - parametersData.primary = "a"; - check(/Expected \[object String\] "a" to be boolean/, message, parametersData); - parametersData.primary = false; + let parametersData; + for (let d of ["foo", "", "get", "Get"]) { + parametersData = {pointerType: d}; + let message = `parametersData: [pointerType: ${parametersData.pointerType}]`; + check(/Unknown pointerType/, message, parametersData); + } + parametersData.pointerType = "mouse"; //TODO "pen"; deepEqual(action.PointerParameters.fromJson(parametersData), - {pointerType: action.PointerType.Pen, primary: false}); + {pointerType: "mouse"}); //TODO action.PointerType.Pen}); run_next_test(); }); @@ -80,29 +79,61 @@ add_test(function test_validateActionDurationAndCoordinates() { check("pointer", "pointerMove"); } actionItem.duration = 5000; - for (let d of [-1, "a"]) { - for (let name of ["x", "y"]) { - actionItem[name] = d; - check("pointer", "pointerMove", `${name}: ${actionItem[name]}`); - } + for (let name of ["x", "y"]) { + actionItem[name] = "a"; + actionItem.type = "pointerMove"; + actionSequence.type = "pointer"; + checkErrors(/Expected '.*' \(.*\) to be an Integer/, + action.Action.fromJson, [actionSequence, actionItem], + `duration: ${actionItem.duration}, subtype: pointerMove`); } run_next_test(); }); -add_test(function test_processPointerMoveActionElementValidation() { +add_test(function test_processPointerMoveActionOriginValidation() { let actionSequence = {type: "pointer", id: "some_id"}; let actionItem = {duration: 5000, type: "pointerMove"}; - for (let d of [-1, "a", {a: "blah"}]) { - actionItem.element = d; - checkErrors(/Expected 'actionItem.element' to be a web element reference/, + for (let d of [-1, {a: "blah"}, []]) { + actionItem.origin = d; + + checkErrors(/Expected \'origin\' to be a string or a web element reference/, action.Action.fromJson, [actionSequence, actionItem], - `actionItem.element: (${getTypeString(d)})`); + `actionItem.origin: (${getTypeString(d)})`); } - actionItem.element = {[element.Key]: "something"}; + + run_next_test(); +}); + +add_test(function test_processPointerMoveActionOriginStringValidation() { + let actionSequence = {type: "pointer", id: "some_id"}; + let actionItem = {duration: 5000, type: "pointerMove"}; + for (let d of ["a", "", "get", "Get"]) { + actionItem.origin = d; + checkErrors(/Unknown pointer-move origin/, + action.Action.fromJson, + [actionSequence, actionItem], + `actionItem.origin: ${d}`); + } + + run_next_test(); +}); + +add_test(function test_processPointerMoveActionElementOrigin() { + let actionSequence = {type: "pointer", id: "some_id"}; + let actionItem = {duration: 5000, type: "pointerMove"}; + actionItem.origin = {[element.Key]: "something"}; let a = action.Action.fromJson(actionSequence, actionItem); - deepEqual(a.element, actionItem.element); + deepEqual(a.origin, actionItem.origin); + run_next_test(); +}); +add_test(function test_processPointerMoveActionDefaultOrigin() { + let actionSequence = {type: "pointer", id: "some_id"}; + // origin left undefined + let actionItem = {duration: 5000, type: "pointerMove"}; + let a = action.Action.fromJson(actionSequence, actionItem); + deepEqual(a.origin, action.PointerOrigin.Viewport); run_next_test(); }); @@ -112,14 +143,14 @@ add_test(function test_processPointerMoveAction() { { duration: 5000, type: "pointerMove", - element: undefined, + origin: undefined, x: undefined, y: undefined, }, { duration: undefined, type: "pointerMove", - element: {[element.Key]: "id", [element.LegacyKey]: "id"}, + origin: {[element.Key]: "id", [element.LegacyKey]: "id"}, x: undefined, y: undefined, }, @@ -128,34 +159,88 @@ add_test(function test_processPointerMoveAction() { type: "pointerMove", x: 0, y: undefined, - element: undefined, + origin: undefined, }, { duration: 5000, type: "pointerMove", x: 1, y: 2, - element: undefined, + origin: undefined, }, ]; for (let expected of actionItems) { let actual = action.Action.fromJson(actionSequence, expected); ok(actual instanceof action.Action); equal(actual.duration, expected.duration); - equal(actual.element, expected.element); equal(actual.x, expected.x); equal(actual.y, expected.y); + + let origin = expected.origin; + if (typeof origin == "undefined") { + origin = action.PointerOrigin.Viewport; + } + deepEqual(actual.origin, origin); + } run_next_test(); }); +add_test(function test_computePointerDestinationViewport() { + let act = { type: "pointerMove", x: 100, y: 200, origin: "viewport"}; + let inputState = new action.InputState.Pointer(action.PointerType.Mouse); + // these values should not affect the outcome + inputState.x = "99"; + inputState.y = "10"; + let target = action.computePointerDestination(act, inputState); + equal(act.x, target.x); + equal(act.y, target.y); + + run_next_test(); +}); + +add_test(function test_computePointerDestinationPointer() { + let act = { type: "pointerMove", x: 100, y: 200, origin: "pointer"}; + let inputState = new action.InputState.Pointer(action.PointerType.Mouse); + inputState.x = 10; + inputState.y = 99; + let target = action.computePointerDestination(act, inputState); + equal(act.x + inputState.x, target.x); + equal(act.y + inputState.y, target.y); + + + run_next_test(); +}); + +add_test(function test_computePointerDestinationElement() { + // origin represents a web element + // using an object literal instead to test default case in computePointerDestination + let act = {type: "pointerMove", x: 100, y: 200, origin: {}}; + let inputState = new action.InputState.Pointer(action.PointerType.Mouse); + let elementCenter = {x: 10, y: 99}; + let target = action.computePointerDestination(act, inputState, elementCenter); + equal(act.x + elementCenter.x, target.x); + equal(act.y + elementCenter.y, target.y); + + Assert.throws( + () => action.computePointerDestination(act, inputState, {a: 1}), + InvalidArgumentError, + "Invalid element center coordinates."); + + Assert.throws( + () => action.computePointerDestination(act, inputState, undefined), + InvalidArgumentError, + "Undefined element center coordinates."); + + run_next_test(); +}); + add_test(function test_processPointerAction() { let actionSequence = { type: "pointer", id: "some_id", parameters: { - pointerType: "touch", - primary: false, + pointerType: "mouse" //TODO "touch" }, }; let actionItems = [ @@ -183,7 +268,6 @@ add_test(function test_processPointerAction() { equal(actual.duration, expected.duration); } if (expected.type !== "pause") { - equal(actual.primary, actionSequence.parameters.primary); equal(actual.pointerType, actionSequence.parameters.pointerType); } } @@ -253,20 +337,24 @@ add_test(function test_processInputSourceActionSequenceValidation() { let check = (message, regex) => checkErrors( regex, action.Sequence.fromJson, [actionSequence], message); check(`actionSequence.type: ${actionSequence.type}`, /Unknown action type/); + action.inputStateMap.clear(); actionSequence.type = "none"; actionSequence.id = -1; check(`actionSequence.id: ${getTypeString(actionSequence.id)}`, /Expected 'id' to be a string/); + action.inputStateMap.clear(); actionSequence.id = undefined; check(`actionSequence.id: ${getTypeString(actionSequence.id)}`, /Expected 'id' to be defined/); + action.inputStateMap.clear(); actionSequence.id = "some_id"; actionSequence.actions = -1; check(`actionSequence.actions: ${getTypeString(actionSequence.actions)}`, /Expected 'actionSequence.actions' to be an Array/); + action.inputStateMap.clear(); run_next_test(); }); @@ -283,6 +371,7 @@ add_test(function test_processInputSourceActionSequence() { let actions = action.Sequence.fromJson(actionSequence); equal(actions.length, 1); deepEqual(actions[0], expectedAction); + action.inputStateMap.clear(); run_next_test(); }); @@ -293,18 +382,17 @@ add_test(function test_processInputSourceActionSequencePointer() { id: "9", actions: [actionItem], parameters: { - pointerType: "pen", - primary: false, + pointerType: "mouse" // TODO "pen" }, }; let expectedAction = new action.Action( actionSequence.id, actionSequence.type, actionItem.type); expectedAction.pointerType = actionSequence.parameters.pointerType; - expectedAction.primary = actionSequence.parameters.primary; expectedAction.button = actionItem.button; let actions = action.Sequence.fromJson(actionSequence); equal(actions.length, 1); deepEqual(actions[0], expectedAction); + action.inputStateMap.clear(); run_next_test(); }); @@ -321,6 +409,7 @@ add_test(function test_processInputSourceActionSequenceKey() { let actions = action.Sequence.fromJson(actionSequence); equal(actions.length, 1); deepEqual(actions[0], expectedAction); + action.inputStateMap.clear(); run_next_test(); }); @@ -349,26 +438,40 @@ add_test(function test_processInputSourceActionSequenceInputStateMap() { add_test(function test_processPointerActionInputStateMap() { let actionItem = {type: "pointerDown"}; let id = "1"; - let parameters = {pointerType: "mouse", primary: false}; + let parameters = {pointerType: "mouse"}; let a = new action.Action(id, "pointer", actionItem.type); - let wrongInputState = new action.InputState.Pointer("pause", true); + let wrongInputState = new action.InputState.Key(); action.inputStateMap.set(id, wrongInputState); checkErrors( - /to be mapped to InputState whose subtype is/, action.processPointerAction, + /to be mapped to InputState whose type is/, action.processPointerAction, [id, parameters, a], - `$subtype ${actionItem.type} with ${wrongInputState.subtype} in inputState`); + `type "pointer" with ${wrongInputState.type} in inputState`); action.inputStateMap.clear(); - let rightInputState = new action.InputState.Pointer("pointerDown", false); + + // TODO - uncomment once pen is supported + //wrongInputState = new action.InputState.Pointer("pen"); + //action.inputStateMap.set(id, wrongInputState); + //checkErrors( + // /to be mapped to InputState whose subtype is/, action.processPointerAction, + // [id, parameters, a], + // `subtype ${parameters.pointerType} with ${wrongInputState.subtype} in inputState`); + //action.inputStateMap.clear(); + + let rightInputState = new action.InputState.Pointer("mouse"); action.inputStateMap.set(id, rightInputState); action.processPointerAction(id, parameters, a); - equal(a.primary, parameters.primary); action.inputStateMap.clear(); run_next_test(); }); add_test(function test_createInputState() { for (let kind in action.InputState) { - let state = new action.InputState[kind](); + let state; + if (kind == "Pointer") { + state = new action.InputState[kind]("mouse"); + } else { + state = new action.InputState[kind](); + } ok(state); if (kind === "Null") { equal(state.type, "none"); @@ -376,6 +479,10 @@ add_test(function test_createInputState() { equal(state.type, kind.toLowerCase()); } } + Assert.throws(() => new action.InputState.Pointer(), InvalidArgumentError, + "Missing InputState.Pointer constructor arg"); + Assert.throws(() => new action.InputState.Pointer("foo"), InvalidArgumentError, + "Invalid InputState.Pointer constructor arg"); run_next_test(); }); @@ -408,6 +515,7 @@ add_test(function test_extractActionChain_oneTickOneInput() { equal(1, actionsByTick.length); equal(1, actionsByTick[0].length); deepEqual(actionsByTick, [[expectedAction]]); + action.inputStateMap.clear(); run_next_test(); }); @@ -427,8 +535,7 @@ add_test(function test_extractActionChain_twoAndThreeTicks() { id: "7", actions: mouseActionItems, parameters: { - pointerType: "touch", - primary: false, + pointerType: "mouse" //TODO "touch" }, }; let keyActionItems = [ @@ -459,12 +566,14 @@ add_test(function test_extractActionChain_twoAndThreeTicks() { let expectedAction = new action.Action(keyActionSequence.id, "key", keyActionItems[2].type); expectedAction.value = keyActionItems[2].value; deepEqual(actionsByTick[2][0], expectedAction); + action.inputStateMap.clear(); // one empty action sequence actionsByTick = action.Chain.fromJson( [keyActionSequence, {type: "none", id: "some", actions: []}]); equal(keyActionItems.length, actionsByTick.length); equal(1, actionsByTick[0].length); + action.inputStateMap.clear(); run_next_test(); }); diff --git a/testing/marionette/test_assert.js b/testing/marionette/test_assert.js index 1d6cd1e9443b..c14f2852e338 100644 --- a/testing/marionette/test_assert.js +++ b/testing/marionette/test_assert.js @@ -40,11 +40,23 @@ add_test(function test_defined() { run_next_test(); }); +add_test(function test_number() { + assert.number(1); + assert.number(0); + assert.number(-1); + assert.number(1.2); + for (let i of ["foo", "1", {}, [], NaN, Infinity, undefined]) { + Assert.throws(() => assert.number(i), InvalidArgumentError); + } + run_next_test(); +}); + add_test(function test_integer() { assert.integer(1); assert.integer(0); assert.integer(-1); Assert.throws(() => assert.integer("foo"), InvalidArgumentError); + Assert.throws(() => assert.integer(1.2), InvalidArgumentError); run_next_test(); }); diff --git a/testing/mozharness/configs/beetmover/en_us.yml.tmpl b/testing/mozharness/configs/beetmover/en_us_build.yml.tmpl similarity index 68% rename from testing/mozharness/configs/beetmover/en_us.yml.tmpl rename to testing/mozharness/configs/beetmover/en_us_build.yml.tmpl index cbef7f3000fb..33287b0426d6 100644 --- a/testing/mozharness/configs/beetmover/en_us.yml.tmpl +++ b/testing/mozharness/configs/beetmover/en_us_build.yml.tmpl @@ -6,17 +6,9 @@ metadata: mapping: {% for locale in locales %} - # common deliverables {{ locale }}: - complete_mar: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar - s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar - checksum: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums - checksum_sig: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc + + {% if platform == "win32" %} buildinfo: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json @@ -35,19 +27,6 @@ mapping: xpi: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi - - {% if platform == "win32" %} - full_installer: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe - {% if "esr" not in version %} - stub_installer: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe - {% endif %} - package: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip @@ -66,12 +45,24 @@ mapping: {% endif %} {% if platform == "win64" %} - full_installer: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe - package: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + buildinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json + mozinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + socorroinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + jsshell: + artifact: {{ artifact_base_url }}/jsshell-{{ platform }}.zip + s3_key: {{ s3_prefix }}jsshell-{{ platform }}.zip + mozharness_package: + artifact: {{ artifact_base_url }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip @@ -90,9 +81,24 @@ mapping: {% endif %} {% if platform == "linux-i686" %} - package: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + buildinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json + mozinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + socorroinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + jsshell: + artifact: {{ artifact_base_url }}/jsshell-{{ platform }}.zip + s3_key: {{ s3_prefix }}jsshell-{{ platform }}.zip + mozharness_package: + artifact: {{ artifact_base_url }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip @@ -111,9 +117,24 @@ mapping: {% endif %} {% if platform == "linux-x86_64" %} - package: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + buildinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json + mozinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + socorroinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + jsshell: + artifact: {{ artifact_base_url }}/jsshell-{{ platform }}.zip + s3_key: {{ s3_prefix }}jsshell-{{ platform }}.zip + mozharness_package: + artifact: {{ artifact_base_url }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.crashreporter-symbols.zip @@ -132,9 +153,24 @@ mapping: {% endif %} {% if platform == "mac" %} - package: - artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.dmg - s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + buildinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.json + mozinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.mozinfo.json + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.mozinfo.json + socorroinfo: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.txt + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.txt + jsshell: + artifact: {{ artifact_base_url }}/jsshell-{{ platform }}.zip + s3_key: {{ s3_prefix }}jsshell-{{ platform }}.zip + mozharness_package: + artifact: {{ artifact_base_url }}/mozharness.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/mozharness.zip + xpi: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi + s3_key: {{ s3_prefix }}{{ platform }}/xpi/{{ locale }}.xpi symbols: artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.crashreporter-symbols.zip s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.crashreporter-symbols.zip diff --git a/testing/mozharness/configs/beetmover/en_us_signing.yml.tmpl b/testing/mozharness/configs/beetmover/en_us_signing.yml.tmpl new file mode 100644 index 000000000000..54fc2c792b3e --- /dev/null +++ b/testing/mozharness/configs/beetmover/en_us_signing.yml.tmpl @@ -0,0 +1,66 @@ +--- +metadata: + name: "Beet Mover Manifest" + description: "Maps artifact locations to s3 key names for the en-US locale" + owner: "release@mozilla.com" + +mapping: +{% for locale in locales %} + {{ locale }}: + {% if platform == "win32" %} + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + full_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + {% if "esr" not in version %} + stub_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe + {% endif %} + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "win64" %} + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + full_installer: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.zip + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.zip + {% endif %} + + {% if platform == "linux-i686" %} + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "linux-x86_64" %} + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.tar.bz2 + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/firefox-{{ version }}.tar.bz2 + {% endif %} + + {% if platform == "mac" %} + complete_mar: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar + s3_key: {{ s3_prefix }}update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar + package: + artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.dmg + s3_key: {{ s3_prefix }}{{ platform }}/{{ locale }}/Firefox {{ version }}.dmg + {% endif %} + +{% endfor %} diff --git a/testing/mozharness/configs/releases/updates_firefox_release.py b/testing/mozharness/configs/releases/updates_firefox_release.py index b9a21e6216c9..a4cd73498581 100644 --- a/testing/mozharness/configs/releases/updates_firefox_release.py +++ b/testing/mozharness/configs/releases/updates_firefox_release.py @@ -40,7 +40,7 @@ "mar_channel_ids": [], "channel_names": ["release", "release-localtest", "release-cdntest"], "rules_to_update": ["firefox-release-cdntest", "firefox-release-localtest"], - "publish_rules": ["firefox-release"], + "publish_rules": ["firefox-release", "firefox-release-nowebsense-bypass"], }, }, "balrog_use_dummy_suffix": False, diff --git a/testing/talos/talos/xtalos/xperf_whitelist.json b/testing/talos/talos/xtalos/xperf_whitelist.json index 7f78f08f473f..96ae959f6ea5 100644 --- a/testing/talos/talos/xtalos/xperf_whitelist.json +++ b/testing/talos/talos/xtalos/xperf_whitelist.json @@ -7,6 +7,7 @@ "{firefox}\\omni.ja": {"mincount": 0, "maxcount": 46, "minbytes": 0, "maxbytes": 3014656}, "{firefox}\\browser\\omni.ja": {"mincount": 0, "maxcount": 28, "minbytes": 0, "maxbytes": 1835008}, "{firefox}\\browser\\features\\aushelper@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000}, + "{firefox}\\browser\\features\\deployment-checker@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000}, "{firefox}\\browser\\features\\e10srollout@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000}, "{firefox}\\browser\\features\\flyweb@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000}, "{firefox}\\browser\\features\\formautofill@mozilla.org.xpi": {"mincount": 0, "maxcount": 100, "minbytes": 0, "maxbytes": 10000000}, diff --git a/testing/web-platform/harness/wptrunner/executors/executormarionette.py b/testing/web-platform/harness/wptrunner/executors/executormarionette.py index d63fe0a4b05d..e212c2945484 100644 --- a/testing/web-platform/harness/wptrunner/executors/executormarionette.py +++ b/testing/web-platform/harness/wptrunner/executors/executormarionette.py @@ -590,5 +590,6 @@ def do_test(self, test): def do_wdspec(self, session, path, timeout): harness_result = ("OK", None) - subtest_results = pytestrunner.run(path, session, timeout=timeout) + subtest_results = pytestrunner.run( + path, session, self.server_url, timeout=timeout) return (harness_result, subtest_results) diff --git a/testing/web-platform/harness/wptrunner/executors/pytestrunner/fixtures.py b/testing/web-platform/harness/wptrunner/executors/pytestrunner/fixtures.py index 77afb4a36842..1b4e8d43d7a3 100644 --- a/testing/web-platform/harness/wptrunner/executors/pytestrunner/fixtures.py +++ b/testing/web-platform/harness/wptrunner/executors/pytestrunner/fixtures.py @@ -4,6 +4,8 @@ import pytest +import urlparse + """pytest fixtures for use in Python-based WPT tests. @@ -56,3 +58,19 @@ def __init__(self, client): def session(self, request): request.addfinalizer(self.client.end) return self.client + +class Server(object): + """Fixture to allow access to wptrunner's base server url. + + :param url_getter: Function to get server url from test environment, given + a protocol. + """ + def __init__(self, url_getter): + self.server_url = url_getter + + def where_is(self, uri, protocol="http"): + return urlparse.urljoin(self.server_url(protocol), uri) + + @pytest.fixture + def server(self, request): + return self diff --git a/testing/web-platform/harness/wptrunner/executors/pytestrunner/runner.py b/testing/web-platform/harness/wptrunner/executors/pytestrunner/runner.py index 8aa575ff8b7f..28b8f609cbf1 100644 --- a/testing/web-platform/harness/wptrunner/executors/pytestrunner/runner.py +++ b/testing/web-platform/harness/wptrunner/executors/pytestrunner/runner.py @@ -27,12 +27,14 @@ def do_delayed_imports(): import pytest -def run(path, session, timeout=0): +def run(path, session, url_getter, timeout=0): """Run Python test at ``path`` in pytest. The provided ``session`` is exposed as a fixture available in the scope of the test functions. :param path: Path to the test file. :param session: WebDriver session to expose. + :param url_getter: Function to get server url from test environment, given + a protocol. :param timeout: Duration before interrupting potentially hanging tests. If 0, there is no timeout. @@ -45,7 +47,8 @@ def run(path, session, timeout=0): recorder = SubtestResultRecorder() plugins = [recorder, - fixtures.Session(session)] + fixtures.Session(session), + fixtures.Server(url_getter)] # TODO(ato): Deal with timeouts diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 806867cbe0ae..65626d6b8cba 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -38758,6 +38758,32 @@ "url": "/webaudio/the-audio-api/the-constantsourcenode-interface/test-constantsourcenode.html" } ] + }, + "wdspec": { + "webdriver/actions/conftest.py": [ + { + "path": "webdriver/actions/conftest.py", + "url": "/webdriver/actions/conftest.py" + } + ], + "webdriver/actions/key.py": [ + { + "path": "webdriver/actions/key.py", + "url": "/webdriver/actions/key.py" + } + ], + "webdriver/actions/mouse.py": [ + { + "path": "webdriver/actions/mouse.py", + "url": "/webdriver/actions/mouse.py" + } + ], + "webdriver/actions/sequence.py": [ + { + "path": "webdriver/actions/sequence.py", + "url": "/webdriver/actions/sequence.py" + } + ] } }, "reftest_nodes": { diff --git a/testing/web-platform/meta/webdriver/actions/key.py.ini b/testing/web-platform/meta/webdriver/actions/key.py.ini new file mode 100644 index 000000000000..d773c233eed6 --- /dev/null +++ b/testing/web-platform/meta/webdriver/actions/key.py.ini @@ -0,0 +1,4 @@ +[key.py] + type: wdspec + disabled: + if (os == "linux") and (bits == 64) and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1318724 diff --git a/testing/web-platform/meta/webdriver/actions/mouse.py.ini b/testing/web-platform/meta/webdriver/actions/mouse.py.ini new file mode 100644 index 000000000000..45918bc213f5 --- /dev/null +++ b/testing/web-platform/meta/webdriver/actions/mouse.py.ini @@ -0,0 +1,6 @@ +[mouse.py] + type: wdspec + disabled: + if (os == "linux") and (bits == 64) and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1318724 + [mouse.py::test_click_at_coordinates] + expected: ERROR diff --git a/testing/web-platform/meta/webdriver/actions/sequence.py.ini b/testing/web-platform/meta/webdriver/actions/sequence.py.ini new file mode 100644 index 000000000000..9c80c29b796e --- /dev/null +++ b/testing/web-platform/meta/webdriver/actions/sequence.py.ini @@ -0,0 +1,3 @@ +[sequence.py] + type: wdspec + disabled: true diff --git a/testing/web-platform/meta/webdriver/contexts.py.ini b/testing/web-platform/meta/webdriver/contexts.py.ini index 6385cb8d4ba0..712259367ee1 100644 --- a/testing/web-platform/meta/webdriver/contexts.py.ini +++ b/testing/web-platform/meta/webdriver/contexts.py.ini @@ -1,12 +1,9 @@ [contexts.py] type: wdspec disabled: - if (os == "linux") and (bits == 64) and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1313282 - expected: - if not debug: TIMEOUT + if (os == "linux") and (bits == 64) and debug: https://bugzilla.mozilla.org/show_bug.cgi?id=1318724 [contexts.py::test_resize] expected: FAIL - [contexts.py::test_resize_by_script] expected: FAIL diff --git a/testing/web-platform/meta/webdriver/navigation.py.ini b/testing/web-platform/meta/webdriver/navigation.py.ini index 454eb34e083d..02d7c5b25f75 100644 --- a/testing/web-platform/meta/webdriver/navigation.py.ini +++ b/testing/web-platform/meta/webdriver/navigation.py.ini @@ -15,6 +15,5 @@ expected: FAIL [navigation.py::test_get_current_url_matches_location] - expected: - if debug: FAIL + expected: FAIL diff --git a/testing/web-platform/tests/html/semantics/grouping-content/the-li-element/grouping-li-novalue-MANUAL.html b/testing/web-platform/tests/html/semantics/grouping-content/the-li-element/grouping-li-novalue-MANUAL.html deleted file mode 100644 index 346ed5662960..000000000000 --- a/testing/web-platform/tests/html/semantics/grouping-content/the-li-element/grouping-li-novalue-MANUAL.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - -The spec states: "If the parent element is an ol element, then the li element has an ordinal value."
-This manual test is needed to verify that NON-ol element parents do NOT result in an ordinal value.
-It needs to be manual because the ordinal value assigned to each list element by the user agent is NOT available programmatically. Values which are set either via markup or IDL are available programmatically, but not the calculated values for all the other list items.
-And, as we cannot be sure how a mistakenly assigned value would be rendered, this test cannot be a reftest.
-So, please use the buttons to answer the following questions:
- -HTML Markup | -Do you see any sort of sequencing information? | -
---|---|
- - | -- - - | -
- - | -- - - | -
-
|
- - - - | -