diff --git a/test/built-ins/RegExp/named-groups/groups-object-undefined.js b/test/built-ins/RegExp/named-groups/groups-object-undefined.js
new file mode 100644
index 00000000000..ce4ef9b6caa
--- /dev/null
+++ b/test/built-ins/RegExp/named-groups/groups-object-undefined.js
@@ -0,0 +1,99 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: The groups object is created unconditionally
+includes: [propertyHelper.js]
+esid: sec-regexpbuiltinexec
+features: [regexp-named-groups]
+info: >
+ Runtime Semantics: RegExpBuiltinExec ( R, S )
+ 24. If _R_ contains any |GroupName|, then
+ a. Let _groups_ be ObjectCreate(*null*).
+ 25. Else,
+ a. Let _groups_ be *undefined*.
+ 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
+---*/
+
+// https://github.com/tc39/proposal-regexp-named-groups/pull/40
+{
+ const re = /./;
+ const result = re.exec("a");
+ assert.sameValue(result.__proto__, Array.prototype);
+ assert(result.hasOwnProperty("groups"));
+ assert.sameValue("a", result[0]);
+ assert.sameValue(0, result.index);
+ assert.sameValue(undefined, result.groups);
+ verifyProperty(result, "groups", {
+ writable: true,
+ enumerable: true,
+ configurable: true,
+ });
+
+ Array.prototype.groups = { a: "b" };
+ assert.sameValue("$", "a".replace(re, "$"));
+ Array.prototype.groups = undefined;
+}
+
+{
+ const re = /(?a).|(?x)/;
+ const result = re.exec("ab");
+ assert.sameValue(result.__proto__, Array.prototype);
+ assert(result.hasOwnProperty("groups"));
+ assert.sameValue("ab", result[0]);
+ assert.sameValue("a", result[1]);
+ assert.sameValue(undefined, result[2]);
+ assert.sameValue(0, result.index);
+ assert.sameValue("a", result.groups.a);
+ assert.sameValue(undefined, result.groups.x);
+
+ // `a` is a matched named capture, `b` is an unmatched named capture, and `z`
+ // is not a named capture.
+ Array.prototype.groups = { a: "b", x: "y", z: "z" };
+ assert.sameValue("a", "ab".replace(re, "$"));
+ assert.sameValue("", "ab".replace(re, "$"));
+ assert.sameValue("", "ab".replace(re, "$"));
+ Array.prototype.groups = undefined;
+}
+
+{
+ class FakeRegExp extends RegExp {
+ exec(subject) {
+ const fakeResult = ["ab", "a"];
+ fakeResult.index = 0;
+ // `groups` is not set, triggering prototype lookup.
+ return fakeResult;
+ }
+ };
+
+ const re = new FakeRegExp();
+ const result = re.exec("ab");
+ assert.sameValue(result.__proto__, Array.prototype);
+ assert.sameValue(false, result.hasOwnProperty("groups"));
+
+ Array.prototype.groups = { a: "b" };
+ Array.prototype.groups.__proto__.b = "c";
+ assert.sameValue("b", "ab".replace(re, "$"));
+ assert.sameValue("c", "ab".replace(re, "$"));
+ Array.prototype.groups = undefined;
+}
+
+{
+ class FakeRegExp extends RegExp {
+ exec(subject) {
+ const fakeResult = ["ab", "a"];
+ fakeResult.index = 0;
+ fakeResult.groups = { a: "b" };
+ fakeResult.groups.__proto__.b = "c";
+ return fakeResult;
+ }
+ };
+
+ const re = new FakeRegExp();
+ const result = re.exec("ab");
+ assert.sameValue(result.__proto__, Array.prototype);
+ assert(result.hasOwnProperty("groups"));
+ assert.sameValue("b", result.groups.a);
+ assert.sameValue("b", "ab".replace(re, "$"));
+ assert.sameValue("c", "ab".replace(re, "$"));
+}
diff --git a/test/built-ins/RegExp/named-groups/groups-object.js b/test/built-ins/RegExp/named-groups/groups-object.js
index a7d2b5433cc..62b7bd7ce70 100644
--- a/test/built-ins/RegExp/named-groups/groups-object.js
+++ b/test/built-ins/RegExp/named-groups/groups-object.js
@@ -1,4 +1,5 @@
// Copyright 2017 Aleksey Shvayka. All rights reserved.
+// Copyright 2017 Mathias Bynens. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
@@ -8,26 +9,31 @@ esid: sec-regexpbuiltinexec
features: [regexp-named-groups]
info: >
Runtime Semantics: RegExpBuiltinExec ( R, S )
- 24. If R contains any GroupName,
- a. Let groups be ObjectCreate(null).
- b. Perform ! CreateDataProperty(A, "groups", groups).
+ 24. If _R_ contains any |GroupName|, then
+ a. Let _groups_ be ObjectCreate(*null*).
+ 25. Else,
+ a. Let _groups_ be *undefined*.
+ 26. Perform ! CreateDataProperty(_A_, `"groups"`, _groups_).
---*/
-// groups is created with Define, not Set
+// `groups` is created with Define, not Set.
let counter = 0;
-Object.defineProperty(Array.prototype, "groups", {set() { counter++; }});
+Object.defineProperty(Array.prototype, "groups", {
+ set() { counter++; }
+});
+
let match = /(?.)/.exec("a");
assert.sameValue(counter, 0);
-// groups is writable, enumerable and configurable
-// (from CreateDataProperty)
+// `groups` is writable, enumerable and configurable
+// (from CreateDataProperty).
verifyProperty(match, "groups", {
writable: true,
enumerable: true,
configurable: true,
});
-// The '__proto__' property on the groups object is not special,
+// The `__proto__` property on the groups object is not special,
// and does not affect the [[Prototype]] of the resulting groups object.
let {groups} = /(?<__proto__>.)/.exec("a");
assert.sameValue("a", groups.__proto__);