Merge mozilla-central to mozilla-inbound. a=merge
authorCosmin Sabou <csabou@mozilla.com>
Fri, 19 Oct 2018 00:59:32 +0300
changeset 500510 72b97e539421a38d16e843783c2359381bc6ac33
parent 500509 7400b733b50f3a9d4fa8ca18363a9dbb52956398 (current diff)
parent 500459 c0c288dc283e315982949e5d6565520f5872ab12 (diff)
child 500511 11f359e1b03813e834e3c34c9d13aa93564d7999
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge
devtools/client/aboutdebugging/test/addons/test-devtools-webextension-nobg/manifest.json
devtools/client/aboutdebugging/test/addons/test-devtools-webextension-noid/manifest.json
devtools/client/aboutdebugging/test/addons/test-devtools-webextension-unknown-prop/manifest.json
devtools/client/aboutdebugging/test/addons/test-devtools-webextension/bg.js
devtools/client/aboutdebugging/test/addons/test-devtools-webextension/manifest.json
devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.html
devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.js
dom/flex/FlexItem.cpp
dom/flex/FlexItem.h
dom/flex/FlexLine.cpp
dom/flex/FlexLine.h
dom/webidl/Flex.webidl
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-3.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-16.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-17.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-18.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-19.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-20.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-21.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-22.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-23.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-24.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-25.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-26.js
js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-3.js
js/src/tests/test262/intl402/NumberFormat/prototype/formatToParts/formatToParts.js
js/src/tests/test262/intl402/NumberFormat/prototype/formatToParts/return-abrupt-tonumber.js
js/src/tests/test262/intl402/NumberFormat/prototype/formatToParts/this-has-not-internal-throws.js
js/src/tests/test262/intl402/NumberFormat/prototype/formatToParts/this-is-not-object-throws.js
js/src/tests/test262/intl402/NumberFormat/prototype/this-value-not-numberformat.js
js/src/tests/test262/language/expressions/async-generator/args-trailing-comma-multiple.js
js/src/tests/test262/language/expressions/async-generator/args-trailing-comma-null.js
js/src/tests/test262/language/expressions/async-generator/args-trailing-comma-single-args.js
js/src/tests/test262/language/expressions/async-generator/args-trailing-comma-undefined.js
js/src/tests/test262/language/expressions/async-generator/named-args-trailing-comma-multiple.js
js/src/tests/test262/language/expressions/async-generator/named-args-trailing-comma-null.js
js/src/tests/test262/language/expressions/async-generator/named-args-trailing-comma-single-args.js
js/src/tests/test262/language/expressions/async-generator/named-args-trailing-comma-undefined.js
js/src/tests/test262/language/expressions/class/async-gen-meth-args-trailing-comma-multiple.js
js/src/tests/test262/language/expressions/class/async-gen-meth-args-trailing-comma-null.js
js/src/tests/test262/language/expressions/class/async-gen-meth-args-trailing-comma-single-args.js
js/src/tests/test262/language/expressions/class/async-gen-meth-args-trailing-comma-undefined.js
js/src/tests/test262/language/expressions/class/async-gen-meth-static-args-trailing-comma-multiple.js
js/src/tests/test262/language/expressions/class/async-gen-meth-static-args-trailing-comma-null.js
js/src/tests/test262/language/expressions/class/async-gen-meth-static-args-trailing-comma-single-args.js
js/src/tests/test262/language/expressions/class/async-gen-meth-static-args-trailing-comma-undefined.js
js/src/tests/test262/language/expressions/class/err-field-delete-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-field-delete-covered-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-field-delete-covered-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-field-delete-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-field-delete-twice-covered-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-field-delete-twice-covered-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-covered-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-covered-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-twice-covered-call-expression-privatename.js
js/src/tests/test262/language/expressions/class/err-method-delete-twice-covered-member-expression-privatename.js
js/src/tests/test262/language/expressions/class/fields-computed-name-propname-constructor.js
js/src/tests/test262/language/expressions/class/fields-computed-variable-name-propname-constructor.js
js/src/tests/test262/language/expressions/class/fields-privatename-constructor-err.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-1-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-10-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-11-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-12-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-13-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-14-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-15-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-16-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-17-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-18-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-19-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-2-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-20-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-21-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-22-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-3-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-4-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-5-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-6-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-7-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-8-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/11.13.2-6-9-s-strict.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T1.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T10.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T11.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T2.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T3.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T4.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T5.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T6.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T7.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T8.js
js/src/tests/test262/language/expressions/compound-assignment/S11.13.2_A1_T9.js
js/src/tests/test262/language/expressions/delete/11.4.1-2-1.js
js/src/tests/test262/language/expressions/delete/11.4.1-2-3.js
js/src/tests/test262/language/expressions/delete/11.4.1-2-4.js
js/src/tests/test262/language/expressions/delete/11.4.1-2-5.js
js/src/tests/test262/language/expressions/delete/11.4.1-2-6.js
js/src/tests/test262/language/expressions/object/method-definition/async-gen-meth-args-trailing-comma-multiple.js
js/src/tests/test262/language/expressions/object/method-definition/async-gen-meth-args-trailing-comma-null.js
js/src/tests/test262/language/expressions/object/method-definition/async-gen-meth-args-trailing-comma-single-args.js
js/src/tests/test262/language/expressions/object/method-definition/async-gen-meth-args-trailing-comma-undefined.js
js/src/tests/test262/language/expressions/postfix-decrement/11.3.2-2-1-s-strict.js
js/src/tests/test262/language/expressions/postfix-decrement/11.3.2-2-2-s-strict.js
js/src/tests/test262/language/expressions/postfix-decrement/S11.3.2_A1.1_T1.js
js/src/tests/test262/language/expressions/postfix-decrement/S11.3.2_A1.1_T2.js
js/src/tests/test262/language/expressions/postfix-decrement/S11.3.2_A1.1_T3.js
js/src/tests/test262/language/expressions/postfix-decrement/S11.3.2_A1.1_T4.js
js/src/tests/test262/language/expressions/postfix-decrement/S11.3.2_A1.2_T1.js
js/src/tests/test262/language/expressions/postfix-increment/11.3.1-2-1-s-strict.js
js/src/tests/test262/language/expressions/postfix-increment/11.3.1-2-2-s-strict.js
js/src/tests/test262/language/expressions/postfix-increment/S11.3.1_A1.1_T1.js
js/src/tests/test262/language/expressions/postfix-increment/S11.3.1_A1.1_T2.js
js/src/tests/test262/language/expressions/postfix-increment/S11.3.1_A1.1_T3.js
js/src/tests/test262/language/expressions/postfix-increment/S11.3.1_A1.1_T4.js
js/src/tests/test262/language/expressions/postfix-increment/S11.3.1_A1.2_T1.js
js/src/tests/test262/language/expressions/prefix-decrement/11.4.5-2-1-s-strict.js
js/src/tests/test262/language/expressions/prefix-decrement/11.4.5-2-2-s-strict.js
js/src/tests/test262/language/expressions/prefix-decrement/S11.4.5_A1.js
js/src/tests/test262/language/expressions/prefix-increment/11.4.4-2-1-s-strict.js
js/src/tests/test262/language/expressions/prefix-increment/11.4.4-2-2-s-strict.js
js/src/tests/test262/language/expressions/prefix-increment/S11.4.4_A1.js
js/src/tests/test262/language/statements/async-generator/args-trailing-comma-multiple.js
js/src/tests/test262/language/statements/async-generator/args-trailing-comma-null.js
js/src/tests/test262/language/statements/async-generator/args-trailing-comma-single-args.js
js/src/tests/test262/language/statements/async-generator/args-trailing-comma-undefined.js
js/src/tests/test262/language/statements/class/async-gen-meth-args-trailing-comma-multiple.js
js/src/tests/test262/language/statements/class/async-gen-meth-args-trailing-comma-null.js
js/src/tests/test262/language/statements/class/async-gen-meth-args-trailing-comma-single-args.js
js/src/tests/test262/language/statements/class/async-gen-meth-args-trailing-comma-undefined.js
js/src/tests/test262/language/statements/class/async-gen-meth-static-args-trailing-comma-multiple.js
js/src/tests/test262/language/statements/class/async-gen-meth-static-args-trailing-comma-null.js
js/src/tests/test262/language/statements/class/async-gen-meth-static-args-trailing-comma-single-args.js
js/src/tests/test262/language/statements/class/async-gen-meth-static-args-trailing-comma-undefined.js
js/src/tests/test262/language/statements/class/err-field-delete-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-field-delete-covered-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-field-delete-covered-member-expression-privatename.js
js/src/tests/test262/language/statements/class/err-field-delete-member-expression-privatename.js
js/src/tests/test262/language/statements/class/err-field-delete-twice-covered-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-field-delete-twice-covered-member-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-covered-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-covered-member-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-member-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-twice-covered-call-expression-privatename.js
js/src/tests/test262/language/statements/class/err-method-delete-twice-covered-member-expression-privatename.js
js/src/tests/test262/language/statements/class/fields-computed-variable-name-propname-constructor.js
js/src/tests/test262/language/statements/class/fields-privatename-constructor-err.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-constructor-empty-missing-class-heritage.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-contains-multiple-constructor.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-has-direct-super-missing-class-heritage.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-method-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-generator-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-generator-propname-constructor.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-get-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-get-propname-constructor.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-set-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-special-method-set-propname-constructor.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-get-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-get-propname-prototype.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-propname-prototype.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-set-contains-direct-super.js
js/src/tests/test262/language/statements/class/syntax/early-errors/class-body-static-method-set-propname-prototype.js
tools/lint/wpt/wpt_manifest.py
tools/lint/wpt_manifest.yml
--- a/accessible/android/AccessibleWrap.cpp
+++ b/accessible/android/AccessibleWrap.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "AccessibleWrap.h"
 
 #include "Accessible-inl.h"
+#include "AndroidInputType.h"
 #include "DocAccessibleWrap.h"
 #include "IDSet.h"
 #include "JavaBuiltins.h"
 #include "SessionAccessibility.h"
 #include "nsAccessibilityService.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIStringBundle.h"
 #include "nsAccUtils.h"
@@ -281,20 +282,21 @@ AccessibleWrap::CreateBundle(int32_t aPa
     if (!IsNaN(aMaxVal)) {
       GECKOBUNDLE_PUT(rangeInfo, "max", java::sdk::Double::New(aMaxVal));
     }
 
     GECKOBUNDLE_FINISH(rangeInfo);
     GECKOBUNDLE_PUT(nodeInfo, "rangeInfo", rangeInfo);
   }
 
