fix(deserialization): error message is different when invalid data is passed for payment method data (#4022)

This commit is contained in:
Narayan Bhat
2024-03-09 01:29:50 +05:30
committed by GitHub
parent f5697f372c
commit f1fe295475
20 changed files with 720 additions and 99 deletions

View File

@ -1095,12 +1095,19 @@ mod payment_method_data_serde {
#[serde(untagged)]
enum __Inner {
RewardString(String),
OptionalPaymentMethod(Box<PaymentMethodDataRequest>),
OptionalPaymentMethod(serde_json::Value),
}
let deserialize_to_inner = __Inner::deserialize(deserializer)?;
match deserialize_to_inner {
__Inner::OptionalPaymentMethod(value) => Ok(Some(*value)),
__Inner::OptionalPaymentMethod(value) => {
let parsed_value = serde_json::from_value::<PaymentMethodDataRequest>(value)
.map_err(|serde_json_error| {
serde::de::Error::custom(serde_json_error.to_string())
})?;
Ok(Some(parsed_value))
}
__Inner::RewardString(inner_string) => {
let payment_method_data = match inner_string.as_str() {
"reward" => PaymentMethodData::Reward,
@ -4048,3 +4055,73 @@ pub enum PaymentLinkStatusWrap {
PaymentLinkStatus(PaymentLinkStatus),
IntentStatus(api_enums::IntentStatus),
}
#[cfg(test)]
mod payments_request_api_contract {
#![allow(clippy::unwrap_used)]
#![allow(clippy::panic)]
use std::str::FromStr;
use super::*;
#[test]
fn test_successful_card_deser() {
let payments_request = r#"
{
"amount": 6540,
"currency": "USD",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "10",
"card_exp_year": "25",
"card_holder_name": "joseph Doe",
"card_cvc": "123"
}
}
}
"#;
let expected_card_number_string = "4242424242424242";
let expected_card_number = CardNumber::from_str(expected_card_number_string).unwrap();
let payments_request = serde_json::from_str::<PaymentsRequest>(payments_request);
assert!(payments_request.is_ok());
if let PaymentMethodData::Card(card_data) = payments_request
.unwrap()
.payment_method_data
.unwrap()
.payment_method_data
{
assert_eq!(card_data.card_number, expected_card_number);
} else {
panic!("Received unexpected response")
}
}
#[test]
fn test_successful_payment_method_reward() {
let payments_request = r#"
{
"amount": 6540,
"currency": "USD",
"payment_method": "reward",
"payment_method_data": "reward",
"payment_method_type": "evoucher"
}
"#;
let payments_request = serde_json::from_str::<PaymentsRequest>(payments_request);
assert!(payments_request.is_ok());
assert_eq!(
payments_request
.unwrap()
.payment_method_data
.unwrap()
.payment_method_data,
PaymentMethodData::Reward
);
}
}

View File

@ -0,0 +1,26 @@
// Validate status 400
pm.test("[POST]::/payments - Status code is 400", function () {
pm.response.to.be.error
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) { }
pm.test("[POST]::/payments - Response has appropriate error message", function () {
pm.expect(jsonData.error.message).eql("Invalid card_cvc length");
})

View File

@ -0,0 +1,41 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "10",
"card_exp_year": "25",
"card_holder_name": "joseph Doe",
"card_cvc": ""
}
}
}
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": ["{{baseUrl}}"],
"path": ["payments"]
},
"description": "Create a Payment to ensure api contract is intact"
}

View File

@ -0,0 +1,16 @@
// Validate status 400
pm.test("[POST]::/payments - Status code is 400", function () {
pm.response.to.be.error
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});

View File

@ -0,0 +1,41 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "1234",
"card_exp_month": "10",
"card_exp_year": "25",
"card_holder_name": "joseph Doe",
"card_cvc": "123"
}
}
}
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": ["{{baseUrl}}"],
"path": ["payments"]
},
"description": "Create a Payment to ensure api contract is intact"
}

View File

