Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ui tests for add / update / remove card #1843

Merged
merged 23 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b4635b4
add test fixture for card data
asnaith Jan 7, 2022
e4464e8
add new billing flow identifiers for page objects
asnaith Jan 7, 2022
84febc8
add card modal test object and subscription plan spec file (wip)
asnaith Jan 7, 2022
acdcd00
add reminder
asnaith Jan 7, 2022
900ced2
allow typing into stripe iframe
Tbaut Jan 7, 2022
7f905eb
Merge branch 'dev' into mnt/add-card-ui-tests-1842
asnaith Jan 7, 2022
8241831
Add new checks for update and removing a card
asnaith Jan 8, 2022
d062e14
improve reliability of another test after spotting issue in ci
asnaith Jan 10, 2022
8559301
ensure we are not trying to click too early, addresses ci failure
asnaith Jan 10, 2022
f3b2799
Merge branch 'dev' into mnt/add-card-ui-tests-1842
asnaith Jan 11, 2022
6bb9fea
add card deletion option (#1850)
Tbaut Jan 12, 2022
abd743e
Merge branch 'dev' into mnt/add-card-ui-tests-1842
Tbaut Jan 13, 2022
9cddd40
add timeout to iframe
asnaith Jan 14, 2022
5b4cbcd
Merge branch 'dev' into mnt/add-card-ui-tests-1842
asnaith Jan 14, 2022
552781c
Merge branch 'dev' into mnt/add-card-ui-tests-1842
Tbaut Jan 14, 2022
5996bf0
add intercepts to spy on requests, remove waits
asnaith Jan 15, 2022
3bc432c
Merge branch 'mnt/add-card-ui-tests-1842' of github.com:ChainSafe/fil…
asnaith Jan 15, 2022
ba6f74e
add strip key to test runner
Tbaut Jan 17, 2022
37519ba
Apply locator syntax suggestions from code review
asnaith Jan 17, 2022
4eec981
Merge branch 'dev' into mnt/add-card-ui-tests-1842
asnaith Jan 17, 2022
6222175
lingui extract
actions-user Jan 17, 2022
3daa6d5
Merge branch 'dev' into mnt/add-card-ui-tests-1842
FSM1 Jan 18, 2022
1c3f884
Merge branch 'dev' into mnt/add-card-ui-tests-1842
asnaith Jan 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-files-on-demand.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
REACT_APP_FILES_VERIFIER_NAME: ${{ secrets.GH_REACT_APP_FILES_VERIFIER_NAME }}
REACT_APP_FILES_UUID_VERIFIER_NAME: 'chainsafe-uuid-testnet'
REACT_APP_TEST: 'true'
REACT_APP_STRIPE_PK: ${{secrets.GH_REACT_APP_STRIPE_PK}}
DEBUG: '@cypress/github-action'
with:
start: yarn start:files-ui
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
REACT_APP_FILES_VERIFIER_NAME: ${{ secrets.GH_REACT_APP_FILES_VERIFIER_NAME }}
REACT_APP_FILES_UUID_VERIFIER_NAME: 'chainsafe-uuid-testnet'
REACT_APP_TEST: 'true'
REACT_APP_STRIPE_PK: ${{secrets.GH_REACT_APP_STRIPE_PK}}
DEBUG: '@cypress/github-action'
with:
start: yarn start:files-ui
Expand Down
3 changes: 2 additions & 1 deletion packages/files-ui/cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"retries": {
"runMode": 2,
"openMode": 0
}
},
"chromeWebSecurity": false
}
6 changes: 6 additions & 0 deletions packages/files-ui/cypress/fixtures/cardData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const visaNumber = "4242424242424242"
export const visaCvc = "123"
export const visaExpiry = "12/30"
export const mastercardNumber = "5555555555554444"
FSM1 marked this conversation as resolved.
Show resolved Hide resolved
export const mastercardCvc = "456"
export const mastercardExpiry = "01/31"
38 changes: 37 additions & 1 deletion packages/files-ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface Web3LoginOptions {
clearTrashBucket?: boolean
deleteShareBucket?: boolean
withNewUser?: boolean
deleteCreditCard? : boolean
}

