diff --git a/packages/files-ui/cypress/fixtures/cardData.ts b/packages/files-ui/cypress/fixtures/cardData.ts index 6e012c8cc3..c95bfe7e41 100644 --- a/packages/files-ui/cypress/fixtures/cardData.ts +++ b/packages/files-ui/cypress/fixtures/cardData.ts @@ -1,3 +1,5 @@ +import dayjs from "dayjs" + export const visaNumber = "4242424242424242" export const visaCvc = "123" export const visaExpiry = "12/30" @@ -6,4 +8,5 @@ export const mastercardCvc = "456" export const mastercardExpiry = "01/31" export const invalidCardNumber = "6242424242424255" export const invalidCvc = "11" -export const invalidExpiry = "02/21" \ No newline at end of file +export const invalidExpiry = "02/21" +export const currentDateExpiry = dayjs().format("MM/YY") \ No newline at end of file diff --git a/packages/files-ui/cypress/support/commands.ts b/packages/files-ui/cypress/support/commands.ts index cdbe4a98bd..c8f9e4b0e6 100644 --- a/packages/files-ui/cypress/support/commands.ts +++ b/packages/files-ui/cypress/support/commands.ts @@ -46,6 +46,7 @@ export interface Web3LoginOptions { clearCSFBucket?: boolean clearTrashBucket?: boolean deleteShareBucket?: boolean + withNewSession?: boolean withNewUser?: boolean deleteCreditCard? : boolean resetToFreePlan?: boolean @@ -60,6 +61,7 @@ Cypress.Commands.add( clearTrashBucket = false, deleteShareBucket = false, withNewUser = true, + withNewSession = false, deleteCreditCard = false, resetToFreePlan = false }: Web3LoginOptions = {}) => { @@ -78,8 +80,9 @@ Cypress.Commands.add( }) }) - if (withNewUser){ - cy.session("web3loginNewUser", () => { + if (withNewUser || withNewSession){ + const sessionName = `web3loginNewUser-${withNewSession ? new Date().toString() : "0"}` + cy.session(sessionName, () => { cy.visit(url) authenticationPage.web3Button().click() authenticationPage.showMoreButton().click() @@ -213,6 +216,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.withNewSession - (default: false) - whether to create a new session. * @param {Boolean} options.deleteCreditCard - (default: false) - whether to delete the default credit card associate to the account. * @param {Boolean} options.resetToFreePlan - (default false) - whether to cancel any plan to make sure the user is on the free one. * @example cy.web3Login({saveBrowser: true, url: 'http://localhost:8080'}) diff --git a/packages/files-ui/cypress/support/page-objects/basePage.ts b/packages/files-ui/cypress/support/page-objects/basePage.ts index d530cefd7d..5fa35e2db0 100644 --- a/packages/files-ui/cypress/support/page-objects/basePage.ts +++ b/packages/files-ui/cypress/support/page-objects/basePage.ts @@ -5,6 +5,14 @@ export const basePage = { searchInput: () => cy.get("[data-testid=input-search-bar]"), signOutDropdown: () => cy.get("[data-testid=dropdown-title-sign-out-dropdown]"), signOutMenuOption: () => cy.get("[data-cy=menu-sign-out]"), + notificationButton: () => cy.get("[data-testid=dropdown-title-notifications]"), + notificationsHeader: () => cy.get("[data-cy=label-notifications-header]"), + notificationsThisWeekHeader: () => cy.get("[data-cy=label-notifications-this-week]"), + notificationsOlderHeader: () => cy.get("[data-cy=label-notifications-older]"), + notificationContainer: () => cy.get("[data-cy=container-notification]"), + notificationTitle: () => cy.get("[data-cy=label-notification-title]"), + notificationTime: () => cy.get("[data-cy=label-notification-time]"), + // Mobile view only element hamburgerMenuButton: () => cy.get("[data-testid=icon-hamburger-menu]"), diff --git a/packages/files-ui/cypress/support/page-objects/settingsPage.ts b/packages/files-ui/cypress/support/page-objects/settingsPage.ts index 36545a222e..eeb62881d8 100644 --- a/packages/files-ui/cypress/support/page-objects/settingsPage.ts +++ b/packages/files-ui/cypress/support/page-objects/settingsPage.ts @@ -1,5 +1,5 @@ import { basePage } from "./basePage" -import { visaNumber, visaExpiry, visaCvc } from "../../fixtures/cardData" +import { visaNumber, visaExpiry, visaCvc, currentDateExpiry } from "../../fixtures/cardData" import { cardAddedToast } from "../../support/page-objects/toasts/cardAddedToast" import { selectPlanModal } from "../../support/page-objects/modals/billing/selectPlanModal" import { planDetailsModal } from "../../support/page-objects/modals/billing/planDetailsModal" @@ -40,8 +40,9 @@ export const settingsPage = { payNowButton: () => cy.get("[data-testid=button-pay-invoice]"), // use this convenience function when an upgraded account is required as a test requisite - upgradeSubscription(plan: "pro" | "max") { - const planContainer = plan === "pro" ? "@filesProBox" : "@filesMaxBox" + upgradeSubscription(subDetails: {plan: "pro"|"max"; isCardExpiring?: boolean}) { + const planContainer = subDetails.plan === "pro" ? "@filesProBox" : "@filesMaxBox" + const cardExpiry = subDetails.isCardExpiring === true ? currentDateExpiry : visaExpiry this.subscriptionTabButton().click() this.changePlanButton().click() @@ -57,7 +58,7 @@ export const settingsPage = { .click() cy.awaitStripeElementReady() selectPaymentMethodModal.cardNumberInput().type(visaNumber) - selectPaymentMethodModal.expiryDateInput().type(visaExpiry) + selectPaymentMethodModal.expiryDateInput().type(cardExpiry) selectPaymentMethodModal.cvcNumberInput().type(visaCvc) selectPaymentMethodModal.useThisCardButton().click() cy.awaitStripeConfirmation() diff --git a/packages/files-ui/cypress/support/utils/apiTestHelper.ts b/packages/files-ui/cypress/support/utils/apiTestHelper.ts index d81765cf99..6b8b99ca73 100644 --- a/packages/files-ui/cypress/support/utils/apiTestHelper.ts +++ b/packages/files-ui/cypress/support/utils/apiTestHelper.ts @@ -55,10 +55,10 @@ export const apiTestHelper = { } resolve() - } catch (e){ - cy.log("Something wrong happened during the subscription cancelation") - console.log(e) + } catch (e: any){ + console.error(e) reject(e) + throw new Error("Something wrong happened during the subscription cancelation") } }) }) @@ -132,6 +132,7 @@ export const apiTestHelper = { } catch(e){ console.error(e) reject(e) + throw new Error("Something wrong happened when creating a folder") } navigationMenu.binNavButton().click() diff --git a/packages/files-ui/cypress/tests/notifications-spec.ts b/packages/files-ui/cypress/tests/notifications-spec.ts new file mode 100644 index 0000000000..d9679f5b26 --- /dev/null +++ b/packages/files-ui/cypress/tests/notifications-spec.ts @@ -0,0 +1,88 @@ +import { homePage } from "../support/page-objects/homePage" +import { navigationMenu } from "../support/page-objects/navigationMenu" +import { settingsPage } from "../support/page-objects/settingsPage" +import { selectPlanModal } from "../support/page-objects/modals/billing/selectPlanModal" +import { planDetailsModal } from "../support/page-objects/modals/billing/planDetailsModal" +import { selectPaymentMethodModal } from "../support/page-objects/modals/billing/selectPaymentMethodModal" +import { planChangeConfirmationModal } from "../support/page-objects/modals/billing/planChangeConfirmationModal" +import { cryptoPaymentModal } from "../support/page-objects/modals/billing/cryptoPaymentModal" + +describe("Notifications", () => { + beforeEach(() => { + cy.intercept("GET", "**/billing/eligibilities", { + body: { is_eligible: true } + }) + }) + context("desktop", () => { + + it("can see and interact with a notification when a card is expiring soon", () => { + cy.web3Login({ deleteCreditCard: true, resetToFreePlan: true }) + + // upgrade subscription with a card expiring this month + navigationMenu.settingsNavButton().click() + settingsPage.upgradeSubscription({ plan: "max", isCardExpiring: true }) + + // access and inspect notification menu + settingsPage.notificationButton().click() + settingsPage.notificationsHeader().should("be.visible") + settingsPage.notificationsThisWeekHeader().should("be.visible") + settingsPage.notificationsOlderHeader().should("not.exist") + settingsPage.notificationContainer().should("have.length", 1) + + // ensure individual notification has title and date + settingsPage.notificationContainer().within(() => { + settingsPage.notificationTitle().should("be.visible") + settingsPage.notificationTime().should("be.visible") + }) + + // click notification button to dismiss + settingsPage.notificationButton().click() + settingsPage.notificationContainer().should("not.be.visible") + + // navigate away and return to plan page from notification + navigationMenu.homeNavButton().click() + cy.url().should("include", "/drive") + homePage.notificationButton().click() + homePage.notificationContainer().click() + cy.url().should("include", "/settings/plan") + }) + + it("can see and interact with a notification when crypto invoice is open", () => { + cy.web3Login({ withNewSession: true }) + navigationMenu.settingsNavButton().click() + + // initiate crypto payment then exit upgrade flow + settingsPage.subscriptionTabButton().click() + settingsPage.changePlanButton().click() + selectPlanModal.createPlanCypressAliases() + cy.get("@filesProBox").parent().within(() => { + selectPlanModal.selectPlanButton().click() + }) + planDetailsModal.durationToggleSwitch().click() + planDetailsModal.selectThisPlanButton().click() + selectPaymentMethodModal.cryptoRadioInput() + .should("be.visible") + .click() + selectPaymentMethodModal.selectPaymentButton().click() + planChangeConfirmationModal.confirmPlanChangeButton().click() + cryptoPaymentModal.closeButton().click() + + // access and inspect notification menu + settingsPage.notificationButton().click() + settingsPage.notificationContainer().should("have.length", 1) + + // ensure individual notification has title and date + settingsPage.notificationContainer().within(() => { + settingsPage.notificationTitle().should("be.visible") + settingsPage.notificationTime().should("be.visible") + }) + + // navigate away and return to the plan page from notification + navigationMenu.homeNavButton().click() + cy.url().should("include", "/drive") + homePage.notificationButton().click() + homePage.notificationContainer().click() + cy.url().should("include", "/settings/plan") + }) + }) +}) \ No newline at end of file diff --git a/packages/files-ui/cypress/tests/subscription-plan-spec.ts b/packages/files-ui/cypress/tests/subscription-plan-spec.ts index 7a0a15dc8c..5a1bcb3046 100644 --- a/packages/files-ui/cypress/tests/subscription-plan-spec.ts +++ b/packages/files-ui/cypress/tests/subscription-plan-spec.ts @@ -219,7 +219,7 @@ describe("Subscription Plan", () => { // upgrade to a Max plan first navigationMenu.settingsNavButton().click() - settingsPage.upgradeSubscription("max") + settingsPage.upgradeSubscription({ plan: "max" }) // setup intercepter, stub the used products response to disallow update cy.intercept("GET", "**/billing/products", (req) => { @@ -401,7 +401,7 @@ describe("Subscription Plan", () => { // upgrade to a max plan first using convenience function navigationMenu.settingsNavButton().click() - settingsPage.upgradeSubscription("max") + settingsPage.upgradeSubscription({ plan: "max" }) // store the upgraded plan name for later comparison settingsPage.planNameLabel() @@ -452,7 +452,7 @@ describe("Subscription Plan", () => { // upgrade to a Pro plan first navigationMenu.settingsNavButton().click() - settingsPage.upgradeSubscription("pro") + settingsPage.upgradeSubscription({ plan: "pro" }) // store the Pro plan name for later comparison settingsPage.planNameLabel() @@ -492,7 +492,7 @@ describe("Subscription Plan", () => { }) it("can initiate and return to a crypto payment flow within 60 minutes", () => { - cy.web3Login({ deleteCreditCard: true, resetToFreePlan: true }) + cy.web3Login({ deleteCreditCard: true, withNewSession: true }) navigationMenu.settingsNavButton().click() settingsPage.subscriptionTabButton().click() settingsPage.changePlanButton().click() diff --git a/packages/files-ui/cypress/tsconfig.json b/packages/files-ui/cypress/tsconfig.json index c58896952f..a591bc253d 100644 --- a/packages/files-ui/cypress/tsconfig.json +++ b/packages/files-ui/cypress/tsconfig.json @@ -4,7 +4,8 @@ "target": "es5", "jsx": "react", "lib": ["es5", "dom"], - "types": ["cypress", "cypress-file-upload"] + "types": ["cypress", "cypress-file-upload"], + "esModuleInterop": true, }, "include": ["**/*.ts"] } \ No newline at end of file diff --git a/packages/files-ui/src/Components/Elements/Notifications/NotificationLine.tsx b/packages/files-ui/src/Components/Elements/Notifications/NotificationLine.tsx index f403808def..73d4366b5b 100644 --- a/packages/files-ui/src/Components/Elements/Notifications/NotificationLine.tsx +++ b/packages/files-ui/src/Components/Elements/Notifications/NotificationLine.tsx @@ -39,11 +39,13 @@ const NotificationLine = ({ notification }: Props) => { return
{notification.title} @@ -51,6 +53,7 @@ const NotificationLine = ({ notification }: Props) => { variant="body2" className={classes.notificationTime} component="p" + data-cy="label-notification-time" > {dayjs.unix(notification.createdAt).fromNow()} diff --git a/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx b/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx index 3d80a7e006..e64ec2357a 100644 --- a/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx +++ b/packages/files-ui/src/Components/Elements/Notifications/NotificationList.tsx @@ -78,6 +78,7 @@ const NotificationList = ({ notifications }: INotificationListProps) => { Notifications @@ -88,6 +89,7 @@ const NotificationList = ({ notifications }: INotificationListProps) => { variant="h5" component="p" className={classes.timeHeader} + data-cy="label-notifications-this-week" > This week @@ -102,6 +104,7 @@ const NotificationList = ({ notifications }: INotificationListProps) => { variant="h5" component="p" className={classes.timeHeader} + data-cy="label-notifications-older" > Older notifications diff --git a/packages/files-ui/src/Components/Elements/Notifications/NotificationsDropdown.tsx b/packages/files-ui/src/Components/Elements/Notifications/NotificationsDropdown.tsx index f9f3ba2bde..61485236f7 100644 --- a/packages/files-ui/src/Components/Elements/Notifications/NotificationsDropdown.tsx +++ b/packages/files-ui/src/Components/Elements/Notifications/NotificationsDropdown.tsx @@ -93,6 +93,7 @@ const NotificationsDropdown = () => { autoclose classNames={{ options: classes.optionsOpen }} onClose={() => setIsActive(false)} + testId="notifications" >
{ setIsCancellingPlan(true) diff --git a/packages/storage-ui/src/Components/Modules/SubscriptionTab/ChangePlan/DowngradeDetails.tsx b/packages/storage-ui/src/Components/Modules/SubscriptionTab/ChangePlan/DowngradeDetails.tsx index ec72b950f4..c02ee7b38b 100644 --- a/packages/storage-ui/src/Components/Modules/SubscriptionTab/ChangePlan/DowngradeDetails.tsx +++ b/packages/storage-ui/src/Components/Modules/SubscriptionTab/ChangePlan/DowngradeDetails.tsx @@ -122,7 +122,7 @@ const DowngradeDetails = ({ const { currentSubscription, cancelCurrentSubscription, invoices } = useBilling() const currentStorage = formatBytes(Number(currentSubscription?.product?.price.metadata?.storage_size_bytes), 2) const [isCancelingPlan, setIsCancellingPlan] = useState(false) - const lastInvoicePaymentMethod = invoices && invoices[invoices.length - 1].payment_method + const lastInvoicePaymentMethod = invoices?.length && invoices[invoices.length - 1].payment_method const onCancelPlan = useCallback(() => { setIsCancellingPlan(true)