PaymentRequest / PaymentResponse should not prevent entering the back/forward cache
authoraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2019 22:13:55 +0000 (22:13 +0000)
committeraestes@apple.com <aestes@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2019 22:13:55 +0000 (22:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=203101
<rdar://problem/56744409>

Reviewed by Chris Dumez.

Source/WebCore:

Removed PaymentRequest's and PaymentResponse's override of
ActiveDOMObject::shouldPreventEnteringBackForwardCache_DEPRECATED and implemented
ActiveDOMObject::suspend instead.

Tests: http/tests/paymentrequest/page-cache-closed-payment-request.https.html
       http/tests/paymentrequest/page-cache-completed-payment-response.https.html
       http/tests/paymentrequest/page-cache-created-payment-request.https.html
       http/tests/paymentrequest/page-cache-created-payment-response.https.html
       http/tests/paymentrequest/page-cache-interactive-payment-request.https.html
       http/tests/paymentrequest/page-cache-retried-payment-response.https.html

* Modules/paymentrequest/PaymentRequest.cpp:
(WebCore::PaymentRequest::suspend):
(WebCore::PaymentRequest::shouldPreventEnteringBackForwardCache_DEPRECATED const): Deleted.
* Modules/paymentrequest/PaymentRequest.h:
* Modules/paymentrequest/PaymentResponse.cpp:
(WebCore::PaymentResponse::suspend):
(WebCore::PaymentResponse::shouldPreventEnteringBackForwardCache_DEPRECATED const): Deleted.
* Modules/paymentrequest/PaymentResponse.h:
* bindings/js/JSDOMPromiseDeferred.cpp:
(WebCore::DeferredPromise::callFunction):

LayoutTests:

* http/tests/paymentrequest/page-cache-closed-payment-request.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-closed-payment-request.https.html: Added.
* http/tests/paymentrequest/page-cache-completed-payment-response.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-completed-payment-response.https.html: Added.
* http/tests/paymentrequest/page-cache-created-payment-request.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-created-payment-request.https.html: Added.
* http/tests/paymentrequest/page-cache-created-payment-response.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-created-payment-response.https.html: Added.
* http/tests/paymentrequest/page-cache-interactive-payment-request.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-interactive-payment-request.https.html: Added.
* http/tests/paymentrequest/page-cache-retried-payment-response.https-expected.txt: Added.
* http/tests/paymentrequest/page-cache-retried-payment-response.https.html: Added.
* resources/js-test.js:
(shouldReject):
(shouldRejectWithErrorName):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252338 268f45cc-cd09-0410-ab3c-d52691b4dbfc

20 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https.html [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https.html [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https.html [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https.html [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https.html [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https.html [new file with mode: 0644]
LayoutTests/resources/js-test.js
Source/WebCore/ChangeLog
Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp
Source/WebCore/Modules/paymentrequest/PaymentRequest.h
Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp
Source/WebCore/Modules/paymentrequest/PaymentResponse.h
Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp

index 692a346..afa6f03 100644 (file)
@@ -1,3 +1,27 @@
+2019-11-11  Andy Estes  <aestes@apple.com>
+
+        PaymentRequest / PaymentResponse should not prevent entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=203101
+        <rdar://problem/56744409>
+
+        Reviewed by Chris Dumez.
+
+        * http/tests/paymentrequest/page-cache-closed-payment-request.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-closed-payment-request.https.html: Added.
+        * http/tests/paymentrequest/page-cache-completed-payment-response.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-completed-payment-response.https.html: Added.
+        * http/tests/paymentrequest/page-cache-created-payment-request.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-created-payment-request.https.html: Added.
+        * http/tests/paymentrequest/page-cache-created-payment-response.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-created-payment-response.https.html: Added.
+        * http/tests/paymentrequest/page-cache-interactive-payment-request.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-interactive-payment-request.https.html: Added.
+        * http/tests/paymentrequest/page-cache-retried-payment-response.https-expected.txt: Added.
+        * http/tests/paymentrequest/page-cache-retried-payment-response.https.html: Added.
+        * resources/js-test.js:
+        (shouldReject):
+        (shouldRejectWithErrorName):
+
 2019-11-11  Youenn Fablet  <youenn@apple.com>
 
         Make MediaStream/MediaStreamTrack page cache friendly
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https-expected.txt
new file mode 100644 (file)
index 0000000..d6b055c
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that a page with a PaymentRequest in the Closed state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentRequest in the Closed state.
+PASS responsePromise rejected promise  with AbortError: The operation was aborted..
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that PaymentRequest remains in the Closed state.
+PASS request.show() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-closed-payment-request.https.html
new file mode 100644 (file)
index 0000000..6a61ea7
--- /dev/null
@@ -0,0 +1,53 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentRequest in the Closed state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', async function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    UIHelper.withUserGesture(async function() {
+        debug('Testing that PaymentRequest remains in the Closed state.');
+        await shouldRejectWithErrorName('request.show()', 'InvalidStateError');
+
+        finishJSTest();
+    });
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    UIHelper.withUserGesture(async function() {
+        debug('Creating a PaymentRequest in the Closed state.');
+        request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+        responsePromise = request.show();
+        await request.abort();
+        await shouldRejectWithErrorName('responsePromise', 'AbortError');
+
+        setTimeout(function() {
+            window.location.href = '/navigation/resources/page-cache-helper.html';
+        }, 0);
+    });
+}, false);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https-expected.txt
new file mode 100644 (file)
index 0000000..2b6dc66
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that a page with a PaymentResponse in the Completed state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentResponse in the Completed state.
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that PaymentResponse remains in the Completed state.
+PASS response.complete() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS response.retry() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-completed-payment-response.https.html
new file mode 100644 (file)
index 0000000..2aabf68
--- /dev/null
@@ -0,0 +1,54 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentResponse in the Completed state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', async function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    debug('Testing that PaymentResponse remains in the Completed state.');
+    await shouldRejectWithErrorName('response.complete()', 'InvalidStateError');
+    await shouldRejectWithErrorName('response.retry()', 'InvalidStateError');
+
+    finishJSTest();
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    UIHelper.withUserGesture(async function() {
+        debug('Creating a PaymentResponse in the Completed state.');
+
+        const request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+        const responsePromise = request.show();
+        internals.mockPaymentCoordinator.acceptPayment();
+        response = await responsePromise;
+        await response.complete('success');
+
+        setTimeout(function() {
+            window.location.href = '/navigation/resources/page-cache-helper.html';
+        }, 0);
+    });
+}, false);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https-expected.txt
new file mode 100644 (file)
index 0000000..0139bb2
--- /dev/null
@@ -0,0 +1,16 @@
+Tests that a page with a PaymentRequest in the Created state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentRequest in the Created state.
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that PaymentRequest remains in the Created state.
+PASS responsePromise rejected promise  with AbortError: The operation was aborted..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-request.https.html
new file mode 100644 (file)
index 0000000..53fd395
--- /dev/null
@@ -0,0 +1,51 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentRequest in the Created state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    UIHelper.withUserGesture(async function() {
+        debug('Testing that PaymentRequest remains in the Created state.')
+        responsePromise = request.show();
+        await request.abort();
+        await shouldRejectWithErrorName('responsePromise', 'AbortError');
+
+        finishJSTest();
+    });
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    debug('Creating a PaymentRequest in the Created state.');
+
+    request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+
+    setTimeout(function() {
+        window.location.href = '/navigation/resources/page-cache-helper.html';
+    }, 0);
+}, false);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https-expected.txt
new file mode 100644 (file)
index 0000000..46c92e1
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that a page with a PaymentResponse in the Created state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentResponse in the Created state.
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that PaymentResponse is now in the Closed state.
+PASS response.complete() rejected promise  with AbortError: The operation was aborted..
+PASS response.retry() rejected promise  with AbortError: The operation was aborted..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-created-payment-response.https.html
new file mode 100644 (file)
index 0000000..ab592ee
--- /dev/null
@@ -0,0 +1,53 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentResponse in the Created state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', async function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    debug('Testing that PaymentResponse is now in the Closed state.');
+    await shouldRejectWithErrorName('response.complete()', 'AbortError');
+    await shouldRejectWithErrorName('response.retry()', 'AbortError');
+
+    finishJSTest();
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    UIHelper.withUserGesture(async function() {
+        debug('Creating a PaymentResponse in the Created state.');
+
+        const request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+        const responsePromise = request.show();
+        internals.mockPaymentCoordinator.acceptPayment();
+        response = await responsePromise;
+
+        setTimeout(function() {
+            window.location.href = '/navigation/resources/page-cache-helper.html';
+        }, 0);
+    });
+}, false);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https-expected.txt
new file mode 100644 (file)
index 0000000..85c2f30
--- /dev/null
@@ -0,0 +1,18 @@
+Tests that a page with a PaymentRequest in the Interactive state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentRequest in the Interactive state.
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that the promise returned by show() was rejected with "AbortError".
+PASS responsePromise rejected promise  with AbortError: The operation was aborted..
+Testing that PaymentRequest is now in the Closed state.
+PASS request.abort() rejected promise  with InvalidStateError: The object is in an invalid state..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-interactive-payment-request.https.html
new file mode 100644 (file)
index 0000000..ef5ccdf
--- /dev/null
@@ -0,0 +1,52 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentRequest in the Interactive state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', async function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    debug('Testing that the promise returned by show() was rejected with "AbortError".');
+    await shouldRejectWithErrorName('responsePromise', 'AbortError');
+
+    debug('Testing that PaymentRequest is now in the Closed state.');
+    await shouldRejectWithErrorName('request.abort()', 'InvalidStateError');
+
+    finishJSTest();
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    UIHelper.withUserGesture(async function() {
+        debug('Creating a PaymentRequest in the Interactive state.');
+        request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+        responsePromise = request.show();
+    });
+
+    setTimeout(function() {
+        window.location.href = '/navigation/resources/page-cache-helper.html';
+    }, 0);
+}, false);
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https-expected.txt b/LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https-expected.txt
new file mode 100644 (file)
index 0000000..ab65e35
--- /dev/null
@@ -0,0 +1,19 @@
+Tests that a page with a PaymentResponse in the Completed state goes into the back/forward cache.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Creating a PaymentResponse in the Created state with a retry promise.
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page did enter and was restored from the back/forward cache
+Testing that the promise returned by retry() was rejected with "AbortError".
+PASS retryPromise rejected promise  with AbortError: The operation was aborted..
+Testing that PaymentResponse is now in the Closed state.
+PASS response.complete() rejected promise  with AbortError: The operation was aborted..
+PASS response.retry() rejected promise  with AbortError: The operation was aborted..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https.html b/LayoutTests/http/tests/paymentrequest/page-cache-retried-payment-response.https.html
new file mode 100644 (file)
index 0000000..4cd6be7
--- /dev/null
@@ -0,0 +1,57 @@
+<!-- webkit-test-runner [ enableBackForwardCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src='/js-test-resources/js-test.js'></script>
+<script src='/js-test-resources/ui-helper.js'></script>
+<script src='/resources/payment-request.js'></script>
+<script>
+description('Tests that a page with a PaymentResponse in the Completed state goes into the back/forward cache.');
+window.jsTestIsAsync = true;
+
+window.addEventListener('pageshow', async function(event) {
+    debug('pageshow - ' + (event.persisted ? '' : 'not ') + 'from cache');
+
+    if (!event.persisted)
+        return;
+
+    testPassed('Page did enter and was restored from the back/forward cache');
+
+    debug('Testing that the promise returned by retry() was rejected with "AbortError".');
+    await shouldRejectWithErrorName('retryPromise', 'AbortError');
+
+    debug('Testing that PaymentResponse is now in the Closed state.');
+    await shouldRejectWithErrorName('response.complete()', 'AbortError');
+    await shouldRejectWithErrorName('response.retry()', 'AbortError');
+
+    finishJSTest();
+}, false);
+
+window.addEventListener('pagehide', function(event) {
+    debug('pagehide - ' + (event.persisted ? '' : 'not ') + 'entering cache');
+
+    if (event.persisted)
+        return;
+
+    testFailed('Page failed to enter the back/forward cache.');
+    finishJSTest();
+}, false);
+
+window.addEventListener('load', function() {
+    UIHelper.withUserGesture(async function() {
+        debug('Creating a PaymentResponse in the Created state with a retry promise.');
+
+        const request = new PaymentRequest([validPaymentMethod()], validPaymentDetails());
+        const responsePromise = request.show();
+        internals.mockPaymentCoordinator.acceptPayment();
+        response = await responsePromise;
+        retryPromise = response.retry();
+
+        setTimeout(function() {
+            window.location.href = '/navigation/resources/page-cache-helper.html';
+        }, 0);
+    });
+}, false);
+</script>
+</body>
+</html>
index 68a456a..1ab2155 100644 (file)
@@ -713,6 +713,11 @@ function expectError()
 
 function shouldReject(_a, _message)
 {
+    return shouldRejectWithErrorName(_a, undefined, _message);
+}
+
+function shouldRejectWithErrorName(_a, _name, _message)
+{
     var _exception;
     var _av;
     try {
@@ -725,7 +730,11 @@ function shouldReject(_a, _message)
     return _av.then(function(result) {
         testFailed((_message ? _message : _a) + " should reject promise. Resolved with " + result + ".");
     }, function(error) {
-        testPassed((_message ? _message : _a) + " rejected promise  with " + error + ".");
+        if (_name === undefined || error['name'] === _name) {
+            // FIXME: Remove the extra space and '.' (DOMException descriptions already end with periods) then rebase tests.
+            testPassed((_message ? _message : _a) + " rejected promise  with " + error + ".");
+        } else
+            testFailed((_message ? _message : _a) + " should reject promise with " + _name + ". Rejected with " + error['name'] + " instead.");
     });
 }
 
index 82eccf9..e711098 100644 (file)
@@ -1,3 +1,33 @@
+2019-11-11  Andy Estes  <aestes@apple.com>
+
+        PaymentRequest / PaymentResponse should not prevent entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=203101
+        <rdar://problem/56744409>
+
+        Reviewed by Chris Dumez.
+
+        Removed PaymentRequest's and PaymentResponse's override of
+        ActiveDOMObject::shouldPreventEnteringBackForwardCache_DEPRECATED and implemented
+        ActiveDOMObject::suspend instead.
+
+        Tests: http/tests/paymentrequest/page-cache-closed-payment-request.https.html
+               http/tests/paymentrequest/page-cache-completed-payment-response.https.html
+               http/tests/paymentrequest/page-cache-created-payment-request.https.html
+               http/tests/paymentrequest/page-cache-created-payment-response.https.html
+               http/tests/paymentrequest/page-cache-interactive-payment-request.https.html
+               http/tests/paymentrequest/page-cache-retried-payment-response.https.html
+
+        * Modules/paymentrequest/PaymentRequest.cpp:
+        (WebCore::PaymentRequest::suspend):
+        (WebCore::PaymentRequest::shouldPreventEnteringBackForwardCache_DEPRECATED const): Deleted.
+        * Modules/paymentrequest/PaymentRequest.h:
+        * Modules/paymentrequest/PaymentResponse.cpp:
+        (WebCore::PaymentResponse::suspend):
+        (WebCore::PaymentResponse::shouldPreventEnteringBackForwardCache_DEPRECATED const): Deleted.
+        * Modules/paymentrequest/PaymentResponse.h:
+        * bindings/js/JSDOMPromiseDeferred.cpp:
+        (WebCore::DeferredPromise::callFunction):
+
 2019-11-11  Youenn Fablet  <youenn@apple.com>
 
         Make MediaStream/MediaStreamTrack page cache friendly
index daf5183..4c75351 100644 (file)
@@ -488,6 +488,20 @@ void PaymentRequest::stop()
     settleShowPromise(Exception { AbortError });
 }
 
+void PaymentRequest::suspend(ReasonForSuspension reason)
+{
+    if (reason != ReasonForSuspension::BackForwardCache)
+        return;
+
+    if (!m_activePaymentHandler) {
+        ASSERT(!m_showPromise);
+        ASSERT(m_state != State::Interactive);
+        return;
+    }
+
+    stop();
+}
+
 // https://www.w3.org/TR/payment-request/#abort()-method
 void PaymentRequest::abort(AbortPromise&& promise)
 {
@@ -539,12 +553,6 @@ Optional<PaymentShippingType> PaymentRequest::shippingType() const
     return WTF::nullopt;
 }
 
-// FIXME: This should never prevent entering the back/forward cache.
-bool PaymentRequest::shouldPreventEnteringBackForwardCache_DEPRECATED() const
-{
-    return hasPendingActivity();
-}
-
 void PaymentRequest::shippingAddressChanged(Ref<PaymentAddress>&& shippingAddress)
 {
     whenDetailsSettled([this, protectedThis = makeRefPtr(this), shippingAddress = makeRefPtr(shippingAddress.get())]() mutable {
index 40a5ea2..68acac9 100644 (file)
@@ -126,8 +126,8 @@ private:
 
     // ActiveDOMObject
     const char* activeDOMObjectName() const final { return "PaymentRequest"; }
-    bool shouldPreventEnteringBackForwardCache_DEPRECATED() const final;
     void stop() final;
+    void suspend(ReasonForSuspension) final;
 
     // EventTarget
     EventTargetInterface eventTargetInterface() const final { return PaymentRequestEventTargetInterfaceType; }
index 1692dc0..05d1ca4 100644 (file)
@@ -125,13 +125,6 @@ void PaymentResponse::settleRetryPromise(ExceptionOr<void>&& result)
     m_retryPromise = nullptr;
 }
 
-// FIXME: This should never prevent entering the back/forward cache.
-bool PaymentResponse::shouldPreventEnteringBackForwardCache_DEPRECATED() const
-{
-    ASSERT(m_state != State::Stopped);
-    return hasPendingActivity();
-}
-
 void PaymentResponse::stop()
 {
     settleRetryPromise(Exception { AbortError });
@@ -139,6 +132,20 @@ void PaymentResponse::stop()
     m_state = State::Stopped;
 }
 
+void PaymentResponse::suspend(ReasonForSuspension reason)
+{
+    if (reason != ReasonForSuspension::BackForwardCache)
+        return;
+
+    if (m_state != State::Created) {
+        ASSERT(!hasPendingActivity());
+        ASSERT(!m_retryPromise);
+        return;
+    }
+
+    stop();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(PAYMENT_REQUEST)
index 657fd56..c4ff4b6 100644 (file)
@@ -98,8 +98,8 @@ private:
 
     // ActiveDOMObject
     const char* activeDOMObjectName() const final { return "PaymentResponse"; }
-    bool shouldPreventEnteringBackForwardCache_DEPRECATED() const final;
     void stop() final;
+    void suspend(ReasonForSuspension) final;
 
     // EventTarget
     EventTargetInterface eventTargetInterface() const final { return PaymentResponseEventTargetInterfaceType; }
index 0bc5a89..2c01f6b 100644 (file)
@@ -52,8 +52,12 @@ void DeferredPromise::callFunction(JSGlobalObject& lexicalGlobalObject, ResolveM
     if (activeDOMObjectsAreSuspended()) {
         JSC::Strong<JSC::Unknown, ShouldStrongDestructorGrabLock::Yes> strongResolution(lexicalGlobalObject.vm(), resolution);
         scriptExecutionContext()->eventLoop().queueTask(TaskSource::Networking, *scriptExecutionContext(), [this, protectedThis = makeRef(*this), mode, strongResolution = WTFMove(strongResolution)]() mutable {
-            if (!shouldIgnoreRequestToFulfill())
-                callFunction(*globalObject(), mode, strongResolution.get());
+            if (shouldIgnoreRequestToFulfill())
+                return;
+
+            JSC::JSGlobalObject* lexicalGlobalObject = globalObject();
+            JSC::JSLockHolder locker(lexicalGlobalObject);
+            callFunction(*globalObject(), mode, strongResolution.get());
         });
         return;
     }