Cypress.Commands.add(
Expand All @@ -57,7 +58,8 @@ Cypress.Commands.add(
clearCSFBucket = false,
clearTrashBucket = false,
deleteShareBucket = false,
withNewUser = true
withNewUser = true,
deleteCreditCard = false
}: Web3LoginOptions = {}) => {

cy.on("window:before:load", (win) => {
Expand Down Expand Up @@ -124,6 +126,10 @@ Cypress.Commands.add(
apiTestHelper.clearBucket("trash")
}

if (deleteCreditCard) {
apiTestHelper.deleteCreditCards()
}

if(clearTrashBucket || clearCSFBucket || deleteShareBucket){
navigationMenu.binNavButton().click()
navigationMenu.homeNavButton().click()
Expand All @@ -135,6 +141,7 @@ Cypress.Commands.add(

Cypress.Commands.add("safeClick", { prevSubject: "element" }, ($element?: JQuery<HTMLElement>) => {
const click = ($el: JQuery<HTMLElement>) => $el.trigger("click")

return cy
.wrap($element)
.should("be.visible")
Expand All @@ -143,6 +150,31 @@ Cypress.Commands.add("safeClick", { prevSubject: "element" }, ($element?: JQuery
.should($el => expect($el).to.not.be.visible)
})

Cypress.Commands.add("iframeLoaded", { prevSubject: "element" }, ($iframe?: JQuery<HTMLElement>): any => {
const contentWindow = $iframe?.prop("contentWindow")
return new Promise(resolve => {
if (
contentWindow &&
contentWindow.document.readyState === "complete"
) {
resolve(contentWindow)
} else {
$iframe?.on("load", () => {
resolve(contentWindow)
})
}
})
})

Cypress.Commands.add("getInDocument", { prevSubject: "document" }, (document: any, selector: keyof HTMLElementTagNameMap) =>
Cypress.$(selector, document))

Cypress.Commands.add("getWithinIframe", (targetElement: any, selector: string) =>
cy.get(selector || "iframe", { timeout: 10000 })
.iframeLoaded()
.its("document")
.getInDocument(targetElement))

// Must be declared global to be detected by typescript (allows import/export)
// eslint-disable @typescript/interface-name
declare global {
Expand All @@ -156,6 +188,7 @@ declare global {
* @param {Boolean} options.clearTrashBucket - (default: false) - whether any file in the trash bucket should be deleted.
* @param {Boolean} options.deleteShareBucket - (default: false) - whether any shared bucket should be deleted.
* @param {Boolean} options.withNewUser - (default: true) - whether to create a new user for this session.
* @param {Boolean} options.deleteCreditCard - (default: false) - whether to delete the default credit card associate to the account.
* @example cy.web3Login({saveBrowser: true, url: 'http://localhost:8080'})
*/
web3Login: (options?: Web3LoginOptions) => void
Expand All @@ -180,6 +213,9 @@ declare global {
* @example cy.clearBucket("csf")
*/
clearBucket: (bucketType: ClearBucketType) => void
iframeLoaded: ($iframe?: JQuery<HTMLElement>) => any
getInDocument: (document: any, selector: keyof HTMLElementTagNameMap) => JQuery<HTMLElement>
getWithinIframe: (targetElement: string, selector: string) => Chainable
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const addOrUpdateCardModal = {
body: () => cy.get("[data-testid=modal-container-add-or-update-card]", { timeout: 10000 }),
addCardButton: () => cy.get("[data-testid=button-add-card]", { timeout: 10000 }),
cancelButton: () => cy.get("[data-cy=button-cancel-add-card]"),
cardErrorLabel: () => cy.get("[data-cy=label-add-card-error]"),
cardNumberInput: () => cy.getWithinIframe("[data-elements-stable-field-name=cardNumber]", "#iframe-card-number iframe"),
cvcNumberInput: () => cy.getWithinIframe("[data-elements-stable-field-name=cardCvc]", "#iframe-card-cvc iframe"),
expiryDateInput: () => cy.getWithinIframe("[data-elements-stable-field-name=cardExpiry]", "#iframe-card-expiry iframe"),
addCardHeader: () => cy.get("[data-cy=header-add-card]"),
updateCardHeader: () => cy.get("[data-cy=header-update-card]"),
updateCardButton: () => cy.get("[data-testid=button-update-card]", { timeout: 10000 }),

awaitStripeElementReady() {
// this waits for all of the posts from stripe to ensure the element is ready event is received
// by waiting for these to complete we can ensure the elements will be ready for interaction
cy.intercept("POST", "**/r.stripe.com/*").as("stripeElementActivation")
cy.wait("@stripeElementActivation")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const removeCardModal = {
body: () => cy.get("[data-testid=modal-container-remove-card-confirmation]"),
cancelButton: () => cy.get("[data-testid=button-cancel-remove]"),
confirmButton: () => cy.get("[data-testid=button-confirm-remove]", { timeout: 10000 })
}

27 changes: 26 additions & 1 deletion packages/files-ui/cypress/support/page-objects/settingsPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { basePage } from "./basePage"

export const settingsPage = {
...basePage,

// profile tab
profileTabButton: () => cy.get("[data-testid=tab-profile]"),
profileTabHeader: () => cy.get("[data-cy=label-profile-header]"),
firstNameInput: () => cy.get("[data-cy=input-profile-firstname]"),
Expand All @@ -12,7 +14,30 @@ export const settingsPage = {
usernameErrorLabel: () => cy.get("[data-cy=input-profile-username] span.error"),
setUsernameButton: () => cy.get("[data-cy=button-set-username]"),
usernamePresentInput: () => cy.get("[data-cy=input-profile-username-present]"),

// security tab
securityTabButton: () => cy.get("[data-testid=tab-security]"),
securityTabHeader: () => cy.get("[data-cy=label-security-header]"),
subscriptionTabButton: () => cy.get("[data-testid=tab-subscription]")

// subscription tab
subscriptionTabButton: () => cy.get("[data-testid=tab-subscription]"),
addCardButton: () => cy.get("[data-testid=button-add-a-card]"),
updateCardButton: () => cy.get("[data-testid=button-update-a-card]"),
defaultCardLabel: () => cy.get("[data-cy=label-default-card]"),
noCardLabel: () => cy.get("[data-cy=label-no-card]"),
removeCardLink: () => cy.get("[data-cy=link-remove-card]"),

// helpers
awaitStripeConfirmation() {
cy.intercept("POST", "**/setup_intents/*/confirm").as("stripeConfirmation")
cy.wait("@stripeConfirmation")
},

awaitDefaultCardRequest() {
cy.intercept("GET", "**/billing/cards/default").as("defaultCard")

cy.wait("@defaultCard").its("response.body").should("contain", {
type: "credit"
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const cardAddedToast = {
body: () => cy.get("[data-testid=toast-card-added]", { timeout: 10000 }),
closeButton: () => cy.get("[data-testid=button-close-toast-card-added]")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const cardUpdatedToast = {
body: () => cy.get("[data-testid=toast-card-updated]", { timeout: 10000 }),
closeButton: () => cy.get("[data-testid=button-close-toast-card-updated]")
}
20 changes: 20 additions & 0 deletions packages/files-ui/cypress/support/utils/apiTestHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ export const apiTestHelper = {
})
})
},
deleteCreditCards() {
const apiClient = getApiClient()

return new Cypress.Promise(async (resolve) => {
cy.window()
.then(async (win) => {
const tokens = await apiClient.getRefreshToken({ refresh: win.sessionStorage.getItem(REFRESH_TOKEN_KEY) || "" })

await apiClient.setToken(tokens.access_token.token)
try {
const card = await apiClient.getDefaultCard()
apiClient.deleteCard(card.id)
} catch {
cy.log("There's no card to delete")
}
cy.log("Done deleting the default card")
resolve()
})
})
},
clearBucket(bucketType: ClearBucketType) {
const apiClient = getApiClient()

Expand Down
2 changes: 2 additions & 0 deletions packages/files-ui/cypress/tests/file-management-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ describe("File management", () => {

// upload a file and ensure the storage space label adjusts
homePage.uploadFile("../fixtures/uploadedFiles/logo.png")
navigationMenu.spaceUsedProgressBar().should("be.visible")
navigationMenu.spaceUsedLabel().should("not.contain.text", "0 Bytes")

// delete the file from the bin and ensure the storage space label adjusts
Expand All @@ -407,6 +408,7 @@ describe("File management", () => {
deleteFileModal.confirmButton().safeClick()
deleteSuccessToast.body().should("be.visible")
deleteSuccessToast.closeButton().click()
navigationMenu.spaceUsedProgressBar().should("be.visible")
navigationMenu.spaceUsedLabel().should("contain.text", "0 Bytes")
})

Expand Down
32 changes: 24 additions & 8 deletions packages/files-ui/cypress/tests/main-navigation-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ describe("Main Navigation", () => {
})

it("can navigate to the bin page", () => {
navigationMenu.binNavButton().click()
navigationMenu.binNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/bin")
})

it("can navigate to the settings page", () => {
navigationMenu.settingsNavButton().click()
navigationMenu.settingsNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/settings")
})

Expand All @@ -24,7 +28,9 @@ describe("Main Navigation", () => {
})

it("can navigate to the home page", () => {
navigationMenu.homeNavButton().click()
navigationMenu.homeNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/drive")
})
})
Expand All @@ -36,26 +42,36 @@ describe("Main Navigation", () => {

beforeEach(() => {
cy.viewport("iphone-6")
homePage.hamburgerMenuButton().click()
homePage.hamburgerMenuButton()
.should("be.visible")
.click()
})

it("can navigate to the bin page", () => {
navigationMenu.binNavButton().click()
navigationMenu.binNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/bin")
})

it("can navigate to the settings page", () => {
navigationMenu.settingsNavButton().click()
navigationMenu.settingsNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/settings")
})

it("can navigate to the home page", () => {
navigationMenu.homeNavButton().click()
navigationMenu.homeNavButton()
.should("be.visible")
.click()
cy.url().should("include", "/drive")
})

it("can sign out from the navigation bar", () => {
navigationMenu.signOutButton().click()
navigationMenu.signOutButton()
.should("be.visible")
.click()
authenticationPage.web3Button().should("be.visible")
cy.url().should("not.include", "/drive")
cy.url().should("not.include", "/bin")
Expand Down
81 changes: 81 additions & 0 deletions packages/files-ui/cypress/tests/subscription-plan-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { navigationMenu } from "../support/page-objects/navigationMenu"
import { settingsPage } from "../support/page-objects/settingsPage"
import { addOrUpdateCardModal } from "../support/page-objects/modals/addCardModal"
import { visaNumber, visaExpiry, visaCvc } from "../fixtures/cardData"
import { mastercardNumber, mastercardExpiry, mastercardCvc } from "../fixtures/cardData"
import { cardAddedToast } from "../support/page-objects/toasts/cardAddedToast"
import { cardUpdatedToast } from "../support/page-objects/toasts/cardUpdatedToast"
import { removeCardModal } from "../support/page-objects/modals/removeCardModal"

describe("Subscription Plan", () => {

context("desktop", () => {

it("can add, update and remove a credit card for billing", () => {
cy.web3Login({ deleteCreditCard: true })

// navigate to settings
navigationMenu.settingsNavButton().click()
settingsPage.subscriptionTabButton().click()

// add a card
settingsPage.addCardButton()
.should("be.visible")
.click()
addOrUpdateCardModal.body().should("be.visible")
addOrUpdateCardModal.addCardHeader().should("be.visible")
addOrUpdateCardModal.awaitStripeElementReady()
addOrUpdateCardModal.cardNumberInput().type(visaNumber)
addOrUpdateCardModal.expiryDateInput().type(visaExpiry)
addOrUpdateCardModal.cvcNumberInput().type(visaCvc)
addOrUpdateCardModal.addCardButton().click()

// for reliability wait for stripe and default card responses / requests
settingsPage.awaitStripeConfirmation()
settingsPage.awaitDefaultCardRequest()

// close toast and ensure a card is now shown on profile
cardAddedToast.body().should("be.visible")
cardAddedToast.closeButton().click()
settingsPage.updateCardButton().should("be.visible")
settingsPage.defaultCardLabel().should("be.visible")

// store the displayed visa details as cypress alias
settingsPage.defaultCardLabel().invoke("text").as("partialMaskedVisa")

// update the card
settingsPage.updateCardButton().click()
addOrUpdateCardModal.body().should("be.visible")
addOrUpdateCardModal.updateCardHeader().should("be.visible")
addOrUpdateCardModal.awaitStripeElementReady()
addOrUpdateCardModal.cardNumberInput().type(mastercardNumber)
addOrUpdateCardModal.expiryDateInput().type(mastercardExpiry)
addOrUpdateCardModal.cvcNumberInput().type(mastercardCvc)
addOrUpdateCardModal.updateCardButton().click()

// for reliability wait for stripe and default card responses / requests
settingsPage.awaitStripeConfirmation()
settingsPage.awaitDefaultCardRequest()

// close toast and ensure a card is shown on profile
cardUpdatedToast.body().should("be.visible")
cardUpdatedToast.closeButton().click()
settingsPage.defaultCardLabel().should("be.visible")

// store the displayed mastercard details as cypress alias
settingsPage.defaultCardLabel().invoke("text").as("partialMaskedMastercard")

// ensure the card number was updated by comparing cypress aliases
cy.get("@partialMaskedVisa").then(($partialMaskedVisa) => {
cy.get("@partialMaskedMastercard").should("not.equal", $partialMaskedVisa)
})

// remove the card
settingsPage.removeCardLink().click()
removeCardModal.body().should("be.visible")
removeCardModal.confirmButton().safeClick()
settingsPage.noCardLabel().should("be.visible")
settingsPage.addCardButton().should("be.visible")
})
})
})
Loading