diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T1.js b/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T1.js
deleted file mode 100644
index 2d3d8ee3ee229b73bdb41d9e44a9524946f9ea0b..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T1.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
-// See LICENSE for details.
-
-/*---
-info: >
-    Promise reaction jobs have predictable environment
-es6id: S25.4.2.1_A3.1_T1
-author: Sam Mikes
-description: Promise.onFulfilled gets undefined as 'this'
-flags: [noStrict]
-includes: [fnGlobalObject.js]
----*/
-
-var expectedThis = fnGlobalObject(),
-    obj = {};
-
-var p = Promise.resolve(obj).then(function(arg) {
-    if (this !== expectedThis) {
-        $ERROR("'this' must be global object, got " + this);
-    }
-    if (arg !== obj) {
-        $ERROR("Expected promise to be fulfilled by obj, actually " + arg);
-    }
-}).then($DONE, $DONE);
diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T2.js b/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T2.js
deleted file mode 100644
index a843cf5a55a9f15e1423a7e6a57be9f39a08216f..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.1_T2.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
-// See LICENSE for details.
-
-/*---
-info: >
-    Promise reaction jobs have predictable environment
-es6id: S25.4.2.1_A3.1_T2
-author: Sam Mikes
-description: Promise.onFulfilled gets undefined as 'this'
-flags: [onlyStrict]
----*/
-
-var expectedThis = undefined,
-    obj = {};
-
-var p = Promise.resolve(obj).then(function(arg) {
-    if (this !== expectedThis) {
-        $ERROR("'this' must be undefined, got " + this);
-    }
-    if (arg !== obj) {
-        $ERROR("Expected promise to be fulfilled by obj, actually " + arg);
-    }
-}).then($DONE, $DONE);
diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T1.js b/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T1.js
deleted file mode 100644
index dccad16d4dda4db622d97273b8a5c9ac70de2729..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T1.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
-// See LICENSE for details.
-
-/*---
-info: >
-    Promise reaction jobs have predictable environment
-    'this' is global object in sloppy mode,
-    undefined in strict mode
-es6id: S25.4.2.1_A3.2_T1
-author: Sam Mikes
-description: onRejected gets default 'this'
-flags: [noStrict]
-includes: [fnGlobalObject.js]
----*/
-
-var expectedThis = fnGlobalObject(),
-    obj = {};
-
-var p = Promise.reject(obj).then(function () {
-    $ERROR("Unexpected fulfillment; expected rejection.");
-}, function(arg) {
-    if (this !== expectedThis) {
-        $ERROR("'this' must be global object, got " + this);
-    }
-
-    if (arg !== obj) {
-        $ERROR("Expected promise to be rejected with obj, actually " + arg);
-    }
-}).then($DONE, $DONE);
diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T2.js b/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T2.js
deleted file mode 100644
index 7ef2666b78b40a0474acd070cc13861a18499ea2..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A3.2_T2.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
-// See LICENSE for details.
-
-/*---
-info: >
-    Promise reaction jobs have predictable environment
-    'this' is global object in sloppy mode,
-    undefined in strict mode
-es6id: S25.4.2.1_A3.2_T2
-author: Sam Mikes
-description: onRejected gets default 'this'
-flags: [onlyStrict]
----*/
-
-var expectedThis = undefined,
-    obj = {};
-
-var p = Promise.reject(obj).then(function () {
-    $ERROR("Unexpected fulfillment; expected rejection.");
-}, function(arg) {
-    if (this !== expectedThis) {
-        $ERROR("'this' must be undefined, got " + this);
-    }
-
-    if (arg !== obj) {
-        $ERROR("Expected promise to be rejected with obj, actually " + arg);
-    }
-}).then($DONE, $DONE);
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js
deleted file mode 100644
index 1b6fcb0c633decd34e395c2cc6ea55451dd36fe1..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/on-fulfilled-return-poisoned-then.js
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2015 the V8 project authors. All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-/*---
-es6id: 25.4.5.3
-description: >
-    Access error for the `then` property of the object returned from the "on fulfilled" handler
-info: >
-    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
-       resultCapability).
-
-    25.4.5.3.1 PerformPromiseThen
-
-    [...]
-    8. Else if the value of promise's [[PromiseState]] internal slot is
-       "fulfilled",
-       a. Let value be the value of promise's [[PromiseResult]] internal slot.
-       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
-          «fulfillReaction, value»).
-
-    25.4.1.3.2 Promise Resolve Functions
-
-    [...]
-    8. Let then be Get(resolution, "then").
-    9. If then is an abrupt completion, then
-       a. Return RejectPromise(promise, then.[[value]]).
----*/
-
-var poisonedThen = {};
-var error = new Test262Error();
-Object.defineProperty(poisonedThen, 'then', {
-  get: function() {
-    throw error;
-  }
-});
-
-var p = new Promise(function(r) { r(); });
-
-p.then(function() {
-  return poisonedThen;
-}).then(function() {
-  $DONE('The promise should not be fulfilled');
-}, function(reason) {
-  assert.sameValue(reason, error);
-
-  $DONE();
-});
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js b/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js
deleted file mode 100644
index 42e2588ef4a66ca9436c0a145df5293f873388fb..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/on-fulfilled-return-self.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2015 the V8 project authors. All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-/*---
-es6id: 25.4.5.3
-description: The return value of the `onFulfilled` method is a "thenable" object
-info: >
-    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
-       resultCapability).
-
-    25.4.5.3.1 PerformPromiseThen
-
-    [...]
-    8. Else if the value of promise's [[PromiseState]] internal slot is
-       "fulfilled",
-       a. Let value be the value of promise's [[PromiseResult]] internal slot.
-       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
-          «fulfillReaction, value»).
-
-    25.4.1.3.2 Promise Resolve Functions
-
-    [...]
-    6. If SameValue(resolution, promise) is true, then
-       a. Let selfResolutionError be a newly created TypeError object.
-       b. Return RejectPromise(promise, selfResolutionError).
----*/
-
-var promise1 = new Promise(function(resolve) {
-  resolve();
-});
-
-var promise2 = promise1.then(function() {
-  return promise2;
-});
-
-promise2.then(function() {
-  $DONE('This promise should not be resolved');
-}, function(reason) {
-  assert.sameValue(reason.constructor, TypeError);
-
-  $DONE();
-});
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js b/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js
deleted file mode 100644
index 434cd57953c0202401e60210dc58f8e628a74ae3..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/on-fulfilled-throw.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2015 the V8 project authors. All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-/*---
-es6id: 25.4.5.3
-description: The `onFulfilled` method throws an error
-info: >
-    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
-       resultCapability).
-
-    25.4.5.3.1 PerformPromiseThen
-
-    [...]
-    8. Else if the value of promise's [[PromiseState]] internal slot is
-       "fulfilled",
-       a. Let value be the value of promise's [[PromiseResult]] internal slot.
-       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
-          «fulfillReaction, value»).
-
-    25.4.1.3.2 Promise Resolve Functions
-
-    [...]
-    8. Let then be Get(resolution, "then").
-    9. If then is an abrupt completion, then
-       a. Return RejectPromise(promise, then.[[value]]).
-    10. Let thenAction be then.[[value]].
-    11. If IsCallable(thenAction) is false, then
-        a. Return FulfillPromise(promise, resolution).
-    12. Perform EnqueueJob ("PromiseJobs", PromiseResolveThenableJob, «promise,
-        resolution, thenAction»)
-    13. Return undefined.
-
-    25.4.2.2 PromiseResolveThenableJob
-
-    2. Let thenCallResult be Call(then, thenable,
-       «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»).
-    3. If thenCallResult is an abrupt completion,
-       a. Let status be Call(resolvingFunctions.[[Reject]], undefined,
-          «thenCallResult.[[value]]»).
-       b. NextJob Completion(status).
----*/
-
-var error = new Test262Error();
-var promiseFulfilled = false;
-var promiseRejected = false;
-var promise = new Promise(function(resolve) {
-    resolve();
-  });
-
-promise.then(function() {
-    throw error;
-  }).then(function() {
-    $DONE('This promise should not be fulfilled');
-  }, function(reason) {
-    assert.sameValue(reason, error);
-
-    $DONE();
-  });
diff --git a/test/built-ins/Promise/prototype/then/on-rejected-return-value.js b/test/built-ins/Promise/prototype/then/on-rejected-return-value.js
deleted file mode 100644
index 14f7c2df910f917ffbe5901f822e69b21dac0b59..0000000000000000000000000000000000000000
--- a/test/built-ins/Promise/prototype/then/on-rejected-return-value.js
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2015 the V8 project authors. All rights reserved.
-// This code is governed by the BSD license found in the LICENSE file.
-/*---
-es6id: 25.4.5.3
-description: The return value of the `onRejected` method
-info: >
-    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
-       resultCapability).
-
-    25.4.5.3.1 PerformPromiseThen
-
-    [...]
-    9. Else if the value of promise's [[PromiseState]] internal slot is
-       "rejected",
-       a. Let reason be the value of promise's [[PromiseResult]] internal slot.
-       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
-          «rejectReaction, reason»).
----*/
-
-var returnVal = {};
-var promise = new Promise(function(_, reject) {
-  reject();
-});
-
-promise.then(null, function() {
-  return returnVal;
-}).then(function(result) {
-  assert.sameValue(result, returnVal);
-
-  $DONE();
-}, function() {
-  $DONE('The promise should not be rejected');
-});
diff --git a/test/built-ins/Promise/prototype/then/prfm-fulfilled.js b/test/built-ins/Promise/prototype/then/prfm-fulfilled.js
new file mode 100644
index 0000000000000000000000000000000000000000..ac49fee03e547671a4560a88fc4e5b7286f99b35
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/prfm-fulfilled.js
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+es6id: 25.4.5.3
+description: PerformPromiseThen on a fulfilled promise
+info: >
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+
+    [...]
+    8. Else if the value of promise's [[PromiseState]] internal slot is
+       "fulfilled",
+       a. Let value be the value of promise's [[PromiseResult]] internal slot.
+       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
+          «fulfillReaction, value»).
+    [...]
+---*/
+
+var value = {};
+var p = new Promise(function(resolve) { resolve(value); });
+
+p.then(function(x) {
+    if (x !== value) {
+      $DONE('The `onFulfilled` handler should be invoked with the promise result.');
+      return;
+    }
+    $DONE();
+  }, function() {
+    $DONE('The `onRejected` handler should not be invoked.');
+  });
diff --git a/test/built-ins/Promise/prototype/then/prfm-pending-fulfulled.js b/test/built-ins/Promise/prototype/then/prfm-pending-fulfulled.js
new file mode 100644
index 0000000000000000000000000000000000000000..b0d63c056e478de4f367bc4c0720d7d2f713388e
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/prfm-pending-fulfulled.js
@@ -0,0 +1,35 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+es6id: 25.4.5.3
+description: PerformPromiseThen on a pending promise that is later fulfilled
+info: >
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+
+    [...]
+    7. If the value of promise's [[PromiseState]] internal slot is "pending",
+       a. Append fulfillReaction as the last element of the List that is the
+          value of promise's [[PromiseFulfillReactions]] internal slot.
+       b. Append rejectReaction as the last element of the List that is the
+          value of promise's [[PromiseRejectReactions]] internal slot.
+    [...]
+---*/
+
+var value = {};
+var resolve;
+var p = new Promise(function(_resolve) { resolve = _resolve; });
+
+p.then(function(x) {
+    if (x !== value) {
+      $DONE('The `onFulfilled` handler should be invoked with the promise result.');
+      return;
+    }
+    $DONE();
+  }, function() {
+    $DONE('The `onRejected` handler should not be invoked.');
+  });
+
+resolve(value);
diff --git a/test/built-ins/Promise/prototype/then/prfm-pending-rejected.js b/test/built-ins/Promise/prototype/then/prfm-pending-rejected.js
new file mode 100644
index 0000000000000000000000000000000000000000..23afce4b32d923dbaede319f2ba0e4097a8147af
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/prfm-pending-rejected.js
@@ -0,0 +1,35 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+es6id: 25.4.5.3
+description: PerformPromiseThen on a pending promise that is later rejected
+info: >
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+
+    [...]
+    7. If the value of promise's [[PromiseState]] internal slot is "pending",
+       a. Append fulfillReaction as the last element of the List that is the
+          value of promise's [[PromiseFulfillReactions]] internal slot.
+       b. Append rejectReaction as the last element of the List that is the
+          value of promise's [[PromiseRejectReactions]] internal slot.
+    [...]
+---*/
+
+var value = {};
+var reject;
+var p = new Promise(function(_, _reject) { reject = _reject; });
+
+p.then(function() {
+    $DONE('The `onFulfilled` handler should not be invoked.');
+  }, function(x) {
+    if (x !== value) {
+      $DONE('The `onRejected` handler should be invoked with the promise result.');
+      return;
+    }
+    $DONE();
+  });
+
+reject(value);
diff --git a/test/built-ins/Promise/prototype/then/on-rejected-throw.js b/test/built-ins/Promise/prototype/then/prfm-rejected.js
similarity index 62%
rename from test/built-ins/Promise/prototype/then/on-rejected-throw.js
rename to test/built-ins/Promise/prototype/then/prfm-rejected.js
index b218329cff5a0c7826a80d2d295544444b7bce7b..727eea81f189861de21ef418cb2f50b47b372c83 100644
--- a/test/built-ins/Promise/prototype/then/on-rejected-throw.js
+++ b/test/built-ins/Promise/prototype/then/prfm-rejected.js
@@ -2,7 +2,7 @@
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 es6id: 25.4.5.3
-description: The `onRejected` method throws an error
+description: PerformPromiseThen on a rejected promise
 info: >
     7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
        resultCapability).
