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:
Pa1NarK
2023-07-10 22:48:07 +05:30
committed by GitHub
parent 6d4943d825
commit 307a470f7d
18 changed files with 1414 additions and 1317 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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,
}

View File

@ -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,

View File

@ -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(),
})
}

View File

@ -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,

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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"),
)
}

View File

@ -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&currency=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);
}

View File

@ -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);
}

View File

@ -91,6 +91,7 @@ fn should_make_3ds_payment_test() {
#[test]
#[serial]
#[ignore]
fn should_make_gpay_payment_test() {
tester!(should_make_gpay_payment);
}

View File

@ -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"],

View File

@ -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&currency=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);
}

View File

@ -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");
}

View File

@ -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(