@ -0,0 +1,26 @@
// Validate status 400
pm.test("[POST]::/payments - Status code is 400", function () {
pm.response.to.be.error
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) { }
pm.test("[POST]::/payments - Response has appropriate error message", function () {
pm.expect(jsonData.error.message).eql("Invalid Expiry Month");
})

View File

@ -0,0 +1,41 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "13",
"card_exp_year": "69",
"card_holder_name": "joseph Doe",
"card_cvc": "123"
}
}
}
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": ["{{baseUrl}}"],
"path": ["payments"]
},
"description": "Create a Payment to ensure api contract is intact"
}

View File

@ -0,0 +1,31 @@
// Validate status 400
pm.test("[POST]::/payments - Status code is 400", function () {
pm.response.to.be.error
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) { }
if (jsonData?.error?.message) {
pm.test(
"[POST]::/payments - Content check for error message to equal `Invalid Expiry Year`",
function () {
pm.expect(jsonData.error.message).to.eql("Invalid Expiry Year");
},
);
}

View File

@ -0,0 +1,41 @@
{
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD",
"payment_method": "card",
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "10",
"card_exp_year": "22",
"card_holder_name": "joseph Doe",
"card_cvc": "123"
}
}
}
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": ["{{baseUrl}}"],
"path": ["payments"]
},
"description": "Create a Payment to ensure api contract is intact"
}

View File

