diff --git a/satellite/payments/stripecoinpayments/stripemock.go b/satellite/payments/stripecoinpayments/stripemock.go index 0fc3cadf1..317049623 100644 --- a/satellite/payments/stripecoinpayments/stripemock.go +++ b/satellite/payments/stripecoinpayments/stripemock.go @@ -41,7 +41,29 @@ var mocks = struct { m: make(map[storj.NodeID]*mockStripeState), } -const testPromoCode string = "testpromocode" +var ( + testPromoCodes = map[string]*stripe.PromotionCode{ + "promo1": { + ID: "p1", + Coupon: &stripe.Coupon{ + AmountOff: 500, + Currency: stripe.CurrencyUSD, + Name: "Test Promo Code 1", + }, + }, + "promo2": { + ID: "p2", + Coupon: &stripe.Coupon{ + PercentOff: 50, + Name: "Test Promo Code 2", + }, + }, + } + promoIDs = map[string]*stripe.PromotionCode{ + "p1": testPromoCodes["promo1"], + "p2": testPromoCodes["promo2"], + } +) // mockStripeState Stripe client mock. type mockStripeState struct { @@ -80,9 +102,6 @@ func NewStripeMock(id storj.NodeID, customersDB CustomersDB, usersDB console.Use state, ok := mocks.m[id] if !ok { - promoCodes := make(map[string][]*stripe.PromotionCode) - promoCodes[testPromoCode] = []*stripe.PromotionCode{{}} - state = &mockStripeState{ customers: &mockCustomersState{}, paymentMethods: newMockPaymentMethods(), @@ -91,7 +110,7 @@ func NewStripeMock(id storj.NodeID, customersDB CustomersDB, usersDB console.Use customerBalanceTransactions: newMockCustomerBalanceTransactions(), charges: &mockCharges{}, promoCodes: &mockPromoCodes{ - promoCodes: promoCodes, + promoCodes: testPromoCodes, }, } mocks.m[id] = state @@ -262,8 +281,8 @@ func (m *mockCustomers) Update(id string, params *stripe.CustomerParams) (*strip if params.Metadata != nil { customer.Metadata = params.Metadata } - if params.PromotionCode != nil { - customer.Discount = &stripe.Discount{Coupon: &stripe.Coupon{}} + if params.PromotionCode != nil && promoIDs[*params.PromotionCode] != nil { + customer.Discount = &stripe.Discount{Coupon: promoIDs[*params.PromotionCode].Coupon} } // TODO update customer with more params as necessary @@ -471,7 +490,7 @@ func (m *mockCharges) List(listParams *stripe.ChargeListParams) *charge.Iter { } type mockPromoCodes struct { - promoCodes map[string][]*stripe.PromotionCode + promoCodes map[string]*stripe.PromotionCode } func (m *mockPromoCodes) List(params *stripe.PromotionCodeListParams) *promotioncode.Iter { @@ -479,15 +498,15 @@ func (m *mockPromoCodes) List(params *stripe.PromotionCodeListParams) *promotion defer mocks.Unlock() query := stripe.Query(func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) { - promoCodes := m.promoCodes[*params.Code] - ret := make([]interface{}, len(promoCodes)) - - for i, v := range promoCodes { - ret[i] = v + promoCode := m.promoCodes[*params.Code] + if promoCode == nil { + return make([]interface{}, 0), &stripe.ListMeta{TotalCount: 0}, nil } + ret := make([]interface{}, 1) + ret[0] = promoCode listMeta := &stripe.ListMeta{ - TotalCount: uint32(len(promoCodes)), + TotalCount: 1, } lc := newListContainer(listMeta) diff --git a/testsuite/ui/satellite/billing_coupon_test.go b/testsuite/ui/satellite/billing_coupon_test.go new file mode 100644 index 000000000..467e5b528 --- /dev/null +++ b/testsuite/ui/satellite/billing_coupon_test.go @@ -0,0 +1,123 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package satellite_test + +import ( + "testing" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/input" + "github.com/stretchr/testify/require" + + "storj.io/common/testcontext" + "storj.io/storj/private/testplanet" + "storj.io/storj/testsuite/ui/uitest" +) + +func TestCouponCodes(t *testing.T) { + uitest.Run(t, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet, browser *rod.Browser) { + signupPageURL := planet.Satellites[0].ConsoleURL() + "/signup" + fullName := "John Doe" + emailAddress := "test@email.com" + password := "qazwsx123" + + page := openPage(browser, signupPageURL) + + // first time User signs up + page.MustElement("[aria-roledescription=name] input").MustInput(fullName) + page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress) + page.MustElement("[aria-roledescription=password] input").MustInput(password) + page.MustElement("[aria-roledescription=retype-password] input").MustInput(password) + page.MustElement(".checkmark").MustClick() + page.Keyboard.MustPress(input.Enter) + waitVueTick(page) + confirmAccountEmailMessage := page.MustElement("[aria-roledescription=title]").MustText() + require.Contains(t, confirmAccountEmailMessage, "You're almost there!") + + // first time user logs in + page.MustElement("[href=\"/login\"]").MustClick() + waitVueTick(page) + page.MustElement("[aria-roledescription=email] input").MustInput(emailAddress) + page.MustElement("[aria-roledescription=password] input").MustInput(password) + page.Keyboard.MustPress(input.Enter) + // waitVueTick(page) + + // skip onboarding process + page.MustElement("[href=\"/project-dashboard\"]").MustClick() + dashboardTitle := page.MustElement("[aria-roledescription=title]").MustText() + require.Contains(t, dashboardTitle, "Dashboard") + + // go to billing page + page.MustElement(".settings-selection").MustClick() + page.MustElementX("(//p[text()=\" Billing \"])").MustClick() + // waitVueTick(page) + + couponText := page.MustElement(".coupon-area__container__text-container").MustText() + require.Contains(t, couponText, "Add a Coupon to Get Started") + require.Contains(t, couponText, "Your coupon will show up here.") + + // Adding a valid promo code (promo1 and promo2 are defined in satellite/payments/stripecoinpayments/stripemock.go) + { + page.MustElementR("span", "Add Coupon Code").MustClick() + page.MustElement("input[placeholder=\"Enter Coupon Code\"]").MustInput("promo1") + page.MustElementR("span", "Apply Coupon Code").MustClick() + page.MustElementR("p", "Successfully applied coupon code") + + page.MustElement(".add-coupon__close-icon").MustClick() + couponText := page.MustElement(".coupon-area__container__text-container").MustText() + require.Contains(t, couponText, "Test Promo Code 1") + require.Contains(t, couponText, "$5 off") + } + + // Attempting replace with invalid promo code + { + page.MustElementR("span", "Add Coupon Code").MustClick() + page.MustElement("input[placeholder=\"Enter Coupon Code\"]").MustInput("notpromo1") + page.MustElementR("span", "Apply Coupon Code").MustClick() + + page.MustElementR(".add-coupon__confirm-message", "Are you sure.*remove.*current coupon.*replace.*new coupon") + page.MustElementR("span", "Back").MustClick() + + page.MustElement("input[placeholder=\"Enter Coupon Code\"]").MustInput("notpromo1") + page.MustElementR("span", "Apply Coupon Code").MustClick() + page.MustElementR(".add-coupon__confirm-message", "Are you sure.*remove.*current coupon.*replace.*new coupon") + page.MustElementR("span", "Yes").MustClick() + + page.MustElementR("p", "Could not apply coupon code") + + // old coupon should still be applied + page.MustElement(".add-coupon__close-icon").MustClick() + couponText := page.MustElement(".coupon-area__container__text-container").MustText() + require.Contains(t, couponText, "Test Promo Code 1") + require.Contains(t, couponText, "$5 off") + } + + // Replacing with a valid promo code + { + page.MustElementR("span", "Add Coupon Code").MustClick() + page.MustElement("input[placeholder=\"Enter Coupon Code\"]").MustInput("promo2") + page.MustElementR("span", "Apply Coupon Code").MustClick() + page.MustElementR(".add-coupon__confirm-message", "Are you sure.*remove.*current coupon.*replace.*new coupon") + page.MustElementR("span", "Yes").MustClick() + page.MustElementR("p", "Successfully applied coupon code") + + page.MustElement(".add-coupon__close-icon").MustClick() + couponText := page.MustElement(".coupon-area__container__text-container").MustText() + require.Contains(t, couponText, "Test Promo Code 2") + require.Contains(t, couponText, "50% off") + + } + + // Rate limit + { + page.MustElementR("span", "Add Coupon Code").MustClick() + for i := 0; i < 3; i++ { + page.MustElement("input[placeholder=\"Enter Coupon Code\"]").MustInput("promo1") + page.MustElementR("span", "Apply Coupon Code").MustClick() + page.MustElementR("span", "Yes").MustClick() + } + page.MustElementR("p", "You've exceeded limit of attempts") + } + }) +} diff --git a/testsuite/ui/uitest/run.go b/testsuite/ui/uitest/run.go index 9d04052b3..ffb37f5fb 100644 --- a/testsuite/ui/uitest/run.go +++ b/testsuite/ui/uitest/run.go @@ -40,6 +40,7 @@ func Run(t *testing.T, test Test) { config.Console.StaticDir = dir } config.Console.NewOnboarding = true + config.Console.CouponCodeBillingUIEnabled = true }, }, NonParallel: true,