-  nsString inputType;
-  nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType, inputType);
-  if (!inputType.IsEmpty()) {
-    GECKOBUNDLE_PUT(nodeInfo, "inputType", jni::StringParam(inputType));
+  nsString inputTypeAttr;
+  nsAccUtils::GetAccAttr(aAttributes, nsGkAtoms::textInputType, inputTypeAttr);
+  int32_t inputType = GetInputType(inputTypeAttr);
+  if (inputType) {
+    GECKOBUNDLE_PUT(nodeInfo, "inputType", java::sdk::Integer::ValueOf(inputType));
   }
 
   nsString posinset;
   nsresult rv = aAttributes->GetStringProperty(NS_LITERAL_CSTRING("posinset"), posinset);
   if (NS_SUCCEEDED(rv)) {
     int32_t rowIndex;
     if (sscanf(NS_ConvertUTF16toUTF8(posinset).get(), "%d", &rowIndex) > 0) {
       GECKOBUNDLE_START(collectionItemInfo);
@@ -457,16 +459,46 @@ AccessibleWrap::GetAndroidClass(role aRo
 #include "RoleMap.h"
     default:
       return java::SessionAccessibility::CLASSNAME_VIEW;
   }
 
 #undef ROLE
 }
 
+int32_t
+AccessibleWrap::GetInputType(const nsString& aInputTypeAttr)
+{
+  if (aInputTypeAttr.EqualsIgnoreCase("email")) {
+    return java::sdk::InputType::TYPE_CLASS_TEXT | java::sdk::InputType::TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
+  }
+
+  if (aInputTypeAttr.EqualsIgnoreCase("number")) {
+    return java::sdk::InputType::TYPE_CLASS_NUMBER;
+  }
+
+  if (aInputTypeAttr.EqualsIgnoreCase("password")) {
+    return java::sdk::InputType::TYPE_CLASS_TEXT | java::sdk::InputType::TYPE_TEXT_VARIATION_WEB_PASSWORD;
+  }
+
+  if (aInputTypeAttr.EqualsIgnoreCase("tel")) {
+    return java::sdk::InputType::TYPE_CLASS_PHONE;
+  }
+
+  if (aInputTypeAttr.EqualsIgnoreCase("text")) {
+    return java::sdk::InputType::TYPE_CLASS_TEXT | java::sdk::InputType::TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
+  }
+
+  if (aInputTypeAttr.EqualsIgnoreCase("url")) {
+    return java::sdk::InputType::TYPE_CLASS_TEXT | java::sdk::InputType::TYPE_TEXT_VARIATION_URI;
+  }
+
+  return 0;
+}
+
 void
 AccessibleWrap::DOMNodeID(nsString& aDOMNodeID)
 {
   if (mContent) {
     nsAtom* id = mContent->GetID();
     if (id) {
       id->ToString(aDOMNodeID);
     }
--- a/accessible/android/AccessibleWrap.h
+++ b/accessible/android/AccessibleWrap.h
@@ -52,16 +52,18 @@ protected:
     const nsTArray<int32_t>& aChildren) const;
 
   // IDs should be a positive 32bit integer.
   static int32_t AcquireID();
   static void ReleaseID(int32_t aID);
 
   static int32_t GetAndroidClass(role aRole);
 
+  static int32_t GetInputType(const nsString& aInputTypeAttr);
+
   int32_t mID;
 
 private:
   void DOMNodeID(nsString& aDOMNodeID);
 
   static void GetRoleDescription(role aRole,
                                  nsAString& aGeckoRole,
                                  nsAString& aRoleDescription);
--- a/browser/base/content/browser-contentblocking.js
+++ b/browser/base/content/browser-contentblocking.js
@@ -121,17 +121,16 @@ var TrackingProtection = {
   },
 
   isBlockerActivated(state) {
     return state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT;
   },
 };
 
 var ThirdPartyCookies = {
-  reportBreakageLabel: "cookierestrictions",
   telemetryIdentifier: "cr",
   PREF_ENABLED: "network.cookie.cookieBehavior",
   PREF_REPORT_BREAKAGE_ENABLED: "browser.contentblocking.rejecttrackers.reportBreakage.enabled",
   PREF_ENABLED_VALUES: [
     // These values match the ones exposed under the Content Blocking section
     // of the Preferences UI.
     Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN,  // Block all third-party cookies
     Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,  // Block third-party cookies from trackers
@@ -139,22 +138,59 @@ var ThirdPartyCookies = {
   PREF_UI_ENABLED: "browser.contentblocking.rejecttrackers.control-center.ui.enabled",
 
   get categoryItem() {
     delete this.categoryItem;
     return this.categoryItem =
       document.getElementById("identity-popup-content-blocking-category-3rdpartycookies");
   },
 
+  get reportBreakageLabel() {
+    switch (this.behaviorPref) {
+    case Ci.nsICookieService.BEHAVIOR_ACCEPT:
+      return "nocookiesblocked";
+    case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
+      return "allthirdpartycookiesblocked";
+    case Ci.nsICookieService.BEHAVIOR_REJECT:
+      return "allcookiesblocked";
+    case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
+      return "cookiesfromunvisitedsitesblocked";
+    default:
+      Cu.reportError(`Error: Unknown cookieBehavior pref observed: ${this.behaviorPref}`);
+      // fall through
+    case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
+      return "cookierestrictions";
+    }
+  },
+
+  get categoryLabelDefault() {
+    delete this.categoryLabelDefault;
+    return this.categoryLabelDefault =
+      document.getElementById("identity-popup-content-blocking-category-label-default");
+  },
+
+  get categoryLabelTrackers() {
+    delete this.categoryLabelTrackers;
+    return this.categoryLabelTrackers =
+      document.getElementById("identity-popup-content-blocking-category-label-trackers");
+  },
+
+  updateCategoryLabel() {
+    let rejectTrackers = this.behaviorPref == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER;
+    this.categoryLabelDefault.hidden = rejectTrackers;
+    this.categoryLabelTrackers.hidden = !rejectTrackers;
+  },
+
   init() {
     XPCOMUtils.defineLazyPreferenceGetter(this, "behaviorPref", this.PREF_ENABLED,
-                                          Ci.nsICookieService.BEHAVIOR_ACCEPT);
+      Ci.nsICookieService.BEHAVIOR_ACCEPT, this.updateCategoryLabel.bind(this));
     XPCOMUtils.defineLazyPreferenceGetter(this, "visible", this.PREF_UI_ENABLED, false);
     XPCOMUtils.defineLazyPreferenceGetter(this, "reportBreakageEnabled",
       this.PREF_REPORT_BREAKAGE_ENABLED, false);
+    this.updateCategoryLabel();
   },
   get enabled() {
     return this.PREF_ENABLED_VALUES.includes(this.behaviorPref);
   },
 
   isBlockerActivated(state) {
     return (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER) != 0 ||
            (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_FOREIGN) != 0;
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
@@ -172,16 +172,28 @@ function testTrackingPage(window) {
                    "#identity-popup-content-blocking-category-3rdpartycookies" :
                    "#identity-popup-content-blocking-category-tracking-protection";
     }
     is(hidden(category + " > .identity-popup-content-blocking-category-add-blocking"), blockedByTP,
       "Category item is" + (blockedByTP ? " not" : "") + " showing add blocking");
     is(hidden(category + " > .identity-popup-content-blocking-category-state-label"), !blockedByTP,
       "Category item is" + (blockedByTP ? "" : " not") + " set to blocked");
   }
+
+  if (Services.prefs.getIntPref(TPC_PREF) == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER) {
+    ok(hidden("#identity-popup-content-blocking-category-label-default"),
+      "Not showing default cookie restrictions label.");
+    ok(!hidden("#identity-popup-content-blocking-category-label-trackers"),
+      "Showing trackers cookie restrictions label.");
+  } else {
+    ok(hidden("#identity-popup-content-blocking-category-label-trackers"),
+      "Not showing trackers cookie restrictions label.");
+    ok(!hidden("#identity-popup-content-blocking-category-label-default"),
+      "Showing default cookie restrictions label.");
+  }
 }
 
 function testTrackingPageUnblocked(blockedByTP, window) {
   info("Tracking content must be white-listed and not blocked");
   ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected");
   ok(ContentBlocking.content.hasAttribute("hasException"), "content shows exception");
 
   let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
--- a/browser/components/controlcenter/content/panel.inc.xul
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -100,17 +100,20 @@
               <label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.trackingProtection.blocking.label;</label>
               <label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
                      id="identity-popup-tracking-protection-add-blocking"
                      onclick="ContentBlocking.openPreferences('identityPopup-CB-tracking-protection'); gIdentityHandler.recordClick('tp_add_blocking');">&contentBlocking.trackingProtection.add.label;</label>
             </hbox>
             <hbox id="identity-popup-content-blocking-category-3rdpartycookies"
                   class="identity-popup-content-blocking-category" align="center" role="group">
               <image class="identity-popup-content-blocking-category-icon thirdpartycookies-icon"/>
-              <label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.3rdPartyCookies.label;</label>
+              <label flex="1" id="identity-popup-content-blocking-category-label-default"
+                     class="identity-popup-content-blocking-category-label">&contentBlocking.3rdPartyCookies.label;</label>
+              <label flex="1" id="identity-popup-content-blocking-category-label-trackers"
+                     hidden="true" class="identity-popup-content-blocking-category-label">&contentBlocking.3rdPartyCookies.trackers.label;</label>
               <label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.3rdPartyCookies.blocking.label;</label>
               <label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
                      id="identity-popup-3rdpartycookies-add-blocking"
                      onclick="ContentBlocking.openPreferences('identityPopup-CB-3rdpartycookies'); gIdentityHandler.recordClick('cookies_add_blocking');">&contentBlocking.3rdPartyCookies.add.label;</label>
             </hbox>
           </vbox>
 
           <button id="tracking-action-unblock"
--- a/browser/components/preferences/browserLanguages.js
+++ b/browser/components/preferences/browserLanguages.js
@@ -5,16 +5,34 @@
 /* import-globals-from ../../../toolkit/content/preferencesBindings.js */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AddonManager",
                                "resource://gre/modules/AddonManager.jsm");
 ChromeUtils.defineModuleGetter(this, "AddonRepository",
                                "resource://gre/modules/addons/AddonRepository.jsm");
+ChromeUtils.defineModuleGetter(this, "RemoteSettings",
+                               "resource://services-settings/remote-settings.js");
+
+async function installFromUrl(url, hash) {
+  let install = await AddonManager.getInstallForURL(
+    url, "application/x-xpinstall", hash);
+  return install.install();
+}
+
+async function dictionaryIdsForLocale(locale) {
+  let entries = await RemoteSettings("language-dictionaries").get({
+    filters: {id: locale},
+  });
+  if (entries.length > 0) {
+    return entries[0].dictionaries;
+  }
+  return [];
+}
 
 class OrderedListBox {
   constructor({richlistbox, upButton, downButton, removeButton, onRemove}) {
     this.richlistbox = richlistbox;
     this.upButton = upButton;
     this.downButton = downButton;
     this.removeButton = removeButton;
     this.onRemove = onRemove;
@@ -389,47 +407,71 @@ var gBrowserLanguagesDialog = {
     items.push({
       label: await document.l10n.formatValue("browser-languages-search"),
       value: "search",
     });
     this._availableLocales.setItems(items);
   },
 
   async availableLanguageSelected(item) {
-    let available = new Set(Services.locale.availableLocales);
-
-    if (available.has(item.value)) {
-      this._requestedLocales.addItem(item);
-      if (available.size == this._requestedLocales.items.length) {
-        // Remove the installed label, they're all installed.
-        this._availableLocales.items.shift();
-        this._availableLocales.setItems(this._availableLocales.items);
-      }
+    if (Services.locale.availableLocales.includes(item.value)) {
+      this.requestLocalLanguage(item);
     } else if (this.availableLangpacks.has(item.value)) {
-      this._availableLocales.disableWithMessageId("browser-languages-downloading");
-
-      let {url, hash} = this.availableLangpacks.get(item.value);
-      let install = await AddonManager.getInstallForURL(
-        url, "application/x-xpinstall", hash);
-
-      try {
-        await install.install();
-      } catch (e) {
-        this.showError();
-        return;
-      }
-
-      item.installed = true;
-      this._requestedLocales.addItem(item);
-      this._availableLocales.enableWithMessageId("browser-languages-select-language");
+      await this.requestRemoteLanguage(item);
     } else {
       this.showError();
     }
   },
 
+  requestLocalLanguage(item, available) {
+    this._requestedLocales.addItem(item);
+    let requestedCount = this._requestedLocales.items.length;
+    let availableCount = Services.locale.availableLocales.length;
+    if (requestedCount == availableCount) {
+      // Remove the installed label, they're all installed.
+      this._availableLocales.items.shift();
+      this._availableLocales.setItems(this._availableLocales.items);
+    }
+  },
+
+  async requestRemoteLanguage(item) {
+    this._availableLocales.disableWithMessageId(
+      "browser-languages-downloading");
+
+    let {url, hash} = this.availableLangpacks.get(item.value);
+
+    try {
+      await installFromUrl(url, hash);
+    } catch (e) {
+      this.showError();
+      return;
+    }
+
+    item.installed = true;
+    this._requestedLocales.addItem(item);
+    this._availableLocales.enableWithMessageId(
+      "browser-languages-select-language");
+
+    // This is an async task that will install the recommended dictionaries for
+    // this locale. This will fail silently at least until a management UI is
+    // added in bug 1493705.
+    this.installDictionariesForLanguage(item.value);
+  },
+
+  async installDictionariesForLanguage(locale) {
+    try {
+      let ids = await dictionaryIdsForLocale(locale);
+      let addonInfos = await AddonRepository.getAddonsByIDs(ids);
+      await Promise.all(addonInfos.map(
+        info => installFromUrl(info.sourceURI.spec)));
+    } catch (e) {
+      Cu.reportError(e);
+    }
+  },
+
   showError() {
     document.querySelectorAll(".warning-message-separator")
       .forEach(separator => separator.classList.add("thin"));
     document.getElementById("warning-message").hidden = false;
     this._availableLocales.enableWithMessageId("browser-languages-select-language");
   },
 
   hideError() {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3113d1fa5da0482256cef2fd3edf78ad2f6e7bc2
GIT binary patch
literal 963
zc$^FHW@Zs#U|`^25U%v`)pC+`E?{I}U}t7v;AW6v$jmD)NzBR7D@sWV4dG;9cKd%I
zx)g*fxEUB(z5-Q(HRn$9FK#jrIQqVhtLyoM56iW9j+Gtzc<1H9@1jj<T%40zR=xeQ
zTYRxg&gstD_umh_YpW^E$$H<cd3I^UuSADGqH~|Df8Bds+DZTKUc=nBj}Hqt_zD%S
z^0jBqN)mdg;k0Va1UpV<ca<+!=2tvF&Sre=PO9|Jldq-TFbXPirk%C4{hBF%>bj43
z*Y;)khnm;EIdkd#loRU~_HgGeSQp6L6z(G}{VI9Q$qLWgzg9juYRTPYEb9>IweWcS
znUAd{D_<YjGT*$z!$LW5%Z3XH7Mp~1Mc!Xo(HHq3%KHACD7W;^uWxo2Zwr#j71^@=
zgKyE4hPI31k;QwrcdVTot-<D|wQJ&~UCwVCK5g6aQ8T%+s8L?vlUdA0FFD&5H|B<0
zhM(_jGu1z^<K}z))C+gc?T^@~V7T(xiVltiDbqqU?h3UXl1TE1wCWc>`Tg#__L9R#
zZ<n6#XWV$gW0(6wix(%867p|d(D--x<x{JFv)_o%dHgSY`DFP3V5D&|fPgYE(pqfH
zLL-4}5EceTT1sYeNoIatVo_#lv3^00USb*~@{)iNmx392!LA_+p27YW7N(ZEMqD95
zkqU{K`KeWTMditr#RVnVxhb20v9&QhDdW|)XP@_{ecV%4SmEgD?;7P76z&`u91!B|
z>#{i1$7`XxlgFuL$1bmTySOGSFoFx=N)4bZ*%!XL%LHUI;cz984|ZiX(1qEUu1o|P
z$H*kdj4Q25fGq-Y8J0AHSSTr%6`FEUjf5D8D;$vx+zO<yhAJy0RPh*$>2+j-qnR)b
Z1_uNyBp@&hW@Q6uW(Gl^;3|-b3;>KuQZoPm
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 prefs =
   extensions.formautofill.available='on'
   extensions.formautofill.creditCards.available=true
 support-files =
   head.js
   privacypane_tests_perwindow.js
+  addons/pl-dictionary.xpi
   addons/set_homepage.xpi
   addons/set_newtab.xpi
 
 [browser_applications_selection.js]
 [browser_advanced_update.js]
 skip-if = !updater
 [browser_basic_rebuild_fonts_test.js]
 [browser_bug410900.js]
--- a/browser/components/preferences/in-content/tests/browser_browser_languages_subdialog.js
+++ b/browser/components/preferences/in-content/tests/browser_browser_languages_subdialog.js
@@ -1,17 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", this);
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
+
 AddonTestUtils.initMochitest(this);
 
 const BROWSER_LANGUAGES_URL = "chrome://browser/content/preferences/browserLanguages.xul";
+const DICTIONARY_ID_PL = "pl@dictionaries.addons.mozilla.org";
 
 function getManifestData(locale) {
   return {
     langpack_id: locale,
     name: `${locale} Language Pack`,
     description: `${locale} Language pack`,
     languages: {
       [locale]: {
@@ -74,16 +76,55 @@ async function createLanguageToolsFile()
   let files = {[filename]: {results}};
   let tempdir = AddonTestUtils.tempDir.clone();
   let dir = await AddonTestUtils.promiseWriteFilesToDir(tempdir.path, files);
   dir.append(filename);
 
   return dir;
 }
 
+async function createDictionaryBrowseResults() {
+  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
+  let dictionaryPath = testDir + "/addons/pl-dictionary.xpi";
+  let filename = "dictionaries.json";
+  let response = {
+    page_size: 25,
+    page_count: 1,
+    count: 1,
+    results: [{
+      current_version: {
+        id: 1823648,
+        compatibility: {
+          firefox: {max: "9999", min: "4.0"},
+        },
+        files: [{
+          platform: "all",
+          url: dictionaryPath,
+        }],
+        version: "1.0.20160228",
+      },
+      default_locale: "pl",
+      description: "Polish spell-check",
+      guid: DICTIONARY_ID_PL,
+      name: "Polish Dictionary",
+      slug: "polish-spellchecker-dictionary",
+      status: "public",
+      summary: "Polish dictionary",
+      type: "dictionary",
+    }],
+  };
+
+  let files = {[filename]: response};
+  let dir = await AddonTestUtils.promiseWriteFilesToDir(
+    AddonTestUtils.tempDir.path, files);
+  dir.append(filename);
+
+  return dir;
+}
+
 function assertLocaleOrder(list, locales) {
   is(list.itemCount, locales.split(",").length,
      "The right number of locales are requested");
   is(Array.from(list.children).map(child => child.value).join(","),
      locales, "The requested locales are in order");
 }
 
 function assertAvailableLocales(list, locales) {
@@ -240,22 +281,26 @@ add_task(async function testAddAndRemove
 });
 
 add_task(async function testInstallFromAMO() {
   let langpacks = await AddonManager.getAddonsByTypes(["locale"]);
   is(langpacks.length, 0, "There are no langpacks installed");
 
   let langpacksFile = await createLanguageToolsFile();
   let langpacksUrl = Services.io.newFileURI(langpacksFile).spec;
+  let dictionaryBrowseFile = await createDictionaryBrowseResults();
+  let browseApiEndpoint = Services.io.newFileURI(dictionaryBrowseFile).spec;
+
   await SpecialPowers.pushPrefEnv({
     set: [
       ["intl.multilingual.enabled", true],
       ["intl.locale.requested", "en-US"],
       ["extensions.getAddons.langpacks.url", langpacksUrl],
       ["extensions.langpacks.signatures.required", false],
+      ["extensions.getAddons.get.url", browseApiEndpoint],
     ],
   });
 
   await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
 
   let doc = gBrowser.contentDocument;
   let messageBar = doc.getElementById("confirmBrowserLanguage");
   is(messageBar.hidden, true, "The message bar is hidden at first");
@@ -272,31 +317,46 @@ add_task(async function testInstallFromA
   }
 
   // The initial order is set by the pref.
   assertLocaleOrder(requested, "en-US");
   assertAvailableLocales(available, ["fr", "he", "pl"]);
   is(Services.locale.availableLocales.join(","),
      "en-US", "There is only one installed locale");
 
+  // Verify that there are no extra dictionaries.
+  let dicts = await AddonManager.getAddonsByTypes(["dictionary"]);
+  is(dicts.length, 0, "There are no installed dictionaries");
+
   // Add Polish, this will install the langpack.
   requestLocale("pl", available, dialogDoc);
 
   // Wait for the langpack to install and be added to the list.
   let requestedLocales = dialogDoc.getElementById("requestedLocales");
   await waitForMutation(
     requestedLocales,
     {childList: true},
     target => requestedLocales.itemCount == 2);
 
   // Verify the list is correct.
   assertLocaleOrder(requested, "pl,en-US");
   assertAvailableLocales(available, ["fr", "he"]);
   is(Services.locale.availableLocales.sort().join(","),
      "en-US,pl", "Polish is now installed");
 
-  // Uninstall the langpack.
-  langpacks = await AddonManager.getAddonsByTypes(["locale"]);
-  is(langpacks.length, 1, "There is one langpacks installed");
-  await Promise.all(langpacks.map(pack => pack.uninstall()));
+  await BrowserTestUtils.waitForCondition(async () => {
+    let newDicts = await AddonManager.getAddonsByTypes(["dictionary"]);
+    let done = newDicts.length != 0;
+
+    if (done) {
+      is(newDicts[0].id, DICTIONARY_ID_PL, "The polish dictionary was installed");
+    }
+
+    return done;
+  });
+
+  // Uninstall the langpack and dictionary.
+  let installs = await AddonManager.getAddonsByTypes(["locale", "dictionary"]);
+  is(installs.length, 2, "There is one langpack and one dictionary installed");
+  await Promise.all(installs.map(item => item.uninstall()));
 
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -997,16 +997,17 @@ you can use these alternative items. Oth
 <!ENTITY contentBlocking.trackingProtection.blocking.label "Blocking">
 <!-- LOCALIZATION NOTE (contentBlocking.trackingProtection.add.label):
      This is displayed as a link to preferences, where the user can add
      this specific type of content blocking. When this text is shown
      the type of content blocking is currently not enabled. -->
 <!ENTITY contentBlocking.trackingProtection.add.label "Add Blocking…">
 
 <!ENTITY contentBlocking.3rdPartyCookies.label "Third-Party Cookies">
+<!ENTITY contentBlocking.3rdPartyCookies.trackers.label "Tracking Cookies">
 <!-- LOCALIZATION NOTE (contentBlocking.3rdPartyCookies.blocked.label):
      This label signals that this type of content blocking is turned
      ON and is successfully blocking third-party cookies, so this is
      a positive thing. It forms the end of the (imaginary) sentence
      "Third-Party Cookies [are] Blocked"-->
 <!ENTITY contentBlocking.3rdPartyCookies.blocked.label "Blocked">
 <!-- LOCALIZATION NOTE (contentBlocking.tranckingProtection.blocking.label):
      This label signals that this type of content blocking is turned
--- a/devtools/client/aboutdebugging-new/aboutdebugging.css
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.css
@@ -1,16 +1,17 @@
 /* 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/. */
 
 @import "chrome://global/skin/in-content/common.css";
 @import "resource://devtools/client/themes/variables.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/App.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/RuntimeInfo.css";
+@import "resource://devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/connect/ConnectSteps.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/connect/NetworkLocationsForm.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/connect/NetworkLocationsList.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetPane.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionDetail.css";
 @import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerDetail.css";
--- a/devtools/client/aboutdebugging-new/src/actions/ui.js
+++ b/devtools/client/aboutdebugging-new/src/actions/ui.js
@@ -1,23 +1,30 @@
 /* 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/. */
 
 "use strict";
 
 const {
+  ADB_ADDON_INSTALL_START,
+  ADB_ADDON_INSTALL_SUCCESS,
+  ADB_ADDON_INSTALL_FAILURE,
+  ADB_ADDON_UNINSTALL_START,
+  ADB_ADDON_UNINSTALL_SUCCESS,
+  ADB_ADDON_UNINSTALL_FAILURE,
   ADB_ADDON_STATUS_UPDATED,
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
   NETWORK_LOCATIONS_UPDATED,
   PAGE_SELECTED,
   PAGES,
 } = require("../constants");
 
 const NetworkLocationsModule = require("../modules/network-locations");
+const { adbAddon } = require("devtools/shared/adb/adb-addon");
 
 const Actions = require("./index");
 
 // XXX: Isolating the code here, because it feels wrong to rely solely on the page "not"
 // being CONNECT to decide what to do. Should we have a page "type" on top of page "id"?
 function _isRuntimePage(page) {
   return page && page !== PAGES.CONNECT;
 }
@@ -64,16 +71,44 @@ function removeNetworkLocation(location)
 function updateAdbAddonStatus(adbAddonStatus) {
   return { type: ADB_ADDON_STATUS_UPDATED, adbAddonStatus };
 }
 
 function updateNetworkLocations(locations) {
   return { type: NETWORK_LOCATIONS_UPDATED, locations };
 }
 
+function installAdbAddon() {
+  return async (dispatch, getState) => {
+    dispatch({ type: ADB_ADDON_INSTALL_START });
+
+    try {
+      await adbAddon.install();
+      dispatch({ type: ADB_ADDON_INSTALL_SUCCESS });
+    } catch (e) {
+      dispatch({ type: ADB_ADDON_INSTALL_FAILURE, error: e.message });
+    }
+  };
+}
+
+function uninstallAdbAddon() {
+  return async (dispatch, getState) => {
+    dispatch({ type: ADB_ADDON_UNINSTALL_START });
+
+    try {
+      await adbAddon.uninstall();
+      dispatch({ type: ADB_ADDON_UNINSTALL_SUCCESS });
+    } catch (e) {
+      dispatch({ type: ADB_ADDON_UNINSTALL_FAILURE, error: e.message });
+    }
+  };
+}
+
 module.exports = {
   addNetworkLocation,
+  installAdbAddon,
   removeNetworkLocation,
   selectPage,
+  uninstallAdbAddon,
   updateAdbAddonStatus,
   updateDebugTargetCollapsibility,
   updateNetworkLocations,
 };
--- a/devtools/client/aboutdebugging-new/src/components/App.js
+++ b/devtools/client/aboutdebugging-new/src/components/App.js
@@ -31,26 +31,35 @@ class App extends PureComponent {
       networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
       networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
       selectedPage: PropTypes.string,
       usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
     };
   }
 
   getSelectedPageComponent() {
-    const { dispatch, networkLocations, selectedPage } = this.props;
+    const {
+      adbAddonStatus,
+      dispatch,
+      networkLocations,
+      selectedPage
+    } = this.props;
 
     if (!selectedPage) {
       // No page selected.
       return null;
     }
 
     switch (selectedPage) {
       case PAGES.CONNECT:
-        return ConnectPage({ dispatch, networkLocations });
+        return ConnectPage({
+          adbAddonStatus,
+          dispatch,
+          networkLocations
+        });
       default:
         // All pages except for the CONNECT page are RUNTIME pages.
         return RuntimePage({ dispatch });
     }
   }
 
   render() {
     const {
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.css
@@ -0,0 +1,7 @@
+/* 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/. */
+
+.connect-page__usb__toggle-button {
+  margin-top: calc(var(--base-distance) * 4);
+}
--- a/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.js
+++ b/devtools/client/aboutdebugging-new/src/components/connect/ConnectPage.js
@@ -6,28 +6,37 @@
 
 const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
 const FluentReact = require("devtools/client/shared/vendor/fluent-react");
 const Localized = createFactory(FluentReact.Localized);
 
+const {
+  USB_STATES,
+} = require("../../constants");
+
+const Actions = require("../../actions/index");
+
+loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
+
 const ConnectSection = createFactory(require("./ConnectSection"));
 const ConnectSteps = createFactory(require("./ConnectSteps"));
 const NetworkLocationsForm = createFactory(require("./NetworkLocationsForm"));
 const NetworkLocationsList = createFactory(require("./NetworkLocationsList"));
 
 const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
 const WIFI_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
 const GLOBE_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
 
 class ConnectPage extends PureComponent {
   static get propTypes() {
     return {
+      adbAddonStatus: PropTypes.string,
       dispatch: PropTypes.func.isRequired,
       // Provided by wrapping the component with FluentReact.withLocalization.
       getString: PropTypes.func.isRequired,
       networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
     };
   }
 
   renderWifi() {
@@ -49,35 +58,101 @@ class ConnectPage extends PureComponent 
             getString("about-debugging-connect-wifi-step-open-options"),
             getString("about-debugging-connect-wifi-step-enable-debug"),
           ]
         })
       )
     );
   }
 
+  onToggleUSBClick() {
+    const { adbAddonStatus } = this.props;
+    const isAddonInstalled = adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
+    if (isAddonInstalled) {
+      this.props.dispatch(Actions.uninstallAdbAddon());
+    } else {
+      this.props.dispatch(Actions.installAdbAddon());
+    }
+  }
+
+  getUsbStatus() {
+    switch (this.props.adbAddonStatus) {
+      case ADB_ADDON_STATES.INSTALLED:
+        return USB_STATES.ENABLED_USB;
+      case ADB_ADDON_STATES.UNINSTALLED:
+        return USB_STATES.DISABLED_USB;
+      default:
+        return USB_STATES.UPDATING_USB;
+    }
+  }
+
+  renderUsbToggleButton() {
+    const usbStatus = this.getUsbStatus();
+
+    const localizedStates = {
+      [USB_STATES.ENABLED_USB]: "about-debugging-connect-usb-disable-button",
+      [USB_STATES.DISABLED_USB]: "about-debugging-connect-usb-enable-button",
+      [USB_STATES.UPDATING_USB]: "about-debugging-connect-usb-updating-button",
+    };
+    const localizedState = localizedStates[usbStatus];
+
+    // Disable the button while the USB status is updating.
+    const disabled = usbStatus === USB_STATES.UPDATING_USB;
+
+    return Localized(
+      {
+        id: localizedState
+      },
+      dom.button(
+        {
+          className: "std-button connect-page__usb__toggle-button " +
+                     "js-connect-usb-toggle-button",
+          disabled,
+          onClick: () => this.onToggleUSBClick(),
+        },
+        localizedState
+      )
+    );
+  }
+
   renderUsb() {
-    const { getString } = this.props;
+    const { adbAddonStatus, getString } = this.props;
+    const isAddonInstalled = adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
     return Localized(
       {
         id: "about-debugging-connect-usb",
         attrs: { title: true }
       },
       ConnectSection(
         {
           icon: USB_ICON_SRC,
           title: "Via USB",
         },
-        ConnectSteps({
-          steps: [
-            getString("about-debugging-connect-usb-step-enable-dev-menu"),
-            getString("about-debugging-connect-usb-step-enable-debug"),
-            getString("about-debugging-connect-usb-step-plug-device"),
-          ]
-        })
+        (isAddonInstalled ?
+          ConnectSteps({
+            steps: [
+              getString("about-debugging-connect-usb-step-enable-dev-menu"),
+              getString("about-debugging-connect-usb-step-enable-debug"),
+              getString("about-debugging-connect-usb-step-plug-device"),
+            ]
+          }) :
+          Localized(
+            {
+              id: "about-debugging-connect-usb-disabled",
+            },
+            dom.aside(
+              {
+                className: "js-connect-usb-disabled-message"
+              },
+              "Enabling this will download and add the required Android USB debugging " +
+              "components to Firefox."
+            )
+          )
+        ),
+        this.renderUsbToggleButton()
       )
     );
   }
 
   renderNetwork() {
     const { dispatch, networkLocations } = this.props;
     return Localized(
       {
--- a/devtools/client/aboutdebugging-new/src/components/connect/moz.build
+++ b/devtools/client/aboutdebugging-new/src/components/connect/moz.build
@@ -1,13 +1,14 @@
 # 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/.
 
 DevToolsModules(
+    'ConnectPage.css',
     'ConnectPage.js',
     'ConnectSection.js',
     'ConnectSteps.css',
     'ConnectSteps.js',
     'NetworkLocationsForm.css',
     'NetworkLocationsForm.js',
     'NetworkLocationsList.css',
     'NetworkLocationsList.js',
--- a/devtools/client/aboutdebugging-new/src/constants.js
+++ b/devtools/client/aboutdebugging-new/src/constants.js
@@ -1,15 +1,21 @@
 /* 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/. */
 
 "use strict";
 
 const actionTypes = {
+  ADB_ADDON_INSTALL_START: "ADB_ADDON_INSTALL_START",
+  ADB_ADDON_INSTALL_SUCCESS: "ADB_ADDON_INSTALL_SUCCESS",
+  ADB_ADDON_INSTALL_FAILURE: "ADB_ADDON_INSTALL_FAILURE",
+  ADB_ADDON_UNINSTALL_START: "ADB_ADDON_UNINSTALL_START",
+  ADB_ADDON_UNINSTALL_SUCCESS: "ADB_ADDON_UNINSTALL_SUCCESS",
+  ADB_ADDON_UNINSTALL_FAILURE: "ADB_ADDON_UNINSTALL_FAILURE",
   ADB_ADDON_STATUS_UPDATED: "ADB_ADDON_STATUS_UPDATED",
   CONNECT_RUNTIME_FAILURE: "CONNECT_RUNTIME_FAILURE",
   CONNECT_RUNTIME_START: "CONNECT_RUNTIME_START",
   CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS",
   DEBUG_TARGET_COLLAPSIBILITY_UPDATED: "DEBUG_TARGET_COLLAPSIBILITY_UPDATED",
   DISCONNECT_RUNTIME_FAILURE: "DISCONNECT_RUNTIME_FAILURE",
   DISCONNECT_RUNTIME_START: "DISCONNECT_RUNTIME_START",
   DISCONNECT_RUNTIME_SUCCESS: "DISCONNECT_RUNTIME_SUCCESS",
@@ -65,17 +71,24 @@ const SERVICE_WORKER_FETCH_STATES = {
 };
 
 const SERVICE_WORKER_STATUSES = {
   RUNNING: "RUNNING",
   REGISTERING: "REGISTERING",
   STOPPED: "STOPPED",
 };
 
+const USB_STATES = {
+  DISABLED_USB: "DISABLED_USB",
+  ENABLED_USB: "ENABLED_USB",
+  UPDATING_USB: "UPDATING_USB",
+};
+
 // flatten constants
 module.exports = Object.assign({}, {
   DEBUG_TARGETS,
   DEBUG_TARGET_PANE,
   PAGES,
   RUNTIMES,
   SERVICE_WORKER_FETCH_STATES,
   SERVICE_WORKER_STATUSES,
+  USB_STATES,
 }, actionTypes);
--- a/devtools/client/aboutdebugging-new/test/browser/browser.ini
+++ b/devtools/client/aboutdebugging-new/test/browser/browser.ini
@@ -6,16 +6,18 @@ support-files =
   head-addons-script.js
   head.js
   resources/test-adb-extension/*
   resources/test-temporary-extension/*
   !/devtools/client/shared/test/shared-head.js
   !/devtools/client/shared/test/telemetry-test-helpers.js
 
 [browser_aboutdebugging_connect_networklocations.js]
+[browser_aboutdebugging_connect_toggle_usb_devices.js]
+skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug 1499638
 [browser_aboutdebugging_debug-target-pane_collapsibilities_interaction.js]
 [browser_aboutdebugging_debug-target-pane_collapsibilities_preference.js]
 [browser_aboutdebugging_debug-target-pane_empty.js]
 [browser_aboutdebugging_navigate.js]
 [browser_aboutdebugging_sidebar_network_runtimes.js]
 [browser_aboutdebugging_sidebar_usb_status.js]
 skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug 1499638
 [browser_aboutdebugging_thisfirefox.js]
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_networklocations.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_networklocations.js
@@ -8,27 +8,17 @@
  * Check that a network location can be added and removed.
  */
 
 const TEST_NETWORK_LOCATION = "localhost:1111";
 
 add_task(async function() {
   const { document, tab } = await openAboutDebugging();
 
-  const sidebarItems = document.querySelectorAll(".js-sidebar-item");
-  const connectSidebarItem = [...sidebarItems].find(element => {
-    return element.textContent === "Connect";
-  });
-  ok(connectSidebarItem, "Sidebar contains a Connect item");
-
-  info("Click on the Connect item in the sidebar");
-  connectSidebarItem.click();
-
-  info("Wait until Connect page is displayed");
-  await waitUntil(() => document.querySelector(".js-connect-page"));
+  await selectConnectPage(document);
 
   let networkLocations = document.querySelectorAll(".js-network-location");
   is(networkLocations.length, 0, "By default, no network locations are displayed");
 
   addNetworkLocation(TEST_NETWORK_LOCATION, document);
 
   info("Wait until the new network location is visible in the list");
   await waitUntil(() => document.querySelectorAll(".js-network-location").length === 1);
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_connect_toggle_usb_devices.js
@@ -0,0 +1,55 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { ADB } = require("devtools/shared/adb/adb");
+
+/**
+ * Check that USB Devices scanning can be enabled and disabled from the connect page.
+ */
+add_task(async function() {
+  await pushPref("devtools.remote.adb.extensionURL",
+                 CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
+
+  const { document, tab } = await openAboutDebugging();
+
+  await selectConnectPage(document);
+
+  info("Wait until Connect page is displayed");
+  await waitUntil(() => document.querySelector(".js-connect-page"));
+
+  info("Check that by default USB devices are disabled");
+  const usbDisabledMessage = document.querySelector(".js-connect-usb-disabled-message");
+  ok(usbDisabledMessage, "A message about enabling USB devices is rendered");
+
+  const usbToggleButton = document.querySelector(".js-connect-usb-toggle-button");
+  ok(usbToggleButton, "The button to toggle USB devices debugging is rendered");
+  ok(usbToggleButton.textContent.includes("Enable"),
+    "The text of the toggle USB button is correct");
+
+  info("Click on the toggle button");
+  usbToggleButton.click();
+
+  info("Wait until the toggle button text is updated");
+  await waitUntil(() => usbToggleButton.textContent.includes("Disable"));
+  ok(!document.querySelector(".js-connect-usb-disabled-message"),
+    "The message about enabling USB devices is no longer rendered");
+
+  // Right now we are resuming as soon as "USB devices enabled" is displayed, but ADB
+  // might still be starting up. If we move to uninstall directly, the ADB startup will
+  // fail and we will have an unhandled promise rejection.
+  // See Bug 1498469.
+  info("Wait until ADB has started.");
+  await waitUntil(() => ADB.ready);
+
+  info("Click on the toggle button");
+  usbToggleButton.click();
+
+  info("Wait until the toggle button text is updated");
+  await waitUntil(() => usbToggleButton.textContent.includes("Enable"));
+  ok(document.querySelector(".js-connect-usb-disabled-message"),
+    "The message about enabling USB devices is rendered again");
+
+  await removeTab(tab);
+});
--- a/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_status.js
+++ b/devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_status.js
@@ -6,27 +6,16 @@
 const { adbAddon } = require("devtools/shared/adb/adb-addon");
 const { ADB } = require("devtools/shared/adb/adb");
 
 /**
  * This test asserts that the sidebar shows a message describing the status of the USB
  * devices scanning.
  */
 add_task(async function() {
-  // Make sure the ADB addon is removed and ADB is stopped when the test ends.
-  registerCleanupFunction(async function() {
-    try {
-      await adbAddon.uninstall();
-    } catch (e) {
-      // Will throw if the addon is already uninstalled, ignore exceptions here.
-    }
-
-    await ADB.kill();
-  });
-
   await pushPref("devtools.remote.adb.extensionURL",
                  CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
 
   const { document, tab } = await openAboutDebugging();
 
   const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
   ok(usbStatusElement, "Sidebar shows the USB status element");
   ok(usbStatusElement.textContent.includes("USB devices disabled"),
--- a/devtools/client/aboutdebugging-new/test/browser/head.js
+++ b/devtools/client/aboutdebugging-new/test/browser/head.js
@@ -12,16 +12,28 @@
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
   this);
 
 // Load collapsibilities helpers
 Services.scriptloader.loadSubScript(
   CHROME_URL_ROOT + "debug-target-pane_collapsibilities_head.js", this);
 
+// Make sure the ADB addon is removed and ADB is stopped when the test ends.
+registerCleanupFunction(async function() {
+  try {
+    const { adbAddon } = require("devtools/shared/adb/adb-addon");
+    await adbAddon.uninstall();
+  } catch (e) {
+    // Will throw if the addon is already uninstalled, ignore exceptions here.
+  }
+  const { ADB } = require("devtools/shared/adb/adb");
+  await ADB.kill();
+});
+
 /**
  * Enable the new about:debugging panel.
  */
 async function enableNewAboutDebugging() {
   await pushPref("devtools.aboutdebugging.new-enabled", true);
 }
 
 async function openAboutDebugging(page, win) {
@@ -37,14 +49,31 @@ async function openAboutDebugging(page, 
   await waitUntil(() => document.querySelector(".app"));
 
   info("Wait until the client connection was established");
   await waitUntil(() => document.querySelector(".js-runtime-page"));
 
   return { tab, document, window };
 }
 
+/**
+ * Navigate to the Connect page. Resolves when the Connect page is rendered.
+ */
+async function selectConnectPage(doc) {
+  const sidebarItems = doc.querySelectorAll(".js-sidebar-item");
+  const connectSidebarItem = [...sidebarItems].find(element => {
+    return element.textContent === "Connect";
+  });
+  ok(connectSidebarItem, "Sidebar contains a Connect item");
+
+  info("Click on the Connect item in the sidebar");
+  connectSidebarItem.click();
+
+  info("Wait until Connect page is displayed");
+  await waitUntil(() => doc.querySelector(".js-connect-page"));
+}
+
 function findSidebarItemByText(text, document) {
   const sidebarItems = document.querySelectorAll(".js-sidebar-item");
   return [...sidebarItems].find(element => {
     return element.textContent.includes(text);
   });
 }
--- a/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
+++ b/devtools/client/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl
@@ -54,16 +54,21 @@ about-debugging-connect-wifi-step-open-o
 
 # WiFi section step by step guide
 about-debugging-connect-wifi-step-enable-debug = Enable Remote Debugging via WiFi in the Developer Tools section
 
 # USB section of the Connect page
 about-debugging-connect-usb
   .title = Via USB
 
+about-debugging-connect-usb-disabled = Enabling this will download and add the required Android USB debugging components to Firefox.
+about-debugging-connect-usb-enable-button = Enable USB Devices
+about-debugging-connect-usb-disable-button = Disable USB Devices
+about-debugging-connect-usb-updating-button = Updating…
+
 # USB section step by step guide
 about-debugging-connect-usb-step-enable-dev-menu = Enable Developer menu on your Android device
 
 # USB section step by step guide
 about-debugging-connect-usb-step-enable-debug = Enable USB Debugging on the Android Developer Menu
 
 # USB section step by step guide
 about-debugging-connect-usb-step-plug-device = Connect the USB Device to your computer
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension-nobg/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "manifest_version": 2,
-  "name": "test-devtools-webextension-nobg",
-  "version": "1.0",
-  "applications": {
-    "gecko": {
-      "id": "test-devtools-webextension-nobg@mozilla.org"
-    }
-  }
-}
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension-noid/manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "manifest_version": 2,
-  "name": "test-devtools-webextension-noid",
-  "version": "1.0"
-}
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension-unknown-prop/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "manifest_version": 2,
-  "name": "test-devtools-webextension-unknown-prop",
-  "version": "1.0",
-  "applications": {
-    "gecko": {
-      "id": "test-devtools-webextension-unknown-prop@mozilla.org"
-    }
-  },
-  "browser_actions": {
-    "default_title": "WebExtension Popup Debugging",
-    "default_popup": "popup.html"
-  }
-}
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/bg.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/* eslint-env browser */
-/* global browser */
-
-"use strict";
-
-document.body.innerText = "Background Page Body Test Content";
-
-// These functions are called from the following about:debugging tests:
-// - browser_addons_debug_webextension.js
-// - browser_addons_debug_webextension_popup.js
-
-// eslint-disable-next-line no-unused-vars
-function myWebExtensionAddonFunction() {
-  console.log("Background page function called", browser.runtime.getManifest());
-}
-
-// eslint-disable-next-line no-unused-vars
-function myWebExtensionShowPopup() {
-  browser.test.sendMessage("readyForOpenPopup");
-}
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "manifest_version": 2,
-  "name": "test-devtools-webextension",
-  "version": "1.0",
-  "applications": {
-    "gecko": {
-      "id": "test-devtools-webextension@mozilla.org"
-    }
-  },
-  "background": {
-    "scripts": ["bg.js"]
-  },
-  "browser_action": {
-    "default_title": "WebExtension Popup Debugging",
-    "default_popup": "popup.html"
-  }
-}
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <script src="popup.js"></script>
-  </head>
-  <body>
-    Background Page Body Test Content
-  </body>
-</html>
deleted file mode 100644
--- a/devtools/client/aboutdebugging/test/addons/test-devtools-webextension/popup.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/* eslint-env browser */
-/* global browser */
-
-"use strict";
-
-// This function is called from the following about:debugging test:
-// browser_addons_debug_webextension.js
-//
-// eslint-disable-next-line no-unused-vars
-function myWebExtensionPopupAddonFunction() {
-  browser.test.sendMessage("popupPageFunctionCalled", browser.runtime.getManifest());
-}
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_info.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_info.js
@@ -34,25 +34,37 @@ add_task(async function testLegacyAddon(
 });
 
 add_task(async function testWebExtension() {
   const addonId = "test-devtools-webextension-nobg@mozilla.org";
   const addonName = "test-devtools-webextension-nobg";
   const { tab, document } = await openAboutDebugging("addons");
 
   await waitForInitialAddonList(document);
+
+  const addonFile = ExtensionTestCommon.generateXPI({
+    manifest: {
+      name: addonName,
+      applications: {
+        gecko: {id: addonId},
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   await installAddon({
     document,
-    path: "addons/test-devtools-webextension-nobg/manifest.json",
+    file: addonFile,
     name: addonName,
     isWebExtension: true
   });
 
   const container = document.querySelector(`[data-addon-id="${addonId}"]`);
-  testFilePath(container, "/test/addons/test-devtools-webextension-nobg/");
+
+  testFilePath(container, addonFile.leafName);
 
   const extensionID = container.querySelector(".extension-id span");
   ok(extensionID.textContent === "test-devtools-webextension-nobg@mozilla.org");
 
   const internalUUID = container.querySelector(".internal-uuid span");
   ok(internalUUID.textContent.match(UUID_REGEX), "internalUUID is correct");
 
   const manifestURL = container.querySelector(".manifest-url");
@@ -63,19 +75,27 @@ add_task(async function testWebExtension
   await closeAboutDebugging(tab);
 });
 
 add_task(async function testTemporaryWebExtension() {
   const addonName = "test-devtools-webextension-noid";
   const { tab, document } = await openAboutDebugging("addons");
 
   await waitForInitialAddonList(document);
+
+  const addonFile = ExtensionTestCommon.generateXPI({
+    manifest: {
+      name: addonName,
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   await installAddon({
     document,
-    path: "addons/test-devtools-webextension-noid/manifest.json",
+    file: addonFile,
     name: addonName,
     isWebExtension: true
   });
 
   const addons =
     document.querySelectorAll("#temporary-extensions .addon-target-container");
   // Assuming that our temporary add-on is now at the top.
   const container = addons[addons.length - 1];
@@ -93,32 +113,45 @@ add_task(async function testTemporaryWeb
 });
 
 add_task(async function testUnknownManifestProperty() {
   const addonId = "test-devtools-webextension-unknown-prop@mozilla.org";
   const addonName = "test-devtools-webextension-unknown-prop";
   const { tab, document } = await openAboutDebugging("addons");
 
   await waitForInitialAddonList(document);
+
+  const addonFile = ExtensionTestCommon.generateXPI({
+    manifest: {
+      name: addonName,
+      applications: {
+        gecko: {id: addonId},
+      },
+      wrong_manifest_property_name: {
+      }
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   await installAddon({
     document,
-    path: "addons/test-devtools-webextension-unknown-prop/manifest.json",
+    file: addonFile,
     name: addonName,
     isWebExtension: true
   });
 
   info("Wait until the addon appears in about:debugging");
   const container = await waitUntilAddonContainer(addonName, document);
 
   info("Wait until the installation message appears for the new addon");
   await waitUntilElement(".addon-target-messages", container);
 
   const messages = container.querySelectorAll(".addon-target-message");
   ok(messages.length === 1, "there is one message");
-  ok(messages[0].textContent.match(/Error processing browser_actions/),
+  ok(messages[0].textContent.match(/Error processing wrong_manifest_property_name/),
      "the message is helpful");
   ok(messages[0].classList.contains("addon-target-warning-message"),
      "the message is a warning");
 
   await uninstallAddon({document, id: addonId, name: addonName});
 
   await closeAboutDebugging(tab);
 });
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension.js
@@ -8,31 +8,46 @@
 const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
 PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
 
 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
 requestLongerTimeout(2);
 
 const ADDON_ID = "test-devtools-webextension@mozilla.org";
 const ADDON_NAME = "test-devtools-webextension";
-const ADDON_MANIFEST_PATH = "addons/test-devtools-webextension/manifest.json";
 
 const {
   BrowserToolboxProcess
 } = ChromeUtils.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 
 /**
  * This test file ensures that the webextension addon developer toolbox:
  * - when the debug button is clicked on a webextension, the opened toolbox
  *   has a working webconsole with the background page as default target;
  */
 add_task(async function testWebExtensionsToolboxWebConsole() {
+  const addonFile = ExtensionTestCommon.generateXPI({
+    background: function() {
+      window.myWebExtensionAddonFunction = function() {
+        console.log("Background page function called",
+                    this.browser.runtime.getManifest());
+      };
+    },
+    manifest: {
+      name: ADDON_NAME,
+      applications: {
+        gecko: {id: ADDON_ID},
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   const {
     tab, document, debugBtn,
-  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
+  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, addonFile);
 
   // Be careful, this JS function is going to be executed in the addon toolbox,
   // which lives in another process. So do not try to use any scope variable!
   const env = Cc["@mozilla.org/process/environment;1"]
               .getService(Ci.nsIEnvironment);
   const testScript = function() {
     /* eslint-disable no-undef */
     function findMessages(hud, text, selector = ".message") {
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_inspector.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_inspector.js
@@ -7,31 +7,43 @@
 const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
 PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
 
 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
 requestLongerTimeout(2);
 
 const ADDON_ID = "test-devtools-webextension@mozilla.org";
 const ADDON_NAME = "test-devtools-webextension";
-const ADDON_PATH = "addons/test-devtools-webextension/manifest.json";
 
 const {
   BrowserToolboxProcess
 } = ChromeUtils.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 
 /**
  * This test file ensures that the webextension addon developer toolbox:
  * - the webextension developer toolbox has a working Inspector panel, with the
  *   background page as default target;
  */
 add_task(async function testWebExtensionsToolboxInspector() {
+  const addonFile = ExtensionTestCommon.generateXPI({
+    background: function() {
+      document.body.innerText = "Background Page Body Test Content";
+    },
+    manifest: {
+      name: ADDON_NAME,
+      applications: {
+        gecko: {id: ADDON_ID},
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   const {
     tab, document, debugBtn,
-  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_PATH);
+  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, addonFile);
 
   // Be careful, this JS function is going to be executed in the addon toolbox,
   // which lives in another process. So do not try to use any scope variable!
   const env = Cc["@mozilla.org/process/environment;1"]
         .getService(Ci.nsIEnvironment);
   const testScript = function() {
     /* eslint-disable no-undef */
     toolbox.selectTool("inspector")
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_nobg.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_nobg.js
@@ -7,75 +7,80 @@
 const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
 PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
 
 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
 requestLongerTimeout(2);
 
 const ADDON_NOBG_ID = "test-devtools-webextension-nobg@mozilla.org";
 const ADDON_NOBG_NAME = "test-devtools-webextension-nobg";
-const ADDON_NOBG_PATH = "addons/test-devtools-webextension-nobg/manifest.json";
 
 const {
   BrowserToolboxProcess
 } = ChromeUtils.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 
 /**
  * This test file ensures that the webextension addon developer toolbox:
  * - the webextension developer toolbox is connected to a fallback page when the
  *   background page is not available (and in the fallback page document body contains
  *   the expected message, which warns the user that the current page is not a real
  *   webextension context);
  */
 add_task(async function testWebExtensionsToolboxNoBackgroundPage() {
+  const addonFile = ExtensionTestCommon.generateXPI({
+    manifest: {
+      name: ADDON_NOBG_NAME,
+      applications: {
+        gecko: {id: ADDON_NOBG_ID},
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   const {
     tab, document, debugBtn,
-  } = await setupTestAboutDebuggingWebExtension(ADDON_NOBG_NAME, ADDON_NOBG_PATH);
+  } = await setupTestAboutDebuggingWebExtension(ADDON_NOBG_NAME, addonFile);
 
   // Be careful, this JS function is going to be executed in the addon toolbox,
   // which lives in another process. So do not try to use any scope variable!
   const env = Cc["@mozilla.org/process/environment;1"]
         .getService(Ci.nsIEnvironment);
   const testScript = function() {
     /* eslint-disable no-undef */
-    toolbox.selectTool("inspector")
-      .then(inspector => {
-        return inspector.walker.querySelector(inspector.walker.rootNode, "body");
-      })
-      .then((nodeActor) => {
-        if (!nodeActor) {
-          throw new Error("nodeActor not found");
-        }
+    toolbox.selectTool("inspector").then(async inspector => {
+      const nodeActor = await inspector.walker.querySelector(
+        inspector.walker.rootNode, "body");
 
-        dump("Got a nodeActor\n");
+      if (!nodeActor) {
+        throw new Error("nodeActor not found");
+      }
 
-        if (!(nodeActor.inlineTextChild)) {
-          throw new Error("inlineTextChild not found");
-        }
+      if (!(nodeActor.inlineTextChild)) {
+        throw new Error("inlineTextChild not found");
+      }
 
-        dump("Got a nodeActor with an inline text child\n");
+      dump("Got a nodeActor with an inline text child\n");
 
-        const expectedValue = "Your addon does not have any document opened yet.";
-        const actualValue = nodeActor.inlineTextChild._form.nodeValue;
+      const expectedValue = "Your addon does not have any document opened yet.";
+      const actualValue = nodeActor.inlineTextChild._form.nodeValue;
 
-        if (actualValue !== expectedValue) {
-          throw new Error(
-            `mismatched inlineTextchild value: "${actualValue}" !== "${expectedValue}"`
-          );
-        }
+      if (actualValue !== expectedValue) {
+        throw new Error(
+          `mismatched inlineTextchild value: "${actualValue}" !== "${expectedValue}"`
+        );
+      }
 
-        dump("Got the expected inline text content in the selected node\n");
-        return Promise.resolve();
-      })
-      .then(() => toolbox.destroy())
-      .catch((error) => {
-        dump("Error while running code in the browser toolbox process:\n");
-        dump(error + "\n");
-        dump("stack:\n" + error.stack + "\n");
-      });
+      dump("Got the expected inline text content in the selected node\n");
+
+      await toolbox.destroy();
+    }).catch((error) => {
+      dump("Error while running code in the browser toolbox process:\n");
+      dump(error + "\n");
+      dump("stack:\n" + error.stack + "\n");
+    });
     /* eslint-enable no-undef */
   };
   env.set("MOZ_TOOLBOX_TEST_SCRIPT", "new " + testScript);
   registerCleanupFunction(() => {
     env.set("MOZ_TOOLBOX_TEST_SCRIPT", "");
   });
 
   const onToolboxClose = BrowserToolboxProcess.once("close");
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_webextension_popup.js
@@ -7,17 +7,16 @@
 const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
 PromiseTestUtils.whitelistRejectionsGlobally(/File closed/);
 
 // Avoid test timeouts that can occur while waiting for the "addon-console-works" message.
 requestLongerTimeout(2);
 
 const ADDON_ID = "test-devtools-webextension@mozilla.org";
 const ADDON_NAME = "test-devtools-webextension";
-const ADDON_MANIFEST_PATH = "addons/test-devtools-webextension/manifest.json";
 
 const {
   BrowserToolboxProcess
 } = ChromeUtils.import("resource://devtools/client/framework/ToolboxProcess.jsm", {});
 
 /**
  * This test file ensures that the webextension addon developer toolbox:
  * - when the debug button is clicked on a webextension, the opened toolbox
@@ -37,16 +36,56 @@ const {
  * Returns the widget id for an extension with the passed id.
  */
 function makeWidgetId(id) {
   id = id.toLowerCase();
   return id.replace(/[^a-z0-9_-]/g, "_");
 }
 
 add_task(async function testWebExtensionsToolboxSwitchToPopup() {
+  const addonFile = ExtensionTestCommon.generateXPI({
+    background: function() {
+      const {browser} = this;
+      window.myWebExtensionShowPopup = function() {
+        browser.test.sendMessage("readyForOpenPopup");
+      };
+    },
+    manifest: {
+      name: ADDON_NAME,
+      applications: {
+        gecko: {id: ADDON_ID},
+      },
+      browser_action: {
+        default_title: "WebExtension Popup Debugging",
+        default_popup: "popup.html",
+      },
+    },
+    files: {
+      "popup.html": `<!DOCTYPE html>
+        <html>
+          <head>
+            <meta charset="utf-8">
+            <script src="popup.js"></script>
+          </head>
+          <body>
+            Background Page Body Test Content
+          </body>
+        </html>
+      `,
+      "popup.js": function() {
+        const {browser} = this;
+        window.myWebExtensionPopupAddonFunction = function() {
+          browser.test.sendMessage("popupPageFunctionCalled",
+                                   browser.runtime.getManifest());
+        };
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   let onReadyForOpenPopup;
   let onPopupCustomMessage;
 
   is(Services.prefs.getBoolPref("ui.popup.disable_autohide"), false,
      "disable_autohide shoult be initially false");
 
   Management.on("startup", function listener(event, extension) {
     if (extension.name != ADDON_NAME) {
@@ -76,17 +115,17 @@ add_task(async function testWebExtension
 
     // Wait for a notification sent by a script evaluated the test addon via
     // the web console.
     onPopupCustomMessage = waitForExtensionTestMessage("popupPageFunctionCalled");
   });
 
   const {
     tab, document, debugBtn,
-  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, ADDON_MANIFEST_PATH);
+  } = await setupTestAboutDebuggingWebExtension(ADDON_NAME, addonFile);
 
   // Be careful, this JS function is going to be executed in the addon toolbox,
   // which lives in another process. So do not try to use any scope variable!
   const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
 
   const testScript = function() {
     /* eslint-disable no-undef */
 
--- a/devtools/client/aboutdebugging/test/browser_addons_remove.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_remove.js
@@ -39,20 +39,30 @@ add_task(async function removeLegacyExte
 
 add_task(async function removeWebextension() {
   const addonID = "test-devtools-webextension@mozilla.org";
   const addonName = "test-devtools-webextension";
 
   const { tab, document } = await openAboutDebugging("addons");
   await waitForInitialAddonList(document);
 
+  const addonFile = ExtensionTestCommon.generateXPI({
+    manifest: {
+      name: addonName,
+      applications: {
+        gecko: {id: addonID},
+      },
+    },
+  });
+  registerCleanupFunction(() => addonFile.remove(false));
+
   // Install this add-on, and verify that it appears in the about:debugging UI
   await installAddon({
     document,
-    path: "addons/test-devtools-webextension/manifest.json",
+    file: addonFile,
     name: addonName,
     isWebExtension: true,
   });
 
   ok(getTargetEl(document, addonID), "add-on is shown");
 
   info("Click on the remove button and wait until the addon container is removed");
   getRemoveButton(document, addonID).click();
--- a/devtools/client/aboutdebugging/test/head.js
+++ b/devtools/client/aboutdebugging/test/head.js
@@ -9,16 +9,17 @@
 
 // Load the shared-head file first.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
   this);
 
 const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
 const { Management } = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
+const { ExtensionTestCommon } = ChromeUtils.import("resource://testing-common/ExtensionTestCommon.jsm", {});
 
 async function openAboutDebugging(page, win) {
   info("opening about:debugging");
   let url = "about:debugging";
   if (page) {
     url += "#" + page;
   }
 
@@ -160,22 +161,26 @@ async function waitUntilElement(selector
  * @param  {DOMDocument}  document   #tabs section container document
  * @return {DOMNode}                 target list or container element
  */
 function getTabList(document) {
   return document.querySelector("#tabs .target-list") ||
     document.querySelector("#tabs.targets");
 }
 
-async function installAddon({document, path, name, isWebExtension}) {
+async function installAddon({document, path, file, name, isWebExtension}) {
   // Mock the file picker to select a test addon
   const MockFilePicker = SpecialPowers.MockFilePicker;
   MockFilePicker.init(window);
-  const file = getSupportsFile(path);
-  MockFilePicker.setFiles([file.file]);
+  if (path) {
+    file = getSupportsFile(path);
+    MockFilePicker.setFiles([file.file]);
+  } else {
+    MockFilePicker.setFiles([file]);
+  }
 
   let onAddonInstalled;
 
   if (isWebExtension) {
     onAddonInstalled = new Promise(done => {
       Management.on("startup", function listener(event, extension) {
         if (extension.name != name) {
           return;
@@ -336,17 +341,17 @@ function waitForDelayedStartupFinished(w
       }
     }, "browser-delayed-startup-finished");
   });
 }
 
 /**
  * open the about:debugging page and install an addon
  */
-async function setupTestAboutDebuggingWebExtension(name, path) {
+async function setupTestAboutDebuggingWebExtension(name, file) {
   await new Promise(resolve => {
     const options = {"set": [
       // Force enabling of addons debugging
       ["devtools.chrome.enabled", true],
       ["devtools.debugger.remote-enabled", true],
       // Disable security prompt
       ["devtools.debugger.prompt-connection", false],
       // Enable Browser toolbox test script execution via env variable
@@ -355,17 +360,17 @@ async function setupTestAboutDebuggingWe
     SpecialPowers.pushPrefEnv(options, resolve);
   });
 
   const { tab, document } = await openAboutDebugging("addons");
   await waitForInitialAddonList(document);
 
   await installAddon({
     document,
-    path,
+    file,
     name,
     isWebExtension: true,
   });
 
   // Retrieve the DEBUG button for the addon
   const names = getInstalledAddonNames(document);
   const nameEl = names.filter(element => element.textContent === name)[0];
   ok(name, "Found the addon in the list");
--- a/devtools/client/debugger/debugger-controller.js
+++ b/devtools/client/debugger/debugger-controller.js
@@ -474,18 +474,18 @@ Workers.prototype = {
 
   connect: function () {
     if (!Prefs.workersEnabled) {
       return;
     }
 
     this._updateWorkerList();
 
-    // `_targetFront` can be BrowsingContextTargetFront (protocol.js front) or
-    // WorkerClient/DebuggerClient (old fashion client)
+    // `_targetFront` can be BrowsingContextTargetFront/WorkerTargetFront (protocol.js
+    // front) or DebuggerClient (old fashion client)
     if (typeof(this._targetFront.on) == "function") {
       this._targetFront.on("workerListChanged", this._onWorkerListChanged);
     } else {
       this._targetFront.addListener("workerListChanged", this._onWorkerListChanged);
     }
   },
 
   disconnect: function () {
@@ -524,18 +524,18 @@ Workers.prototype = {
     });
   },
 
   _onWorkerListChanged: function () {
     this._updateWorkerList();
   },
 
   _onWorkerSelect: function (workerForm) {
-    DebuggerController.client.attachWorker(workerForm.actor).then(([response, workerClient]) => {
-      let toolbox = gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
+    DebuggerController.client.attachWorker(workerForm.actor).then(([response, workerTargetFront]) => {
+      let toolbox = gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
                                           "jsdebugger", Toolbox.HostType.WINDOW);
       window.emit(EVENTS.WORKER_SELECTED, toolbox);
     });
   }
 };
 
 /**
  * ThreadState keeps the UI up to date with the state of the
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -59,21 +59,21 @@ DebuggerPanel.prototype = {
     return this._store.getState();
   },
 
   openLink: function(url) {
     openContentLink(url);
   },
 
   openWorkerToolbox: async function(worker) {
-    const [response, workerClient] =
+    const [response, workerTargetFront] =
       await this.toolbox.target.client.attachWorker(worker.actor);
-    const workerTarget = TargetFactory.forWorker(workerClient);
+    const workerTarget = TargetFactory.forWorker(workerTargetFront);
     const toolbox = await gDevTools.showToolbox(workerTarget, "jsdebugger", Toolbox.HostType.WINDOW);
-    toolbox.once("destroy", () => workerClient.detach());
+    toolbox.once("destroy", () => workerTargetFront.detach());
   },
 
   getFrames: function() {
     let frames = this._selectors.getFrames(this._getState());
 
     // Frames is null when the debugger is not paused.
     if (!frames) {
       return {
--- a/devtools/client/debugger/new/src/client/firefox/events.js
+++ b/devtools/client/debugger/new/src/client/firefox/events.js
@@ -36,18 +36,18 @@ function setupEvents(dependencies) {
   });
 
   if (threadClient) {
     Object.keys(clientEvents).forEach(eventName => {
       threadClient.addListener(eventName, clientEvents[eventName]);
     });
 
     if (threadClient._parent) {
-      // Parent may be BrowsingContextTargetFront and be protocol.js.
-      // Or DebuggerClient/WorkerClient and still be old fashion actor.
+      // Parent may be BrowsingContextTargetFront/WorkerTargetFront and be protocol.js.
+      // Or DebuggerClient and still be old fashion actor.
       if (threadClient._parent.on) {
         threadClient._parent.on("workerListChanged", workerListChanged);
       } else {
         threadClient._parent.addListener("workerListChanged", workerListChanged);
       }
     }
   }
 }
--- a/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
@@ -23,20 +23,20 @@ add_task(async function() {
   let tab = await addTab(TAB_URL);
   let { tabs } = await listTabs(client);
   let [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
 
   await listWorkers(targetFront);
   await createWorkerInTab(tab, WORKER_URL);
 
   let { workers } = await listWorkers(targetFront);
-  let [, workerClient] = await attachWorker(targetFront,
+  let [, workerTargetFront] = await attachWorker(targetFront,
                                              findWorker(workers, WORKER_URL));
 
-  let toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
+  let toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
                                             "jsdebugger",
                                             Toolbox.HostType.WINDOW);
 
   is(toolbox.hostType, "window", "correct host");
 
   await new Promise(done => {
     toolbox.win.parent.addEventListener("message", function onmessage(event) {
       if (event.data.name == "set-host-title") {
@@ -50,13 +50,13 @@ add_task(async function() {
 
   let toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
   let activeTools = [...toolTabs].map(tab=>tab.getAttribute("data-id"));
 
   is(activeTools.join(","), "webconsole,jsdebugger,scratchpad",
     "Correct set of tools supported by worker");
 
   terminateWorkerInTab(tab, WORKER_URL);
-  await waitForWorkerClose(workerClient);
+  await waitForWorkerClose(workerTargetFront);
   await close(client);
 
   await toolbox.destroy();
 });
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -1109,24 +1109,24 @@ function attachWorker(targetFront, worke
   return targetFront.attachWorker(worker.actor);
 }
 
 function waitForWorkerListChanged(targetFront) {
   info("Waiting for worker list to change.");
   return targetFront.once("workerListChanged");
 }
 
-function attachThread(workerClient, options) {
+function attachThread(workerTargetFront, options) {
   info("Attaching to thread.");
-  return workerClient.attachThread(options);
+  return workerTargetFront.attachThread(options);
 }
 
-async function waitForWorkerClose(workerClient) {
+async function waitForWorkerClose(workerTargetFront) {
   info("Waiting for worker to close.");
-  await workerClient.once("close");
+  await workerTargetFront.once("close");
   info("Worker did close.");
 }
 
 function resume(threadClient) {
   info("Resuming thread.");
   return threadClient.resume();
 }
 
@@ -1283,20 +1283,20 @@ async function initWorkerDebugger(TAB_UR
 
   let tab = await addTab(TAB_URL);
   let { tabs } = await listTabs(client);
   let [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
 
   await createWorkerInTab(tab, WORKER_URL);
 
   let { workers } = await listWorkers(targetFront);
-  let [, workerClient] = await attachWorker(targetFront,
+  let [, workerTargetFront] = await attachWorker(targetFront,
                                              findWorker(workers, WORKER_URL));
 
-  let toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
+  let toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
                                             "jsdebugger",
                                             Toolbox.HostType.WINDOW);
 
   let debuggerPanel = toolbox.getCurrentPanel();
   let gDebugger = debuggerPanel.panelWin;
 
-  return {client, tab, targetFront, workerClient, toolbox, gDebugger};
+  return {client, tab, targetFront, workerTargetFront, toolbox, gDebugger};
 }
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -370,20 +370,20 @@ var gDevToolsBrowser = exports.gDevTools
    * Open a window-hosted toolbox to debug the worker associated to the provided
    * worker actor.
    *
    * @param  {DebuggerClient} client
    * @param  {Object} workerTargetActor
    *         worker actor form to debug
    */
   async openWorkerToolbox(client, workerTargetActor) {
-    const [, workerClient] = await client.attachWorker(workerTargetActor);
-    const workerTarget = TargetFactory.forWorker(workerClient);
+    const [, workerTargetFront] = await client.attachWorker(workerTargetActor);
+    const workerTarget = TargetFactory.forWorker(workerTargetFront);
     const toolbox = await gDevTools.showToolbox(workerTarget, null, Toolbox.HostType.WINDOW);
-    toolbox.once("destroy", () => workerClient.detach());
+    toolbox.once("destroy", () => workerTargetFront.detach());
   },
 
   /**
    * Install WebIDE widget
    */
   // Used by itself
   installWebIDEWidget() {
     if (this.isWebIDEWidgetInstalled()) {
--- a/devtools/client/framework/target.js
+++ b/devtools/client/framework/target.js
@@ -115,21 +115,21 @@ const TargetFactory = exports.TargetFact
     if (targetPromise == null) {
       const target = new TabTarget(options);
       targetPromise = target.attach().then(() => target);
       promiseTargets.set(options, targetPromise);
     }
     return targetPromise;
   },
 
-  forWorker: function(workerClient) {
-    let target = targets.get(workerClient);
+  forWorker: function(workerTargetFront) {
+    let target = targets.get(workerTargetFront);
     if (target == null) {
-      target = new WorkerTarget(workerClient);
-      targets.set(workerClient, target);
+      target = new WorkerTarget(workerTargetFront);
+      targets.set(workerTargetFront, target);
     }
     return target;
   },
 
   /**
    * Creating a target for a tab that is being closed is a problem because it
    * allows a leak as a result of coming after the close event which normally
    * clears things up. This function allows us to ask if there is a known
@@ -843,29 +843,29 @@ TabTarget.prototype = {
   logWarningInPage: function(text, category) {
     if (this.activeTab && this.activeTab.traits.logInPage) {
       const warningFlag = 1;
       this.activeTab.logInPage({ text, category, flags: warningFlag });
     }
   },
 };
 
-function WorkerTarget(workerClient) {
+function WorkerTarget(workerTargetFront) {
   EventEmitter.decorate(this);
-  this._workerClient = workerClient;
+  this._workerTargetFront = workerTargetFront;
 }
 
 /**
  * A WorkerTarget represents a worker. Unlike TabTarget, which can represent
  * either a local or remote tab, WorkerTarget always represents a remote worker.
  * Moreover, unlike TabTarget, which is constructed with a placeholder object
  * for remote tabs (from which a TargetFront can then be lazily obtained),
- * WorkerTarget is constructed with a WorkerClient directly.
+ * WorkerTarget is constructed with a WorkerTargetFront directly.
  *
- * WorkerClient is designed to mimic the interface of TargetFront as closely as
+ * WorkerTargetFront is designed to mimic the interface of TargetFront as closely as
  * possible. This allows us to debug workers as if they were ordinary tabs,
  * requiring only minimal changes to the rest of the frontend.
  */
 WorkerTarget.prototype = {
   get isRemote() {
     return true;
   },
 
@@ -873,47 +873,47 @@ WorkerTarget.prototype = {
     return true;
   },
 
   get name() {
     return "Worker";
   },
 
   get url() {
-    return this._workerClient.url;
+    return this._workerTargetFront.url;
   },
 
   get isWorkerTarget() {
     return true;
   },
 
   get form() {
     return {
-      consoleActor: this._workerClient.consoleActor
+      consoleActor: this._workerTargetFront.consoleActor
     };
   },
 
   get activeTab() {
-    return this._workerClient;
+    return this._workerTargetFront;
   },
 
   get activeConsole() {
     return this.client._clients.get(this.form.consoleActor);
   },
 
   get client() {
-    return this._workerClient.client;
+    return this._workerTargetFront.client;
   },
 
   get canRewind() {
     return false;
   },
 
   destroy: function() {
-    this._workerClient.detach();
+    this._workerTargetFront.detach();
   },
 
   hasActor: function(name) {
     // console is the only one actor implemented by WorkerTargetActor
     if (name == "console") {
       return true;
     }
     return false;
--- a/devtools/client/framework/toolbox-highlighter-utils.js
+++ b/devtools/client/framework/toolbox-highlighter-utils.js
@@ -23,48 +23,35 @@ const flags = require("devtools/shared/f
  * This should be done once only by the toolbox itself and stored there so that
  * panels can get it from there. That's because the API returned has a stateful
  * scope that would be different for another instance returned by this function.
  *
  * @param {Toolbox} toolbox
  * @return {Object} the highlighterUtils public API
  */
 exports.getHighlighterUtils = function(toolbox) {
-  if (!toolbox || !toolbox.target) {
+  if (!toolbox) {
     throw new Error("Missing or invalid toolbox passed to getHighlighterUtils");
   }
 
   // Exported API properties will go here
   const exported = {};
 
-  // The current toolbox target
-  let target = toolbox.target;
-
   // Is the highlighter currently in pick mode
   let isPicking = false;
 
   // Is the box model already displayed, used to prevent dispatching
   // unnecessary requests, especially during toolbox shutdown
   let isNodeFrontHighlighted = false;
 
   /**
    * Release this utils, nullifying the references to the toolbox
    */
   exported.release = function() {
-    toolbox = target = null;
-  };
-
-  /**
-   * Does the target have the highlighter actor.
-   * The devtools must be backwards compatible with at least B2G 1.3 (28),
-   * which doesn't have the highlighter actor. This can be removed as soon as
-   * the minimal supported version becomes 1.4 (29)
-   */
-  const isRemoteHighlightable = exported.isRemoteHighlightable = function() {
-    return target.client.traits.highlightable;
+    toolbox = null;
   };
 
   /**
    * Make a function that initializes the inspector before it runs.
    * Since the init of the inspector is asynchronous, the return value will be
    * produced by Task.async and the argument should be a generator
    * @param {Function*} generator A generator function
    * @return {Function} A function
@@ -110,59 +97,44 @@ exports.getHighlighterUtils = function(t
         return;
       }
       isPicking = true;
 
       toolbox.pickerButton.isChecked = true;
       await toolbox.selectTool("inspector", "inspect_dom");
       toolbox.on("select", cancelPicker);
 
-      if (isRemoteHighlightable()) {
-        toolbox.walker.on("picker-node-hovered", onPickerNodeHovered);
-        toolbox.walker.on("picker-node-picked", onPickerNodePicked);
-        toolbox.walker.on("picker-node-previewed", onPickerNodePreviewed);
-        toolbox.walker.on("picker-node-canceled", onPickerNodeCanceled);
+      toolbox.walker.on("picker-node-hovered", onPickerNodeHovered);
+      toolbox.walker.on("picker-node-picked", onPickerNodePicked);
+      toolbox.walker.on("picker-node-previewed", onPickerNodePreviewed);
+      toolbox.walker.on("picker-node-canceled", onPickerNodeCanceled);
 
-        await toolbox.highlighter.pick(doFocus);
-        toolbox.emit("picker-started");
-      } else {
-        // If the target doesn't have the highlighter actor, we can use the
-        // walker's pick method instead, knowing that it only responds when a node
-        // is picked (instead of emitting events)
-        toolbox.emit("picker-started");
-        const node = await toolbox.walker.pick();
-        onPickerNodePicked({node: node});
-      }
+      await toolbox.highlighter.pick(doFocus);
+      toolbox.emit("picker-started");
     });
 
   /**
    * Stop the element picker. Note that the picker is automatically stopped when
    * an element is picked
    * @return A promise that resolves when the picker has stopped or immediately
    * if it is already stopped
    */
   const stopPicker = exported.stopPicker = requireInspector(async function() {
     if (!isPicking) {
       return;
     }
     isPicking = false;
 
     toolbox.pickerButton.isChecked = false;
 
-    if (isRemoteHighlightable()) {
-      await toolbox.highlighter.cancelPick();
-      toolbox.walker.off("picker-node-hovered", onPickerNodeHovered);
-      toolbox.walker.off("picker-node-picked", onPickerNodePicked);
-      toolbox.walker.off("picker-node-previewed", onPickerNodePreviewed);
-      toolbox.walker.off("picker-node-canceled", onPickerNodeCanceled);
-    } else {
-      // If the target doesn't have the highlighter actor, use the walker's
-      // cancelPick method instead
-      await toolbox.walker.cancelPick();
-    }
+    await toolbox.highlighter.cancelPick();
+    toolbox.walker.off("picker-node-hovered", onPickerNodeHovered);
+    toolbox.walker.off("picker-node-picked", onPickerNodePicked);
+    toolbox.walker.off("picker-node-previewed", onPickerNodePreviewed);
+    toolbox.walker.off("picker-node-canceled", onPickerNodeCanceled);
 
     toolbox.off("select", cancelPicker);
     toolbox.emit("picker-stopped");
   });
 
   /**
    * Stop the picker, but also emit an event that the picker was canceled.
    */
@@ -216,23 +188,17 @@ exports.getHighlighterUtils = function(t
    */
   const highlightNodeFront = exported.highlightNodeFront = requireInspector(
   async function(nodeFront, options = {}) {
     if (!nodeFront) {
       return;
     }
 
     isNodeFrontHighlighted = true;
-    if (isRemoteHighlightable()) {
-      await toolbox.highlighter.showBoxModel(nodeFront, options);
-    } else {
-      // If the target doesn't have the highlighter actor, revert to the
-      // walker's highlight method, which draws a simple outline
-      await toolbox.walker.highlight(nodeFront);
-    }
+    await toolbox.highlighter.showBoxModel(nodeFront, options);
 
     toolbox.emit("node-highlight", nodeFront);
   });
 
   /**
    * This is a convenience method in case you don't have a nodeFront but a
    * valueGrip. This is often the case with VariablesView properties.
    * This method will simply translate the grip into a nodeFront and call
@@ -266,20 +232,17 @@ exports.getHighlighterUtils = function(t
    * in the markup view doesn't hide/show the highlighter to ease testing. The
    * highlighter stays visible at all times, except when the mouse leaves the
    * markup view, which is when this param is passed to true
    * @return a promise that resolves when the highlighter is hidden
    */
   exported.unhighlight = async function(forceHide = false) {
     forceHide = forceHide || !flags.testing;
 
-    // Note that if isRemoteHighlightable is true, there's no need to hide the
-    // highlighter as the walker uses setTimeout to hide it after some time
-    if (isNodeFrontHighlighted && forceHide && toolbox.highlighter &&
-        isRemoteHighlightable()) {
+    if (isNodeFrontHighlighted && forceHide && toolbox.highlighter) {
       isNodeFrontHighlighted = false;
       await toolbox.highlighter.hideBoxModel();
     }
 
     // unhighlight is called when destroying the toolbox, which means that by
     // now, the toolbox reference might have been nullified already.
     if (toolbox) {
       toolbox.emit("node-unhighlight");
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -2340,17 +2340,17 @@ Toolbox.prototype = {
    * Highlight a frame in the page
    */
   onHighlightFrame: async function(frameId) {
     // Need to initInspector to check presence of getNodeActorFromWindowID
     // and use the highlighter later
     await this.initInspector();
 
     // Only enable frame highlighting when the top level document is targeted
-    if (this._supportsFrameHighlight && this.rootFrameSelected) {
+    if (this.rootFrameSelected) {
       const frameActor = await this.walker.getNodeActorFromWindowID(frameId);
       this.highlighterUtils.highlightNodeFront(frameActor);
     }
   },
 
   /**
    * A handler for 'frameUpdate' packets received from the backend.
    * Following properties might be set on the packet:
@@ -2675,28 +2675,21 @@ Toolbox.prototype = {
         // TODO: replace with getFront once inspector is separated from the toolbox
         this._inspector = this.target.getInspector();
         const pref = "devtools.inspector.showAllAnonymousContent";
         const showAllAnonymousContent = Services.prefs.getBoolPref(pref);
         this._walker = await this._inspector.getWalker({ showAllAnonymousContent });
         this._selection = new Selection(this._walker);
         this._selection.on("new-node-front", this._onNewSelectedNodeFront);
 
-        if (this.highlighterUtils.isRemoteHighlightable()) {
-          this.walker.on("highlighter-ready", this._highlighterReady);
-          this.walker.on("highlighter-hide", this._highlighterHidden);
-
-          const autohide = !flags.testing;
-          this._highlighter = await this._inspector.getHighlighter(autohide);
-        }
-        if (!("_supportsFrameHighlight" in this)) {
-          // Only works with FF58+ targets
-          this._supportsFrameHighlight =
-            await this.target.actorHasMethod("domwalker", "getNodeActorFromWindowID");
-        }
+        this.walker.on("highlighter-ready", this._highlighterReady);
+        this.walker.on("highlighter-hide", this._highlighterHidden);
+
+        const autohide = !flags.testing;
+        this._highlighter = await this._inspector.getHighlighter(autohide);
       }.bind(this))();
     }
     return this._initInspector;
   },
 
   _onNewSelectedNodeFront: function() {
     // Emit a "selection-changed" event when the toolbox.selection has been set
     // to a new node (or cleared). Currently used in the WebExtensions APIs (to
@@ -2764,24 +2757,16 @@ Toolbox.prototype = {
       } else {
         await this.highlighterUtils.stopPicker();
       }
       // Temporary fix for bug #1493131 - inspector has a different life cycle
       // than most other fronts because it is closely related to the toolbox.
       this._inspector.destroy();
 
       if (this._highlighter) {
-        // Note that if the toolbox is closed, this will work fine, but will fail
-        // in case the browser is closed and will trigger a noSuchActor message.
-        // We ignore the promise that |_hideBoxModel| returns, since we should still
-        // proceed with the rest of destruction if it fails.
-        // FF42+ now does the cleanup from the actor.
-        if (!this.highlighter.traits.autoHideOnDestroy) {
-          this.highlighterUtils.unhighlight();
-        }
         await this._highlighter.destroy();
       }
       if (this._selection) {
         this._selection.off("new-node-front", this._onNewSelectedNodeFront);
         this._selection.destroy();
       }
 
       if (this.walker) {
--- a/devtools/client/inspector/flexbox/test/browser.ini
+++ b/devtools/client/inspector/flexbox/test/browser.ini
@@ -1,23 +1,26 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   doc_flexbox_simple.html
   doc_flexbox_pseudos.html
+  doc_flexbox_text_nodes.html
   head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/shared-head.js
   !/devtools/client/shared/test/telemetry-test-helpers.js
   !/devtools/client/shared/test/test-actor.js
   !/devtools/client/shared/test/test-actor-registry.js
 
 [browser_flexbox_highlighter_color_picker_on_ESC.js]
 [browser_flexbox_highlighter_color_picker_on_RETURN.js]
 [browser_flexbox_item_outline_exists.js]
 [browser_flexbox_item_outline_has_correct_layout.js]
 [browser_flexbox_item_outline_rotates_for_column.js]
 [browser_flexbox_pseudo_elements_are_listed.js]
 [browser_flexbox_sizing_info_exists.js]
 [browser_flexbox_sizing_info_for_pseudos.js]
+[browser_flexbox_sizing_info_for_text_nodes.js]
 [browser_flexbox_sizing_info_has_correct_sections.js]
+[browser_flexbox_text_nodes_are_listed.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/flexbox/test/browser_flexbox_sizing_info_for_text_nodes.js
@@ -0,0 +1,38 @@
+/* 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 the flex item sizing UI also appears for text nodes.
+
+const TEST_URI = URL_ROOT + "doc_flexbox_text_nodes.html";
+
+add_task(async function() {
+  await addTab(TEST_URI);
+  const { inspector, flexboxInspector } = await openLayoutView();
+  const { document: doc } = flexboxInspector;
+
+  info("Select the first text node in the flex container");
+  const containerNode = await getNodeFront(".container", inspector);
+  const { nodes } = await inspector.walker.children(containerNode);
+  const firstTextNode = nodes[0];
+
+  const onFlexItemSizingRendered = waitForDOM(doc, "ul.flex-item-sizing");
+  const onFlexItemOutlineRendered = waitForDOM(doc, ".flex-outline-container");
+  await selectNode(firstTextNode, inspector);
+  const [flexSizingContainer] = await onFlexItemSizingRendered;
+  const [flexOutlineContainer] = await onFlexItemOutlineRendered;
+
+  ok(flexSizingContainer, "The flex sizing exists in the DOM");
+  ok(flexOutlineContainer, "The flex outline exists in the DOM");
+
+  info("Check that the various sizing sections are displayed");
+  const allSections = [...flexSizingContainer.querySelectorAll(".section")];
+  ok(allSections.length, "Sizing sections are displayed");
+
+  info("Check that the various parts of the outline are displayed");
+  const [basis, final] = [...flexOutlineContainer.querySelectorAll(
+    ".flex-outline-basis, .flex-outline-final")];
+  ok(basis && final, "The final and basis parts of the outline exist");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/flexbox/test/browser_flexbox_text_nodes_are_listed.js
@@ -0,0 +1,27 @@
+/* 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 text nodes that are flex items do appear in the list of items.
+
+const TEST_URI = URL_ROOT + "doc_flexbox_text_nodes.html";
+
+add_task(async function() {
+  await addTab(TEST_URI);
+  const { inspector, flexboxInspector } = await openLayoutView();
+  const { document: doc } = flexboxInspector;
+
+  // Select the flex container in the inspector.
+  const onItemsListRendered = waitForDOM(doc,
+    "#layout-flexbox-container .flex-item-list");
+  await selectNode(".container", inspector);
+  const [flexItemList] = await onItemsListRendered;
+
+  const items = [...flexItemList.querySelectorAll("li")];
+  is(items.length, 3, "There are 3 items displayed in the list");
+
+  is(items[0].textContent, "#text", "The first item is a text node");
+  is(items[2].textContent, "#text", "The third item is a text node");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/flexbox/test/doc_flexbox_text_nodes.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+.container {
+  width: 400px;
+  display: flex;
+}
+.container div {
+  flex-basis: 100px;
+  flex-shrink: 0;
+  background: #f06;
+  align-self: stretch;
+}
+</style>
+<div class="container">
+  A text node will be wrapped into an anonymous block container
+  <div></div>
+  Here is yet another text node
+</div>
--- a/devtools/client/inspector/rules/test/browser.ini
+++ b/devtools/client/inspector/rules/test/browser.ini
@@ -263,14 +263,13 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_rules_shapes-toggle_06.js]
 [browser_rules_shapes-toggle_07.js]
 [browser_rules_shorthand-overridden-lists.js]
 [browser_rules_strict-search-filter-computed-list_01.js]
 [browser_rules_strict-search-filter_01.js]
 [browser_rules_strict-search-filter_02.js]
 [browser_rules_strict-search-filter_03.js]
 [browser_rules_style-editor-link.js]
-skip-if = true # Bug 1309759
 [browser_rules_url-click-opens-new-tab.js]
 [browser_rules_urls-clickable.js]
 [browser_rules_user-agent-styles.js]
 [browser_rules_user-agent-styles-uneditable.js]
 [browser_rules_user-property-reset.js]
--- a/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
@@ -5,18 +5,17 @@
 "use strict";
 
 // Test the links from the rule-view to the styleeditor
 
 const STYLESHEET_DATA_URL_CONTENTS = ["#first {",
                                       "color: blue",
                                       "}"].join("\n");
 const STYLESHEET_DATA_URL =
-      `data:text/css,${encodeURIComponent(STYLESHEET_DATA_URL_CONTENTS)}`;
-const STYLESHEET_DECODED_DATA_URL = `data:text/css,${STYLESHEET_DATA_URL_CONTENTS}`;
+  `data:text/css,${encodeURIComponent(STYLESHEET_DATA_URL_CONTENTS)}`;
 
 const EXTERNAL_STYLESHEET_FILE_NAME = "doc_style_editor_link.css";
 const EXTERNAL_STYLESHEET_URL = URL_ROOT + EXTERNAL_STYLESHEET_FILE_NAME;
 
 const DOCUMENT_URL = "data:text/html;charset=utf-8," + encodeURIComponent(`
   <html>
   <head>
   <title>Rule view style editor link test</title>
@@ -50,38 +49,23 @@ const DOCUMENT_URL = "data:text/html;cha
   </html>
 `);
 
 add_task(async function() {
   await addTab(DOCUMENT_URL);
   const {toolbox, inspector, view, testActor} = await openRuleView();
   await selectNode("div", inspector);
 
-  await testInlineStyle(view);
+  testRuleViewLinkLabel(view);
   await testFirstInlineStyleSheet(view, toolbox, testActor);
   await testSecondInlineStyleSheet(view, toolbox, testActor);
   await testExternalStyleSheet(view, toolbox, testActor);
   await testDisabledStyleEditor(view, toolbox);
 });
 
-async function testInlineStyle(view) {
-  info("Testing inline style");
-
-  const onTab = waitForTab();
-  info("Clicking on the first link in the rule-view");
-  clickLinkByIndex(view, 0);
-
-  const tab = await onTab;
-
-  const tabURI = tab.linkedBrowser.documentURI.spec;
-  ok(tabURI.startsWith("view-source:"), "View source tab is open");
-  info("Closing tab");
-  gBrowser.removeTab(tab);
-}
-
 async function testFirstInlineStyleSheet(view, toolbox, testActor) {
   info("Testing inline stylesheet");
 
   info("Listening for toolbox switch to the styleeditor");
   const onSwitch = waitForStyleEditor(toolbox);
 
   info("Clicking an inline stylesheet");
   clickLinkByIndex(view, 4);
@@ -98,17 +82,16 @@ async function testSecondInlineStyleShee
   info("Waiting for the stylesheet editor to be selected");
   const panel = toolbox.getCurrentPanel();
   const onSelected = panel.UI.once("editor-selected");
 
   info("Switching back to the inspector panel in the toolbox");
   await toolbox.selectTool("inspector");
 
   info("Clicking on second inline stylesheet link");
-  testRuleViewLinkLabel(view);
   clickLinkByIndex(view, 3);
   const editor = await onSelected;
 
   is(toolbox.currentToolId, "styleeditor",
     "The style editor is selected again");
   await validateStyleEditorSheet(editor, 1, testActor);
 }
 
@@ -118,35 +101,34 @@ async function testExternalStyleSheet(vi
   info("Waiting for the stylesheet editor to be selected");
   const panel = toolbox.getCurrentPanel();
   const onSelected = panel.UI.once("editor-selected");
 
   info("Switching back to the inspector panel in the toolbox");
   await toolbox.selectTool("inspector");
 
   info("Clicking on an external stylesheet link");
-  testRuleViewLinkLabel(view);
   clickLinkByIndex(view, 1);
   const editor = await onSelected;
 
   is(toolbox.currentToolId, "styleeditor",
     "The style editor is selected again");
   await validateStyleEditorSheet(editor, 2, testActor);
 }
 
 async function validateStyleEditorSheet(editor, expectedSheetIndex, testActor) {
   info("validating style editor stylesheet");
   is(editor.styleSheet.styleSheetIndex, expectedSheetIndex,
      "loaded stylesheet index matches document stylesheet");
 
   const href = editor.styleSheet.href || editor.styleSheet.nodeHref;
 
   const expectedHref = await testActor.eval(
-    `content.document.styleSheets[${expectedSheetIndex}].href ||
-     content.document.location.href`);
+    `document.styleSheets[${expectedSheetIndex}].href ||
+     document.location.href`);
 
   is(href, expectedHref, "loaded stylesheet href matches document stylesheet");
 }
 
 async function testDisabledStyleEditor(view, toolbox) {
   info("Testing with the style editor disabled");
 
   info("Switching to the inspector panel in the toolbox");
@@ -178,19 +160,19 @@ async function testDisabledStyleEditor(v
 function testRuleViewLinkLabel(view) {
   info("Checking the data URL link label");
 
   let link = getRuleViewLinkByIndex(view, 1);
   let labelElem = link.querySelector(".ruleview-rule-source-label");
   let value = labelElem.textContent;
   let tooltipText = labelElem.getAttribute("title");
 
-  is(value, `${STYLESHEET_DATA_URL_CONTENTS}:1`,
+  is(value, encodeURIComponent(STYLESHEET_DATA_URL_CONTENTS) + ":1",
     "Rule view data URL stylesheet display value matches contents");
-  is(tooltipText, `${STYLESHEET_DECODED_DATA_URL}:1`,
+  is(tooltipText, STYLESHEET_DATA_URL + ":1",
     "Rule view data URL stylesheet tooltip text matches the full URI path");
 
   info("Checking the external link label");
   link = getRuleViewLinkByIndex(view, 2);
   labelElem = link.querySelector(".ruleview-rule-source-label");
   value = labelElem.textContent;
   tooltipText = labelElem.getAttribute("title");
 
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -278,17 +278,22 @@ RuleEditor.prototype = {
     if (this.source.hasAttribute("unselectable") || !this._currentLocation) {
       return;
     }
 
     const target = this.ruleView.inspector.target;
     if (Tools.styleEditor.isTargetSupported(target)) {
       gDevTools.showToolbox(target, "styleeditor").then(toolbox => {
         const {url, line, column} = this._currentLocation;
-        toolbox.getCurrentPanel().selectStyleSheet(url, line, column);
+
+        if (!this.rule.sheet.href && this.rule.sheet.nodeHref) {
+          toolbox.getCurrentPanel().selectStyleSheet(this.rule.sheet, line, column);
+        } else {
+          toolbox.getCurrentPanel().selectStyleSheet(url, line, column);
+        }
       });
     }
   },
 
   /**
    * Update the text of the source link to reflect whether we're showing
    * original sources or not.  This is a callback for
    * SourceMapURLService.subscribe, which see.
--- a/devtools/client/shared/test/browser_dbg_WorkerTargetActor.attach.js
+++ b/devtools/client/shared/test/browser_dbg_WorkerTargetActor.attach.js
@@ -39,40 +39,40 @@ function test() {
 
     // If a page still has pending network requests, it will not be moved into
     // the bfcache. Consequently, we cannot use waitForWorkerListChanged here,
     // because the worker is not guaranteed to have finished loading when it is
     // registered. Instead, we have to wait for the promise returned by
     // createWorker in the tab to be resolved.
     yield createWorkerInTab(tab, WORKER1_URL);
     let { workers } = yield listWorkers(targetFront);
-    let [, workerClient1] = yield attachWorker(targetFront,
+    let [, workerTargetFront1] = yield attachWorker(targetFront,
                                                findWorker(workers, WORKER1_URL));
-    is(workerClient1.isClosed, false, "worker in tab 1 should not be closed");
+    is(workerTargetFront1.isClosed, false, "worker in tab 1 should not be closed");
 
     executeSoon(() => {
       BrowserTestUtils.loadURI(tab.linkedBrowser, TAB2_URL);
     });
-    yield waitForWorkerClose(workerClient1);
-    is(workerClient1.isClosed, true, "worker in tab 1 should be closed");
+    yield waitForWorkerClose(workerTargetFront1);
+    is(workerTargetFront1.isClosed, true, "worker in tab 1 should be closed");
 
     yield createWorkerInTab(tab, WORKER2_URL);
     ({ workers } = yield listWorkers(targetFront));
-    const [, workerClient2] = yield attachWorker(targetFront,
+    const [, workerTargetFront2] = yield attachWorker(targetFront,
                                                findWorker(workers, WORKER2_URL));
-    is(workerClient2.isClosed, false, "worker in tab 2 should not be closed");
+    is(workerTargetFront2.isClosed, false, "worker in tab 2 should not be closed");
 
     executeSoon(() => {
       tab.linkedBrowser.goBack();
     });
-    yield waitForWorkerClose(workerClient2);
-    is(workerClient2.isClosed, true, "worker in tab 2 should be closed");
+    yield waitForWorkerClose(workerTargetFront2);
+    is(workerTargetFront2.isClosed, true, "worker in tab 2 should be closed");
 
     ({ workers } = yield listWorkers(targetFront));
-    [, workerClient1] = yield attachWorker(targetFront,
+    [, workerTargetFront1] = yield attachWorker(targetFront,
                                            findWorker(workers, WORKER1_URL));
-    is(workerClient1.isClosed, false, "worker in tab 1 should not be closed");
+    is(workerTargetFront1.isClosed, false, "worker in tab 1 should not be closed");
 
     yield close(client);
     SpecialPowers.setIntPref(MAX_TOTAL_VIEWERS, oldMaxTotalViewers);
     finish();
   });
 }
--- a/devtools/client/shared/test/browser_dbg_worker-console-01.js
+++ b/devtools/client/shared/test/browser_dbg_worker-console-01.js
@@ -13,22 +13,22 @@
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
 var TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
 var WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
 
 add_task(async function testNormalExecution() {
-  const {client, tab, workerClient, toolbox} =
+  const {client, tab, workerTargetFront, toolbox} =
     await initWorkerDebugger(TAB_URL, WORKER_URL);
 
   const jsterm = await getSplitConsole(toolbox);
   const executed = await jsterm.execute("this.location.toString()");
   ok(executed.textContent.includes(WORKER_URL),
       "Evaluating the global's location works");
 
   terminateWorkerInTab(tab, WORKER_URL);
-  await waitForWorkerClose(workerClient);
-  await gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
+  await waitForWorkerClose(workerTargetFront);
+  await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
   await close(client);
   await removeTab(tab);
 });
--- a/devtools/client/shared/test/browser_dbg_worker-console-02.js
+++ b/devtools/client/shared/test/browser_dbg_worker-console-02.js
@@ -14,17 +14,17 @@ Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/shared/test/helper_workers.js",
   this);
 
 var TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
 var WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
 
 add_task(async function testWhilePaused() {
   const dbg = await initWorkerDebugger(TAB_URL, WORKER_URL);
-  const {client, tab, workerClient, toolbox} = dbg;
+  const {client, tab, workerTargetFront, toolbox} = dbg;
 
   // Execute some basic math to make sure evaluations are working.
   const jsterm = await getSplitConsole(toolbox);
   let executed = await jsterm.execute("10000+1");
   ok(executed.textContent.includes("10001"), "Text for message appeared correct");
 
   await clickElement(dbg, "pause");
   once(dbg.client, "willInterrupt").then(() => {
@@ -50,13 +50,13 @@ add_task(async function testWhilePaused(
   info("Trying to get the result of command3");
   executed = await command3;
   ok(executed.textContent.includes("ReferenceError: foobar is not defined"),
      "command3 executed successfully");
 
   await resume(dbg);
 
   terminateWorkerInTab(tab, WORKER_URL);
-  await waitForWorkerClose(workerClient);
-  await gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
+  await waitForWorkerClose(workerTargetFront);
+  await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
   await close(client);
   await removeTab(tab);
 });
--- a/devtools/client/shared/test/browser_dbg_worker-console-03.js
+++ b/devtools/client/shared/test/browser_dbg_worker-console-03.js
@@ -15,17 +15,17 @@ Services.scriptloader.loadSubScript(
   this);
 
 var TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
 var WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
 
 // Test to see if creating the pause from the console works.
 add_task(async function testPausedByConsole() {
   const dbg = await initWorkerDebugger(TAB_URL, WORKER_URL);
-  const {client, tab, workerClient, toolbox} = dbg;
+  const {client, tab, workerTargetFront, toolbox} = dbg;
 
   const jsterm = await getSplitConsole(toolbox);
   let executed = await jsterm.execute("10000+1");
   ok(executed.textContent.includes("10001"),
       "Text for message appeared correct");
 
   await clickElement(dbg, "pause");
 
@@ -41,13 +41,13 @@ add_task(async function testPausedByCons
   info("Waiting for a resume");
   await clickElement(dbg, "resume");
 
   executed = await pausedExecution;
   ok(executed.textContent.includes("10002"),
       "Text for message appeared correct");
 
   terminateWorkerInTab(tab, WORKER_URL);
-  await waitForWorkerClose(workerClient);
-  await gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
+  await waitForWorkerClose(workerTargetFront);
+  await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
   await close(client);
   await removeTab(tab);
 });
--- a/devtools/client/shared/test/browser_dbg_worker-console-04.js
+++ b/devtools/client/shared/test/browser_dbg_worker-console-04.js
@@ -22,28 +22,28 @@ Services.scriptloader.loadSubScript(
 // See bug 1018184 for resolving these issues.
 const { PromiseTestUtils } = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
 PromiseTestUtils.whitelistRejectionsGlobally(/connection just closed/);
 
 const TAB_URL = EXAMPLE_URL + "doc_WorkerTargetActor.attachThread-tab.html";
 const WORKER_URL = "code_WorkerTargetActor.attachThread-worker.js";
 
 add_task(async function testPausedByConsole() {
-  const {client, tab, workerClient, toolbox} =
+  const {client, tab, workerTargetFront, toolbox} =
     await initWorkerDebugger(TAB_URL, WORKER_URL);
 
   info("Check Date objects can be used in the console");
   const jsterm = await getSplitConsole(toolbox);
   let executed = await jsterm.execute("new Date(0)");
   ok(executed.textContent.includes("1970-01-01T00:00:00.000Z"),
       "Text for message appeared correct");
 
   info("Check RegExp objects can be used in the console");
   executed = await jsterm.execute("new RegExp('.*')");
   ok(executed.textContent.includes("/.*/"),
       "Text for message appeared correct");
 
   terminateWorkerInTab(tab, WORKER_URL);
-  await waitForWorkerClose(workerClient);
-  await gDevTools.closeToolbox(TargetFactory.forWorker(workerClient));
+  await waitForWorkerClose(workerTargetFront);
+  await gDevTools.closeToolbox(TargetFactory.forWorker(workerTargetFront));
   await close(client);
   await removeTab(tab);
 });
--- a/devtools/client/shared/test/helper_workers.js
+++ b/devtools/client/shared/test/helper_workers.js
@@ -113,24 +113,24 @@ function findWorker(workers, url) {
   return null;
 }
 
 function attachWorker(targetFront, worker) {
   info("Attaching to worker with url '" + worker.url + "'.");
   return targetFront.attachWorker(worker.actor);
 }
 
-function attachThread(workerClient, options) {
+function attachThread(workerTargetFront, options) {
   info("Attaching to thread.");
-  return workerClient.attachThread(options);
+  return workerTargetFront.attachThread(options);
 }
 
-async function waitForWorkerClose(workerClient) {
+async function waitForWorkerClose(workerTargetFront) {
   info("Waiting for worker to close.");
-  await workerClient.once("close");
+  await workerTargetFront.once("close");
   info("Worker did close.");
 }
 
 // Return a promise with a reference to jsterm, opening the split
 // console if necessary.  This cleans up the split console pref so
 // it won't pollute other tests.
 function getSplitConsole(toolbox, win) {
   if (!win) {
@@ -159,30 +159,30 @@ async function initWorkerDebugger(TAB_UR
 
   const tab = await addTab(TAB_URL);
   const { tabs } = await listTabs(client);
   const [, targetFront] = await attachTarget(client, findTab(tabs, TAB_URL));
 
   await createWorkerInTab(tab, WORKER_URL);
 
   const { workers } = await listWorkers(targetFront);
-  const [, workerClient] = await attachWorker(targetFront,
+  const [, workerTargetFront] = await attachWorker(targetFront,
                                              findWorker(workers, WORKER_URL));
 
-  const toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
+  const toolbox = await gDevTools.showToolbox(TargetFactory.forWorker(workerTargetFront),
                                             "jsdebugger",
                                             Toolbox.HostType.WINDOW);
 
   const debuggerPanel = toolbox.getCurrentPanel();
 
   const gDebugger = debuggerPanel.panelWin;
 
   const context = createDebuggerContext(toolbox);
 
-  return { ...context, client, tab, targetFront, workerClient, toolbox, gDebugger};
+  return { ...context, client, tab, targetFront, workerTargetFront, toolbox, gDebugger};
 }
 
 // Override addTab/removeTab as defined by shared-head, since these have
 // an extra window parameter and add a frame script
 this.addTab = function addTab(url, win) {
   info("Adding tab: " + url);
 
   const deferred = getDeferredPromise().defer();
--- a/devtools/server/actors/highlighters.js
+++ b/devtools/server/actors/highlighters.js
@@ -108,19 +108,16 @@ exports.HighlighterActor = protocol.Acto
 
   get conn() {
     return this._inspector && this._inspector.conn;
   },
 
   form: function() {
     return {
       actor: this.actorID,
-      traits: {
-        autoHideOnDestroy: true
-      }
     };
   },
 
   _createHighlighter: function() {
     this._isPreviousWindowXUL = isXUL(this._targetActor.window);
 
     if (!this._isPreviousWindowXUL) {
       this._highlighter = new BoxModelHighlighter(this._highlighterEnv,
--- a/devtools/server/actors/layout.js
+++ b/devtools/server/actors/layout.js
@@ -310,33 +310,39 @@ const LayoutActor = ActorClassWithSpec(l
     if (node.rawNode) {
       node = node.rawNode;
     }
 
     const treeWalker = this.walker.getDocumentWalker(node, SHOW_ELEMENT);
     let currentNode = treeWalker.currentNode;
     let displayType = this.walker.getNode(currentNode).displayType;
 
-    if (!displayType) {
-      return null;
-    }
-
-    if (type == "flex") {
-      if (displayType == "inline-flex" || displayType == "flex") {
-        return new FlexboxActor(this, currentNode);
-      } else if (onlyLookAtCurrentNode) {
+    // If the node is an element, check first if it is itself a flex or a grid.
+    if (currentNode.nodeType === currentNode.ELEMENT_NODE) {
+      if (!displayType) {
         return null;
       }
-    } else if (type == "grid" &&
-               (displayType == "inline-grid" || displayType == "grid")) {
-      return new GridActor(this, currentNode);
+
+      if (type == "flex") {
+        if (displayType == "inline-flex" || displayType == "flex") {
+          return new FlexboxActor(this, currentNode);
+        } else if (onlyLookAtCurrentNode) {
+          return null;
+        }
+      } else if (type == "grid" &&
+                 (displayType == "inline-grid" || displayType == "grid")) {
+        return new GridActor(this, currentNode);
+      }
     }
 
     // Otherwise, check if this is a flex/grid item or the parent node is a flex/grid
     // container.
+    // Note that text nodes that are children of flex/grid containers are wrapped in
+    // anonymous containers, so even if their displayType getter returns null we still
+    // want to walk up the chain to find their container.
     while ((currentNode = treeWalker.parentNode())) {
       if (!currentNode) {
         break;
       }
 
       displayType = this.walker.getNode(currentNode).displayType;
 
       if (type == "flex" &&
--- a/devtools/server/actors/root.js
+++ b/devtools/server/actors/root.js
@@ -111,19 +111,16 @@ function RootActor(connection, parameter
 }
 
 RootActor.prototype = {
   constructor: RootActor,
   applicationType: "browser",
 
   traits: {
     sources: true,
-    // Whether the server-side highlighter actor exists and can be used to
-    // remotely highlight nodes (see server/actors/highlighters.js)
-    highlightable: true,
     networkMonitor: true,
     // Whether the storage inspector actor to inspect cookies, etc.
     storageInspector: true,
     // Whether storage inspector is read only
     storageInspectorReadOnly: true,
     // Whether conditional breakpoints are supported
     conditionalBreakpoints: true,
     // Whether the server supports full source actors (breakpoints on
--- a/devtools/server/actors/targets/addon.js
+++ b/devtools/server/actors/targets/addon.js
@@ -91,17 +91,16 @@ AddonTargetActor.prototype = {
       debuggable: this._addon.isDebuggable,
       temporarilyInstalled: this._addon.temporarilyInstalled,
       type: this._addon.type,
       isWebExtension: this._addon.isWebExtension,
       isAPIExtension: this._addon.isAPIExtension,
       consoleActor: this._consoleActor.actorID,
 
       traits: {
-        highlightable: false,
         networkMonitor: false,
       },
     };
   },
 
   destroy() {
     this.conn.removeActorPool(this._contextPool);
     this._contextPool = null;
--- a/devtools/server/actors/targets/content-process.js
+++ b/devtools/server/actors/targets/content-process.js
@@ -114,17 +114,16 @@ ContentProcessTargetActor.prototype = {
       name: "Content process",
 
       consoleActor: this._consoleActor.actorID,
       chromeDebugger: this.threadActor.actorID,
       memoryActor: this.memoryActor.actorID,
       promisesActor: this._promisesActor.actorID,
 
       traits: {
-        highlightable: false,
         networkMonitor: false,
       },
     };
   },
 
   onListWorkers: function() {
     if (!this._workerList) {
       this._workerList = new WorkerTargetActorList(this.conn, {});
--- a/devtools/shared/client/thread-client.js
+++ b/devtools/shared/client/thread-client.js
@@ -20,17 +20,17 @@ loader.lazyRequireGetter(this, "SourceCl
 
 const noop = () => {};
 
 /**
  * Creates a thread client for the remote debugging protocol server. This client
  * is a front to the thread actor created in the server side, hiding the
  * protocol details in a traditional JavaScript API.
  *
- * @param client DebuggerClient, WorkerClient or BrowsingContextFront
+ * @param client DebuggerClient, WorkerTargetFront or BrowsingContextFront
  *        The parent of the thread (tab for target-scoped debuggers,
  *        DebuggerClient for chrome debuggers).
  * @param actor string
  *        The actor ID for this thread.
  */
 function ThreadClient(client, actor) {
   this._parent = client;
   this.client = client instanceof DebuggerClient ? client : client.client;
--- a/devtools/shared/protocol.js
+++ b/devtools/shared/protocol.js
@@ -1599,17 +1599,23 @@ var generateRequestMethods = function(ac
  * @param object proto
  *    The object prototype.  Must have a 'typeName' property,
  *    should have method definitions, can have event definitions.
  */
 var FrontClassWithSpec = function(actorSpec, frontProto) {
   // Existing Fronts are relying on the initialize instead of constructor methods.
   const cls = function() {
     const instance = Object.create(cls.prototype);
-    instance.initialize.apply(instance, arguments);
+    const initializer = instance.initialize.apply(instance, arguments);
+
+    // Async Initialization
+    // return a promise that resolves with the instance if the initializer is async
+    if (initializer && typeof initializer.then === "function") {
+      return initializer.then(resolve => instance);
+    }
     return instance;
   };
   cls.prototype = extend(Front.prototype, generateRequestMethods(actorSpec, frontProto));
 
   if (!registeredTypes.has(actorSpec.typeName)) {
     types.addActorType(actorSpec.typeName);
   }
   registeredTypes.get(actorSpec.typeName).frontClass = cls;
--- a/devtools/shared/webconsole/test/common.js
+++ b/devtools/shared/webconsole/test/common.js
@@ -106,26 +106,26 @@ var _attachConsole = async function(
 
     const { workers } = await targetFront.listWorkers();
     const workerTargetActor = workers.filter(w => w.url == workerName)[0].actor;
     if (!workerTargetActor) {
       console.error("listWorkers failed. Unable to find the " +
                     "worker actor\n");
       return;
     }
-    const [workerResponse, workerClient] =
+    const [workerResponse, workerTargetFront] =
       await targetFront.attachWorker(workerTargetActor);
-    if (!workerClient || workerResponse.error) {
-      console.error("attachWorker failed. No worker client or " +
+    if (!workerTargetFront || workerResponse.error) {
+      console.error("attachWorker failed. No worker target front or " +
                     " error: " + workerResponse.error);
       return;
     }
-    await workerClient.attachThread({});
-    state.actor = workerClient.consoleActor;
-    state.dbgClient.attachConsole(workerClient.consoleActor, listeners)
+    await workerTargetFront.attachThread({});
+    state.actor = workerTargetFront.consoleActor;
+    state.dbgClient.attachConsole(workerTargetFront.consoleActor, listeners)
       .then(_onAttachConsole.bind(null, state), _onAttachError.bind(null, state));
   } else {
     state.actor = tab.consoleActor;
     state.dbgClient.attachConsole(tab.consoleActor, listeners)
       .then(_onAttachConsole.bind(null, state), _onAttachError.bind(null, state));
   }
 };
 
rename from dom/webidl/Flex.webidl
rename to dom/chrome-webidl/Flex.webidl
--- a/dom/webidl/Flex.webidl
+++ b/dom/chrome-webidl/Flex.webidl
@@ -4,50 +4,73 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 /**
  * These objects support visualization of flex containers by the
  * dev tools.
  */
 
+/**
+ * A flex container's main and cross axes are either horizontal or
+ * vertical, each with two possible directions.
+ */
+enum FlexPhysicalDirection {
+  "horizontal-lr",
+  "horizontal-rl",
+  "vertical-tb",
+  "vertical-bt",
+};
+
 [ChromeOnly]
 interface Flex
 {
-  sequence<FlexLine> getLines();
+  sequence<FlexLineValues> getLines();
+
+  /**
+   * The physical direction in which successive flex items are placed,
+   * within a flex line in this flex container.
+   */
+  readonly attribute FlexPhysicalDirection mainAxisDirection;
+
+  /**
+   * The physical direction in which successive flex lines are placed
+   * in this flex container (if it is or were multi-line).
+   */
+  readonly attribute FlexPhysicalDirection crossAxisDirection;
 };
 
 /**
  * Lines with items that have been shrunk are shrinking; with items
  * that have grown are growing, and all others are unchanged.
  */
 enum FlexLineGrowthState { "unchanged", "shrinking", "growing" };
 
 [ChromeOnly]
-interface FlexLine
+interface FlexLineValues
 {
   readonly attribute FlexLineGrowthState growthState;
   readonly attribute double crossStart;
   readonly attribute double crossSize;
 
   // firstBaselineOffset measures from flex-start edge.
   readonly attribute double firstBaselineOffset;
 
   // lastBaselineOffset measures from flex-end edge.
   readonly attribute double lastBaselineOffset;
 
   /**
-   * getItems() returns FlexItems only for the Elements in this Flex
-   * container -- ignoring struts and abs-pos Elements.
+   * getItems() returns FlexItemValues only for the Elements in
+   * this Flex container -- ignoring struts and abs-pos Elements.
    */
-  sequence<FlexItem> getItems();
+  sequence<FlexItemValues> getItems();
 };
 
 [ChromeOnly]
-interface FlexItem
+interface FlexItemValues
 {
   readonly attribute Node? node;
   readonly attribute double mainBaseSize;
   readonly attribute double mainDeltaSize;
   readonly attribute double mainMinSize;
   readonly attribute double mainMaxSize;
   readonly attribute double crossMinSize;
   readonly attribute double crossMaxSize;
--- a/dom/chrome-webidl/moz.build
+++ b/dom/chrome-webidl/moz.build
@@ -5,16 +5,19 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 with Files("ChannelWrapper.webidl"):
     BUG_COMPONENT = ("WebExtensions", "Request Handling")
 
+with Files("Flex.webidl"):
+    BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
+
 with Files("HeapSnapshot.webidl"):
     BUG_COMPONENT = ("DevTools", "Memory")
 
 with Files("InspectorUtils.webidl"):
     BUG_COMPONENT = ("DevTools", "Inspector")
 
 with Files("MatchGlob.webidl"):
     BUG_COMPONENT = ("WebExtensions", "General")
@@ -28,16 +31,17 @@ with Files("WebExtension*.webidl"):
 PREPROCESSED_WEBIDL_FILES = [
     'ChromeUtils.webidl',
 ]
 
 WEBIDL_FILES = [
     'BrowsingContext.webidl',
     'ChannelWrapper.webidl',
     'DominatorTree.webidl',
+    'Flex.webidl',
     'HeapSnapshot.webidl',
     'InspectorUtils.webidl',
     'IteratorResult.webidl',
     'MatchGlob.webidl',
     'MatchPattern.webidl',
     'MessageManager.webidl',
     'MozDocumentObserver.webidl',
     'MozSharedMap.webidl',
--- a/dom/flex/Flex.cpp
+++ b/dom/flex/Flex.cpp
@@ -1,17 +1,17 @@
 /* -*- 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 "Flex.h"
 
-#include "FlexLine.h"
+#include "FlexLineValues.h"
 #include "mozilla/dom/FlexBinding.h"
 #include "nsFlexContainerFrame.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Flex, mParent, mLines)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Flex)
@@ -32,28 +32,43 @@ Flex::Flex(Element* aParent,
   // going to keep it around.
   const ComputedFlexContainerInfo* containerInfo =
     aFrame->GetFlexContainerInfo();
   MOZ_ASSERT(containerInfo, "Should only be passed a frame with info.");
 
   mLines.SetLength(containerInfo->mLines.Length());
   uint32_t index = 0;
   for (auto&& l : containerInfo->mLines) {
-    FlexLine* line = new FlexLine(this, &l);
+    FlexLineValues* line = new FlexLineValues(this, &l);
     mLines.ElementAt(index) = line;
     index++;
   }
+
+  mMainAxisDirection = containerInfo->mMainAxisDirection;
+  mCrossAxisDirection = containerInfo->mCrossAxisDirection;
 }
 
 JSObject*
 Flex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return Flex_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void
-Flex::GetLines(nsTArray<RefPtr<FlexLine>>& aResult)
+Flex::GetLines(nsTArray<RefPtr<FlexLineValues>>& aResult)
 {
   aResult.AppendElements(mLines);
 }
 
+FlexPhysicalDirection
+Flex::MainAxisDirection() const
+{
+  return mMainAxisDirection;
+}
+
+FlexPhysicalDirection
+Flex::CrossAxisDirection() const
+{
+  return mCrossAxisDirection;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/flex/Flex.h
+++ b/dom/flex/Flex.h
@@ -3,25 +3,26 @@
 /* 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 mozilla_dom_Flex_h
 #define mozilla_dom_Flex_h
 
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/FlexBinding.h"
 #include "nsISupports.h"
 #include "nsWrapperCache.h"
 
 class nsFlexContainerFrame;
 
 namespace mozilla {
 namespace dom {
 
-class FlexLine;
+class FlexLineValues;
 
 class Flex : public nsISupports
            , public nsWrapperCache
 {
 public:
   explicit Flex(Element* aParent, nsFlexContainerFrame* aFrame);
 
 protected:
@@ -32,19 +33,23 @@ public:
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Flex)
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
   Element* GetParentObject()
   {
     return mParent;
   }
 
-  void GetLines(nsTArray<RefPtr<FlexLine>>& aResult);
+  void GetLines(nsTArray<RefPtr<FlexLineValues>>& aResult);
+  FlexPhysicalDirection MainAxisDirection() const;
+  FlexPhysicalDirection CrossAxisDirection() const;
 
 protected:
   nsCOMPtr<Element> mParent;
-  nsTArray<RefPtr<FlexLine>> mLines;
+  nsTArray<RefPtr<FlexLineValues>> mLines;
+  FlexPhysicalDirection mMainAxisDirection;
+  FlexPhysicalDirection mCrossAxisDirection;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_Flex_h */
rename from dom/flex/FlexItem.cpp
rename to dom/flex/FlexItemValues.cpp
--- a/dom/flex/FlexItem.cpp
+++ b/dom/flex/FlexItemValues.cpp
@@ -1,26 +1,26 @@
 /* -*- 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 "FlexItem.h"
+#include "FlexItemValues.h"
 
 #include "mozilla/dom/FlexBinding.h"
 #include "nsFlexContainerFrame.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexItem, mParent)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexItem)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexItem)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexItem)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexItemValues, mParent)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexItemValues)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexItemValues)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexItemValues)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 /**
  * Utility function to convert a nscoord size to CSS pixel values, with
  * graceful treatment of NS_UNCONSTRAINEDSIZE (which this function converts to
  * the double "positive infinity" value).
@@ -33,18 +33,18 @@ static double
 ToPossiblyUnconstrainedPixels(nscoord aSize)
 {
   if (aSize == NS_UNCONSTRAINEDSIZE) {
     return std::numeric_limits<double>::infinity();
   }
   return nsPresContext::AppUnitsToDoubleCSSPixels(aSize);
 }
 
-FlexItem::FlexItem(FlexLine* aParent,
-                   const ComputedFlexItemInfo* aItem)
+FlexItemValues::FlexItemValues(FlexLineValues* aParent,
+                               const ComputedFlexItemInfo* aItem)
   : mParent(aParent)
 {
   MOZ_ASSERT(aItem,
     "Should never be instantiated with a null ComputedFlexLineInfo.");
 
   // Eagerly copy values from aItem, because we're not
   // going to keep it around.
   mNode = aItem->mNode;
@@ -58,57 +58,57 @@ FlexItem::FlexItem(FlexLine* aParent,
     aItem->mMainMinSize);
   mMainMaxSize = ToPossiblyUnconstrainedPixels(aItem->mMainMaxSize);
   mCrossMinSize = nsPresContext::AppUnitsToDoubleCSSPixels(
     aItem->mCrossMinSize);
   mCrossMaxSize = ToPossiblyUnconstrainedPixels(aItem->mCrossMaxSize);
 }
 
 JSObject*
-FlexItem::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+FlexItemValues::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  return FlexItem_Binding::Wrap(aCx, this, aGivenProto);
+  return FlexItemValues_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 nsINode*
-FlexItem::GetNode() const
+FlexItemValues::GetNode() const
 {
   return mNode;
 }
 
 double
-FlexItem::MainBaseSize() const
+FlexItemValues::MainBaseSize() const
 {
   return mMainBaseSize;
 }
 
 double
-FlexItem::MainDeltaSize() const
+FlexItemValues::MainDeltaSize() const
 {
   return mMainDeltaSize;
 }
 
 double
-FlexItem::MainMinSize() const
+FlexItemValues::MainMinSize() const
 {
   return mMainMinSize;
 }
 
 double
-FlexItem::MainMaxSize() const
+FlexItemValues::MainMaxSize() const
 {
   return mMainMaxSize;
 }
 
 double
-FlexItem::CrossMinSize() const
+FlexItemValues::CrossMinSize() const
 {
   return mCrossMinSize;
 }
 
 double
-FlexItem::CrossMaxSize() const
+FlexItemValues::CrossMaxSize() const
 {
   return mCrossMaxSize;
 }
 
 } // namespace dom
 } // namespace mozilla
rename from dom/flex/FlexItem.h
rename to dom/flex/FlexItemValues.h
--- a/dom/flex/FlexItem.h
+++ b/dom/flex/FlexItemValues.h
@@ -1,65 +1,65 @@
 /* -*- 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 mozilla_dom_FlexItem_h
-#define mozilla_dom_FlexItem_h
+#ifndef mozilla_dom_FlexItemValues_h
+#define mozilla_dom_FlexItemValues_h
 
 #include "mozilla/dom/FlexBinding.h"
 #include "nsISupports.h"
 #include "nsWrapperCache.h"
 
 struct ComputedFlexItemInfo;
 
 namespace mozilla {
 namespace dom {
 
-class FlexLine;
+class FlexLineValues;
 
-class FlexItem : public nsISupports
-               , public nsWrapperCache
+class FlexItemValues : public nsISupports
+                     , public nsWrapperCache
 {
 public:
-  explicit FlexItem(FlexLine* aParent,
-                    const ComputedFlexItemInfo* aItem);
+  explicit FlexItemValues(FlexLineValues* aParent,
+                          const ComputedFlexItemInfo* aItem);
 
 protected:
-  virtual ~FlexItem() = default;
+  virtual ~FlexItemValues() = default;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexItem)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexItemValues)
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-  FlexLine* GetParentObject()
+  FlexLineValues* GetParentObject()
   {
     return mParent;
   }
 
   nsINode* GetNode() const;
   double MainBaseSize() const;
   double MainDeltaSize() const;
   double MainMinSize() const;
   double MainMaxSize() const;
   double CrossMinSize() const;
   double CrossMaxSize() const;
 
 protected:
-  RefPtr<FlexLine> mParent;
+  RefPtr<FlexLineValues> mParent;
   RefPtr<nsINode> mNode;
 
   // These sizes are all CSS pixel units.
   double mMainBaseSize;
   double mMainDeltaSize;
   double mMainMinSize;
   double mMainMaxSize;
   double mCrossMinSize;
   double mCrossMaxSize;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif /* mozilla_dom_FlexItem_h */
+#endif /* mozilla_dom_FlexItemValues_h */
rename from dom/flex/FlexLine.cpp
rename to dom/flex/FlexLineValues.cpp
--- a/dom/flex/FlexLine.cpp
+++ b/dom/flex/FlexLineValues.cpp
@@ -1,33 +1,33 @@
 /* -*- 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 "FlexLine.h"
+#include "FlexLineValues.h"
 
-#include "FlexItem.h"
+#include "FlexItemValues.h"
 #include "mozilla/dom/FlexBinding.h"
 #include "nsFlexContainerFrame.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexLine, mParent, mItems)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexLine)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexLine)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexLine)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexLineValues, mParent, mItems)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexLineValues)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexLineValues)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexLineValues)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-FlexLine::FlexLine(Flex* aParent,
-                   const ComputedFlexLineInfo* aLine)
+FlexLineValues::FlexLineValues(Flex* aParent,
+                               const ComputedFlexLineInfo* aLine)
   : mParent(aParent)
 {
   MOZ_ASSERT(aLine,
     "Should never be instantiated with a null ComputedFlexLineInfo.");
 
   // Eagerly copy values from aLine, because we're not
   // going to keep it around.
   switch (aLine->mGrowthState) {
@@ -51,58 +51,58 @@ FlexLine::FlexLine(Flex* aParent,
   mFirstBaselineOffset = nsPresContext::AppUnitsToDoubleCSSPixels(
     aLine->mFirstBaselineOffset);
   mLastBaselineOffset = nsPresContext::AppUnitsToDoubleCSSPixels(
     aLine->mLastBaselineOffset);
 
   mItems.SetLength(aLine->mItems.Length());
   uint32_t index = 0;
   for (auto&& i : aLine->mItems) {
-    FlexItem* item = new FlexItem(this, &i);
+    FlexItemValues* item = new FlexItemValues(this, &i);
     mItems.ElementAt(index) = item;
     index++;
   }
 }
 
 JSObject*
-FlexLine::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+FlexLineValues::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  return FlexLine_Binding::Wrap(aCx, this, aGivenProto);
+  return FlexLineValues_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 FlexLineGrowthState
-FlexLine::GrowthState() const
+FlexLineValues::GrowthState() const
 {
   return mGrowthState;
 }
 
 double
-FlexLine::CrossStart() const
+FlexLineValues::CrossStart() const
 {
   return mCrossStart;
 }
 
 double
-FlexLine::CrossSize() const
+FlexLineValues::CrossSize() const
 {
   return mCrossSize;
 }
 
 double
-FlexLine::FirstBaselineOffset() const
+FlexLineValues::FirstBaselineOffset() const
 {
   return mFirstBaselineOffset;
 }
 
 double
-FlexLine::LastBaselineOffset() const
+FlexLineValues::LastBaselineOffset() const
 {
   return mLastBaselineOffset;
 }
 
 void
-FlexLine::GetItems(nsTArray<RefPtr<FlexItem>>& aResult)
+FlexLineValues::GetItems(nsTArray<RefPtr<FlexItemValues>>& aResult)
 {
   aResult.AppendElements(mItems);
 }
 
 } // namespace dom
 } // namespace mozilla
rename from dom/flex/FlexLine.h
rename to dom/flex/FlexLineValues.h
--- a/dom/flex/FlexLine.h
+++ b/dom/flex/FlexLineValues.h
@@ -1,65 +1,65 @@
 /* -*- 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 mozilla_dom_FlexLine_h
-#define mozilla_dom_FlexLine_h
+#ifndef mozilla_dom_FlexLineValues_h
+#define mozilla_dom_FlexLineValues_h
 
 #include "mozilla/dom/FlexBinding.h"
 #include "nsISupports.h"
 #include "nsWrapperCache.h"
 
 struct ComputedFlexLineInfo;
 
 namespace mozilla {
 namespace dom {
 
 class Flex;
-class FlexItem;
+class FlexItemValues;
 
-class FlexLine : public nsISupports
-               , public nsWrapperCache
+class FlexLineValues : public nsISupports
+                     , public nsWrapperCache
 {
 public:
-  explicit FlexLine(Flex* aParent,
-                    const ComputedFlexLineInfo* aLine);
+  explicit FlexLineValues(Flex* aParent,
+                          const ComputedFlexLineInfo* aLine);
 
 protected:
-  virtual ~FlexLine() = default;
+  virtual ~FlexLineValues() = default;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexLine)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexLineValues)
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
   Flex* GetParentObject()
   {
     return mParent;
   }
 
   FlexLineGrowthState GrowthState() const;
   double CrossStart() const;
   double CrossSize() const;
   double FirstBaselineOffset() const;
   double LastBaselineOffset() const;
 
-  void GetItems(nsTArray<RefPtr<FlexItem>>& aResult);
+  void GetItems(nsTArray<RefPtr<FlexItemValues>>& aResult);
 
 protected:
   RefPtr<Flex> mParent;
 
   FlexLineGrowthState mGrowthState;
   double mCrossStart;
   double mCrossSize;
   double mFirstBaselineOffset;
   double mLastBaselineOffset;
 
-  nsTArray<RefPtr<FlexItem>> mItems;
+  nsTArray<RefPtr<FlexItemValues>> mItems;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif /* mozilla_dom_FlexLine_h */
+#endif /* mozilla_dom_FlexLineValues_h */
--- a/dom/flex/moz.build
+++ b/dom/flex/moz.build
@@ -6,23 +6,23 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
 
 MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
 
 EXPORTS.mozilla.dom += [
     'Flex.h',
-    'FlexItem.h',
-    'FlexLine.h',
+    'FlexItemValues.h',
+    'FlexLineValues.h',
 ]
 
 UNIFIED_SOURCES += [
     'Flex.cpp',
-    'FlexItem.cpp',
-    'FlexLine.cpp',
+    'FlexItemValues.cpp',
+    'FlexLineValues.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/layout/generic',
 ]
 
 FINAL_LIBRARY = 'xul'
--- a/dom/flex/test/chrome.ini
+++ b/dom/flex/test/chrome.ini
@@ -1,2 +1,3 @@
+[chrome/test_flex_axis_directions.html]
 [chrome/test_flex_items.html]
 [chrome/test_flex_lines.html]
new file mode 100644
--- /dev/null
+++ b/dom/flex/test/chrome/test_flex_axis_directions.html
@@ -0,0 +1,204 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+<style>
+  f {
+    display: flex;
+    width: 400px;
+    height: 50px;
+    margin-bottom: 2px;
+  }
+
+  b {
+    background-color: gold;
+    width: 100px;
+    height: 15px;
+  }
+  b::after {
+    content: "B";
+  }
+
+  c {
+    background-color: yellow;
+    width: 100px;
+    height: 15px;
+  }
+  c::after {
+    content: "C";
+  }
+
+  d {
+    background-color: orange;
+    width: 100px;
+    height: 15px;
+  }
+  d::after {
+    content: "D";
+  }
+
+  .fdR {
+    flex-direction: row;
+    background-color: lightgrey;
+  }
+  .fdRR {
+    flex-direction: row-reverse;
+    background-color: lightgreen;
+  }
+  .fdC {
+    flex-direction: column;
+    background-color: lightblue;
+  }
+  .fdCR {
+    flex-direction: column-reverse;
+    background-color: lavender;
+  }
+
+  .wmHTB {
+    writing-mode: horizontal-tb;
+  }
+  .wmVLR {
+    writing-mode: vertical-lr;
+  }
+  .wmVRL {
+    writing-mode: vertical-rl;
+  }
+  .wmSLR {
+    writing-mode: sideways-lr;
+  }
+  .wmSRL {
+    writing-mode: sideways-rl;
+  }
+
+  .dLR {
+    direction: ltr;
+  }
+  .dRL {
+    direction: rtl;
+  }
+</style>
+
+<script>
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+function testContainerMatchesExpectedValues(flex, values, flexIndex) {
+  is(flex.mainAxisDirection, values.m, "Flex index " + flexIndex + " should have expected mainAxisDirection.");
+  is(flex.crossAxisDirection, values.c, "Flex index " + flexIndex + " should have expected crossAxisDirection.");
+}
+
+function runTests() {
+  const expectedValues = [
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "vertical-tb", c: "horizontal-lr" },
+    { m: "vertical-bt", c: "horizontal-lr" },
+    { m: "vertical-tb", c: "horizontal-rl" },
+    { m: "vertical-bt", c: "horizontal-rl" },
+    { m: "vertical-bt", c: "horizontal-lr" },
+    { m: "vertical-tb", c: "horizontal-lr" },
+    { m: "vertical-tb", c: "horizontal-rl" },
+    { m: "vertical-bt", c: "horizontal-rl" },
+
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "vertical-bt", c: "horizontal-lr" },
+    { m: "vertical-tb", c: "horizontal-lr" },
+    { m: "vertical-bt", c: "horizontal-rl" },
+    { m: "vertical-tb", c: "horizontal-rl" },
+    { m: "vertical-tb", c: "horizontal-lr" },
+    { m: "vertical-bt", c: "horizontal-lr" },
+    { m: "vertical-bt", c: "horizontal-rl" },
+    { m: "vertical-tb", c: "horizontal-rl" },
+
+    { m: "vertical-tb", c: "horizontal-lr" },
+    { m: "vertical-tb", c: "horizontal-rl" },
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "horizontal-lr", c: "vertical-bt" },
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "horizontal-rl", c: "vertical-bt" },
+    { m: "horizontal-lr", c: "vertical-bt" },
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "horizontal-rl", c: "vertical-bt" },
+
+    { m: "vertical-bt", c: "horizontal-lr" },
+    { m: "vertical-bt", c: "horizontal-rl" },
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "horizontal-rl", c: "vertical-bt" },
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "horizontal-lr", c: "vertical-bt" },
+    { m: "horizontal-rl", c: "vertical-bt" },
+    { m: "horizontal-rl", c: "vertical-tb" },
+    { m: "horizontal-lr", c: "vertical-tb" },
+    { m: "horizontal-lr", c: "vertical-bt" },
+  ];
+
+  const children = document.body.children;
+  is(children.length, expectedValues.length, "Document should have expected number of flex containers.");
+
+  for (let i = 0; i < children.length; ++i) {
+    const flex = children.item(i).getAsFlexContainer();
+    ok(flex, "Document child index " + i + " should be a flex container.");
+    if (flex) {
+      const values = expectedValues[i];
+      testContainerMatchesExpectedValues(flex, values, i);
+    }
+  }
+
+  SimpleTest.finish();
+}
+</script>
+</head>
+
+<body onLoad="runTests();">
+
+<f class="fdR wmHTB dLR"><b></b><c></c><d></d></f>
+<f class="fdR wmHTB dRL"><b></b><c></c><d></d></f>
+<f class="fdR wmVLR dLR"><b></b><c></c><d></d></f>
+<f class="fdR wmVLR dRL"><b></b><c></c><d></d></f>
+<f class="fdR wmVRL dLR"><b></b><c></c><d></d></f>
+<f class="fdR wmVRL dRL"><b></b><c></c><d></d></f>
+<f class="fdR wmSLR dLR"><b></b><c></c><d></d></f>
+<f class="fdR wmSLR dRL"><b></b><c></c><d></d></f>
+<f class="fdR wmSRL dLR"><b></b><c></c><d></d></f>
+<f class="fdR wmSRL dRL"><b></b><c></c><d></d></f>
+
+<f class="fdRR wmHTB dLR"><b></b><c></c><d></d></f>
+<f class="fdRR wmHTB dRL"><b></b><c></c><d></d></f>
+<f class="fdRR wmVLR dLR"><b></b><c></c><d></d></f>
+<f class="fdRR wmVLR dRL"><b></b><c></c><d></d></f>
+<f class="fdRR wmVRL dLR"><b></b><c></c><d></d></f>
+<f class="fdRR wmVRL dRL"><b></b><c></c><d></d></f>
+<f class="fdRR wmSLR dLR"><b></b><c></c><d></d></f>
+<f class="fdRR wmSLR dRL"><b></b><c></c><d></d></f>
+<f class="fdRR wmSRL dLR"><b></b><c></c><d></d></f>
+<f class="fdRR wmSRL dRL"><b></b><c></c><d></d></f>
+
+<f class="fdC wmHTB dLR"><b></b><c></c><d></d></f>
+<f class="fdC wmHTB dRL"><b></b><c></c><d></d></f>
+<f class="fdC wmVLR dLR"><b></b><c></c><d></d></f>
+<f class="fdC wmVLR dRL"><b></b><c></c><d></d></f>
+<f class="fdC wmVRL dLR"><b></b><c></c><d></d></f>
+<f class="fdC wmVRL dRL"><b></b><c></c><d></d></f>
+<f class="fdC wmSLR dLR"><b></b><c></c><d></d></f>
+<f class="fdC wmSLR dRL"><b></b><c></c><d></d></f>
+<f class="fdC wmSRL dLR"><b></b><c></c><d></d></f>
+<f class="fdC wmSRL dRL"><b></b><c></c><d></d></f>
+
+<f class="fdCR wmHTB dLR"><b></b><c></c><d></d></f>
+<f class="fdCR wmHTB dRL"><b></b><c></c><d></d></f>
+<f class="fdCR wmVLR dLR"><b></b><c></c><d></d></f>
+<f class="fdCR wmVLR dRL"><b></b><c></c><d></d></f>
+<f class="fdCR wmVRL dLR"><b></b><c></c><d></d></f>
+<f class="fdCR wmVRL dRL"><b></b><c></c><d></d></f>
+<f class="fdCR wmSLR dLR"><b></b><c></c><d></d></f>
+<f class="fdCR wmSLR dRL"><b></b><c></c><d></d></f>
+<f class="fdCR wmSRL dLR"><b></b><c></c><d></d></f>
+<f class="fdCR wmSRL dRL"><b></b><c></c><d></d></f>
+
+</body>
+</html>
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2710,17 +2710,18 @@ MediaDecoderStateMachine::MediaDecoderSt
   INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
   INIT_MIRROR(mVolume, 1.0),
   INIT_MIRROR(mPreservesPitch, true),
   INIT_MIRROR(mLooping, false),
   INIT_MIRROR(mSameOriginMedia, false),
   INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
   INIT_CANONICAL(mDuration, NullableTimeUnit()),
   INIT_CANONICAL(mCurrentPosition, TimeUnit::Zero()),
-  INIT_CANONICAL(mIsAudioDataAudible, false)
+  INIT_CANONICAL(mIsAudioDataAudible, false),
+  mSetSinkRequestsCount(0)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   InitVideoQueuePrefs();
 
   DDLINKCHILD("reader", aReader);
 }
@@ -3669,17 +3670,17 @@ MediaDecoderStateMachine::LoopingChanged
 }
 
 RefPtr<GenericPromise>
 MediaDecoderStateMachine::InvokeSetSink(RefPtr<AudioDeviceInfo> aSink)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aSink);
 
-  ++mSetSinkRequestsCount;
+  Unused << ++mSetSinkRequestsCount;
   return InvokeAsync(
            OwnerThread(), this, __func__,
            &MediaDecoderStateMachine::SetSink, aSink);
 }
 
 RefPtr<GenericPromise>
 MediaDecoderStateMachine::SetSink(RefPtr<AudioDeviceInfo> aSink)
 {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -98,19 +98,16 @@ with Files("DynamicsCompressorNode.webid
     BUG_COMPONENT = ("Core", "Web Audio")
 
 with Files("FakePluginTagInit.webidl"):
     BUG_COMPONENT = ("Core", "Plug-ins")
 
 with Files("FeaturePolicy.webidl"):
     BUG_COMPONENT = ("Core", "DOM: Security")
 
-with Files("Flex.webidl"):
-    BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
-
 with Files("FocusEvent.webidl"):
     BUG_COMPONENT = ("Core", "DOM: Events")
 
 with Files("Font*"):
     BUG_COMPONENT = ("Core", "CSS Parsing and Computation")
 
 with Files("FormData.webidl"):
     BUG_COMPONENT = ("Core", "DOM: Core & HTML")
@@ -502,17 +499,16 @@ WEBIDL_FILES = [
     'FileMode.webidl',
     'FileReader.webidl',
     'FileReaderSync.webidl',
     'FileSystem.webidl',
     'FileSystemDirectoryEntry.webidl',
     'FileSystemDirectoryReader.webidl',
     'FileSystemEntry.webidl',
     'FileSystemFileEntry.webidl',
-    'Flex.webidl',
     'FocusEvent.webidl',
     'FontFace.webidl',
     'FontFaceSet.webidl',
     'FontFaceSource.webidl',
     'FormData.webidl',
     'FrameLoader.webidl',
     'Function.webidl',
     'GainNode.webidl',
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -393,26 +393,34 @@ skip-if(!xulRuntime.shell) script test26
 skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-nan.js
 skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-two.js
 skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-in-order.js
 skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-one.js
 skip-if(!xulRuntime.shell) script test262/built-ins/Atomics/wake/wake-all-on-loc.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1346081
 skip script test262/intl402/NumberFormat/prototype/format/format-fraction-digits.js
+skip script test262/intl402/NumberFormat/prototype/format/format-fraction-digits-precision.js
 skip script test262/intl402/NumberFormat/prototype/format/format-significant-digits.js
+skip script test262/intl402/NumberFormat/prototype/format/format-significant-digits-precision.js
 
 # Hoisted block-level function named "arguments" not initialized with undefined per B.3.3.1
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1339123
 skip script test262/annexB/language/function-code/block-decl-func-skip-arguments.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1407587
 skip script test262/language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order.js
 skip script test262/language/expressions/assignment/destructuring/iterator-destructuring-property-reference-target-evaluation-order.js
 
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1495072
+skip script test262/language/expressions/await/await-monkey-patched-promise.js
+skip script test262/language/expressions/await/async-await-interleaved.js
+skip script test262/language/expressions/await/for-await-of-interleaved.js
+skip script test262/language/expressions/await/async-generator-interleaved.js
+
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1321616
 skip script test262/annexB/built-ins/Function/createdynfn-html-close-comment-params.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1334813
 skip script test262/built-ins/DataView/length.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1462741
 skip script test262/built-ins/Function/prototype/toString/well-known-intrinsic-object-functions.js
@@ -445,16 +453,21 @@ skip script test262/intl402/RelativeTime
 skip script test262/intl402/RelativeTimeFormat/prototype/format/unit-plural.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1483547
 skip script test262/intl402/RelativeTimeFormat/prototype/format/pl-pl-style-short.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1483548
 skip script test262/intl402/RelativeTimeFormat/prototype/format/value-non-finite.js
 
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1499933
+skip script test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
+skip script test262/intl402/PluralRules/prototype/resolvedOptions/order.js
+skip script test262/intl402/NumberFormat/prototype/resolvedOptions/order.js
+
 
 ###########################################################
 # Tests disabled due to issues in test262 importer script #
 ###########################################################
 
 # test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
 skip script test262/harness/detachArrayBuffer.js
 
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -16,32 +16,39 @@ import sys
 
 from functools import partial
 from itertools import chain
 
 # Skip all tests which use features not supported in SpiderMonkey.
 UNSUPPORTED_FEATURES = set([
     "tail-call-optimization",
     "class-fields-public",
+    "class-static-fields-public",
     "class-fields-private",
+    "class-static-fields-private",
+    "class-methods-private",
+    "class-static-methods-private",
+    "dynamic-import",
     "regexp-dotall",
     "regexp-lookbehind",
     "regexp-named-groups",
     "regexp-unicode-property-escapes",
     "numeric-separator-literal",
     "Intl.Locale",
     "String.prototype.matchAll",
     "Symbol.matchAll",
     "global",
     "export-star-as-namespace-from-module",
 ])
 FEATURE_CHECK_NEEDED = {
     "Atomics": "!this.hasOwnProperty('Atomics')",
     "BigInt": "!this.hasOwnProperty('BigInt')",
     "SharedArrayBuffer": "!this.hasOwnProperty('SharedArrayBuffer')",
+    "Intl.ListFormat": "!Intl.hasOwnProperty('ListFormat')",
+    "Intl.Segmenter": "!Intl.hasOwnProperty('Segmenter')",
 }
 RELEASE_OR_BETA = set()
 
 
 @contextlib.contextmanager
 def TemporaryDirectory():
     tmpDir = tempfile.mkdtemp()
     try:
--- a/js/src/tests/test262/GIT-INFO
+++ b/js/src/tests/test262/GIT-INFO
@@ -1,7 +1,36 @@
-commit ab436c465106be86719c4849c9cedecd7b570ff9
-Author: Leo Balter <leonardo.balter@gmail.com>
-Date:   Fri Aug 17 18:06:19 2018 -0400
+commit b98c45ca5a46966bce1ac691d5f608beb36d5db7
+Author: Maya Lekova <apokalyptra@gmail.com>
+Date:   Wed Oct 17 22:10:09 2018 +0200
 
-    Merge pull request #1677 from tc39/ofe-use-verifyproperty
+    AsyncFunction: Add tests ensuring the new 1-tick await behaviour (#1843)
+    
+    * AsyncFunction: Add tests ensuring the new 1-tick await behaviour
+    
+    This commit adds 3 tests ensuring the optimized behaviour of await
+    (see https://github.com/tc39/ecma262/pull/1250) in the following cases:
+    - async functions
+    - yielding from async generator functions
+    - for-await-of loops
+    
+    * AsyncFunction: Add tests ensuring the monkey-patched promises behaviour
     
-    Object.fromEntries: use verifyProperty; add specification details
+    This commit adds 2 more tests ensuring the optimized behaviour of await
+    (see tc39/ecma262#1250) in the following cases:
+    - awaiting on a native promise with monkey-patched "then"
+    - awaiting on a non-native promise (a "thenable" object)
+    
+    * AsyncFunction: Add tests ensuring the non-native promises behaviour
+    
+    This commit adds 1 more tests ensuring the optimized behaviour of await
+    (see tc39/ecma262#1250) in the following cases:
+    - awaiting on a non-promise, non-thenable object
+    
+    It also renames the previous test for non-promise (a "thenable" object)
+    to distinguish from the new case.
+    
+    The commit adds checks for proper await/promises interleaving in the
+    aforementioned cases and includes a small code clean-up.
+    
+    * AsyncFunction: Refactor tests ensuring the new 1-tick await behaviour
+    
+    Gather all the tests to their appropriate folder and update copyright header.
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/array-like-objects.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/array-like-objects.js
@@ -11,23 +11,23 @@ features: [Array.prototype.flat]
 function getArgumentsObject() {
   return arguments;
 }
 
 var a = getArgumentsObject([1], [2]);
 var actual = [].flat.call(a);
 assert.compareArray(actual, [1, 2], 'arguments objects');
 
-var a = {
+a = {
   length: 1,
   0: [1],
 };
-var actual = [].flat.call(a);
+actual = [].flat.call(a);
 assert.compareArray(actual, [1], 'array-like objects');
 
-var a = {
+a = {
   length: undefined,
   0: [1],
 };
-var actual = [].flat.call(a);
+actual = [].flat.call(a);
 assert.compareArray(actual, [], 'array-like objects; undefined length');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/length.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/length.js
@@ -9,13 +9,15 @@ includes: [propertyHelper.js]
 features: [Array.prototype.flat]
 ---*/
 
 assert.sameValue(
   Array.prototype.flat.length, 0,
   'The value of `Array.prototype.flat.length` is `0`'
 );
 
-verifyNotEnumerable(Array.prototype.flat, 'length');
-verifyNotWritable(Array.prototype.flat, 'length');
-verifyConfigurable(Array.prototype.flat, 'length');
+verifyProperty(Array.prototype.flat, 'length', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/name.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/name.js
@@ -10,13 +10,15 @@ includes: [propertyHelper.js]
 features: [Array.prototype.flat]
 ---*/
 
 assert.sameValue(
   Array.prototype.flat.name, 'flat',
   'The value of `Array.prototype.flat.name` is `"flat"`'
 );
 
-verifyNotEnumerable(Array.prototype.flat, 'name');
-verifyNotWritable(Array.prototype.flat, 'name');
-verifyConfigurable(Array.prototype.flat, 'name');
+verifyProperty(Array.prototype.flat, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js
@@ -12,34 +12,34 @@ var a = [1, [2]];
 var expected = a;
 
 // non integral string depthNum is converted to 0
 var depthNum = 'TestString';
 var actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'non integral string depthNum');
 
 // object type depthNum is converted to 0
-var depthNum = {};
-var actual = a.flat(depthNum);
+depthNum = {};
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'object type depthNum');
 
 // negative infinity depthNum is converted to 0
-var depthNum = Number.NEGATIVE_INFINITY;
-var actual = a.flat(depthNum);
+depthNum = Number.NEGATIVE_INFINITY;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'negative infinity depthNum');
 
 // positive zero depthNum is converted to 0
-var depthNum = +0;
-var actual = a.flat(depthNum);
+depthNum = +0;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'positive zero depthNum');
 
 // negative zero depthNum is converted to 0
-var depthNum = -0;
-var actual = a.flat(depthNum);
+depthNum = -0;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'negative zero depthNum');
 
 // integral string depthNum is converted to an integer
-var depthNum = '1';
-var actual = a.flat(depthNum);
-var expected = [1, 2]
+depthNum = '1';
+actual = a.flat(depthNum);
+expected = [1, 2]
 assert(compareArray(actual, expected), 'integral string depthNum');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/non-object-ctor-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/non-object-ctor-throws.js
@@ -9,27 +9,27 @@ features: [Array.prototype.flat]
 ---*/
 
 var a = [];
 a.constructor = null;
 assert.throws(TypeError, function() {
   a.flat();
 }, 'null value');
 
-var a = [];
+a = [];
 a.constructor = 1;
 assert.throws(TypeError, function() {
   a.flat();
 }, 'number value');
 
-var a = [];
+a = [];
 a.constructor = 'string';
 assert.throws(TypeError, function() {
   a.flat();
 }, 'string value');
 
-var a = [];
+a = [];
 a.constructor = true;
 assert.throws(TypeError, function() {
   a.flat();
 }, 'boolean value');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flat/prop-desc.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/prop-desc.js
@@ -1,23 +1,24 @@
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flat
-es6id: 22.1.3
 description: Property type and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
 includes: [propertyHelper.js]
 features: [Array.prototype.flat]
 ---*/
 
 assert.sameValue(
   typeof Array.prototype.flat,
   'function',
   '`typeof Array.prototype.flat` is `function`'
 );
 
-verifyNotEnumerable(Array.prototype, 'flat');
-verifyWritable(Array.prototype, 'flat');
-verifyConfigurable(Array.prototype, 'flat');
+verifyProperty(Array.prototype, 'flat', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Array/prototype/flat/proxy-access-count.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 Richard Lawrence. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flat
+description: >
+  properties are accessed correct number of times by .flat
+info: |
+  Array.prototype.flat( [ depth ] )
+
+  ...
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray (target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      i. Let element be ? Get(source, P).
+features: [Array.prototype.flat]
+includes: [compareArray.js]
+---*/
+
+const getCalls = [], hasCalls = [];
+const handler = {
+  get : function (t, p, r) { getCalls.push(p); return Reflect.get(t, p, r); },
+  has : function (t, p, r) { hasCalls.push(p); return Reflect.has(t, p, r); }
+}
+
+const tier2 = new Proxy([4, 3], handler);
+const tier1 = new Proxy([2, [3, [4, 2], 2], 5, tier2, 6], handler);
+
+Array.prototype.flat.call(tier1, 3);
+
+assert.compareArray(getCalls, ["length", "constructor", "0", "1", "2", "3", "length", "0", "1", "4"], 'getProperty by .flat should occur exactly once per property and once for length and constructor');
+assert.compareArray(hasCalls, ["0", "1", "2", "3", "0", "1", "4"], 'hasProperty by .flat should occur exactly once per property');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/array-like-objects.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/array-like-objects.js
@@ -15,23 +15,23 @@ function getArgumentsObject() {
 function double(e) {
   return [e * 2];
 }
 
 var a = getArgumentsObject(1, 2);
 var actual = [].flatMap.call(a, double);
 assert.compareArray(actual, [2, 4], 'arguments objects');
 
-var a = {
+a = {
   length: 1,
   0: 1,
 };
-var actual = [].flatMap.call(a, double);
+actual = [].flatMap.call(a, double);
 assert.compareArray(actual, [2], 'array-like objects');
 
-var a = {
+a = {
   length: void 0,
   0: 1,
 };
-var actual = [].flatMap.call(a, double);
+actual = [].flatMap.call(a, double);
 assert.compareArray(actual, [], 'array-like objects; undefined length');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/length.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/length.js
@@ -9,13 +9,15 @@ includes: [propertyHelper.js]
 features: [Array.prototype.flatMap]
 ---*/
 
 assert.sameValue(
   Array.prototype.flatMap.length, 1,
   'The value of `Array.prototype.flatmap.length` is `1`'
 );
 
-verifyNotEnumerable(Array.prototype.flatMap, 'length');
-verifyNotWritable(Array.prototype.flatMap, 'length');
-verifyConfigurable(Array.prototype.flatMap, 'length');
+verifyProperty(Array.prototype.flatMap, 'length', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/name.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/name.js
@@ -9,13 +9,15 @@ includes: [propertyHelper.js]
 features: [Array.prototype.flatMap]
 ---*/
 
 assert.sameValue(
   Array.prototype.flatMap.name, 'flatMap',
   'The value of `Array.prototype.flatMap.name` is `"flatMap"`'
 );
 
-verifyNotEnumerable(Array.prototype.flatMap, 'name');
-verifyNotWritable(Array.prototype.flatMap, 'name');
-verifyConfigurable(Array.prototype.flatMap, 'name');
+verifyProperty(Array.prototype.flatMap, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js
@@ -9,27 +9,27 @@ features: [Array.prototype.flatMap]
 ---*/
 
 var a = [];
 a.constructor = null;
 assert.throws(TypeError, function() {
   a.flatMap();
 }, 'null value');
 
-var a = [];
+a = [];
 a.constructor = 1;
 assert.throws(TypeError, function() {
   a.flatMap();
 }, 'number value');
 
-var a = [];
+a = [];
 a.constructor = 'string';
 assert.throws(TypeError, function() {
   a.flatMap();
 }, 'string value');
 
-var a = [];
+a = [];
 a.constructor = true;
 assert.throws(TypeError, function() {
   a.flatMap();
 }, 'boolean value');
 
 reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/prop-desc.js
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: Property type and descriptor.
+info: >
+  17 ECMAScript Standard Built-in Objects
+
+  Every other data property described in clauses 18 through 26 and in Annex B.2
+  has the attributes { [[Writable]]: true, [[Enumerable]]: false,
+  [[Configurable]]: true } unless otherwise specified.
+includes: [propertyHelper.js]
+features: [Array.prototype.flatMap]
+---*/
+
+assert.sameValue(
+  typeof Array.prototype.flatMap,
+  'function',
+  '`typeof Array.prototype.flatMap` is `function`'
+);
+
+verifyProperty(Array.prototype, 'flatMap', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/proxy-access-count.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2018 Richard Lawrence. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  properties are accessed correct number of times by .flatMap
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  ...
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
+
+  FlattenIntoArray (target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      i. Let element be ? Get(source, P).
+features: [Array.prototype.flat]
+includes: [compareArray.js]
+---*/
+
+const getCalls = [], hasCalls = [];
+const handler = {
+  get : function (t, p, r) { getCalls.push(p); return Reflect.get(t, p, r); },
+  has : function (t, p, r) { hasCalls.push(p); return Reflect.has(t, p, r); }
+}
+
+const tier2 = new Proxy([4, 3], handler);
+const tier1 = new Proxy([2, [3, 4, 2, 2], 5, tier2, 6], handler);
+
+Array.prototype.flatMap.call(tier1, function(a){ return a; });
+
+assert.compareArray(getCalls, ["length", "constructor", "0", "1", "2", "3", "length", "0", "1", "4"], 'getProperty by .flatMap should occur exactly once per property and once for length and constructor');
+assert.compareArray(hasCalls, ["0", "1", "2", "3", "0", "1", "4"], 'hasProperty by .flatMap should occur exactly once per property');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/notify/shell.js
+++ b/js/src/tests/test262/built-ins/Atomics/notify/shell.js
@@ -2,23 +2,16 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: >
     Collection of functions used to interact with Atomics.* operations across agent boundaries.
 ---*/
 
 /**
- * The amount of slack allowed for testing time-related Atomics methods (i.e. wait and notify).
- * The absolute value of the difference of the observed time and the expected time must
- * be epsilon-close.
- */
-$262.agent.MAX_TIME_EPSILON = 100;
-
-/**
  * @return {String} A report sent from an agent.
  */
 {
   // This is only necessary because the original
   // $262.agent.getReport API was insufficient.
   //
   // All runtimes currently have their own
   // $262.agent.getReport which is wrong, so we
--- a/js/src/tests/test262/built-ins/Atomics/notify/undefined-index-defaults-to-zero.js
+++ b/js/src/tests/test262/built-ins/Atomics/notify/undefined-index-defaults-to-zero.js
@@ -63,14 +63,14 @@ const i32a = new Int32Array(
 var woken = 0;
 while ((woken = Atomics.notify(i32a, undefined, 1)) === 0) ;
 assert.sameValue(woken, 1, 'Atomics.notify(i32a, undefined, 1) returns 1');
 
 assert.sameValue($262.agent.getReport(), 'ok', '$262.agent.getReport() returns "ok"');
 
 // Notify again at index 0, default => 0.
 var woken = 0;
-while ((woken = Atomics.notify(i32a, /*, default values used */)) === 0) ;
+while ((woken = Atomics.notify(i32a /*, default values used */)) === 0) ;
 assert.sameValue(woken, 1, 'Atomics.notify(i32a /*, default values used */) returns 1');
 
 assert.sameValue($262.agent.getReport(), 'ok', '$262.agent.getReport() returns "ok"');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/bigint/false-for-timeout-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/bigint/false-for-timeout-agent.js
@@ -31,26 +31,23 @@ const RUNNING = 1;
       return false;
     }
   };
 
   $262.agent.receiveBroadcast(function(sab) {
     const i64a = new BigInt64Array(sab);
     Atomics.add(i64a, ${RUNNING}, 1n);
 
-    const before = $262.agent.monotonicNow();
     const status1 = Atomics.wait(i64a, 0, 0n, false);
     const status2 = Atomics.wait(i64a, 0, 0n, valueOf);
     const status3 = Atomics.wait(i64a, 0, 0n, toPrimitive);
-    const duration = $262.agent.monotonicNow() - before;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
     $262.agent.report(status3);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i64a = new BigInt64Array(
   new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -71,17 +68,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "timed-out"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'timed-out',
   '$262.agent.getReport() returns "timed-out"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true');
-
 assert.sameValue(Atomics.notify(i64a, 0), 0, 'Atomics.notify(i64a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/false-for-timeout-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/false-for-timeout-agent.js
@@ -31,26 +31,23 @@ const RUNNING = 1;
       return false;
     }
   };
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
-    const before = $262.agent.monotonicNow();
     const status1 = Atomics.wait(i32a, 0, 0, false);
     const status2 = Atomics.wait(i32a, 0, 0, valueOf);
     const status3 = Atomics.wait(i32a, 0, 0, toPrimitive);
-    const duration = $262.agent.monotonicNow() - before;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
     $262.agent.report(status3);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -71,17 +68,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "timed-out"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'timed-out',
   '$262.agent.getReport() returns "timed-out"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/null-for-timeout-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/null-for-timeout-agent.js
@@ -31,26 +31,23 @@ const RUNNING = 1;
       return null;
     }
   };
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
-    const before = $262.agent.monotonicNow();
     const status1 = Atomics.wait(i32a, 0, 0, null);
     const status2 = Atomics.wait(i32a, 0, 0, valueOf);
     const status3 = Atomics.wait(i32a, 0, 0, toPrimitive);
-    const duration = $262.agent.monotonicNow() - before;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
     $262.agent.report(status3);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -71,17 +68,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "timed-out"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'timed-out',
   '$262.agent.getReport() returns "timed-out"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/object-for-timeout-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/object-for-timeout-agent.js
@@ -37,26 +37,23 @@ const RUNNING = 1;
       return 0;
     }
   };
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
-    const before = $262.agent.monotonicNow();
     const status1 = Atomics.wait(i32a, 0, 0, valueOf);
     const status2 = Atomics.wait(i32a, 0, 0, toString);
     const status3 = Atomics.wait(i32a, 0, 0, toPrimitive);
-    const duration = $262.agent.monotonicNow() - before;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
     $262.agent.report(status3);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -77,17 +74,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "timed-out"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'timed-out',
   '$262.agent.getReport() returns "timed-out"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/poisoned-object-for-timeout-throws-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/poisoned-object-for-timeout-throws-agent.js
@@ -34,32 +34,29 @@ const RUNNING = 1;
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
     let status1 = "";
     let status2 = "";
 
-    const start = $262.agent.monotonicNow();
     try {
       Atomics.wait(i32a, 0, 0, poisonedValueOf);
     } catch (error) {
       status1 = "poisonedValueOf";
     }
     try {
       Atomics.wait(i32a, 0, 0, poisonedToPrimitive);
     } catch (error) {
       status2 = "poisonedToPrimitive";
     }
-    const duration = $262.agent.monotonicNow() - start;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -75,17 +72,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "poisonedValueOf"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'poisonedToPrimitive',
   '$262.agent.getReport() returns "poisonedToPrimitive"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/shell.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/shell.js
@@ -2,23 +2,16 @@
 // Copyright (C) 2017 Mozilla Corporation.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: >
     Collection of functions used to interact with Atomics.* operations across agent boundaries.
 ---*/
 
 /**
- * The amount of slack allowed for testing time-related Atomics methods (i.e. wait and notify).
- * The absolute value of the difference of the observed time and the expected time must
- * be epsilon-close.
- */
-$262.agent.MAX_TIME_EPSILON = 100;
-
-/**
  * @return {String} A report sent from an agent.
  */
 {
   // This is only necessary because the original
   // $262.agent.getReport API was insufficient.
   //
   // All runtimes currently have their own
   // $262.agent.getReport which is wrong, so we
--- a/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-index-throws-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-index-throws-agent.js
@@ -47,32 +47,29 @@ const RUNNING = 1;
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
     let status1 = "";
     let status2 = "";
 
-    const start = $262.agent.monotonicNow();
     try {
       Atomics.wait(i32a, Symbol("1"), poisonedValueOf, poisonedValueOf);
     } catch (error) {
       status1 = 'Symbol("1")';
     }
     try {
       Atomics.wait(i32a, Symbol("2"), poisonedToPrimitive, poisonedToPrimitive);
     } catch (error) {
       status2 = 'Symbol("2")';
     }
-    const duration = $262.agent.monotonicNow() - start;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -88,16 +85,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "Symbol("1")"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'Symbol("2")',
   '$262.agent.getReport() returns "Symbol("2")"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (The result of `(lapse >= 0)` is true (timeout should be a min of 0ms))');
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON))');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-timeout-throws-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-timeout-throws-agent.js
@@ -22,32 +22,29 @@ const RUNNING = 1;
 $262.agent.start(`
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
     let status1 = "";
     let status2 = "";
 
-    const start = $262.agent.monotonicNow();
     try {
       Atomics.wait(i32a, 0, 0, Symbol("1"));
     } catch (error) {
       status1 = 'Symbol("1")';
     }
     try {
       Atomics.wait(i32a, 0, 0, Symbol("2"));
     } catch (error) {
       status2 = 'Symbol("2")';
     }
-    const duration = $262.agent.monotonicNow() - start;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -63,16 +60,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "Symbol("1")"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'Symbol("2")',
   '$262.agent.getReport() returns "Symbol("2")"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-value-throws-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/symbol-for-value-throws-agent.js
@@ -38,32 +38,29 @@ const RUNNING = 1;
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
     let status1 = "";
     let status2 = "";
 
-    const before = $262.agent.monotonicNow();
     try {
       Atomics.wait(i32a, 0, Symbol("1"), poisonedValueOf);
     } catch (error) {
       status1 = 'Symbol("1")';
     }
     try {
       Atomics.wait(i32a, 0, Symbol("2"), poisonedToPrimitive);
     } catch (error) {
       status2 = 'Symbol("2")';
     }
-    const duration = $262.agent.monotonicNow() - before;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -79,16 +76,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "Symbol("1")"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'Symbol("2")',
   '$262.agent.getReport() returns "Symbol("2")"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/true-for-timeout-agent.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/true-for-timeout-agent.js
@@ -31,26 +31,23 @@ const RUNNING = 1;
       return true;
     }
   };
 
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
     Atomics.add(i32a, ${RUNNING}, 1);
 
-    const start = $262.agent.monotonicNow();
     const status1 = Atomics.wait(i32a, 0, 0, true);
     const status2 = Atomics.wait(i32a, 0, 0, valueOf);
     const status3 = Atomics.wait(i32a, 0, 0, toPrimitive);
-    const duration = $262.agent.monotonicNow() - start;
 
     $262.agent.report(status1);
     $262.agent.report(status2);
     $262.agent.report(status3);
-    $262.agent.report(duration);
     $262.agent.leaving();
   });
 `);
 
 const i32a = new Int32Array(
   new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4)
 );
 
@@ -71,17 +68,11 @@ assert.sameValue(
   '$262.agent.getReport() returns "timed-out"'
 );
 assert.sameValue(
   $262.agent.getReport(),
   'timed-out',
   '$262.agent.getReport() returns "timed-out"'
 );
 
-const lapse = $262.agent.getReport();
-
-assert(lapse >= 0, 'The result of `(lapse >= 0)` is true (timeout should be a min of 0ms)');
-
-assert(lapse <= $262.agent.MAX_TIME_EPSILON, 'The result of `(lapse <= $262.agent.MAX_TIME_EPSILON)` is true (timeout should be a max of $$262.agent.MAX_TIME_EPSILON)');
-
 assert.sameValue(Atomics.notify(i32a, 0), 0, 'Atomics.notify(i32a, 0) returns 0');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/Atomics/wait/was-woken-before-timeout.js
+++ b/js/src/tests/test262/built-ins/Atomics/wait/was-woken-before-timeout.js
@@ -1,9 +1,9 @@
-// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('BigInt')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,BigInt,SharedArrayBuffer is not enabled unconditionally
+// |reftest| skip-if(!this.hasOwnProperty('Atomics')||!this.hasOwnProperty('SharedArrayBuffer')) -- Atomics,SharedArrayBuffer is not enabled unconditionally
 // Copyright (C) 2018 Amal Hussein. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-atomics.wait
 description: >
   Test that Atomics.wait returns the right result when it was awoken before
   a timeout
 info: |
@@ -15,17 +15,17 @@ info: |
 
       9.If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
         ...
           3.If bufferData is a Data Block, return false
 
           If value is undefined, then
           Let index be 0.
 includes: [atomicsHelper.js]
-features: [Atomics, BigInt, SharedArrayBuffer, TypedArray]
+features: [Atomics, SharedArrayBuffer, TypedArray]
 ---*/
 
 const RUNNING = 1;
 const TIMEOUT = $262.agent.timeouts.huge;
 
 $262.agent.start(`
   $262.agent.receiveBroadcast(function(sab) {
     const i32a = new Int32Array(sab);
--- a/js/src/tests/test262/built-ins/DataView/instance-extensibility-sab.js
+++ b/js/src/tests/test262/built-ins/DataView/instance-extensibility-sab.js
@@ -24,16 +24,34 @@ info: |
   3. Return ObjectCreate(proto, internalSlotsList).
 
   9.1.12 ObjectCreate (proto [ , internalSlotsList ])
 
   ...
   5. Set the [[Extensible]] internal slot of obj to true.
   ...
 features: [SharedArrayBuffer]
+includes: [propertyHelper.js]
 ---*/
 
 var buffer = new SharedArrayBuffer(8);
 var sample = new DataView(buffer, 0);
 
 assert(Object.isExtensible(sample));
 
+Object.defineProperty(sample, 'baz', {});
+assert(sample.hasOwnProperty('baz'), 'confirms extensibility adding a new property');
+
+Object.defineProperty(sample, 'foo', {
+  value: 'bar',
+  writable: true,
+  configurable: true,
+  enumerable: false,
+});
+
+verifyProperty(sample, 'foo', {
+  value: 'bar',
+  writable: true,
+  configurable: true,
+  enumerable: false,
+});
+
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/DataView/instance-extensibility.js
+++ b/js/src/tests/test262/built-ins/DataView/instance-extensibility.js
@@ -21,16 +21,34 @@ info: |
   ...
   3. Return ObjectCreate(proto, internalSlotsList).
 
   9.1.12 ObjectCreate (proto [ , internalSlotsList ])
 
   ...
   5. Set the [[Extensible]] internal slot of obj to true.
   ...
+includes: [propertyHelper.js]
 ---*/
 
 var buffer = new ArrayBuffer(8);
 var sample = new DataView(buffer, 0);
 
 assert(Object.isExtensible(sample));
 
+Object.defineProperty(sample, 'baz', {});
+assert(sample.hasOwnProperty('baz'), 'confirms extensibility adding a new property');
+
+Object.defineProperty(sample, 'foo', {
+  value: 'bar',
+  writable: true,
+  configurable: true,
+  enumerable: false,
+});
+
+verifyProperty(sample, 'foo', {
+  value: 'bar',
+  writable: true,
+  configurable: true,
+  enumerable: false,
+});
+
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/GeneratorPrototype/throw/try-finally-nested-try-catch-within-inner-try.js
+++ b/js/src/tests/test262/built-ins/GeneratorPrototype/throw/try-finally-nested-try-catch-within-inner-try.js
@@ -49,17 +49,17 @@ assert.sameValue(
 );
 
 result = iter.next();
 assert.sameValue(result.value, 3, 'Fourth result `value');
 assert.sameValue(result.done, false, 'Fourth result `done` flag');
 
 result = iter.next();
 assert.sameValue(result.value, 4, 'Fifth result `value`');
-assert.sameValue(result.done, false, 'Firth result `done` flag');
+assert.sameValue(result.done, false, 'Fifth result `done` flag');
 
 result = iter.next();
 assert.sameValue(result.value, 5, 'Sixth result `value`');
 assert.sameValue(result.done, false, 'Sixth result `done` flag');
 
 result = iter.next();
 assert.sameValue(
   result.value, undefined, 'Result `value` is undefined when done'
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-1.js
+++ b/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-1.js
@@ -1,24 +1,18 @@
 // Copyright (c) 2012 Ecma International.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 info: |
     This test should be run without any built-ins being added/augmented.
-    The name JSON must be bound to an object.
-    Section 15 says that every built-in Function object described in this
-    section � whether as a constructor, an ordinary function, or both � has
-    a length property whose value is an integer. Unless otherwise specified,
-    this value is equal to the largest number of named arguments shown in
-    the section headings for the function description, including optional
-    parameters.
-    This default applies to JSON.stringify, and it must exist as a function
-    taking 3 parameters.
+    The initial value of [[Configurable]] on JSON is true. This means we
+    should be able to delete (8.6.2.5) the stringify and parse properties.
 es5id: 15.12.3-0-1
-description: JSON.stringify must exist as be a function
+description: JSON.stringify must be deletable (configurable)
 ---*/
 
-var f = JSON.stringify;
+var o = JSON;
+var desc = Object.getOwnPropertyDescriptor(o, "stringify");
 
-assert.sameValue(typeof(f), "function", 'typeof(f)');
+assert.sameValue(desc.configurable, true, 'desc.configurable');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-2.js
+++ b/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-2.js
@@ -9,17 +9,17 @@ info: |
     section � whether as a constructor, an ordinary function, or both � has
     a length property whose value is an integer. Unless otherwise specified,
     this value is equal to the largest number of named arguments shown in
     the section headings for the function description, including optional
     parameters.
     This default applies to JSON.stringify, and it must exist as a function
     taking 3 parameters.
 es5id: 15.12.3-0-2
-description: JSON.stringify must exist as be a function taking 3 parameters
+description: JSON.stringify must exist as a function taking 3 parameters
 ---*/
 
 var f = JSON.stringify;
 
 assert.sameValue(typeof(f), "function", 'typeof(f)');
 assert.sameValue(f.length, 3, 'f.length');
 
 reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-0-3.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-info: |
-    This test should be run without any built-ins being added/augmented.
-    The initial value of [[Configurable]] on JSON is true. This means we
-    should be able to delete (8.6.2.5) the stringify and parse properties.
-es5id: 15.12.3-0-3
-description: JSON.stringify must be deletable (configurable)
----*/
-
-var o = JSON;
-var desc = Object.getOwnPropertyDescriptor(o, "stringify");
-
-assert.sameValue(desc.configurable, true, 'desc.configurable');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-16.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-16
-description: >
-    JSON.stringify - stringifying an object where property name is the
-    union of all null character (The abstract operation Quote(value)
-    step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F": "John"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-17.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-17
-description: >
-    JSON.stringify - stringifying an object where property name starts
-    with the union of all null character (The abstract operation
-    Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001Fname": "John"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-18.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-18
-description: >
-    JSON.stringify - stringifying an object where property name ends
-    with the union of all null character (The abstract operation
-    Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F": "John"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-19.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-19
-description: >
-    JSON.stringify - stringifying an object where property name starts
-    and ends with the union of all null character (The abstract
-    operation Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001Fname\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F": "John"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1 && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-2.js
+++ b/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-2.js
@@ -1,15 +1,15 @@
 // Copyright (c) 2012 Ecma International.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 es5id: 15.12.3-11-2
 description: >
-    A JSON.stringify replacer function works is applied to a top level
+    A JSON.stringify replacer function is applied to a top level
     undefined value.
 ---*/
 
 assert.sameValue(JSON.stringify(undefined, function(k, v) {
   return "replacement"
 }), '"replacement"', 'JSON.stringify(undefined, function(k, v) { return "replacement" })');
 
 reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-20.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-20
-description: >
-    JSON.stringify - stringifying an object where property name
-    middles with the union of all null character (The abstract
-    operation Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "na\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001Fme": "John"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-21.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-21
-description: >
-    JSON.stringify - stringifying an object where property value is
-    the union of all null character (The abstract operation
-    Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-22.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-22
-description: >
-    JSON.stringify - stringifying an object where property value
-    starts with the union of all null character (The abstract
-    operation Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001FJohn"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-23.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-23
-description: >
-    JSON.stringify - stringifying an object where property value ends
-    with the union of all null character (The abstract operation
-    Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name": "John\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-24.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-24
-description: >
-    JSON.stringify - stringifying an object where property value
-    starts and ends with the union of all null character (The abstract
-    operation Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001FJohn\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1 && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-25.js
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-25
-description: >
-    JSON.stringify - stringifying an object where property value
-    middles with the union of all null character (The abstract
-    operation Quote(value) step 2.c)
----*/
-
-var result = true;
-
-var expectedNullChars = new Array();
-expectedNullChars[0] = "\\u0000";
-expectedNullChars[1] = "\\u0001";
-expectedNullChars[2] = "\\u0002";
-expectedNullChars[3] = "\\u0003";
-expectedNullChars[4] = "\\u0004";
-expectedNullChars[5] = "\\u0005";
-expectedNullChars[6] = "\\u0006";
-expectedNullChars[7] = "\\u0007";
-expectedNullChars[8] = "\\b";
-expectedNullChars[9] = "\\t";
-expectedNullChars[10] = "\\n";
-expectedNullChars[11] = "\\u000b";
-expectedNullChars[12] = "\\f";
-expectedNullChars[13] = "\\r";
-expectedNullChars[14] = "\\u000e";
-expectedNullChars[15] = "\\u000f";
-expectedNullChars[16] = "\\u0010";
-expectedNullChars[17] = "\\u0011";
-expectedNullChars[18] = "\\u0012";
-expectedNullChars[19] = "\\u0013";
-expectedNullChars[20] = "\\u0014";
-expectedNullChars[21] = "\\u0015";
-expectedNullChars[22] = "\\u0016";
-expectedNullChars[23] = "\\u0017";
-expectedNullChars[24] = "\\u0018";
-expectedNullChars[25] = "\\u0019";
-expectedNullChars[26] = "\\u001a";
-expectedNullChars[27] = "\\u001b";
-expectedNullChars[28] = "\\u001c";
-expectedNullChars[29] = "\\u001d";
-expectedNullChars[30] = "\\u001e";
-expectedNullChars[31] = "\\u001f";
-
-for (var index in expectedNullChars) {
-
-  var str = JSON.stringify({
-    "name": "Jo\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001Fhn"
-  });
-  result = (result && str.indexOf(expectedNullChars[index]) !== -1 && str.indexOf(expectedNullChars[index]) !== -1);
-}
-
-assert(result, 'result !== true');
-
-reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3-11-26.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3-11-26
-description: >
-    JSON.stringify - the last element of the concatenation is ']' (The
-    abstract operation JA(value) step 10.b.iii)
----*/
-
-var arrObj = [];
-arrObj[0] = "a";
-arrObj[1] = "b";
-arrObj[2] = "c";
-
-var jsonText = JSON.stringify(arrObj, undefined, "").toString();
-
-assert.sameValue(jsonText.charAt(jsonText.length - 1), "]", 'jsonText.charAt(jsonText.length - 1)');
-
-reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-1.js
+++ b/js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-1.js
@@ -1,14 +1,14 @@
 // Copyright (c) 2012 Ecma International.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 es5id: 15.12.3_4-1-1
-description: JSON.stringify a circular object throws a error
+description: JSON.stringify of a circular object throws a TypeError
 ---*/
 
 var obj = {};
 obj.prop = obj;
 
 assert.throws(TypeError, function() {
   JSON.stringify(obj);
 });
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-2.js
+++ b/js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-2.js
@@ -1,16 +1,20 @@
 // Copyright (c) 2012 Ecma International.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 es5id: 15.12.3_4-1-2
-description: JSON.stringify a circular object throws a TypeError
+description: JSON.stringify of an indirectly circular object throws a TypeError
 ---*/
 
-var obj = {};
-obj.prop = obj;
+var obj = {
+  p1: {
+    p2: {}
+  }
+};
+obj.p1.p2.prop = obj;
 
 assert.throws(TypeError, function() {
   JSON.stringify(obj);
 });
 
 reportCompare(0, 0);
deleted file mode 100644
--- a/js/src/tests/test262/built-ins/JSON/stringify/15.12.3_4-1-3.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 Ecma International.  All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-
-/*---
-es5id: 15.12.3_4-1-3
-description: JSON.stringify a indirectly circular object throws a error
----*/
-
-var obj = {
-  p1: {
-    p2: {}
-  }
-};
-obj.p1.p2.prop = obj;
-
-assert.throws(TypeError, function() {
-  JSON.stringify(obj);
-});
-
-reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/JSON/stringify/string-escape-ascii.js
@@ -0,0 +1,68 @@
+// Copyright (c) 2018 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-quotejsonstring
+description: >
+    JSON.stringify property names and values containing ASCII
+    characters that require escaping
+---*/
+
+var char_to_json = {
+  '"': '\\"',
+  "\\": "\\\\",
+  "\x00": "\\u0000",
+  "\x01": "\\u0001",
+  "\x02": "\\u0002",
+  "\x03": "\\u0003",
+  "\x04": "\\u0004",
+  "\x05": "\\u0005",
+  "\x06": "\\u0006",
+  "\x07": "\\u0007",
+  "\x08": "\\b",
+  "\x09": "\\t",
+  "\x0A": "\\n",
+  "\x0B": "\\u000b",
+  "\x0C": "\\f",
+  "\x0D": "\\r",
+  "\x0E": "\\u000e",
+  "\x0F": "\\u000f",
+  "\x10": "\\u0010",
+  "\x11": "\\u0011",
+  "\x12": "\\u0012",
+  "\x13": "\\u0013",
+  "\x14": "\\u0014",
+  "\x15": "\\u0015",
+  "\x16": "\\u0016",
+  "\x17": "\\u0017",
+  "\x18": "\\u0018",
+  "\x19": "\\u0019",
+  "\x1A": "\\u001a",
+  "\x1B": "\\u001b",
+  "\x1C": "\\u001c",
+  "\x1D": "\\u001d",
+  "\x1E": "\\u001e",
+  "\x1F": "\\u001f"
+}
+
+var chars = Object.keys(char_to_json).join("");
+var chars_reversed = Object.keys(char_to_json).reverse().join("");
+var jsonChars = Object.values(char_to_json).join("");
+var jsonChars_reversed = Object.values(char_to_json).reverse().join("");
+var json = JSON.stringify({
+  ["name" + chars + chars_reversed]: chars_reversed + chars + "value"
+});
+
+for (var char in char_to_json) {
+  var count = json.split(char_to_json[char]).length - 1;
+  assert.sameValue(count, 4,
+    "Every ASCII 0x" + char.charCodeAt(0).toString(16) + " serializes to " + char_to_json[char]);
+}
+
+assert.sameValue(
+  json,
+  `{"${"name" + jsonChars + jsonChars_reversed}":"${jsonChars_reversed + jsonChars + "value"}"}`,
+  "JSON.stringify(objectUsingControlCharacters)"
+);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/JSON/stringify/string-escape-unicode.js
@@ -0,0 +1,38 @@
+// Copyright (c) 2018 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-quotejsonstring
+description: >
+    JSON.stringify strings containing surrogate code units
+features: [well-formed-json-stringify]
+---*/
+
+assert.sameValue(JSON.stringify("\uD834"), '"\\ud834"',
+  'JSON.stringify("\\uD834")');
+assert.sameValue(JSON.stringify("\uDF06"), '"\\udf06"',
+  'JSON.stringify("\\uDF06")');
+
+assert.sameValue(JSON.stringify("\uD834\uDF06"), '"𝌆"',
+  'JSON.stringify("\\uD834\\uDF06")');
+assert.sameValue(JSON.stringify("\uD834\uD834\uDF06\uD834"), '"\\ud834𝌆\\ud834"',
+  'JSON.stringify("\\uD834\\uD834\\uDF06\\uD834")');
+assert.sameValue(JSON.stringify("\uD834\uD834\uDF06\uDF06"), '"\\ud834𝌆\\udf06"',
+  'JSON.stringify("\\uD834\\uD834\\uDF06\\uDF06")');
+assert.sameValue(JSON.stringify("\uDF06\uD834\uDF06\uD834"), '"\\udf06𝌆\\ud834"',
+  'JSON.stringify("\\uDF06\\uD834\\uDF06\\uD834")');
+assert.sameValue(JSON.stringify("\uDF06\uD834\uDF06\uDF06"), '"\\udf06𝌆\\udf06"',
+  'JSON.stringify("\\uDF06\\uD834\\uDF06\\uDF06")');
+
+assert.sameValue(JSON.stringify("\uDF06\uD834"), '"\\udf06\\ud834"',
+  'JSON.stringify("\\uDF06\\uD834")');
+assert.sameValue(JSON.stringify("\uD834\uDF06\uD834\uD834"), '"𝌆\\ud834\\ud834"',
+  'JSON.stringify("\\uD834\\uDF06\\uD834\\uD834")');
+assert.sameValue(JSON.stringify("\uD834\uDF06\uD834\uDF06"), '"𝌆𝌆"',
+  'JSON.stringify("\\uD834\\uDF06\\uD834\\uDF06")');
+assert.sameValue(JSON.stringify("\uDF06\uDF06\uD834\uD834"), '"\\udf06\\udf06\\ud834\\ud834"',
+  'JSON.stringify("\\uDF06\\uDF06\\uD834\\uD834")');
+assert.sameValue(JSON.stringify("\uDF06\uDF06\uD834\uDF06"), '"\\udf06\\udf06𝌆"',
+  'JSON.stringify("\\uDF06\\uDF06\\uD834\\uDF06")');
+
+reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/isregexp-called-once.js
+++ b/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/isregexp-called-once.js
@@ -1,43 +1,60 @@
 // |reftest| skip -- Symbol.matchAll is not supported
 // Copyright (C) 2018 Peter Wong. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: pending
 description: IsRegExp should only be called once
 info: |
   RegExp.prototype [ @@matchAll ] ( string )
-    [...]
-    3. Return ? MatchAllIterator(R, string).
-
-  MatchAllIterator ( R, O )
+    1. Let R be the this value.
     [...]
-    2. If ? IsRegExp(R) is true, then
-      [...]
-    3. Else,
-      a. Let flags be "g".
-      b. Let matcher be ? RegExpCreate(R, flags).
+    4. Let C be ? SpeciesConstructor(R, %RegExp%).
+    5. Let flags be ? ToString(? Get(R, "flags")).
+    6. Let matcher be ? Construct(C, « R, flags »).
+
+  21.2.3.1 RegExp ( pattern, flags )
+    1. Let patternIsRegExp be ? IsRegExp(pattern).
+    [...]
 features: [Symbol.match, Symbol.matchAll]
 ---*/
 
 var internalCount = 0;
 Object.defineProperty(RegExp.prototype, Symbol.match, {
   get: function() {
     ++internalCount;
     return true;
   }
 });
 
-var count = 0;
+var calls = [];
 var o = {
   get [Symbol.match]() {
-    ++count;
+    calls.push('get @@match');
     return false;
-  }
+  },
+  get flags() {
+    calls.push('get flags');
+    return {
+      toString() {
+        calls.push('flags toString');
+        return "";
+      }
+    };
+  },
 };
 
-RegExp.prototype[Symbol.matchAll].call(o, '1');
+RegExp.prototype[Symbol.matchAll].call(o, {
+  toString() {
+    calls.push('arg toString')
+  }
+});
 
 assert.sameValue(0, internalCount);
-assert.sameValue(1, count);
+
+assert.sameValue(calls.length, 4);
+assert.sameValue(calls[0], 'arg toString');
+assert.sameValue(calls[1], 'get flags');
+assert.sameValue(calls[2], 'flags toString');
+assert.sameValue(calls[3], 'get @@match');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-constructor.js
+++ b/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-constructor.js
@@ -2,24 +2,23 @@
 // Copyright (C) 2018 Peter Wong. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: pending
 description: Custom species constructor is called when creating internal RegExp
 info: |
   RegExp.prototype [ @@matchAll ] ( string )
     [...]
-    3. Return ? MatchAllIterator(R, string).
-
-  MatchAllIterator ( R, O )
+    4. Let C be ? SpeciesConstructor(R, %RegExp%).
+    5. Let flags be ? ToString(? Get(R, "flags")).
+    6. Let matcher be ? Construct(C, « R, flags »).
     [...]
-    2. If ? IsRegExp(R) is true, then
-      a. Let C be ? SpeciesConstructor(R, RegExp).
-      b. Let flags be ? ToString(? Get(R, "flags"))
-      c. Let matcher be ? Construct(C, R, flags).
+    9. If flags contains "g", let global be true.
+    10. Else, let global be false.
+    [...]
 features: [Symbol.matchAll, Symbol.species]
 includes: [compareArray.js, compareIterator.js, regExpUtils.js]
 ---*/
 
 var callCount = 0;
 var callArgs;
 var regexp = /\d/u;
 regexp.constructor = {
@@ -34,12 +33,11 @@ var iter = regexp[Symbol.matchAll](str);
 
 assert.sameValue(callCount, 1);
 assert.sameValue(callArgs.length, 2);
 assert.sameValue(callArgs[0], regexp);
 assert.sameValue(callArgs[1], 'u');
 
 assert.compareIterator(iter, [
   matchValidator(['a'], 0, str),
-  matchValidator(['b'], 2, str)
 ]);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-regexp-get-global-throws.js
+++ b/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-regexp-get-global-throws.js
@@ -1,37 +1,34 @@
 // |reftest| skip -- Symbol.matchAll is not supported
 // Copyright (C) 2018 Peter Wong. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: pending
 description: |
-  Re-throws errors thrown while accessing species constructed RegExp's
-  global property
+  Doesn't access the "global" property of the constructed RegExp
 info: |
   RegExp.prototype [ @@matchAll ] ( string )
     [...]
-    3. Return ? MatchAllIterator(R, string).
-
-  MatchAllIterator ( R, O )
+    4. Let C be ? SpeciesConstructor(R, %RegExp%).
+    5. Let flags be ? ToString(? Get(R, "flags")).
+    6. Let matcher be ? Construct(C, « R, flags »).
     [...]
-    2. If ? IsRegExp(R) is true, then
-      [...]
-      d. Let global be ? ToBoolean(? Get(matcher, "global")).
+    9. If flags contains "g", let global be true.
+    10. Else, let global be false.
+    [...]
 features: [Symbol.matchAll, Symbol.species]
 ---*/
 
 var regexp = /./;
 regexp.constructor = {
   [Symbol.species]: function() {
     return Object.defineProperty(/./, 'global', {
       get() {
         throw new Test262Error();
       }
     });
   }
 };
 
-assert.throws(Test262Error, function() {
-  regexp[Symbol.matchAll]('');
-});
+regexp[Symbol.matchAll]('');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-regexp-get-unicode-throws.js
+++ b/js/src/tests/test262/built-ins/RegExp/prototype/Symbol.matchAll/species-regexp-get-unicode-throws.js
@@ -1,37 +1,34 @@
 // |reftest| skip -- Symbol.matchAll is not supported
 // Copyright (C) 2018 Peter Wong. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: pending
 description: |
-  Re-throws errors thrown while accessing species constructed RegExp's
-  unicode property
+  Doesn't access the "unicode" property of the constructed RegExp
 info: |
   RegExp.prototype [ @@matchAll ] ( string )
     [...]
-    3. Return ? MatchAllIterator(R, string).
-
-  MatchAllIterator ( R, O )
+    4. Let C be ? SpeciesConstructor(R, %RegExp%).
+    5. Let flags be ? ToString(? Get(R, "flags")).
+    6. Let matcher be ? Construct(C, « R, flags »).
     [...]
-    2. If ? IsRegExp(R) is true, then
-      [...]
-      e. Let fullUnicode be ? ToBoolean(? Get(matcher, "unicode")).
+    11. If flags contains "u", let fullUnicode be true.
+    12. Else, let fullUnicode be false.
+    [...]
 features: [Symbol.matchAll, Symbol.species]
 ---*/
 
 var regexp = /./;
 regexp.constructor = {
   [Symbol.species]: function() {
     return Object.defineProperty(/./, 'unicode', {
       get() {
         throw new Test262Error();
       }
     });
   }
 };
 
-assert.throws(Test262Error, function() {
-  regexp[Symbol.matchAll]('');
-});
+regexp[Symbol.matchAll]('');
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/matchAll/regexp-prototype-has-no-matchAll.js
+++ b/js/src/tests/test262/built-ins/String/prototype/matchAll/regexp-prototype-has-no-matchAll.js
@@ -6,22 +6,33 @@ esid: pending
 description: Behavior when @@matchAll is removed from RegExp's prototype
 info: |
   String.prototype.matchAll ( regexp )
     1. Let O be ? RequireObjectCoercible(this value).
     2. If regexp is neither undefined nor null, then
       a. Let matcher be ? GetMethod(regexp, @@matchAll).
       b. If matcher is not undefined, then
         [...]
-    3. Return ? MatchAllIterator(regexp, O).
+    [...]
+    4. Let matcher be ? RegExpCreate(R, "g").
+    [...]
+
+  21.2.3.2.3 Runtime Semantics: RegExpCreate ( P, F )
+    [...]
+    2. Return ? RegExpInitialize(obj, P, F).
+
+  21.2.3.2.2 Runtime Semantics: RegExpInitialize ( obj, pattern, flags )
+    1. If pattern is undefined, let P be the empty String.
+    2. Else, let P be ? ToString(pattern).
+    [...]
 features: [Symbol.matchAll, String.prototype.matchAll]
 includes: [compareArray.js, compareIterator.js, regExpUtils.js]
 ---*/
 
 delete RegExp.prototype[Symbol.matchAll];
-var str = 'a*b';
+var str = '/a/g*/b/g';
 
 assert.compareIterator(str.matchAll(/\w/g), [
-  matchValidator(['a'], 0, str),
-  matchValidator(['b'], 2, str)
+  matchValidator(['/a/g'], 0, str),
+  matchValidator(['/b/g'], 5, str)
 ]);
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-line-terminator.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-line-terminator.js
@@ -21,12 +21,12 @@ var trimEnd = String.prototype.trimEnd;
 // A string of all valid LineTerminator Unicode code points
 var lt = '\u000A\u000D\u2028\u2029';
 
 var str = lt + 'a' + lt + 'b' + lt;
 var expected = lt + 'a' + lt + 'b';
 
 assert.sameValue(
   trimEnd.call(str),
-  expected,
+  expected
 );
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-cannot-convert-to-primitive-err.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-cannot-convert-to-primitive-err.js
@@ -50,12 +50,12 @@ var thisVal = {
 };
 
 // If trimEnd is called on an object with neither Symbol.toPrimitive, toString
 // nor valueOf defined, then a TypeError exception should be thrown.
 assert.throws(
   TypeError,
   function() {
     String.prototype.trimEnd.call(thisVal);
-  },
+  }
 );
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-toprimitive-meth-priority.js
@@ -58,17 +58,17 @@ var result = String.prototype.trimEnd.ca
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive] expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal[Symbol.toPrimitive] expected to have been called.',
+  'thisVal[Symbol.toPrimitive] expected to have been called.'
 );
 
 // Test that thisVal.toString and thisVal.valueOf have not been accessedo
 
 assert.sameValue(
   toStringAccessed,
   0,
   'thisVal.toString should not have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-tostring-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-tostring-meth-priority.js
@@ -72,17 +72,17 @@ var result = String.prototype.trimEnd.ca
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal.toString expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal.toString expected to have been called.',
+  'thisVal.toString expected to have been called.'
 );
 
 // Test that thisVal[toPrimitive] has been accessed.
 
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive should have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-valueof-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-object-valueof-meth-priority.js
@@ -71,17 +71,17 @@ var result = String.prototype.trimEnd.ca
 assert.sameValue(
   valueOfAccessed,
   1,
   'thisVal.toString expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal.valueOf expected to have been called.',
+  'thisVal.valueOf expected to have been called.'
 );
 
 // Test that thisVal[toPrimitive] and thisVal.toString has been accessed.
 
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive should have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-whitespace.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimEnd/this-value-whitespace.js
@@ -24,12 +24,12 @@ var trimEnd = String.prototype.trimEnd;
 // A string of all valid WhiteSpace Unicode code points
 var wspc = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
 
 var str = wspc + 'a' + wspc + 'b' + wspc;
 var expected = wspc + 'a' + wspc + 'b';
 
 assert.sameValue(
   trimEnd.call(str),
-  expected,
+  expected
 );
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-line-terminator.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-line-terminator.js
@@ -21,12 +21,12 @@ var trimStart = String.prototype.trimSta
 // A string of all valid LineTerminator Unicode code points
 var lt = '\u000A\u000D\u2028\u2029';
 
 var str = lt + 'a' + lt + 'b' + lt;
 var expected = 'a' + lt + 'b' + lt;
 
 assert.sameValue(
   trimStart.call(str),
-  expected,
+  expected
 );
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-cannot-convert-to-primitive-err.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-cannot-convert-to-primitive-err.js
@@ -50,12 +50,12 @@ var thisVal = {
 };
 
 // If trimStart is called on an object with neither Symbol.toPrimitive, toString
 // nor valueOf defined, then a TypeError exception should be thrown.
 assert.throws(
   TypeError,
   function() {
     String.prototype.trimStart.call(thisVal);
-  },
+  }
 );
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-toprimitive-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-toprimitive-meth-priority.js
@@ -58,17 +58,17 @@ var result = String.prototype.trimStart.
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive] expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal[Symbol.toPrimitive] expected to have been called.',
+  'thisVal[Symbol.toPrimitive] expected to have been called.'
 );
 
 // Test that thisVal.toString and thisVal.valueOf have not been accessedo
 
 assert.sameValue(
   toStringAccessed,
   0,
   'thisVal.toString should not have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-tostring-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-tostring-meth-priority.js
@@ -72,17 +72,17 @@ var result = String.prototype.trimStart.
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal.toString expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal.toString expected to have been called.',
+  'thisVal.toString expected to have been called.'
 );
 
 // Test that thisVal[toPrimitive] has been accessed.
 
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive should have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-valueof-meth-priority.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-object-valueof-meth-priority.js
@@ -71,17 +71,17 @@ var result = String.prototype.trimStart.
 assert.sameValue(
   valueOfAccessed,
   1,
   'thisVal.toString expected to have been accessed.'
 );
 assert.sameValue(
   result,
   '42',
-  'thisVal.valueOf expected to have been called.',
+  'thisVal.valueOf expected to have been called.'
 );
 
 // Test that thisVal[toPrimitive] and thisVal.toString has been accessed.
 
 assert.sameValue(
   toPrimitiveAccessed,
   1,
   'thisVal[Symbol.toPrimitive should have been accessed.'
--- a/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-whitespace.js
+++ b/js/src/tests/test262/built-ins/String/prototype/trimStart/this-value-whitespace.js
@@ -24,12 +24,12 @@ var trimStart = String.prototype.trimSta
 // A string of all valid WhiteSpace Unicode code points
 var wspc = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
 
 var str = wspc + 'a' + wspc + 'b' + wspc;
 var expected = 'a' + wspc + 'b' + wspc;
 
 assert.sameValue(
   trimStart.call(str),
-  expected,
+  expected
 );
 
 reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Symbol/asyncIterator/cross-realm.js
@@ -0,0 +1,17 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-symbol.asynciterator
+description: Value shared by all realms
+info: |
+  Unless otherwise specified, well-known symbols values are shared by all
+  realms.
+features: [cross-realm, Symbol.asyncIterator]
+---*/
+
+var OSymbol = $262.createRealm().global.Symbol;
+
+assert.sameValue(Symbol.asyncIterator, OSymbol.asyncIterator);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Symbol/asyncIterator/prop-desc.js
@@ -0,0 +1,23 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-symbol.asynciterator
+description: >
+    `Symbol.asyncIterator` property descriptor
+info: |
+    This property has the attributes { [[Writable]]: false, [[Enumerable]]:
+    false, [[Configurable]]: false }.
+includes: [propertyHelper.js]
+features: [Symbol.asyncIterator]
+---*/
+
+assert.sameValue(typeof Symbol.asyncIterator, 'symbol');
+
+verifyProperty(Symbol, 'asyncIterator', {
+    enumerable: false,
+    writable: false,
+    configurable: false,
+});
+
+reportCompare(0, 0);
new file mode 100644
--- a/js/src/tests/test262/built-ins/TypedArrayConstructors/Float32Array/length.js
+++ b/js/src/tests/test262/built-ins/TypedArrayConstructors/Float32Array/length.js
@@ -1,9 +1,8 @@
-// |reftest| skip-if(!this.hasOwnProperty('BigInt')) -- BigInt is not enabled unconditionally
 // Copyright (C) 2015 André Bargull. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 esid: sec-typedarray-constructors
 description: Float32Array.length property descriptor
 info: |
   The TypedArray Constructors
@@ -13,17 +12,17 @@ info: |
   17 ECMAScript Standard Built-in Objects
 
   ...
 
   Unless otherwise specified, the length property of a built-in function
   object has the attributes { [[Writable]]: false, [[Enumerable]]: false,
   [[Configurable]]: true }.
 includes: [propertyHelper.js]
-features: [BigInt]
+features: [TypedArray]
 ---*/
 
 verifyProperty(Float32Array, "length", {
   value: 3,
   writable: false,
   enumerable: false,
   configurable: true
 });
--- a/js/src/tests/test262/harness/assert-false.js
+++ b/js/src/tests/test262/harness/assert-false.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     `false` does not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert(false);
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-notsamevalue-nan.js
+++ b/js/src/tests/test262/harness/assert-notsamevalue-nan.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Two references to NaN do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.notSameValue(NaN, NaN);
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-obj.js
+++ b/js/src/tests/test262/harness/assert-obj.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     An object literal does not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert({});
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-samevalue-objects.js
+++ b/js/src/tests/test262/harness/assert-samevalue-objects.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Distinct objects do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.sameValue({}, {});
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-samevalue-zeros.js
+++ b/js/src/tests/test262/harness/assert-samevalue-zeros.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Positive and negative zero do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.sameValue(0, -0);
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-throws-incorrect-ctor.js
+++ b/js/src/tests/test262/harness/assert-throws-incorrect-ctor.js
@@ -1,16 +1,15 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   Functions that throw values whose constructor does not match the specified
   constructor do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.throws(Error, function() {
     throw new TypeError();
   });
--- a/js/src/tests/test262/harness/assert-throws-native.js
+++ b/js/src/tests/test262/harness/assert-throws-native.js
@@ -1,16 +1,15 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Functions that throw instances of the specified native Error constructor
     satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 assert.throws(Error, function() {
   throw new Error();
 });
 
 assert.throws(EvalError, function() {
   throw new EvalError();
--- a/js/src/tests/test262/harness/assert-throws-no-arg.js
+++ b/js/src/tests/test262/harness/assert-throws-no-arg.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     The assertion fails when invoked without arguments.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.throws();
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-throws-no-error.js
+++ b/js/src/tests/test262/harness/assert-throws-no-error.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Functions that do not throw errors do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.throws(Error, function() {});
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-throws-null-fn.js
+++ b/js/src/tests/test262/harness/assert-throws-null-fn.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   Fails if second arg is not a function
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.throws(TypeError, null);
 } catch(err) {
   threw = true;
--- a/js/src/tests/test262/harness/assert-throws-null.js
+++ b/js/src/tests/test262/harness/assert-throws-null.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Functions that throw the `null` value do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 
 var threw = false;
 
 try {
   assert.throws(Error, function() {
     throw null;
   });
--- a/js/src/tests/test262/harness/assert-throws-primitive.js
+++ b/js/src/tests/test262/harness/assert-throws-primitive.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Functions that throw primitive values do not satisfy the assertion.
-includes: [sta.js]
 ---*/
 var threw = false;
 
 try {
   assert.throws(Error, function() {
     throw 3;
   });
 } catch(err) {
--- a/js/src/tests/test262/harness/assert-throws-single-arg.js
+++ b/js/src/tests/test262/harness/assert-throws-single-arg.js
@@ -1,15 +1,14 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     The assertion fails when invoked with a single argument.
-includes: [sta.js]
 ---*/
 var threw = false;
 
 try {
   assert.throws(function() {});
 } catch(err) {
   threw = true;
   if (err.constructor !== Test262Error) {
--- a/js/src/tests/test262/harness/assertRelativeDateMs.js
+++ b/js/src/tests/test262/harness/assertRelativeDateMs.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: >
      Only passes when the provided date is exactly the specified number of
      milliseconds from the Unix epoch
-includes: [assertRelativeDateMs.js,sta.js]
+includes: [assertRelativeDateMs.js]
 ---*/
 
 var thrown;
 
 assertRelativeDateMs(new Date(1970, 0), 0);
 assertRelativeDateMs(new Date(1970, 0, 1, 0, 0, 0, 0), 0);
 assertRelativeDateMs(new Date(1970, 0, 1, 0, 0, 0, 1), 1);
 assertRelativeDateMs(new Date(1970, 0, 1, 0, 0, 0, -1), -1);
--- a/js/src/tests/test262/harness/detachArrayBuffer-host-detachArrayBuffer.js
+++ b/js/src/tests/test262/harness/detachArrayBuffer-host-detachArrayBuffer.js
@@ -3,17 +3,17 @@
 /*---
 description: >
     Including detachArrayBuffer.js will expose a function:
 
         $DETACHBUFFER
 
     $DETACHBUFFER relies on the presence of a host definition for $262.detachArrayBuffer
 
-includes: [detachArrayBuffer.js,sta.js]
+includes: [detachArrayBuffer.js]
 ---*/
 
 var $262 = {
   detachArrayBuffer() {
     throw new Test262Error('$262.detachArrayBuffer called.');
   },
   destroy() {}
 };
--- a/js/src/tests/test262/harness/detachArrayBuffer.js
+++ b/js/src/tests/test262/harness/detachArrayBuffer.js
@@ -4,18 +4,16 @@
 description: >
     Including detachArrayBuffer.js will expose a function:
 
         $DETACHBUFFER
 
     $DETACHBUFFER relies on the presence of a definition for $262.detachArrayBuffer.
 
     Without a definition, calling $DETACHBUFFER will result in a ReferenceError
-
-includes: [sta.js]
 ---*/
 
 var ab = new ArrayBuffer(1);
 var threw = false;
 
 try {
   $DETACHBUFFER(ab);
 } catch(err) {
--- a/js/src/tests/test262/harness/promiseHelper.js
+++ b/js/src/tests/test262/harness/promiseHelper.js
@@ -5,17 +5,17 @@ description: >
     Including promiseHelper.js will expose a function:
 
         checkSequence
 
     To ensure execution order of some async chain, checkSequence accepts an array
     of numbers, each added during some operation, and verifies that they
     are in numeric order.
 
-includes: [promiseHelper.js,sta.js]
+includes: [promiseHelper.js]
 ---*/
 
 assert(checkSequence([1, 2, 3, 4, 5]));
 
 var threw = false;
 
 try {
   checkSequence([2, 1, 3, 4, 5]);
--- a/js/src/tests/test262/harness/propertyhelper-verifyconfigurable-not-configurable-not-strict.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifyconfigurable-not-configurable-not-strict.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is not configurable do not satisfy the
     assertion outside of strict mode.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 flags: [noStrict]
 ---*/
 
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   configurable: false
 });
--- a/js/src/tests/test262/harness/propertyhelper-verifyconfigurable-not-configurable-strict-strict.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifyconfigurable-not-configurable-strict-strict.js
@@ -1,17 +1,17 @@
 'use strict';
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is not configurable do not satisfy the
     assertion in strict mode.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 flags: [onlyStrict]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   configurable: false
 });
 
--- a/js/src/tests/test262/harness/propertyhelper-verifyenumerable-not-enumerable-symbol.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifyenumerable-not-enumerable-symbol.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified symbol property is not enumerable do not satisfy the
     assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 features: [Symbol]
 ---*/
 var threw = false;
 var obj = {};
 var s = Symbol('1');
 Object.defineProperty(obj, s, {
   enumerable: false
 });
--- a/js/src/tests/test262/harness/propertyhelper-verifyenumerable-not-enumerable.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifyenumerable-not-enumerable.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified string property is not enumerable do not satisfy the
     assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   enumerable: false
 });
 
 try {
--- a/js/src/tests/test262/harness/propertyhelper-verifynotconfigurable-configurable.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifynotconfigurable-configurable.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is configurable do not satisfy the
     assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   configurable: true
 });
 
 try {
--- a/js/src/tests/test262/harness/propertyhelper-verifynotconfigurable-not-configurable-strict-strict.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifynotconfigurable-not-configurable-strict-strict.js
@@ -1,17 +1,17 @@
 'use strict';
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is not configurable satisfy the assertion
     in strict mode.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 flags: [onlyStrict]
 ---*/
 var obj = {};
 Object.defineProperty(obj, 'a', {
   configurable: false
 });
 
 verifyNotConfigurable(obj, 'a');
--- a/js/src/tests/test262/harness/propertyhelper-verifynotenumerable-enumerable-symbol.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifynotenumerable-enumerable-symbol.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2016 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified symbol property is enumerable do not satisfy the
     assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 features: [Symbol]
 ---*/
 var threw = false;
 var obj = {};
 var s = Symbol('1');
 Object.defineProperty(obj, s, {
   enumerable: true
 });
--- a/js/src/tests/test262/harness/propertyhelper-verifynotenumerable-enumerable.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifynotenumerable-enumerable.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified string property is enumerable do not satisfy the
     assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   enumerable: true
 });
 
 try {
--- a/js/src/tests/test262/harness/propertyhelper-verifynotwritable-writable.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifynotwritable-writable.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is writable do not satisfy the assertion.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   writable: true,
   value: 1
 });
 
--- a/js/src/tests/test262/harness/propertyhelper-verifywritable-not-writable-not-strict.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifywritable-not-writable-not-strict.js
@@ -1,16 +1,16 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is not writable do not satisfy the
     assertion outside of strict mode.
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 flags: [noStrict]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   writable: false
 });
 
--- a/js/src/tests/test262/harness/propertyhelper-verifywritable-not-writable-strict-strict.js
+++ b/js/src/tests/test262/harness/propertyhelper-verifywritable-not-writable-strict-strict.js
@@ -2,17 +2,17 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     Objects whose specified property is not writable do not satisfy the
     assertion in strict mode.
 
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 flags: [onlyStrict]
 ---*/
 var threw = false;
 var obj = {};
 Object.defineProperty(obj, 'a', {
   writable: false
 });
 
--- a/js/src/tests/test262/harness/sta-error.js
+++ b/js/src/tests/test262/harness/sta-error.js
@@ -1,16 +1,15 @@
 // Copyright (C) 2015 the V8 project authors. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
     The global `$ERROR` function throws an instance of the global `Test262Error`
     function with the specified message.
-includes: [sta.js]
 ---*/
 var threw = false;
 
 try {
   $ERROR('This is a test message');
 } catch(err) {
   threw = true;
   if (err.constructor !== Test262Error) {
--- a/js/src/tests/test262/harness/sta-override-error.js
+++ b/js/src/tests/test262/harness/sta-override-error.js
@@ -4,17 +4,16 @@
 /*---
 description: >
     Including sta.js will expose two functions:
 
         Test262Error
         $ERROR
 
     Assert that global $ERROR is overridable
-includes: [sta.js]
 ---*/
 function BaloneyError() {}
 
 // Override $ERROR
 $ERROR = function() {
   throw new BaloneyError();
 };
 
--- a/js/src/tests/test262/harness/sta.js
+++ b/js/src/tests/test262/harness/sta.js
@@ -1,17 +1,15 @@
 // Copyright (c) 2017 Rick Waldron.  All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 description: >
     Including sta.js will expose two functions:
 
         Test262Error
         $ERROR
-
-includes: [sta.js]
 ---*/
 
 assert(typeof Test262Error === "function");
 assert(typeof Test262Error.prototype.toString === "function");
 assert(typeof $ERROR === "function");
 
 reportCompare(0, 0);
--- a/js/src/tests/test262/harness/verifyProperty-arguments.js
+++ b/js/src/tests/test262/harness/verifyProperty-arguments.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2017 Leo Balter. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   verifyProperty should receive at least 3 arguments: obj, name, and descriptor
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 assert.throws(Test262Error, () => {
   verifyProperty();
 }, "0 arguments");
 
 assert.throws(Test262Error, () => {
   verifyProperty(Object);
 }, "1 argument");
--- a/js/src/tests/test262/harness/verifyProperty-desc-is-not-object.js
+++ b/js/src/tests/test262/harness/verifyProperty-desc-is-not-object.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2017 Leo Balter. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   The desc argument should be an object or undefined
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 features: [Symbol]
 ---*/
 var sample = { foo: 42 };
 
 assert.throws(Test262Error, () => {
   verifyProperty(sample, "foo", 'configurable');
 }, "string");
 
--- a/js/src/tests/test262/harness/verifyProperty-noproperty.js
+++ b/js/src/tests/test262/harness/verifyProperty-noproperty.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2017 Leo Balter. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   The first argument should have an own property
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 assert.throws(Test262Error, () => {
   verifyProperty(Object, 'JeanPaulSartre', {});
 }, "inexisting property");
 
 assert.throws(Test262Error, () => {
   verifyProperty({}, 'hasOwnProperty', {});
 }, "inexisting own property");
--- a/js/src/tests/test262/harness/verifyProperty-undefined-desc.js
+++ b/js/src/tests/test262/harness/verifyProperty-undefined-desc.js
@@ -1,15 +1,15 @@
 // Copyright (C) 2017 Leo Balter. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 
 /*---
 description: >
   Verify an undefined descriptor
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 var sample = {
   bar: undefined,
   get baz() {}
 };
 
 assert.sameValue(
   verifyProperty(sample, "foo", undefined),
--- a/js/src/tests/test262/harness/verifyProperty-value-error.js
+++ b/js/src/tests/test262/harness/verifyProperty-value-error.js
@@ -3,17 +3,17 @@
 
 /*---
 description: >
     Including propertyHelper.js will expose:
 
         verifyProperty()
         ...
 
-includes: [propertyHelper.js,sta.js]
+includes: [propertyHelper.js]
 ---*/
 
 var threw = false;
 var object = Object.defineProperty({}, "prop", {
   value: 1
 });
 
 try {
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/Collator/constructor-options-throwing-getters.js
@@ -0,0 +1,30 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializecollator
+description: Checks the propagation of exceptions from the options for the Collator constructor.
+---*/
+
+function CustomError() {}
+
+const options = [
+  "usage",
+  "localeMatcher",
+  "numeric",
+  "caseFirst",
+  "sensitivity",
+  "ignorePunctuation",
+];
+
+for (const option of options) {
+  assert.throws(CustomError, () => {
+    new Intl.Collator("en", {
+      get [option]() {
+        throw new CustomError();
+      }
+    });
+  }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/Collator/prototype/resolvedOptions/order.js
@@ -0,0 +1,33 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.collator.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+includes: [compareArray.js]
+---*/
+
+const options = new Intl.Collator([], {
+  "numeric": true,
+  "caseFirst": "upper",
+}).resolvedOptions();
+
+const expected = [
+  "locale",
+  "usage",
+  "sensitivity",
+  "ignorePunctuation",
+  "collation",
+];
+
+if ("numeric" in options) {
+  expected.push("numeric");
+}
+
+if ("caseFirst" in options) {
+  expected.push("caseFirst");
+}
+
+assert.compareArray(Object.getOwnPropertyNames(options), expected);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-order.js
@@ -0,0 +1,116 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializedatetimeformat
+description: Checks the order of getting options for the DateTimeFormat constructor.
+includes: [compareArray.js]
+---*/
+
+const expected = [
+  // ToDateTimeOptions step 4.
+  "weekday", "year", "month", "day",
+  // ToDateTimeOptions step 5.
+  "hour", "minute", "second",
+
+  // InitializeDateTimeFormat step 4.
+  "localeMatcher",
+  // InitializeDateTimeFormat step 6.
+  "hour12",
+  // InitializeDateTimeFormat step 7.
+  "hourCycle",
+  // InitializeDateTimeFormat step 17.
+  "timeZone",
+  // InitializeDateTimeFormat step 22.
+  "weekday",
+  "era",
+  "year",
+  "month",
+  "day",
+  "hour",
+  "minute",
+  "second",
+  "timeZoneName",
+  // InitializeDateTimeFormat step 25.
+  "formatMatcher",
+];
+
+const actual = [];
+
+const options = {
+  get day() {
+    actual.push("day");
+    return "numeric";
+  },
+
+  get era() {
+    actual.push("era");
+    return "long";
+  },
+
+  get formatMatcher() {
+    actual.push("formatMatcher");
+    return "best fit";
+  },
+
+  get hour() {
+    actual.push("hour");
+    return "numeric";
+  },
+
+  get hour12() {
+    actual.push("hour12");
+    return true;
+  },
+
+  get hourCycle() {
+    actual.push("hourCycle");
+    return "h24";
+  },
+
+  get localeMatcher() {
+    actual.push("localeMatcher");
+    return "best fit";
+  },
+
+  get minute() {
+    actual.push("minute");
+    return "numeric";
+  },
+
+  get month() {
+    actual.push("month");
+    return "numeric";
+  },
+
+  get second() {
+    actual.push("second");
+    return "numeric";
+  },
+
+  get timeZone() {
+    actual.push("timeZone");
+    return "UTC";
+  },
+
+  get timeZoneName() {
+    actual.push("timeZoneName");
+    return "long";
+  },
+
+  get weekday() {
+    actual.push("weekday");
+    return "long";
+  },
+
+  get year() {
+    actual.push("year");
+    return "numeric";
+  },
+};
+
+new Intl.DateTimeFormat("en", options);
+
+assert.compareArray(actual, expected);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/constructor-options-throwing-getters.js
@@ -0,0 +1,33 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-initializedatetimeformat
+description: Checks the propagation of exceptions from the options for the DateTimeFormat constructor.
+---*/
+
+function CustomError() {}
+
+const options = [
+  "weekday", "year", "month", "day",
+  "hour", "minute", "second",
+  "localeMatcher",
+  "hour12",
+  "hourCycle",
+  "timeZone",
+  "era",
+  "timeZoneName",
+  "formatMatcher",
+];
+
+for (const option of options) {
+  assert.throws(CustomError, () => {
+    new Intl.DateTimeFormat("en", {
+      get [option]() {
+        throw new CustomError();
+      }
+    });
+  }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
@@ -0,0 +1,43 @@
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.datetimeformat.prototype.resolvedoptions
+description: Verifies the property order for the object returned by resolvedOptions().
+includes: [compareArray.js]
+---*/
+
+const options = new Intl.DateTimeFormat([], {
+  "hourCycle": "h24",
+  "weekday": "short",
+  "era": "short",
+  "year": "numeric",
+  "month": "numeric",
+  "day": "numeric",
+  "hour": "numeric",
+  "minute": "numeric",
+  "second": "numeric",
+  "timeZoneName": "short",
+}).resolvedOptions();
+
+const expected = [
+  "locale",
+  "calendar",
+  "numberingSystem",
+  "timeZone",
+  "hourCycle",
+  "hour12",
+  "weekday",
+  "era",
+  "year",
+  "month",
+  "day",
+  "hour",
+  "minute",
+  "second",
+  "timeZoneName",
+];
+
+assert.compareArray(Object.getOwnPropertyNames(options), expected);
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/locales-invalid.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks error cases for the locales argument to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    1. Let _requestedLocales_ be ? CanonicalizeLocaleList(_locales_).
+includes: [testIntl.js]
+features: [Intl.ListFormat]
+---*/
+
+for (const [locales, expectedError] of getInvalidLocaleArguments()) {
+    assert.throws(expectedError, function() { new Intl.ListFormat(locales) })
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/locales-valid.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks various cases for the locales argument to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    1. Let _requestedLocales_ be ? CanonicalizeLocaleList(_locales_).
+includes: [testIntl.js]
+features: [Intl.ListFormat]
+---*/
+
+const defaultLocale = new Intl.ListFormat().resolvedOptions().locale;
+
+const tests = [
+  [undefined, defaultLocale, "undefined"],
+  ["EN", "en", "Single value"],
+  [[], defaultLocale, "Empty array"],
+  [["en-GB-oed"], "en-GB", "Grandfathered"],
+  [["x-private"], defaultLocale, "Private", ["lookup"]],
+  [["en", "EN"], "en", "Duplicate value (canonical first)"],
+  [["EN", "en"], "en", "Duplicate value (canonical last)"],
+  [{ 0: "DE", length: 0 }, defaultLocale, "Object with zero length"],
+  [{ 0: "DE", length: 1 }, "de", "Object with length"],
+];
+
+for (const [locales, expected, name, matchers = ["lookup", "best fit"]] of tests) {
+  for (const matcher of matchers) {
+    const rtf = new Intl.ListFormat(locales, {localeMatcher: matcher});
+    assert.sameValue(rtf.resolvedOptions().locale, expected, name);
+  }
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/newtarget-undefined.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-intl.ListFormat
+description: >
+    Verifies the NewTarget check for Intl.ListFormat.
+info: |
+    Intl.ListFormat ([ locales [ , options ]])
+
+    1. If NewTarget is undefined, throw a TypeError exception.
+features: [Intl.ListFormat]
+---*/
+
+assert.throws(TypeError, function() {
+  Intl.ListFormat();
+});
+
+assert.throws(TypeError, function() {
+  Intl.ListFormat("en");
+});
+
+assert.throws(TypeError, function() {
+  Intl.ListFormat("not-valid-tag");
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-bad-combinations.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of invalid value for the type option to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    7. Let type be GetOption(options, "type", "string", « "conjunction", "disjunction", "unit" », "conjunction").
+features: [Intl.ListFormat]
+---*/
+
+const invalidTypes = [
+  "conjunction",
+  "disjunction",
+];
+
+for (const type of invalidTypes) {
+  assert.throws(RangeError, function() {
+    new Intl.ListFormat([], { style: "narrow", type });
+  }, `${type} is an invalid type option value when style is narrow.`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-invalid.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of a null options argument to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    3. Else
+        a. Let options be ? ToObject(options).
+features: [Intl.ListFormat]
+---*/
+
+assert.throws(TypeError, function() { new Intl.ListFormat([], null) })
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-localeMatcher-invalid.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of invalid value for the localeMatcher option to the ListFormat constructor.
+info: |
+    Intl.ListFormat ( [ locales [ , options ] ] )
+    12. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
+features: [Intl.ListFormat]
+---*/
+
+const invalidOptions = [
+  null,
+  1,
+  "",
+  "Lookup",
+  "LOOKUP",
+  "lookup\0",
+  "Best fit",
+  "BEST FIT",
+  "best\u00a0fit",
+];
+
+for (const localeMatcher of invalidOptions) {
+  assert.throws(RangeError, function() {
+    new Intl.ListFormat([], { localeMatcher });
+  }, `${localeMatcher} is an invalid localeMatcher option value`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-order.js
@@ -0,0 +1,60 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks the order of operations on the options argument to the ListFormat constructor.
+info: |
+    Intl.ListFormat ( [ locales [ , options ] ] )
+    7. Let type be GetOption(options, "type", "string", « "conjunction", "disjunction", "unit" », "conjunction").
+    9. Let style be GetOption(options, "style", "string", « "long", "short", "narrow" », "long").
+    12. Let matcher be ? GetOption(options, "localeMatcher", "string", « "lookup", "best fit" », "best fit").
+includes: [compareArray.js]
+features: [Intl.ListFormat]
+---*/
+
+const callOrder = [];
+
+new Intl.ListFormat([], {
+  get localeMatcher() {
+    callOrder.push("localeMatcher");
+    return {
+      toString() {
+        callOrder.push("localeMatcher toString");
+        return "best fit";
+      }
+    };
+  },
+
+  get type() {
+    callOrder.push("type");
+    return {
+      toString() {
+        callOrder.push("type toString");
+        return "unit";
+      }
+    };
+  },
+
+  get style() {
+    callOrder.push("style");
+    return {
+      toString() {
+        callOrder.push("style toString");
+        return "short";
+      }
+    };
+  },
+});
+
+assert.compareArray(callOrder, [
+  "type",
+  "type toString",
+  "style",
+  "style toString",
+  "localeMatcher",
+  "localeMatcher toString",
+]);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-style-invalid.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of invalid value for the style option to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    9. Let s be ? GetOption(options, "style", "string", «"long", "short", "narrow"», "long").
+features: [Intl.ListFormat]
+---*/
+
+const invalidOptions = [
+  null,
+  1,
+  "",
+  "Long",
+  "LONG",
+  "long\0",
+  "Short",
+  "SHORT",
+  "short\0",
+  "Narrow",
+  "NARROW",
+  "narrow\0",
+];
+
+for (const invalidOption of invalidOptions) {
+  assert.throws(RangeError, function() {
+    new Intl.ListFormat([], {"style": invalidOption});
+  }, `${invalidOption} is an invalid style option value`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-style-valid.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of valid values for the style option to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    9. Let s be ? GetOption(options, "style", "string", «"long", "short", "narrow"», "long").
+    10. Set listFormat.[[Style]] to s.
+    14. If style is "narrow" and type is not "unit", throw a RangeError exception.
+features: [Intl.ListFormat]
+---*/
+
+const validOptions = [
+  [undefined, "long"],
+  ["long", "long"],
+  ["short", "short"],
+  [{ toString() { return "short"; } }, "short"],
+];
+
+for (const [validOption, expected] of validOptions) {
+  const lf = new Intl.ListFormat([], {"style": validOption});
+  const resolvedOptions = lf.resolvedOptions();
+  assert.sameValue(resolvedOptions.style, expected);
+}
+
+const lf = new Intl.ListFormat([], {"style": "narrow", "type": "unit"});
+const resolvedOptions = lf.resolvedOptions();
+assert.sameValue(resolvedOptions.style, "narrow");
+
+assert.throws(RangeError, () => lf = new Intl.ListFormat([], {"style": "narrow"}));
+assert.throws(RangeError, () => lf = new Intl.ListFormat([], {"style": "narrow", "type": "conjuction"}));
+assert.throws(RangeError, () => lf = new Intl.ListFormat([], {"style": "narrow", "type": "disjuction"}));
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-throwing-getters.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks the propagation of exceptions from the options for the ListFormat constructor.
+features: [Intl.ListFormat]
+---*/
+
+function CustomError() {}
+
+const options = [
+  "type",
+  "style",
+];
+
+for (const option of options) {
+  assert.throws(CustomError, () => {
+    new Intl.ListFormat("en", {
+      get [option]() {
+        throw new CustomError();
+      }
+    });
+  }, `Exception from ${option} getter should be propagated`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-toobject-prototype.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of non-object option arguments to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+features: [Intl.ListFormat]
+---*/
+
+Object.defineProperties(Object.prototype, {
+  "type": {
+    value: "unit",
+  },
+  "style": {
+    value: "short",
+  },
+})
+
+const optionsArguments = [
+  true,
+  "test",
+  7,
+  Symbol(),
+];
+
+for (const options of optionsArguments) {
+  const lf = new Intl.ListFormat([], options);
+  const resolvedOptions = lf.resolvedOptions();
+  assert.sameValue(resolvedOptions.type, "unit",
+    `options argument ${String(options)} should yield the correct value for "type"`);
+  assert.sameValue(resolvedOptions.style, "short",
+    `options argument ${String(options)} should yield the correct value for "style"`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-toobject.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of non-object option arguments to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+features: [Intl.ListFormat]
+---*/
+
+const optionsArguments = [
+  true,
+  "test",
+  7,
+  Symbol(),
+];
+
+for (const options of optionsArguments) {
+  const lf = new Intl.ListFormat([], options);
+  const resolvedOptions = lf.resolvedOptions();
+  assert.sameValue(resolvedOptions.type, "conjunction",
+    `options argument ${String(options)} should yield the correct value for "type"`);
+  assert.sameValue(resolvedOptions.style, "long",
+    `options argument ${String(options)} should yield the correct value for "style"`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-type-invalid.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of invalid value for the type option to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    7. Let type be GetOption(options, "type", "string", « "conjunction", "disjunction", "unit" », "conjunction").
+features: [Intl.ListFormat]
+---*/
+
+const invalidOptions = [
+  null,
+  1,
+  "",
+  "Conjunction",
+  "CONJUNCTION",
+  "conjunction\0",
+  "Disjunction",
+  "DISJUNCTION",
+  "disjunction\0",
+  "Unit",
+  "UNIT",
+  "unit\0",
+];
+
+for (const invalidOption of invalidOptions) {
+  assert.throws(RangeError, function() {
+    new Intl.ListFormat([], {"type": invalidOption});
+  }, `${invalidOption} is an invalid type option value`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-type-valid.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of valid values for the style option to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+    7. Let type be GetOption(options, "type", "string", « "conjunction", "disjunction", "unit" », "conjunction").
+    8. Set listFormat.[[Type]] to type.
+features: [Intl.ListFormat]
+---*/
+
+const validOptions = [
+  [undefined, "conjunction"],
+  ["conjunction", "conjunction"],
+  ["disjunction", "disjunction"],
+  ["unit", "unit"],
+  [{ toString() { return "unit"; } }, "unit"],
+];
+
+for (const [validOption, expected] of validOptions) {
+  const lf = new Intl.ListFormat([], {"type": validOption});
+  const resolvedOptions = lf.resolvedOptions();
+  assert.sameValue(resolvedOptions.type, expected);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/options-undefined.js
@@ -0,0 +1,41 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks handling of non-object option arguments to the ListFormat constructor.
+info: |
+    InitializeListFormat (listFormat, locales, options)
+features: [Intl.ListFormat]
+---*/
+
+Object.defineProperties(Object.prototype, {
+  "type": {
+    get() {
+      throw new Error("Should not call type getter");
+    }
+  },
+  "style": {
+    get() {
+      throw new Error("Should not call style getter");
+    }
+  },
+})
+
+const optionsArguments = [
+  [],
+  [[]],
+  [[], undefined],
+];
+
+for (const args of optionsArguments) {
+  const lf = new Intl.ListFormat(...args);
+  const resolvedOptions = lf.resolvedOptions();
+  assert.sameValue(resolvedOptions.type, "conjunction",
+    `Calling with ${args.length} empty arguments should yield the correct value for "type"`);
+  assert.sameValue(resolvedOptions.style, "long",
+    `Calling with ${args.length} empty arguments should yield the correct value for "style"`);
+}
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/constructor/subclassing.js
@@ -0,0 +1,42 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Checks that ListFormat can be subclassed.
+info: |
+    Intl.ListFormat ( [ locales [ , options ] ] )
+
+    2. Let listFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%ListFormatPrototype%", « [[InitializedListFormat]], [[Locale]], [[Type]], [[Style]] »).
+
+features: [Intl.ListFormat]
+---*/
+
+class CustomListFormat extends Intl.ListFormat {
+  constructor(locales, options) {
+    super(locales, options);
+    this.isCustom = true;
+  }
+}
+
+const locale = "de";
+const argument = ["foo", "bar"];
+
+const real_lf = new Intl.ListFormat(locale);
+assert.sameValue(real_lf.isCustom, undefined, "Custom property");
+
+const custom_lf = new CustomListFormat(locale);
+assert.sameValue(custom_lf.isCustom, true, "Custom property");
+
+assert.sameValue(custom_lf.format(argument),
+                 real_lf.format(argument),
+                 "Direct call");
+
+assert.sameValue(Intl.ListFormat.prototype.format.call(custom_lf, argument),
+                 Intl.ListFormat.prototype.format.call(real_lf, argument),
+                 "Indirect call");
+
+assert.sameValue(Object.getPrototypeOf(custom_lf), CustomListFormat.prototype, "Prototype");
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/length.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: >
+    Checks the "length" property of the ListFormat constructor.
+info: |
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+    The ListFormat constructor is a standard built-in property of the Intl object.
+    Every built-in function object, including constructors, has a length property whose value is an integer. Unless otherwise specified, this value is equal to the largest number of named arguments shown in the subclause headings for the function description. Optional parameters (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form «...name») are not included in the default argument count.
+    Unless otherwise specified, the length property of a built-in function object has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+verifyProperty(Intl.ListFormat, "length", {
+  value: 0,
+  writable: false,
+  enumerable: false,
+  configurable: true
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/name.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: >
+    Checks the "name" property of the ListFormat constructor.
+info: |
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+    Every built-in function object, including constructors, that is not identified as an anonymous function has a name property whose value is a String. Unless otherwise specified, this value is the name that is given to the function in this specification.
+    Unless otherwise specified, the name property of a built-in function object, if it exists, has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+verifyProperty(Intl.ListFormat, "name", {
+  value: "ListFormat",
+  writable: false,
+  enumerable: false,
+  configurable: true
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/prop-desc.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: >
+  "ListFormat" property of Intl.
+info: |
+  Intl.ListFormat (...)
+
+  7 Requirements for Standard Built-in ECMAScript Objects
+
+    Unless specified otherwise in this document, the objects, functions, and constructors
+    described in this standard are subject to the generic requirements and restrictions
+    specified for standard built-in ECMAScript objects in the ECMAScript 2018 Language
+    Specification, 9th edition, clause 17, or successor.
+
+  17 ECMAScript Standard Built-in Objects:
+
+    Every other data property described in clauses 18 through 26 and in Annex B.2 has the
+    attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }
+    unless otherwise specified.
+
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat, "function");
+
+verifyProperty(Intl, "ListFormat", {
+  value: Intl.ListFormat,
+  writable: true,
+  enumerable: false,
+  configurable: true,
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/prototype.js
@@ -0,0 +1,20 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: The prototype of the Intl.ListFormat constructor is %FunctionPrototype%.
+info: |
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+    Unless otherwise specified every built-in function object has the %FunctionPrototype% object as the initial value of its [[Prototype]] internal slot.
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(
+  Object.getPrototypeOf(Intl.ListFormat),
+  Function.prototype,
+  "Object.getPrototypeOf(Intl.ListFormat) equals the value of Function.prototype"
+);
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/basic.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Google Inc., Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: >
+    Tests that Intl.ListFormat has a supportedLocalesOf property,
+    and it works as planned.
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "supportedLocalesOf should be supported.");
+
+const defaultLocale = new Intl.ListFormat().resolvedOptions().locale;
+const notSupported = 'zxx'; // "no linguistic content"
+const requestedLocales = [defaultLocale, notSupported];
+
+const supportedLocales = Intl.ListFormat.supportedLocalesOf(requestedLocales);
+assert.sameValue(supportedLocales.length, 1, 'The length of supported locales list is not 1.');
+assert.sameValue(supportedLocales[0], defaultLocale, 'The default locale is not returned in the supported list.');
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/branding.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: >
+    Verifies there's no branding check for Intl.ListFormat.supportedLocalesOf().
+info: |
+    Intl.ListFormat.supportedLocalesOf ( locales [, options ])
+features: [Intl.ListFormat]
+---*/
+
+const fn = Intl.ListFormat.supportedLocalesOf;
+const thisValues = [
+  undefined,
+  null,
+  true,
+  "",
+  Symbol(),
+  1,
+  {},
+  Intl.ListFormat,
+  Intl.ListFormat.prototype,
+];
+
+for (const thisValue of thisValues) {
+  const result = fn.call(thisValue);
+  assert.sameValue(Array.isArray(result), true);
+}
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/length.js
@@ -0,0 +1,25 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: >
+    Checks the "length" property of Intl.ListFormat.supportedLocalesOf().
+info: |
+    The value of the length property of the supportedLocalesOf method is 1.
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+    Every built-in function object, including constructors, has a length property whose value is an integer.
+    Unless otherwise specified, the length property of a built-in function object has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+verifyProperty(Intl.ListFormat.supportedLocalesOf, "length", {
+  value: 1,
+  writable: false,
+  enumerable: false,
+  configurable: true
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/locales-invalid.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Checks error cases for the locales argument to the supportedLocalesOf function.
+info: |
+    Intl.ListFormat.supportedLocalesOf ( locales [, options ])
+
+    2. Let requestedLocales be CanonicalizeLocaleList(locales).
+includes: [testIntl.js]
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "Should support Intl.ListFormat.supportedLocalesOf.");
+
+for (const [locales, expectedError] of getInvalidLocaleArguments()) {
+    assert.throws(expectedError, () => Intl.ListFormat.supportedLocalesOf(locales));
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/name.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: >
+    Checks the "name" property of Intl.ListFormat.supportedLocalesOf().
+info: |
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+    Every built-in function object, including constructors, that is not identified as an anonymous function has a name property whose value is a String. Unless otherwise specified, this value is the name that is given to the function in this specification.
+    Unless otherwise specified, the name property of a built-in function object, if it exists, has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+verifyProperty(Intl.ListFormat.supportedLocalesOf, "name", {
+  value: "supportedLocalesOf",
+  writable: false,
+  enumerable: false,
+  configurable: true
+});
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/options-localeMatcher-invalid.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Checks handling of invalid values for the localeMatcher option to the supportedLocalesOf function.
+info: |
+    SupportedLocales ( availableLocales, requestedLocales, options )
+
+    1. If options is not undefined, then
+        b. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "Should support Intl.ListFormat.supportedLocalesOf.");
+
+const invalidOptions = [
+  null,
+  1,
+  "",
+  "Lookup",
+  "LOOKUP",
+  "lookup\0",
+  "Best fit",
+  "BEST FIT",
+  "best\u00a0fit",
+];
+
+for (const invalidOption of invalidOptions) {
+  assert.throws(RangeError, function() {
+    Intl.ListFormat.supportedLocalesOf([], {"localeMatcher": invalidOption});
+  }, `${invalidOption} is an invalid localeMatcher option value`);
+}
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/options-null.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Checks handling of a null options argument to the supportedLocalesOf function.
+info: |
+    SupportedLocales ( availableLocales, requestedLocales, options )
+
+    1. If options is not undefined, then
+        a. Let options be ? ToObject(options).
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "Should support Intl.ListFormat.supportedLocalesOf.");
+
+assert.throws(TypeError, function() {
+  Intl.ListFormat.supportedLocalesOf([], null);
+}, "Should throw when passing null as the options argument");
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/options-toobject.js
@@ -0,0 +1,44 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Checks handling of non-object options arguments to the supportedLocalesOf function.
+info: |
+    SupportedLocales ( availableLocales, requestedLocales, options )
+
+    1. If options is not undefined, then
+        a. Let options be ? ToObject(options).
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "Should support Intl.ListFormat.supportedLocalesOf.");
+
+let called;
+Object.defineProperties(Object.prototype, {
+  "localeMatcher": {
+    get() {
+      ++called;
+      return "best fit";
+    }
+  }
+});
+
+const optionsArguments = [
+  true,
+  "test",
+  7,
+  Symbol(),
+];
+
+for (const options of optionsArguments) {
+  called = 0;
+  const result = Intl.ListFormat.supportedLocalesOf([], options);
+  assert.sameValue(Array.isArray(result), true, `Expected array from ${String(options)}`);
+  assert.sameValue(called, 1, `Expected one call from ${String(options)}`);
+}
+
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/options-undefined.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Checks handling of an undefined options argument to the supportedLocalesOf function.
+info: |
+    SupportedLocales ( availableLocales, requestedLocales, options )
+
+    1. If options is not undefined, then
+        b. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(typeof Intl.ListFormat.supportedLocalesOf, "function",
+                 "Should support Intl.ListFormat.supportedLocalesOf.");
+
+Object.defineProperties(Object.prototype, {
+  "localeMatcher": {
+    get() { throw new Error("Should not call localeMatcher getter"); }
+  }
+});
+
+assert.sameValue(Array.isArray(Intl.ListFormat.supportedLocalesOf()), true, "No arguments");
+assert.sameValue(Array.isArray(Intl.ListFormat.supportedLocalesOf([])), true, "One argument");
+assert.sameValue(Array.isArray(Intl.ListFormat.supportedLocalesOf([], undefined)), true, "Two arguments");
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/prop-desc.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: >
+    Checks the "supportedLocalesOf" property of the ListFormat prototype object.
+info: |
+    Intl.ListFormat.supportedLocalesOf ( locales [, options ])
+
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+
+    Every other data property described in clauses 18 through 26 and in Annex B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(
+  typeof Intl.ListFormat.supportedLocalesOf,
+  "function",
+  "typeof Intl.ListFormat.supportedLocalesOf is function"
+);
+
+verifyProperty(Intl.ListFormat, "supportedLocalesOf", {
+  writable: true,
+  enumerable: false,
+  configurable: true,
+});
+
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/constructor/supportedLocalesOf/result-type.js
@@ -0,0 +1,37 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.supportedLocalesOf
+description: Verifies the type of the return value of Intl.ListFormat.supportedLocalesOf().
+info: |
+    Intl.ListFormat.supportedLocalesOf ( locales [, options ])
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]
+---*/
+
+const result = Intl.ListFormat.supportedLocalesOf("en");
+assert.sameValue(Array.isArray(result), true,
+  "Array.isArray() should return true");
+assert.sameValue(Object.getPrototypeOf(result), Array.prototype,
+  "The prototype should be Array.prototype");
+assert.sameValue(Object.isExtensible(result), true,
+  "Object.isExtensible() should return true");
+
+assert.notSameValue(result.length, 0);
+for (let i = 0; i < result.length; ++i) {
+  verifyProperty(result, String(i), {
+    "writable": false,
+    "enumerable": true,
+    "configurable": false,
+  });
+}
+
+verifyProperty(result, "length", {
+  "writable": false,
+  "enumerable": false,
+  "configurable": false,
+});
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/instance/extensibility.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Intl.ListFormat instance object extensibility
+info: |
+    17 ECMAScript Standard Built-in Objects:
+
+    Unless specified otherwise, the [[Extensible]] internal slot
+    of a built-in object initially has the value true.
+features: [Intl.ListFormat]
+---*/
+
+assert.sameValue(
+  Object.isExtensible(new Intl.ListFormat()),
+  true,
+  "Object.isExtensible(new Intl.ListFormat()) returns true"
+);
+
+reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/instance/prototype.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat
+description: Intl.ListFormat instance object is created from %ListFormatPrototype%.
+info: |
+    Intl.ListFormat ([ locales [ , options ]])
+
+    2. Let listFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%ListFormatPrototype%", « [[InitializedListFormat]], [[Locale]], [[Type]], [[Style]] »).
+features: [Intl.ListFormat]
+---*/
+
+const value = new Intl.ListFormat();
+assert.sameValue(
+  Object.getPrototypeOf(value),
+  Intl.ListFormat.prototype,
+  "Object.getPrototypeOf(value) equals the value of Intl.ListFormat.prototype"
+);
+
+reportCompare(0, 0);
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/intl402/ListFormat/prototype/constructor/prop-desc.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!Intl.hasOwnProperty('ListFormat')) -- Intl.ListFormat is not enabled unconditionally
+// Copyright 2018 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-Intl.ListFormat.prototype.constructor
+description: Checks the "constructor" property of the ListFormat prototype object.
+info: |
+    Intl.ListFormat.prototype.constructor
+
+    The initial value of Intl.ListFormat.prototype.constructor is %ListFormat%.
+
+    Unless specified otherwise in this document, the objects, functions, and constructors described in this standard are subject to the generic requirements and restrictions specified for standard built-in ECMAScript objects in the ECMAScript 2019 Language Specification, 10th edition, clause 17, or successor.
+
+    Every other data property described in clauses 18 through 26 and in Annex B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified.
+includes: [propertyHelper.js]
+features: [Intl.ListFormat]