mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
fix(core): Fix wallet payments throwing Invalid 'payment_method_type' provided and UI test issues (#1633)
Co-authored-by: Jagan Elavarasan <jaganelavarasan@gmail.com>
This commit is contained in:
8
.github/scripts/run_ui_tests.sh
vendored
8
.github/scripts/run_ui_tests.sh
vendored
@ -28,4 +28,10 @@ while netstat -lnt | awk '$4 ~ /:8080$/ {exit 1}'; do
|
||||
else
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
IN="$INPUT"
|
||||
for i in $(echo $IN | tr "," "\n"); do
|
||||
cargo test --package router --test connectors -- "${i}_ui::" --test-threads=1 >> tests/test_results.log 2>&1
|
||||
done
|
||||
cat tests/test_results.log
|
||||
2306
.github/testcases/ui_tests.json
vendored
2306
.github/testcases/ui_tests.json
vendored
File diff suppressed because it is too large
Load Diff
29
.github/workflows/connector-ui-sanity-tests.yml
vendored
29
.github/workflows/connector-ui-sanity-tests.yml
vendored
@ -72,9 +72,9 @@ jobs:
|
||||
connector:
|
||||
# do not use more than 8 runners, try to group less time taking connectors together
|
||||
- stripe
|
||||
- adyen_uk|shift4|worldline
|
||||
- airwallex|bluesnap|checkout
|
||||
- paypal|mollie|payu
|
||||
- adyen_uk,shift4,worldline
|
||||
- airwallex,bluesnap,checkout
|
||||
- paypal,mollie,payu
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@ -101,8 +101,8 @@ jobs:
|
||||
- name: Install latest compiler
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
toolchain: stable
|
||||
|
||||
- uses: Swatinem/rust-cache@v2.4.0
|
||||
|
||||
- uses: baptiste0928/cargo-install@v2.1.0
|
||||
@ -111,23 +111,26 @@ jobs:
|
||||
features: postgres
|
||||
args: "--no-default-features"
|
||||
|
||||
- name: diesel migration run
|
||||
- name: Diesel migration run
|
||||
shell: bash
|
||||
env:
|
||||
DATABASE_URL: postgres://db_user:db_pass@localhost:5432/hyperswitch_db
|
||||
run: diesel migration run
|
||||
|
||||
- name: Start server
|
||||
- name: Start server and run tests
|
||||
env:
|
||||
UI_TESTCASES_PATH: ${{ secrets.UI_TESTCASES_PATH }}
|
||||
INPUT: ${{ matrix.connector }}
|
||||
shell: bash
|
||||
run: sh .github/scripts/run_ui_tests.sh
|
||||
|
||||
- name: Run tests
|
||||
- name: View test results
|
||||
shell: bash
|
||||
run: cat tests/test_results.log
|
||||
|
||||
- name: Check test results
|
||||
shell: bash
|
||||
run: |
|
||||
IN="${{ matrix.connector }}"
|
||||
connectors=(${IN//|/ })
|
||||
for i in "${connectors[@]}"; do
|
||||
cargo test --package router --test connectors -- "${i}_ui::" --test-threads=1
|
||||
done
|
||||
if test "$( grep 'test result: FAILED' -r tests/test_results.log | wc -l )" -gt "0"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -16,6 +16,7 @@ RegioBank = "RegioBank"
|
||||
SOM = "SOM" # Somalia country code
|
||||
THA = "THA" # Thailand country code
|
||||
ZAR = "ZAR" # South African Rand currency code
|
||||
klick = "klick" # Swedish word for clicks
|
||||
|
||||
[default.extend-words]
|
||||
aci = "aci" # Name of a connector
|
||||
|
||||
@ -227,6 +227,7 @@ impl TryFrom<&types::ConnectorAuthType> for PaypalAuthType {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum PaypalOrderStatus {
|
||||
Pending,
|
||||
Completed,
|
||||
Voided,
|
||||
Created,
|
||||
@ -246,7 +247,9 @@ impl ForeignFrom<(PaypalOrderStatus, PaypalPaymentIntent)> for storage_enums::At
|
||||
}
|
||||
}
|
||||
PaypalOrderStatus::Voided => Self::Voided,
|
||||
PaypalOrderStatus::Created | PaypalOrderStatus::Saved => Self::Pending,
|
||||
PaypalOrderStatus::Created | PaypalOrderStatus::Saved | PaypalOrderStatus::Pending => {
|
||||
Self::Pending
|
||||
}
|
||||
PaypalOrderStatus::Approved => Self::AuthenticationSuccessful,
|
||||
PaypalOrderStatus::PayerActionRequired => Self::AuthenticationPending,
|
||||
}
|
||||
|
||||
@ -1370,7 +1370,7 @@ impl TryFrom<&types::VerifyRouterData> for SetupIntentRequest {
|
||||
metadata_txn_id,
|
||||
metadata_txn_uuid,
|
||||
payment_data,
|
||||
return_url: item.return_url.clone(),
|
||||
return_url: item.request.router_return_url.clone(),
|
||||
off_session: item.request.off_session,
|
||||
usage: item.request.setup_future_usage,
|
||||
payment_method_options: None,
|
||||
|
||||
@ -928,6 +928,14 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::VerifyRequestDat
|
||||
connector_name,
|
||||
payment_data.creds_identifier.as_deref(),
|
||||
));
|
||||
let browser_info: Option<types::BrowserInformation> = attempt
|
||||
.browser_info
|
||||
.clone()
|
||||
.map(|b| b.parse_value("BrowserInformation"))
|
||||
.transpose()
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "browser_info",
|
||||
})?;
|
||||
Ok(Self {
|
||||
currency: payment_data.currency,
|
||||
confirm: true,
|
||||
@ -942,6 +950,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::VerifyRequestDat
|
||||
router_return_url,
|
||||
email: payment_data.email,
|
||||
return_url: payment_data.payment_intent.return_url,
|
||||
browser_info,
|
||||
payment_method_type: attempt.payment_method_type.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -339,6 +339,7 @@ pub struct VerifyRequestData {
|
||||
pub off_session: Option<bool>,
|
||||
pub setup_mandate_details: Option<payments::MandateData>,
|
||||
pub router_return_url: Option<String>,
|
||||
pub browser_info: Option<BrowserInformation>,
|
||||
pub email: Option<Email>,
|
||||
pub return_url: Option<String>,
|
||||
pub payment_method_type: Option<storage_enums::PaymentMethodType>,
|
||||
@ -767,7 +768,7 @@ impl From<&VerifyRouterData> for PaymentsAuthorizeData {
|
||||
capture_method: None,
|
||||
webhook_url: None,
|
||||
complete_authorize_url: None,
|
||||
browser_info: None,
|
||||
browser_info: data.request.browser_info.clone(),
|
||||
order_details: None,
|
||||
order_category: None,
|
||||
session_token: None,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use api_models::enums as api_enums;
|
||||
pub use api_models::payment_methods::{
|
||||
CardDetail, CardDetailFromLocker, CustomerPaymentMethod, CustomerPaymentMethodsListResponse,
|
||||
DeleteTokenizeByDateRequest, DeleteTokenizeByTokenRequest, GetTokenizePayloadRequest,
|
||||
@ -9,109 +8,30 @@ pub use api_models::payment_methods::{
|
||||
TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
|
||||
};
|
||||
use error_stack::report;
|
||||
use literally::hmap;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{
|
||||
core::errors::{self, RouterResult},
|
||||
types::api::enums as api_enums,
|
||||
types::transformers::ForeignFrom,
|
||||
};
|
||||
|
||||
/// Static collection that contains valid Payment Method Type and Payment Method SubType
|
||||
/// tuples. Used for validation.
|
||||
static PAYMENT_METHOD_TYPE_SET: Lazy<
|
||||
HashMap<api_enums::PaymentMethod, Vec<api_enums::PaymentMethodType>>,
|
||||
> = Lazy::new(|| {
|
||||
use api_enums::{PaymentMethod as T, PaymentMethodType as ST};
|
||||
|
||||
hmap! {
|
||||
T::Card => vec![
|
||||
ST::Credit,
|
||||
ST::Debit
|
||||
],
|
||||
T::Wallet => vec![]
|
||||
}
|
||||
});
|
||||
|
||||
/// Static collection that contains valid Payment Method Issuer and Payment Method Issuer
|
||||
/// Type tuples. Used for validation.
|
||||
static PAYMENT_METHOD_ISSUER_SET: Lazy<
|
||||
HashMap<api_enums::PaymentMethod, Vec<api_enums::PaymentMethodIssuerCode>>,
|
||||
> = Lazy::new(|| {
|
||||
use api_enums::{PaymentMethod as T, PaymentMethodIssuerCode as IC};
|
||||
|
||||
hmap! {
|
||||
T::Card => vec![
|
||||
IC::JpHdfc,
|
||||
IC::JpIcici,
|
||||
],
|
||||
T::Wallet => vec![
|
||||
IC::JpApplepay,
|
||||
IC::JpGooglepay,
|
||||
IC::JpWechat
|
||||
],
|
||||
}
|
||||
});
|
||||
|
||||
pub(crate) trait PaymentMethodCreateExt {
|
||||
fn validate(&self) -> RouterResult<()>;
|
||||
fn check_subtype_mapping<T, U>(
|
||||
dict: &HashMap<T, Vec<U>>,
|
||||
the_type: T,
|
||||
the_subtype: Option<U>,
|
||||
) -> bool
|
||||
where
|
||||
T: Eq + std::hash::Hash,
|
||||
U: PartialEq;
|
||||
}
|
||||
|
||||
// convert self.payment_method_type to payment_method and compare it against self.payment_method
|
||||
impl PaymentMethodCreateExt for PaymentMethodCreate {
|
||||
fn validate(&self) -> RouterResult<()> {
|
||||
let pm_subtype_map = Lazy::get(&PAYMENT_METHOD_TYPE_SET)
|
||||
.unwrap_or_else(|| Lazy::force(&PAYMENT_METHOD_TYPE_SET));
|
||||
if !Self::check_subtype_mapping(
|
||||
pm_subtype_map,
|
||||
self.payment_method,
|
||||
self.payment_method_type,
|
||||
) {
|
||||
let payment_method: Option<api_enums::PaymentMethod> =
|
||||
self.payment_method_type.map(ForeignFrom::foreign_from);
|
||||
if payment_method
|
||||
.map(|payment_method| payment_method != self.payment_method)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "Invalid 'payment_method_type' provided.".to_string()
|
||||
message: "Invalid 'payment_method_type' provided".to_string()
|
||||
})
|
||||
.attach_printable("Invalid payment method type"));
|
||||
}
|
||||
|
||||
let issuer_map = Lazy::get(&PAYMENT_METHOD_ISSUER_SET)
|
||||
.unwrap_or_else(|| Lazy::force(&PAYMENT_METHOD_ISSUER_SET));
|
||||
if !Self::check_subtype_mapping(
|
||||
issuer_map,
|
||||
self.payment_method,
|
||||
self.payment_method_issuer_code,
|
||||
) {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "Invalid 'payment_method_issuer_code' provided.".to_string()
|
||||
})
|
||||
.attach_printable("Invalid payment method issuer code"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_subtype_mapping<T, U>(
|
||||
dict: &HashMap<T, Vec<U>>,
|
||||
the_type: T,
|
||||
the_subtype: Option<U>,
|
||||
) -> bool
|
||||
where
|
||||
T: Eq + std::hash::Hash,
|
||||
U: PartialEq,
|
||||
{
|
||||
let the_subtype = match the_subtype {
|
||||
Some(st) => st,
|
||||
None => return true,
|
||||
};
|
||||
|
||||
dict.get(&the_type)
|
||||
.map(|subtypes| subtypes.contains(&the_subtype))
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +229,53 @@ impl ForeignTryFrom<api_enums::IntentStatus> for storage_enums::EventType {
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignFrom<api_enums::PaymentMethodType> for api_enums::PaymentMethod {
|
||||
fn foreign_from(payment_method_type: api_enums::PaymentMethodType) -> Self {
|
||||
match payment_method_type {
|
||||
api_enums::PaymentMethodType::ApplePay
|
||||
| api_enums::PaymentMethodType::GooglePay
|
||||
| api_enums::PaymentMethodType::Paypal
|
||||
| api_enums::PaymentMethodType::AliPay
|
||||
| api_enums::PaymentMethodType::AliPayHk
|
||||
| api_enums::PaymentMethodType::MbWay
|
||||
| api_enums::PaymentMethodType::MobilePay
|
||||
| api_enums::PaymentMethodType::SamsungPay
|
||||
| api_enums::PaymentMethodType::WeChatPay => Self::Wallet,
|
||||
api_enums::PaymentMethodType::Affirm
|
||||
| api_enums::PaymentMethodType::AfterpayClearpay
|
||||
| api_enums::PaymentMethodType::Klarna
|
||||
| api_enums::PaymentMethodType::PayBright
|
||||
| api_enums::PaymentMethodType::Walley => Self::PayLater,
|
||||
api_enums::PaymentMethodType::Giropay
|
||||
| api_enums::PaymentMethodType::Ideal
|
||||
| api_enums::PaymentMethodType::Sofort
|
||||
| api_enums::PaymentMethodType::Eps
|
||||
| api_enums::PaymentMethodType::BancontactCard
|
||||
| api_enums::PaymentMethodType::Blik
|
||||
| api_enums::PaymentMethodType::OnlineBankingCzechRepublic
|
||||
| api_enums::PaymentMethodType::OnlineBankingFinland
|
||||
| api_enums::PaymentMethodType::OnlineBankingPoland
|
||||
| api_enums::PaymentMethodType::OnlineBankingSlovakia
|
||||
| api_enums::PaymentMethodType::Przelewy24
|
||||
| api_enums::PaymentMethodType::Swish
|
||||
| api_enums::PaymentMethodType::Trustly
|
||||
| api_enums::PaymentMethodType::Interac => Self::BankRedirect,
|
||||
api_enums::PaymentMethodType::UpiCollect => Self::Upi,
|
||||
api_enums::PaymentMethodType::CryptoCurrency => Self::Crypto,
|
||||
api_enums::PaymentMethodType::Ach
|
||||
| api_enums::PaymentMethodType::Sepa
|
||||
| api_enums::PaymentMethodType::Bacs
|
||||
| api_enums::PaymentMethodType::Becs => Self::BankDebit,
|
||||
api_enums::PaymentMethodType::Credit | api_enums::PaymentMethodType::Debit => {
|
||||
Self::Card
|
||||
}
|
||||
api_enums::PaymentMethodType::Evoucher
|
||||
| api_enums::PaymentMethodType::ClassicReward => Self::Reward,
|
||||
api_enums::PaymentMethodType::Multibanco => Self::BankTransfer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignTryFrom<storage_enums::RefundStatus> for storage_enums::EventType {
|
||||
type Error = errors::ValidationError;
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ impl utils::Connector for AdyenTest {
|
||||
fn get_auth_token(&self) -> types::ConnectorAuthType {
|
||||
types::ConnectorAuthType::from(
|
||||
connector_auth::ConnectorAuthentication::new()
|
||||
.adyen
|
||||
.adyen_uk
|
||||
.expect("Missing connector authentication configuration"),
|
||||
)
|
||||
}
|
||||
|
||||
@ -75,8 +75,8 @@ async fn should_make_adyen_gpay_mandate_payment(
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
Event::Assert(Assert::IsPresent("Mandate ID")),
|
||||
Event::Assert(Assert::IsPresent("man_")),// mandate id starting with man_
|
||||
Event::Trigger(Trigger::Click(By::Id("pm-mandate-btn"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("pay-with-mandate-btn"))),
|
||||
Event::Trigger(Trigger::Click(By::Css("#pm-mandate-btn a"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
]).await?;
|
||||
Ok(())
|
||||
@ -92,8 +92,8 @@ async fn should_make_adyen_gpay_zero_dollar_mandate_payment(
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
Event::Assert(Assert::IsPresent("Mandate ID")),
|
||||
Event::Assert(Assert::IsPresent("man_")),// mandate id starting with man_
|
||||
Event::Trigger(Trigger::Click(By::Id("pm-mandate-btn"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("pay-with-mandate-btn"))),
|
||||
Event::Trigger(Trigger::Click(By::Css("#pm-mandate-btn a"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
]).await?;
|
||||
Ok(())
|
||||
@ -103,29 +103,45 @@ async fn should_make_adyen_klarna_mandate_payment(
|
||||
web_driver: WebDriver,
|
||||
) -> Result<(), WebDriverError> {
|
||||
let conn = AdyenSeleniumTest {};
|
||||
conn.make_redirection_payment(web_driver,
|
||||
conn.make_redirection_payment(
|
||||
web_driver,
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/klarna-redirect?amount=70.00&country=SE¤cy=SEK&mandate_data[customer_acceptance][acceptance_type]=offline&mandate_data[customer_acceptance][accepted_at]=1963-05-03T04:07:52.723Z&mandate_data[customer_acceptance][online][ip_address]=127.0.0.1&mandate_data[customer_acceptance][online][user_agent]=amet%20irure%20esse&mandate_data[mandate_type][multi_use][amount]=700&mandate_data[mandate_type][multi_use][currency]=SEK&return_url={CHEKOUT_BASE_URL}/payments"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("klarna-redirect-btn"))),
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/195"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Trigger(Trigger::SwitchFrame(By::Id("klarna-apf-iframe"))),
|
||||
Event::Trigger(Trigger::Sleep(5)),
|
||||
Event::Trigger(Trigger::Click(By::Id("signInWithBankId"))),
|
||||
Event::Assert(Assert::IsPresent("Klart att betala")),
|
||||
Event::EitherOr(Assert::IsPresent("Klart att betala"), vec![
|
||||
Event::Trigger(Trigger::Click(By::Css("button[data-testid='confirm-and-pay']"))),
|
||||
],
|
||||
vec![
|
||||
Event::Trigger(Trigger::Click(By::Css("button[data-testid='SmoothCheckoutPopUp:skip']"))),
|
||||
Event::Trigger(Trigger::Click(By::Css("button[data-testid='confirm-and-pay']"))),
|
||||
]
|
||||
Event::EitherOr(
|
||||
Assert::IsPresent("Klart att betala"),
|
||||
vec![Event::Trigger(Trigger::Click(By::Css(
|
||||
"button[data-testid='confirm-and-pay']",
|
||||
)))],
|
||||
vec![
|
||||
Event::Trigger(Trigger::Click(By::Css(
|
||||
"button[data-testid='SmoothCheckoutPopUp:skip']",
|
||||
))),
|
||||
Event::Trigger(Trigger::Click(By::Css(
|
||||
"button[data-testid='confirm-and-pay']",
|
||||
))),
|
||||
],
|
||||
),
|
||||
Event::RunIf(
|
||||
Assert::IsPresent("Färre klick, snabbare betalning"),
|
||||
vec![Event::Trigger(Trigger::Click(By::Css(
|
||||
"button[data-testid='SmoothCheckoutPopUp:enable']",
|
||||
)))],
|
||||
),
|
||||
Event::Trigger(Trigger::SwitchTab(Position::Prev)),
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
Event::Assert(Assert::IsPresent("Mandate ID")),
|
||||
Event::Assert(Assert::IsPresent("man_")),// mandate id starting with man_
|
||||
Event::Trigger(Trigger::Click(By::Id("pm-mandate-btn"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("pay-with-mandate-btn"))),
|
||||
Event::Assert(Assert::IsPresent("man_")), // mandate id starting with man_
|
||||
Event::Trigger(Trigger::Click(By::Css("#pm-mandate-btn a"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
]).await?;
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -139,11 +155,14 @@ async fn should_make_adyen_alipay_hk_payment(c: WebDriver) -> Result<(), WebDriv
|
||||
Event::EitherOr(
|
||||
Assert::IsPresent("Payment Method Not Available"),
|
||||
vec![Event::Assert(Assert::IsPresent(
|
||||
" (Note: these error messages are not visible on the live platform) ",
|
||||
"Please try again or select a different payment method",
|
||||
))],
|
||||
vec![
|
||||
Event::Trigger(Trigger::Click(By::Css("button[value='authorised']"))),
|
||||
Event::Assert(Assert::IsPresent("succeeded")),
|
||||
Event::Assert(Assert::Contains(
|
||||
Selector::QueryParamStr,
|
||||
"status=succeeded",
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -193,7 +212,6 @@ fn should_make_adyen_3ds_payment_success_test() {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
fn should_make_adyen_alipay_hk_payment_test() {
|
||||
tester!(should_make_adyen_alipay_hk_payment);
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ async fn should_make_gpay_payment(driver: WebDriver) -> Result<(), WebDriverErro
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
fn should_make_3ds_payment_test() {
|
||||
tester!(should_make_3ds_payment);
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ fn should_make_3ds_payment_test() {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
fn should_make_gpay_payment_test() {
|
||||
tester!(should_make_gpay_payment);
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ async fn should_make_paypal_paypal_wallet_payment(
|
||||
web_driver,
|
||||
&format!("{CHEKOUT_BASE_URL}/saved/21"),
|
||||
vec![
|
||||
Event::Assert(Assert::IsPresent("Google")),
|
||||
Event::Assert(Assert::IsPresent("How Search works")),
|
||||
Event::Assert(Assert::ContainsAny(
|
||||
Selector::QueryParamStr,
|
||||
vec!["status=succeeded"],
|
||||
|
||||
@ -11,10 +11,10 @@ impl SeleniumTest for PayUSeleniumTest {
|
||||
}
|
||||
}
|
||||
|
||||
async fn should_make_no_3ds_card_payment(c: WebDriver) -> Result<(), WebDriverError> {
|
||||
async fn should_make_no_3ds_card_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
|
||||
let conn = PayUSeleniumTest {};
|
||||
conn.make_redirection_payment(
|
||||
c,
|
||||
web_driver,
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/72"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
@ -27,19 +27,14 @@ async fn should_make_no_3ds_card_payment(c: WebDriver) -> Result<(), WebDriverEr
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn should_make_gpay_payment(c: WebDriver) -> Result<(), WebDriverError> {
|
||||
async fn should_make_gpay_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
|
||||
let conn = PayUSeleniumTest {};
|
||||
conn.make_redirection_payment(
|
||||
c,
|
||||
conn.make_gpay_payment(web_driver,
|
||||
&format!("{CHEKOUT_BASE_URL}/gpay?gatewayname=payu&gatewaymerchantid=459551&amount=70.00&country=US¤cy=PLN"),
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(&format!("{CHEKOUT_BASE_URL}/saved/77"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Trigger(Trigger::Sleep(1)),
|
||||
Event::Assert(Assert::IsPresent("status")),
|
||||
Event::Assert(Assert::IsPresent("processing")),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Event::Assert(Assert::IsPresent("Status")),
|
||||
Event::Assert(Assert::IsPresent("processing")),
|
||||
]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -51,6 +46,7 @@ fn should_make_no_3ds_card_payment_test() {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
fn should_make_gpay_payment_test() {
|
||||
tester!(should_make_gpay_payment);
|
||||
}
|
||||
|
||||
@ -265,12 +265,11 @@ pub trait SeleniumTest {
|
||||
driver.execute(script, Vec::new()).await?;
|
||||
}
|
||||
Trigger::Click(by) => {
|
||||
let ele = driver.query(by).first().await?;
|
||||
ele.wait_until().enabled().await?;
|
||||
ele.wait_until().displayed().await?;
|
||||
ele.wait_until().clickable().await?;
|
||||
ele.scroll_into_view().await?;
|
||||
ele.click().await?;
|
||||
let res = self.click_element(driver, by.clone()).await;
|
||||
if res.is_err() {
|
||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||
self.click_element(driver, by).await?;
|
||||
}
|
||||
}
|
||||
Trigger::ClickNth(by, n) => {
|
||||
let ele = driver.query(by).all().await?.into_iter().nth(n).unwrap();
|
||||
@ -334,22 +333,54 @@ pub trait SeleniumTest {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn click_element(&self, driver: &WebDriver, by: By) -> Result<(), WebDriverError> {
|
||||
let ele = driver.query(by).first().await?;
|
||||
ele.wait_until().enabled().await?;
|
||||
ele.wait_until().displayed().await?;
|
||||
ele.wait_until().clickable().await?;
|
||||
ele.scroll_into_view().await?;
|
||||
ele.click().await
|
||||
}
|
||||
|
||||
async fn make_redirection_payment(
|
||||
&self,
|
||||
c: WebDriver,
|
||||
web_driver: WebDriver,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
// To support failure retries
|
||||
let result = self
|
||||
.execute_steps(web_driver.clone(), actions.clone())
|
||||
.await;
|
||||
if result.is_err() {
|
||||
self.execute_steps(web_driver, actions).await
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
async fn execute_steps(
|
||||
&self,
|
||||
web_driver: WebDriver,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
let config = self.get_configs().automation_configs.unwrap();
|
||||
if config.run_minimum_steps.unwrap() {
|
||||
self.complete_actions(&c, actions[..3].to_vec()).await
|
||||
self.complete_actions(&web_driver, actions[..3].to_vec())
|
||||
.await
|
||||
} else {
|
||||
println!("Run all steps");
|
||||
self.complete_actions(&c, actions).await
|
||||
self.complete_actions(&web_driver, actions).await
|
||||
}
|
||||
}
|
||||
async fn make_gpay_payment(
|
||||
&self,
|
||||
c: WebDriver,
|
||||
web_driver: WebDriver,
|
||||
url: &str,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
self.execute_gpay_steps(web_driver, url, actions).await
|
||||
}
|
||||
async fn execute_gpay_steps(
|
||||
&self,
|
||||
web_driver: WebDriver,
|
||||
url: &str,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
@ -384,22 +415,35 @@ pub trait SeleniumTest {
|
||||
),
|
||||
],
|
||||
),
|
||||
Event::Trigger(Trigger::SwitchFrame(By::Id("sM432dIframe"))),
|
||||
Event::Trigger(Trigger::SwitchFrame(By::Css(
|
||||
".bootstrapperIframeContainerElement iframe",
|
||||
))),
|
||||
Event::Assert(Assert::IsPresent("Gpay Tester")),
|
||||
Event::Trigger(Trigger::Click(By::ClassName("jfk-button-action"))),
|
||||
Event::Trigger(Trigger::SwitchTab(Position::Prev)),
|
||||
];
|
||||
self.complete_actions(&c, default_actions).await?;
|
||||
self.complete_actions(&c, actions).await
|
||||
self.complete_actions(&web_driver, default_actions).await?;
|
||||
self.complete_actions(&web_driver, actions).await
|
||||
}
|
||||
async fn make_paypal_payment(
|
||||
&self,
|
||||
c: WebDriver,
|
||||
web_driver: WebDriver,
|
||||
url: &str,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
let pypl_url = url.to_string();
|
||||
// To support failure retries
|
||||
self.execute_paypal_steps(web_driver.clone(), &pypl_url, actions.clone())
|
||||
.await
|
||||
}
|
||||
async fn execute_paypal_steps(
|
||||
&self,
|
||||
web_driver: WebDriver,
|
||||
url: &str,
|
||||
actions: Vec<Event<'_>>,
|
||||
) -> Result<(), WebDriverError> {
|
||||
self.complete_actions(
|
||||
&c,
|
||||
&web_driver,
|
||||
vec![
|
||||
Event::Trigger(Trigger::Goto(url)),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
@ -421,30 +465,33 @@ pub trait SeleniumTest {
|
||||
.unwrap(),
|
||||
);
|
||||
let mut pypl_actions = vec![
|
||||
Event::RunIf(
|
||||
Assert::IsPresent("Enter your email address to get started."),
|
||||
Event::EitherOr(
|
||||
Assert::IsPresent("Forgot email?"),
|
||||
vec![
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("email"), email)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnNext"))),
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
|
||||
],
|
||||
vec![
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
|
||||
],
|
||||
),
|
||||
Event::EitherOr(
|
||||
Assert::IsPresent("Password"),
|
||||
Assert::IsPresent("See Offers and Apply for PayPal Credit"),
|
||||
vec![
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
|
||||
],
|
||||
vec![
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("email"), email)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnNext"))),
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("password"), pass)),
|
||||
Event::Trigger(Trigger::Click(By::Id("btnLogin"))),
|
||||
Event::RunIf(
|
||||
Assert::IsElePresent(By::Id("spinner")),
|
||||
vec![Event::Trigger(Trigger::Sleep(5))],
|
||||
),
|
||||
Event::Trigger(Trigger::Click(By::Css(".reviewButton"))),
|
||||
],
|
||||
vec![Event::Trigger(Trigger::Click(By::Id("payment-submit-btn")))],
|
||||
),
|
||||
Event::Trigger(Trigger::Click(By::Id("payment-submit-btn"))),
|
||||
];
|
||||
pypl_actions.extend(actions);
|
||||
self.complete_actions(&c, pypl_actions).await
|
||||
self.complete_actions(&web_driver, pypl_actions).await
|
||||
}
|
||||
}
|
||||
async fn is_text_present_now(driver: &WebDriver, key: &str) -> WebDriverResult<bool> {
|
||||
@ -494,9 +541,9 @@ macro_rules! tester_inner {
|
||||
// make sure we close, even if an assertion fails
|
||||
let client = driver.clone();
|
||||
let x = runtime.block_on(async move {
|
||||
let r = tokio::spawn($execute(driver)).await;
|
||||
let run = tokio::spawn($execute(driver)).await;
|
||||
let _ = client.quit().await;
|
||||
r
|
||||
run
|
||||
});
|
||||
drop(runtime);
|
||||
x.expect("test panicked")
|
||||
@ -522,8 +569,8 @@ pub fn get_browser() -> String {
|
||||
"firefox".to_string()
|
||||
}
|
||||
|
||||
pub fn make_capabilities(s: &str) -> Capabilities {
|
||||
match s {
|
||||
pub fn make_capabilities(browser: &str) -> Capabilities {
|
||||
match browser {
|
||||
"firefox" => {
|
||||
let mut caps = DesiredCapabilities::firefox();
|
||||
let ignore_profile = env::var("IGNORE_BROWSER_PROFILE").ok();
|
||||
@ -544,6 +591,7 @@ pub fn make_capabilities(s: &str) -> Capabilities {
|
||||
&_ => DesiredCapabilities::safari().into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_chrome_profile_path() -> Result<String, WebDriverError> {
|
||||
let exe = env::current_exe()?;
|
||||
let dir = exe.parent().expect("Executable must be in some directory");
|
||||
@ -558,6 +606,7 @@ fn get_chrome_profile_path() -> Result<String, WebDriverError> {
|
||||
base_path.push_str(r#"/Library/Application\ Support/Google/Chrome/Default"#); //Issue: 1573
|
||||
Ok(base_path)
|
||||
}
|
||||
|
||||
fn get_firefox_profile_path() -> Result<String, WebDriverError> {
|
||||
let exe = env::current_exe()?;
|
||||
let dir = exe.parent().expect("Executable must be in some directory");
|
||||
@ -573,8 +622,8 @@ fn get_firefox_profile_path() -> Result<String, WebDriverError> {
|
||||
Ok(base_path)
|
||||
}
|
||||
|
||||
pub fn make_url(s: &str) -> &'static str {
|
||||
match s {
|
||||
pub fn make_url(browser: &str) -> &'static str {
|
||||
match browser {
|
||||
"firefox" => "http://localhost:4444",
|
||||
"chrome" => "http://localhost:9515",
|
||||
&_ => "",
|
||||
@ -586,13 +635,13 @@ pub fn handle_test_error(
|
||||
) -> bool {
|
||||
match res {
|
||||
Ok(Ok(_)) => true,
|
||||
Ok(Err(e)) => {
|
||||
eprintln!("test future failed to resolve: {:?}", e);
|
||||
Ok(Err(web_driver_error)) => {
|
||||
eprintln!("test future failed to resolve: {:?}", web_driver_error);
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
if let Some(e) = e.downcast_ref::<WebDriverError>() {
|
||||
eprintln!("test future panicked: {:?}", e);
|
||||
if let Some(web_driver_error) = e.downcast_ref::<WebDriverError>() {
|
||||
eprintln!("test future panicked: {:?}", web_driver_error);
|
||||
} else {
|
||||
eprintln!("test future panicked; an assertion probably failed");
|
||||
}
|
||||
|
||||
@ -135,6 +135,12 @@ async fn should_make_stripe_klarna_payment(c: WebDriver) -> Result<(), WebDriver
|
||||
Event::Trigger(Trigger::SendKeys(By::Id("otp_field"), "123456")),
|
||||
],
|
||||
),
|
||||
Event::RunIf(
|
||||
Assert::IsPresent("We've updated our Shopping terms"),
|
||||
vec![Event::Trigger(Trigger::Click(By::Css(
|
||||
"button[data-testid='kaf-button']",
|
||||
)))],
|
||||
),
|
||||
Event::RunIf(
|
||||
Assert::IsPresent("Pick a plan"),
|
||||
vec![Event::Trigger(Trigger::Click(By::Css(
|
||||
|
||||
Reference in New Issue
Block a user