PaymentRequest: Make the PaymentResponse interface serializable.

Related spec change:
  https://github.com/w3c/browser-payment-api/pull/252

BUG=648238

Review-Url: https://codereview.chromium.org/2349133002
Cr-Commit-Position: refs/heads/master@{#420044}
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 5fe6198..aa3bddaa 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4356,6 +4356,7 @@
     getter region
     getter sortingCode
     method constructor
+    method toJSON
 interface PaymentRequest : EventTarget
     attribute @@toStringTag
     getter onshippingaddresschange
@@ -4381,6 +4382,7 @@
     getter shippingOption
     method complete
     method constructor
+    method toJSON
 interface Performance : EventTarget
     attribute @@toStringTag
     getter memory
diff --git a/third_party/WebKit/Source/modules/payments/PaymentAddress.cpp b/third_party/WebKit/Source/modules/payments/PaymentAddress.cpp
index fea61124..ded6d4c 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentAddress.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentAddress.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/payments/PaymentAddress.h"
 
+#include "bindings/core/v8/V8ObjectBuilder.h"
 #include "wtf/text/StringBuilder.h"
 
 namespace blink {
@@ -33,4 +34,21 @@
 
 PaymentAddress::~PaymentAddress() {}
 
+ScriptValue PaymentAddress::toJSONForBinding(ScriptState* scriptState) const
+{
+    V8ObjectBuilder result(scriptState);
+    result.addString("country", country());
+    result.add("addressLine", addressLine());
+    result.addString("region", region());
+    result.addString("city", city());
+    result.addString("dependentLocality", dependentLocality());
+    result.addString("postalCode", postalCode());
+    result.addString("sortingCode", sortingCode());
+    result.addString("languageCode", languageCode());
+    result.addString("organization", organization());
+    result.addString("recipient", recipient());
+    result.addString("phone", phone());
+    return result.scriptValue();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/PaymentAddress.h b/third_party/WebKit/Source/modules/payments/PaymentAddress.h
index c857e1b..444f490 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentAddress.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentAddress.h
@@ -5,6 +5,7 @@
 #ifndef PaymentAddress_h
 #define PaymentAddress_h
 
+#include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "modules/ModulesExport.h"
 #include "platform/heap/Handle.h"
@@ -23,6 +24,8 @@
     explicit PaymentAddress(mojom::blink::PaymentAddressPtr);
     virtual ~PaymentAddress();
 
+    ScriptValue toJSONForBinding(ScriptState*) const;
+
     const String& country() const { return m_country; }
     const Vector<String>& addressLine() const { return m_addressLine; }
     const String& region() const { return m_region; }
diff --git a/third_party/WebKit/Source/modules/payments/PaymentAddress.idl b/third_party/WebKit/Source/modules/payments/PaymentAddress.idl
index 9863a1a..2e29406 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentAddress.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentAddress.idl
@@ -7,6 +7,7 @@
 [
     RuntimeEnabled=PaymentRequest,
 ] interface PaymentAddress {
+    serializer = {attribute};
     readonly attribute DOMString country;
     readonly attribute FrozenArray<DOMString> addressLine;
     readonly attribute DOMString region;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
index bf3d766..b2e9b57 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
@@ -4,7 +4,9 @@
 
 #include "modules/payments/PaymentResponse.h"
 
+#include "bindings/core/v8/ExceptionStatePlaceholder.h"
 #include "bindings/core/v8/JSONValuesForV8.h"
+#include "bindings/core/v8/V8ObjectBuilder.h"
 #include "modules/payments/PaymentAddress.h"
 #include "modules/payments/PaymentCompleter.h"
 #include "wtf/Assertions.h"
@@ -27,6 +29,35 @@
 {
 }
 
+ScriptValue PaymentResponse::toJSONForBinding(ScriptState* scriptState) const
+{
+    V8ObjectBuilder result(scriptState);
+    result.addString("methodName", methodName());
+    result.add("details", details(scriptState, ASSERT_NO_EXCEPTION));
+
+    if (shippingAddress())
+        result.add("shippingAddress", shippingAddress()->toJSONForBinding(scriptState));
+    else
+        result.addNull("shippingAddress");
+
+    if (shippingOption().isNull())
+        result.addNull("shippingOption");
+    else
+        result.addString("shippingOption", shippingOption());
+
+    if (payerEmail().isNull())
+        result.addNull("payerEmail");
+    else
+        result.addString("payerEmail", payerEmail());
+
+    if (payerPhone().isNull())
+        result.addNull("payerPhone");
+    else
+        result.addString("payerPhone", payerPhone());
+
+    return result.scriptValue();
+}
+
 ScriptValue PaymentResponse::details(ScriptState* scriptState, ExceptionState& exceptionState) const
 {
     return ScriptValue(scriptState, fromJSONString(scriptState, m_stringifiedDetails, exceptionState));
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.h b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
index 1f9594c..9364358 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
@@ -30,6 +30,8 @@
     PaymentResponse(mojom::blink::PaymentResponsePtr, PaymentCompleter*);
     virtual ~PaymentResponse();
 
+    ScriptValue toJSONForBinding(ScriptState*) const;
+
     const String& methodName() const { return m_methodName; }
     ScriptValue details(ScriptState*, ExceptionState&) const;
     PaymentAddress* shippingAddress() const { return m_shippingAddress.get(); }
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
index 42cfba3..a8f6fd8 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
@@ -15,6 +15,8 @@
 [
     RuntimeEnabled=PaymentRequest,
 ] interface PaymentResponse {
+    serializer = {attribute};
+
     readonly attribute DOMString methodName;
     readonly attribute DOMString? payerEmail;
     readonly attribute DOMString? payerPhone;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
index 327e4a65..787a305 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
@@ -9,6 +9,7 @@
 #include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/V8Binding.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
+#include "modules/payments/PaymentAddress.h"
 #include "modules/payments/PaymentCompleter.h"
 #include "modules/payments/PaymentTestHelper.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -110,5 +111,40 @@
     output.complete(scope.getScriptState(), "fail");
 }
 
+TEST(PaymentResponseTest, JSONSerializerTest)
+{
+    V8TestingScope scope;
+    mojom::blink::PaymentResponsePtr input = mojom::blink::PaymentResponse::New();
+    input->method_name = "foo";
+    input->stringified_details = "{\"transactionId\": 123}";
+    input->shipping_option = "standardShippingOption";
+    input->payer_email = "abc@gmail.com";
+    input->payer_phone = "0123";
+    input->shipping_address = mojom::blink::PaymentAddress::New();
+    input->shipping_address->country = "US";
+    input->shipping_address->language_code = "en";
+    input->shipping_address->script_code = "Latn";
+    input->shipping_address->address_line = mojo::WTFArray<WTF::String>::New(3);
+    input->shipping_address->address_line[0] = "340 Main St";
+    input->shipping_address->address_line[1] = "BIN1";
+    input->shipping_address->address_line[2] = "First floor";
+
+    PaymentResponse output(std::move(input), new MockPaymentCompleter);
+    ScriptValue jsonObject = output.toJSONForBinding(scope.getScriptState());
+    EXPECT_TRUE(jsonObject.isObject());
+
+    String jsonString = v8StringToWebCoreString<String>(
+        v8::JSON::Stringify(scope.context(),
+        jsonObject.v8Value().As<v8::Object>()).ToLocalChecked(),
+        DoNotExternalize);
+    String expected = "{\"methodName\":\"foo\",\"details\":{\"transactionId\":123},"
+        "\"shippingAddress\":{\"country\":\"US\",\"addressLine\":[\"340 Main St\","
+        "\"BIN1\",\"First floor\"],\"region\":\"\",\"city\":\"\",\"dependentLocality\":"
+        "\"\",\"postalCode\":\"\",\"sortingCode\":\"\",\"languageCode\":\"en-Latn\","
+        "\"organization\":\"\",\"recipient\":\"\",\"phone\":\"\"},\"shippingOption\":"
+        "\"standardShippingOption\",\"payerEmail\":\"abc@gmail.com\",\"payerPhone\":\"0123\"}";
+    EXPECT_EQ(expected, jsonString);
+}
+
 } // namespace
 } // namespace blink