@ -0,0 +1,33 @@
// Validate status 2xx
pm.test("[POST]::/payments - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response header has matching content-type
pm.test("[POST]::/payments - Content-Type is application/json", function () {
pm.expect(pm.response.headers.get("Content-Type")).to.include(
"application/json",
);
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});
// Set response object as internal variable
let jsonData = {};
try {
jsonData = pm.response.json();
} catch (e) { }
// Response body should have value "requires_payment_method" for "status"
if (jsonData?.status) {
pm.test(
"[POST]::/payments - Content check if value for 'status' matches 'requires_confirmation'",
function () {
pm.expect(jsonData.status).to.eql("requires_confirmation");
},
);
}

View File

@ -1,9 +0,0 @@
// Validate status 2xx
pm.test("[POST]::/payments - Status code is 2xx", function () {
pm.response.to.be.success;
});
// Validate if response has JSON Body
pm.test("[POST]::/payments - Response has JSON Body", function () {
pm.response.to.have.jsonBody();
});

View File

@ -21,51 +21,12 @@ try {
jsonData = pm.response.json();
} catch (e) { }
// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id
if (jsonData?.payment_id) {
pm.collectionVariables.set("payment_id", jsonData.payment_id);
console.log(
"- use {{payment_id}} as collection variable for value",
jsonData.payment_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.",
);
}
// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id
if (jsonData?.mandate_id) {
pm.collectionVariables.set("mandate_id", jsonData.mandate_id);
console.log(
"- use {{mandate_id}} as collection variable for value",
jsonData.mandate_id,
);
} else {
console.log(
"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.",
);
}
// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret
if (jsonData?.client_secret) {
pm.collectionVariables.set("client_secret", jsonData.client_secret);
console.log(
"- use {{client_secret}} as collection variable for value",
jsonData.client_secret,
);
} else {
console.log(
"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.",
);
}
// Response body should have value "requires_payment_method" for "status"
if (jsonData?.status) {
pm.test(
"[POST]::/payments - Content check if value for 'status' matches 'requires_payment_method'",
"[POST]::/payments - Content check if value for 'status' matches 'requires_confirmation'",
function () {
pm.expect(jsonData.status).to.eql("requires_payment_method");
pm.expect(jsonData.status).to.eql("requires_confirmation");
},
);
}

View File

@ -19,7 +19,10 @@
},
"raw_json_formatted": {
"amount": 6540,
"currency": "USD"
"currency": "USD",
"payment_method": "reward",
"payment_method_type": "evoucher",
"payment_method_data": "reward"
}
},
"url": {

View File

@ -21800,7 +21800,290 @@
"name": "Scenario32-Ensure API Contract for Payment Method Data",
"item": [
{
"name": "Payments - Card Payment Method",
"name": "Payments - Card Payment Method Invalid Card CVC",
"event": [
{
"listen": "test",
"script": {
"exec": [
"// Validate status 400",
"pm.test(\"[POST]::/payments - Status code is 400\", function () {",
" pm.response.to.be.error",
"});",
"",
"// Validate if response header has matching content-type",
"pm.test(\"[POST]::/payments - Content-Type is application/json\", function () {",
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
" \"application/json\",",
" );",
"});",
"",
"// Validate if response has JSON Body",
"pm.test(\"[POST]::/payments - Response has JSON Body\", function () {",
" pm.response.to.have.jsonBody();",
"});",
"",
"// Set response object as internal variable",
"let jsonData = {};",
"try {",
" jsonData = pm.response.json();",
"} catch (e) { }",
"",
"pm.test(\"[POST]::/payments - Response has appropriate error message\", function () {",
" pm.expect(jsonData.error.message).eql(\"Invalid card_cvc length\");",
"})",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4242424242424242\",\"card_exp_month\":\"10\",\"card_exp_year\":\"25\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"\"}}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": [
"{{baseUrl}}"
],
"path": [
"payments"
]
},
"description": "Create a Payment to ensure api contract is intact"
}
},
{
"name": "Payments - Card Payment Method Invalid Card Number",
"event": [
{
"listen": "test",
"script": {
"exec": [
"// Validate status 400",
"pm.test(\"[POST]::/payments - Status code is 400\", function () {",
" pm.response.to.be.error",
"});",
"",
"// Validate if response header has matching content-type",
"pm.test(\"[POST]::/payments - Content-Type is application/json\", function () {",
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
" \"application/json\",",
" );",
"});",
"",
"// Validate if response has JSON Body",
"pm.test(\"[POST]::/payments - Response has JSON Body\", function () {",
" pm.response.to.have.jsonBody();",
"});",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"1234\",\"card_exp_month\":\"10\",\"card_exp_year\":\"25\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": [
"{{baseUrl}}"
],
"path": [
"payments"
]
},
"description": "Create a Payment to ensure api contract is intact"
}
},
{
"name": "Payments - Card Payment Method Invalid Expiry month",
"event": [
{
"listen": "test",
"script": {
"exec": [
"// Validate status 400",
"pm.test(\"[POST]::/payments - Status code is 400\", function () {",
" pm.response.to.be.error",
"});",
"",
"// Validate if response header has matching content-type",
"pm.test(\"[POST]::/payments - Content-Type is application/json\", function () {",
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
" \"application/json\",",
" );",
"});",
"",
"// Validate if response has JSON Body",
"pm.test(\"[POST]::/payments - Response has JSON Body\", function () {",
" pm.response.to.have.jsonBody();",
"});",
"",
"// Set response object as internal variable",
"let jsonData = {};",
"try {",
" jsonData = pm.response.json();",
"} catch (e) { }",
"",
"pm.test(\"[POST]::/payments - Response has appropriate error message\", function () {",
" pm.expect(jsonData.error.message).eql(\"Invalid Expiry Month\");",
"})",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4242424242424242\",\"card_exp_month\":\"13\",\"card_exp_year\":\"69\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": [
"{{baseUrl}}"
],
"path": [
"payments"
]
},
"description": "Create a Payment to ensure api contract is intact"
}
},
{
"name": "Payments - Card Payment Method Invalid Expiry year",
"event": [
{
"listen": "test",
"script": {
"exec": [
"// Validate status 400",
"pm.test(\"[POST]::/payments - Status code is 400\", function () {",
" pm.response.to.be.error",
"});",
"",
"// Validate if response header has matching content-type",
"pm.test(\"[POST]::/payments - Content-Type is application/json\", function () {",
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
" \"application/json\",",
" );",
"});",
"",
"// Validate if response has JSON Body",
"pm.test(\"[POST]::/payments - Response has JSON Body\", function () {",
" pm.response.to.have.jsonBody();",
"});",
"",
"// Set response object as internal variable",
"let jsonData = {};",
"try {",
" jsonData = pm.response.json();",
"} catch (e) { }",
"",
"if (jsonData?.error?.message) {",
" pm.test(",
" \"[POST]::/payments - Content check for error message to equal `Invalid Expiry Year`\",",
" function () {",
" pm.expect(jsonData.error.message).to.eql(\"Invalid Expiry Year\");",
" },",
" );",
"}",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Accept",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"options": {
"raw": {
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"payment_method\":\"card\",\"payment_method_data\":{\"card\":{\"card_number\":\"4242424242424242\",\"card_exp_month\":\"10\",\"card_exp_year\":\"22\",\"card_holder_name\":\"joseph Doe\",\"card_cvc\":\"123\"}}}"
},
"url": {
"raw": "{{baseUrl}}/payments",
"host": [
"{{baseUrl}}"
],
"path": [
"payments"
]
},
"description": "Create a Payment to ensure api contract is intact"
}
},
{
"name": "Payments - Card Payment Method Success",
"event": [
{
"listen": "test",
@ -21811,10 +22094,35 @@
" pm.response.to.be.success;",
"});",
"",
"// Validate if response header has matching content-type",
"pm.test(\"[POST]::/payments - Content-Type is application/json\", function () {",
" pm.expect(pm.response.headers.get(\"Content-Type\")).to.include(",
" \"application/json\",",
" );",
"});",
"",
"// Validate if response has JSON Body",
"pm.test(\"[POST]::/payments - Response has JSON Body\", function () {",
" pm.response.to.have.jsonBody();",
"});"
"});",
"",
"",
"// Set response object as internal variable",
"let jsonData = {};",
"try {",
" jsonData = pm.response.json();",
"} catch (e) { }",
"",
"// Response body should have value \"requires_payment_method\" for \"status\"",
"if (jsonData?.status) {",
" pm.test(",
" \"[POST]::/payments - Content check if value for 'status' matches 'requires_confirmation'\",",
" function () {",
" pm.expect(jsonData.status).to.eql(\"requires_confirmation\");",
" },",
" );",
"}",
""
],
"type": "text/javascript"
}
@ -21883,51 +22191,12 @@
" jsonData = pm.response.json();",
"} catch (e) { }",
"",
"// pm.collectionVariables - Set payment_id as variable for jsonData.payment_id",
"if (jsonData?.payment_id) {",
" pm.collectionVariables.set(\"payment_id\", jsonData.payment_id);",
" console.log(",
" \"- use {{payment_id}} as collection variable for value\",",
" jsonData.payment_id,",
" );",
"} else {",
" console.log(",
" \"INFO - Unable to assign variable {{payment_id}}, as jsonData.payment_id is undefined.\",",
" );",
"}",
"",
"// pm.collectionVariables - Set mandate_id as variable for jsonData.mandate_id",
"if (jsonData?.mandate_id) {",
" pm.collectionVariables.set(\"mandate_id\", jsonData.mandate_id);",
" console.log(",
" \"- use {{mandate_id}} as collection variable for value\",",
" jsonData.mandate_id,",
" );",
"} else {",
" console.log(",
" \"INFO - Unable to assign variable {{mandate_id}}, as jsonData.mandate_id is undefined.\",",
" );",
"}",
"",
"// pm.collectionVariables - Set client_secret as variable for jsonData.client_secret",
"if (jsonData?.client_secret) {",
" pm.collectionVariables.set(\"client_secret\", jsonData.client_secret);",
" console.log(",
" \"- use {{client_secret}} as collection variable for value\",",
" jsonData.client_secret,",
" );",
"} else {",
" console.log(",
" \"INFO - Unable to assign variable {{client_secret}}, as jsonData.client_secret is undefined.\",",
" );",
"}",
"",
"// Response body should have value \"requires_payment_method\" for \"status\"",
"if (jsonData?.status) {",
" pm.test(",
" \"[POST]::/payments - Content check if value for 'status' matches 'requires_payment_method'\",",
" \"[POST]::/payments - Content check if value for 'status' matches 'requires_confirmation'\",",
" function () {",
" pm.expect(jsonData.status).to.eql(\"requires_payment_method\");",
" pm.expect(jsonData.status).to.eql(\"requires_confirmation\");",
" },",
" );",
"}",
@ -21956,7 +22225,7 @@
"language": "json"
}
},
"raw": "{\"amount\":6540,\"currency\":\"USD\"}"
"raw": "{\"amount\":6540,\"currency\":\"USD\",\"payment_method\":\"reward\",\"payment_method_type\":\"evoucher\",\"payment_method_data\":\"reward\"}"
},
"url": {
"raw": "{{baseUrl}}/payments",