@@ -15,19 +15,18 @@ info: >
        a. Let reason be the value of promise's [[PromiseResult]] internal slot.
        b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
           «rejectReaction, reason»).
+    [...]
 ---*/
 
-var error = new Test262Error();
-var promise = new Promise(function(_, reject) {
-  reject();
-});
-
-promise.then(null, function() {
-  throw error;
-  }).then(function(result) {
-    $DONE('This promise should not be fulfilled');
-  }, function(reason) {
-    assert.sameValue(reason, error);
+var value = {};
+var p = new Promise(function(_, reject) { reject(value); });
 
+p.then(function() {
+    $DONE('The `onFulfilled` handler should not be invoked.');
+  }, function(x) {
+    if (x !== value) {
+      $DONE('The `onRejected` handler should be invoked with the promise result.');
+      return;
+    }
     $DONE();
   });
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js b/test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-fulfilled.js
similarity index 100%
rename from test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-fulfilled.js
rename to test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-fulfilled.js
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js b/test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-pending-to-fulfilled.js
similarity index 100%
rename from test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-fulfilled.js
rename to test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-pending-to-fulfilled.js
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js b/test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-pending-to-rejected.js
similarity index 100%
rename from test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-pending-to-rejected.js
rename to test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-pending-to-rejected.js
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js b/test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-rejected.js
similarity index 100%
rename from test/built-ins/Promise/prototype/then/on-fulfilled-return-prms-rejected.js
rename to test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-prms-rejected.js
diff --git a/test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js b/test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-thenable.js
similarity index 100%
rename from test/built-ins/Promise/prototype/then/on-fulfilled-return-thenable.js
rename to test/built-ins/Promise/prototype/then/prfm-when-fulfilled-return-thenable.js
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-nonstrict.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-nonstrict.js
new file mode 100644
index 0000000000000000000000000000000000000000..c149da931afb5b81ef0aeef8f27a4ff2216b814a
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-nonstrict.js
@@ -0,0 +1,38 @@
+// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
+// See LICENSE for details.
+
+/*---
+info: >
+    [...]
+    6. Else, let handlerResult be Call(handler, undefined, «argument»).
+es6id: S25.4.2.1_A3.1_T1
+author: Sam Mikes
+description: >
+    "fulfilled" handler invoked correctly outside of strict mode
+flags: [noStrict]
+includes: [fnGlobalObject.js]
+---*/
+
+var expectedThis = fnGlobalObject(),
+    obj = {};
+
+var p = Promise.resolve(obj).then(function(arg) {
+    if (this !== expectedThis) {
+        $DONE("'this' must be global object, got " + this);
+        return;
+    }
+
+    if (arg !== obj) {
+        $DONE("Expected promise to be fulfilled by obj, actually " + arg);
+        return;
+    }
+
+    if (arguments.length !== 1) {
+        $DONE('Expected handler function to be called with exactly 1 argument.');
+        return;
+    }
+
+    $DONE();
+}, function() {
+  $DONE('The promise should not be rejected.');
+});
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-strict.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-strict.js
new file mode 100644
index 0000000000000000000000000000000000000000..33068c06e41ace2e34f39636af17eca8a2b493be
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-invoke-strict.js
@@ -0,0 +1,37 @@
+// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
+// See LICENSE for details.
+
+/*---
+info: >
+    [...]
+    6. Else, let handlerResult be Call(handler, undefined, «argument»).
+es6id: S25.4.2.1_A3.1_T2
+author: Sam Mikes
+description: >
+    "fulfilled" handler invoked correctly in strict mode
+flags: [onlyStrict]
+---*/
+
+var expectedThis = undefined,
+    obj = {};
+
+var p = Promise.resolve(obj).then(function(arg) {
+    if (this !== expectedThis) {
+        $DONE("'this' must be undefined, got " + this);
+        return;
+    }
+
+    if (arg !== obj) {
+        $DONE("Expected promise to be fulfilled by obj, actually " + arg);
+        return;
+    }
+
+    if (arguments.length !== 1) {
+        $DONE('Expected handler function to be called with exactly 1 argument.');
+        return;
+    }
+
+    $DONE();
+}, function() {
+  $DONE('The promise should not be rejected.');
+});
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next-abrupt.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next-abrupt.js
new file mode 100644
index 0000000000000000000000000000000000000000..00d6aeff0442eb98ef5fa4f6dca043ca7344d1d3
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next-abrupt.js
@@ -0,0 +1,44 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Abrupt completions should not preclude additional jobs
+es6id: 25.4.2.1
+info: >
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var promise = new Promise(function(resolve) {
+  resolve();
+});
+var fulfilledCallCount = 0;
+var rejectedCallCount = 0;
+
+promise.then(function() {
+    fulfilledCallCount += 1;
+    throw new Error();
+  }, function() {
+    rejectedCallCount += 1;
+  });
+
+promise.then(function() {
+    if (fulfilledCallCount !== 1) {
+      $DONE('Expected "onFulfilled" handler to be invoked exactly once.');
+      return;
+    }
+
+    if (rejectedCallCount !== 0) {
+      $DONE('Expected "onRejected" handler to not be invoked.');
+      return;
+    }
+
+    $DONE();
+  }, function() {
+    $DONE('This promise should not be rejected.');
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next.js
new file mode 100644
index 0000000000000000000000000000000000000000..1443459a1643d10e7ce7c1aae58f1c55af77ae52
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-next.js
@@ -0,0 +1,52 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: All queued jobs should be executed in series
+es6id: 25.4.2.1
+info: >
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var promise = new Promise(function(resolve) {
+  resolve();
+});
+var log = '';
+
+promise.then(function() {
+    log += 'a';
+  }, function() {
+    log += 'A';
+  });
+
+promise.then(function() {
+    log += 'b';
+  }, function() {
+    log += 'B';
+  });
+
+promise.then(function() {
+    log += 'c';
+  }, function() {
+    log += 'C';
+  });
+
+promise.then(function() {
+    if (log !== 'abc') {
+      $DONE(
+        'Expected each "onFulfilled" handler to be invoked exactly once in series. ' +
+        'Expected: abc. Actual: ' + log
+      );
+      return;
+    }
+
+    $DONE();
+  }, function() {
+    $DONE('This promise should not be rejected.');
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-abrupt.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-abrupt.js
new file mode 100644
index 0000000000000000000000000000000000000000..429c3171f52e1dadaada48524ed1b57b11233e26
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-abrupt.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: An abrupt completion should trigger promise rejection
+es6id: 25.4.5.3
+info: >
+    [...]
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+    [...]
+    8. Else if the value of promise's [[PromiseState]] internal slot is
+       "fulfilled",
+       a. Let value be the value of promise's [[PromiseResult]] internal slot.
+       b. EnqueueJob("PromiseJobs", PromiseReactionJob, «fulfillReaction,
+          value»).
+
+    25.4.2.1 PromiseReactionJob
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var value = {};
+var p1 = new Promise(function(resolve) {
+  resolve();
+});
+var p2;
+
+p2 = p1.then(function() {
+    throw value;
+  }, function() {});
+
+p2.then(function() {
+    $DONE('The `onFulfilled` handler should not be invoked.');
+  }, function(x) {
+    if (x !== value) {
+      $DONE('The `onRejected` handler should be invoked with the promise result.');
+      return;
+    }
+
+    $DONE();
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-normal.js b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-normal.js
new file mode 100644
index 0000000000000000000000000000000000000000..4437d5fb7356a47ffe36b272d26fb2a71480921b
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-fulfilled-return-normal.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: A normal completion should trigger promise fulfillment
+es6id: 25.4.5.3
+info: >
+    [...]
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+    [...]
+    8. Else if the value of promise's [[PromiseState]] internal slot is
+       "fulfilled",
+       a. Let value be the value of promise's [[PromiseResult]] internal slot.
+       b. EnqueueJob("PromiseJobs", PromiseReactionJob, «fulfillReaction,
+          value»).
+
+    25.4.2.1 PromiseReactionJob
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var value = {};
+var p1 = new Promise(function(resolve) {
+  resolve();
+});
+var p2;
+
+p2 = p1.then(function() {
+    return value;
+  }, function() {});
+
+p2.then(function(x) {
+    if (x !== value) {
+      $DONE('The `onFulfilled` handler should be invoked with the promise result.');
+      return;
+    }
+
+    $DONE();
+  }, function() {
+    $DONE('The `onRejected` handler should not be invoked.');
+  });
diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A1.1_T1.js b/test/built-ins/Promise/prototype/then/rxn-handler-identity.js
similarity index 64%
rename from test/built-ins/Promise/prototype/then/S25.4.2.1_A1.1_T1.js
rename to test/built-ins/Promise/prototype/then/rxn-handler-identity.js
index d5bf88f39c8444e753089a7b682109d10d766ce1..6230f9c9bea85691f769d25dd182c17053656e0d 100644
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A1.1_T1.js
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-identity.js
@@ -14,6 +14,10 @@ var obj = {};
 var p = Promise.resolve(obj).then(/*Identity, Thrower*/)
         .then(function (arg) {
             if (arg !== obj) {
-                $ERROR("Expected promise to be fulfilled with obj, actually " + arg);
+                $DONE("Expected promise to be fulfilled with obj, actually " + arg);
+                return;
             }
-        }).then($DONE, $DONE);
+            $DONE();
+        }, function() {
+          $DONE('The promise should not be rejected.');
+        });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-nonstrict.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-nonstrict.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee2bff37221ff789d9f0eb9010cffa50cf5c5a4d
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-nonstrict.js
@@ -0,0 +1,38 @@
+// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
+// See LICENSE for details.
+
+/*---
+info: >
+    [...]
+    6. Else, let handlerResult be Call(handler, undefined, «argument»).
+es6id: S25.4.2.1_A3.2_T1
+author: Sam Mikes
+description: >
+    "rejected" handler invoked correctly outside of strict mode
+flags: [noStrict]
+includes: [fnGlobalObject.js]
+---*/
+
+var expectedThis = fnGlobalObject(),
+    obj = {};
+
+var p = Promise.reject(obj).then(function () {
+    $DONE("Unexpected fulfillment; expected rejection.");
+}, function(arg) {
+    if (this !== expectedThis) {
+        $DONE("'this' must be global object, got " + this);
+        return;
+    }
+
+    if (arg !== obj) {
+        $DONE("Expected promise to be rejected with obj, actually " + arg);
+        return;
+    }
+
+    if (arguments.length !== 1) {
+        $DONE('Expected handler function to be called with exactly 1 argument.');
+        return;
+    }
+
+    $DONE();
+});
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-strict.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-strict.js
new file mode 100644
index 0000000000000000000000000000000000000000..c782ddb9d005083d51acdd70ffd680e994593cdc
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-invoke-strict.js
@@ -0,0 +1,37 @@
+// Copyright 2014 Cubane Canada, Inc.  All rights reserved.
+// See LICENSE for details.
+
+/*---
+info: >
+    [...]
+    6. Else, let handlerResult be Call(handler, undefined, «argument»).
+es6id: S25.4.2.1_A3.2_T2
+author: Sam Mikes
+description: >
+    "rejected" handler invoked correctly in strict mode
+flags: [onlyStrict]
+---*/
+
+var expectedThis = undefined,
+    obj = {};
+
+var p = Promise.reject(obj).then(function () {
+    $DONE("Unexpected fulfillment; expected rejection.");
+}, function(arg) {
+    if (this !== expectedThis) {
+        $DONE("'this' must be undefined, got " + this);
+        return;
+    }
+
+    if (arg !== obj) {
+        $DONE("Expected promise to be rejected with obj, actually " + arg);
+        return;
+    }
+
+    if (arguments.length !== 1) {
+        $DONE('Expected handler function to be called with exactly 1 argument.');
+        return;
+    }
+
+    $DONE();
+});
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next-abrupt.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next-abrupt.js
new file mode 100644
index 0000000000000000000000000000000000000000..6c3d18b40d9795583debf3ed8b4b7822e3324620
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next-abrupt.js
@@ -0,0 +1,44 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Abrupt completions should not preclude additional jobs
+es6id: 25.4.2.1
+info: >
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var promise = new Promise(function(_, reject) {
+  reject();
+});
+var fulfilledCallCount = 0;
+var rejectedCallCount = 0;
+
+promise.then(function() {
+    fulfilledCallCount += 1;
+  }, function() {
+    rejectedCallCount += 1;
+    throw new Error();
+  });
+
+promise.then(function() {
+    $DONE('This promise should not be fulfilled.');
+  }, function() {
+    if (fulfilledCallCount !== 0) {
+      $DONE('Expected "onFulfilled" handler to not be invoked.');
+      return;
+    }
+
+    if (rejectedCallCount !== 1) {
+      $DONE('Expected "onRejected" handler to be invoked exactly once.');
+      return;
+    }
+
+    $DONE();
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next.js
new file mode 100644
index 0000000000000000000000000000000000000000..59a3916b3a9319606927f322ce3a952b33605458
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-next.js
@@ -0,0 +1,52 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: All queued jobs should be executed in series
+es6id: 25.4.2.1
+info: >
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var promise = new Promise(function(_, reject) {
+  reject();
+});
+var log = '';
+
+promise.then(function() {
+    log += 'A';
+  }, function() {
+    log += 'a';
+  });
+
+promise.then(function() {
+    log += 'B';
+  }, function() {
+    log += 'b';
+  });
+
+promise.then(function() {
+    log += 'C';
+  }, function() {
+    log += 'c';
+  });
+
+promise.then(function() {
+    $DONE('This promise should not be fulfilled.');
+  }, function() {
+    if (log !== 'abc') {
+      $DONE(
+        'Expected each "onFulfilled" handler to be invoked exactly once in series. ' +
+        'Expected: abc. Actual: ' + log
+      );
+      return;
+    }
+
+    $DONE();
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-abrupt.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-abrupt.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b95a5a042a3e18bbcaf85de6a2ba2c18359447e
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-abrupt.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: An abrupt completion should trigger promise rejection
+es6id: 25.4.5.3
+info: >
+    [...]
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+    [...]
+    9. Else if the value of promise's [[PromiseState]] internal slot is
+       "rejected",
+       a. Let reason be the value of promise's [[PromiseResult]] internal slot.
+       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
+          «rejectReaction, reason»).
+
+    25.4.2.1 PromiseReactionJob
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var value = {};
+var p1 = new Promise(function(_, reject) {
+  reject();
+});
+var p2;
+
+p2 = p1.then(function() {}, function() {
+    throw value;
+  });
+
+p2.then(function() {
+    $DONE('The `onFulfilled` handler should not be invoked.');
+  }, function(x) {
+    if (x !== value) {
+      $DONE('The `onRejected` handler should be invoked with the promise result.');
+      return;
+    }
+
+    $DONE();
+  });
diff --git a/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-normal.js b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-normal.js
new file mode 100644
index 0000000000000000000000000000000000000000..1277801c501276724928cd9372cb8cd09dde817b
--- /dev/null
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-rejected-return-normal.js
@@ -0,0 +1,49 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: A normal completion should trigger promise fulfillment
+es6id: 25.4.5.3
+info: >
+    [...]
+    7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
+       resultCapability).
+
+    25.4.5.3.1 PerformPromiseThen
+    [...]
+    9. Else if the value of promise's [[PromiseState]] internal slot is
+       "rejected",
+       a. Let reason be the value of promise's [[PromiseResult]] internal slot.
+       b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
+          «rejectReaction, reason»).
+
+    25.4.2.1 PromiseReactionJob
+    [...]
+    7. If handlerResult is an abrupt completion, then
+       a. Let status be Call(promiseCapability.[[Reject]], undefined,
+          «handlerResult.[[value]]»).
+       b. NextJob Completion(status).
+    8. Let status be Call(promiseCapability.[[Resolve]], undefined,
+       «handlerResult.[[value]]»).
+    9. NextJob Completion(status).
+---*/
+
+var value = {};
+var p1 = new Promise(function(_, reject) {
+  reject();
+});
+var p2;
+
+p2 = p1.then(function() {}, function() {
+    return value;
+  });
+
+p2.then(function(x) {
+    if (x !== value) {
+      $DONE('The `onFulfilled` handler should be invoked with the promise result.');
+      return;
+    }
+
+    $DONE();
+  }, function() {
+    $DONE('The `onRejected` handler should not be invoked.');
+  });
diff --git a/test/built-ins/Promise/prototype/then/S25.4.2.1_A2.1_T1.js b/test/built-ins/Promise/prototype/then/rxn-handler-thrower.js
similarity index 67%
rename from test/built-ins/Promise/prototype/then/S25.4.2.1_A2.1_T1.js
rename to test/built-ins/Promise/prototype/then/rxn-handler-thrower.js
index 4c6eb976391bfdf9547b130682358c168782ac05..437792f970d62b50a8bc783796c07588e0ea7f3a 100644
--- a/test/built-ins/Promise/prototype/then/S25.4.2.1_A2.1_T1.js
+++ b/test/built-ins/Promise/prototype/then/rxn-handler-thrower.js
@@ -13,9 +13,11 @@ var obj = {};
 
 var p = Promise.reject(obj).then(/*Identity, Thrower*/)
         .then(function () {
-            $ERROR("Unexpected fulfillment - promise should reject.");
+            $DONE("Unexpected fulfillment - promise should reject.");
         }, function (arg) {
             if (arg !== obj) {
-                $ERROR("Expected reject reason to be obj, actually " + arg);
+                $DONE("Expected reject reason to be obj, actually " + arg);
+                return;
             }
-        }).then($DONE, $DONE);
+            $DONE();
+        });