diff --git a/cypress/e2e/01-pin-input.cy.ts b/cypress/e2e/01-pin-input.cy.ts index dacb1f50..4d0e60aa 100644 --- a/cypress/e2e/01-pin-input.cy.ts +++ b/cypress/e2e/01-pin-input.cy.ts @@ -86,7 +86,7 @@ describe("Create Account and Login Tests", () => { }); // Cannot be automated at this moment - xit("A8 - If Stay Unlocked is toggled on, user should bypass PIN page when logging in", () => {}); + it.skip("A8 - If Stay Unlocked is toggled on, user should bypass PIN page when logging in", () => {}); it("A10 - User can see menu to switch to a different profile", () => { loginPinPage.launchApplication(); @@ -99,5 +99,5 @@ describe("Create Account and Login Tests", () => { }); // Cannot be automated at this moment - xit("A12 - If incorrect pin is entered, error message should be displayed", () => {}); + it.skip("A12 - If incorrect pin is entered, error message should be displayed", () => {}); }); diff --git a/cypress/e2e/03-chats-sidebar.cy.ts b/cypress/e2e/03-chats-sidebar.cy.ts index 6a4c74fd..9de10c78 100644 --- a/cypress/e2e/03-chats-sidebar.cy.ts +++ b/cypress/e2e/03-chats-sidebar.cy.ts @@ -74,9 +74,54 @@ describe("Chats Sidebar Tests", () => { it("C10 - Textbox should have highlighted border when clicking into Chat Search", () => { chatsMainPage.ensureSidebarIsDisplayed(); - chatsMainPage.inputSidebarSearch.click().type("test"); + chatsMainPage.inputSidebarSearch.focus(); chatsMainPage.inputSidebarSearch - .parents(".input-group") - .should("have.css", "border-color", "rgb(215, 226, 255)"); + .parents(".input-container") + .should("have.css", "box-shadow", "rgb(77, 77, 255) 0px 0px 0px 1px"); + }); + + // Cannot be automated until app is wired + it.skip("C11 - ProfilePicFrame should display for any friends that have one", () => { + // Test code for C11 + }); + + // Cannot be automated until app is wired + it.skip("C12 - Favorites should appear on left side of Sidebar", () => { + // Test code for C12 + }); + + // Cannot be automated until app is wired + it.skip("C13 - Number of members in group should appear on that chat in both Sidebar and Favorites", () => { + // Test code for C13 + }); + + // Cannot be automated until app is wired + it.skip("C14 - Clicking a favorite should take you to that chat", () => { + // Test code for C14 + }); + + // Cannot be automated until app is wired + it.skip("C15 - Right clicking a chat in sidebar should open context menu", () => { + // Test code for C15 + }); + + // Cannot be automated until app is wired + it.skip("C16 - Context menu should display: Favorite, Hide, Mark as read", () => { + // Test code for C16 + }); + + // Cannot be automated until app is wired + it.skip("C17 - Timestamp of most recent message sent or received in chat should be displayed in the sidebar", () => { + // Test code for C17 + }); + + // Cannot be automated until app is wired + it.skip("C18 - Typing indicator should be displayed around users profile picture when they are typing (this applies to favorites as well)", () => { + // Test code for C18 + }); + + // Cannot be automated until app is wired + it.skip("C19 - After selecting Hide chat chat should no longer be displayed in sidebar", () => { + // Test code for C19 }); }); diff --git a/cypress/e2e/05-settings-profile.cy.ts b/cypress/e2e/05-settings-profile.cy.ts index 569edc4c..3f1530ac 100644 --- a/cypress/e2e/05-settings-profile.cy.ts +++ b/cypress/e2e/05-settings-profile.cy.ts @@ -6,15 +6,22 @@ import { friendsPage } from "./PageObjects/Friends"; describe("Settings Profile Tests", () => { beforeEach(() => { + // Login with pin and wrap data from creating a new account loginPinPage.loginWithPin("1234"); - cy.wrap(authNewAccount.createRandomUser()).as("username"); + cy.wrap(null) + .then(() => { + return authNewAccount.createRandomUser(); + }) + .as("newUser"); + + // Go to settings profile chatsMainPage.validateChatsMainPageIsShown(); chatsMainPage.goToSettings(); cy.location("href").should("include", "/settings/profile"); }); // Skipped since it needs investigation on how to implement pseudo elements validation in cypress - xit("I1 - Banner Picture - Tooltip displayed", () => { + it.skip("I1 - Banner Picture - Tooltip displayed", () => { // Shows tooltip when hovering settingsProfile.profileBanner.realHover(); }); @@ -45,13 +52,15 @@ describe("Settings Profile Tests", () => { }); // Skipped since it needs investigation on how to truly delete data before executing test - xit("I5 - Profile picture appears blank until custom profile picture is set", () => { + it.skip("I5 - Profile picture appears blank until custom profile picture is set", () => { + // Profile Picture should not have a src attribute settingsProfile.profilePictureImage.should("not.have.attr", "src"); }); it("I6 - Username should be displayed in the Username textbox", () => { // Username displayed will be equal to the username assigned randomly when creating account - cy.get("@username").then((username) => { + cy.get("@newUser").then((newUser) => { + const { username }: any = newUser; settingsProfile.inputSettingsProfileUsername.should( "have.value", username, @@ -75,6 +84,7 @@ describe("Settings Profile Tests", () => { "Copy", ); + // Obtain the clipboard text and store it in a Cypress alias cy.window().then(async (win) => { const text = await win.navigator.clipboard.readText(); const statusText = String(text); @@ -84,6 +94,7 @@ describe("Settings Profile Tests", () => { cy.wrap(last8Chars).as("last8Chars"); }); + // Validate Copied ID last 8 chars are matching with the Short ID displayed cy.get("@last8Chars").then((last8Chars) => { settingsProfile.inputSettingsProfileShortID.should( "have.value", @@ -92,14 +103,270 @@ describe("Settings Profile Tests", () => { }); }); - xit("I9 - User should be able to click into username textbox and change username", () => {}); - xit("I10 - Toast notifcation should appear when user changes username", () => {}); - xit("I12 - Highlighted border should appear when clicked into the username textbox", () => {}); - xit("I14 - Highlighted border should appear when user is clicked into Status textbox", () => {}); - xit("I15 - User should be able to click into the Status Message textbox", () => {}); - xit("I16 - Toast notification should appear when user updates status", () => {}); - xit("I19 - Status dropdown should show Online, Offline, Idle, Do not Disturb", () => {}); - xit("I20 - Status should show correctly depending on which status user has set", () => {}); - xit("I21 - Clicking Reveal Phrase should display the users Recovery Phrases", () => {}); - xit("I24 - Clicking LogOut should log user out of the account", () => {}); + it("I8 - Clicking usernameID should copy it to clipboard", () => { + // Go to friends and copy short ID + chatsMainPage.buttonFriends.click(); + cy.location("href").should("include", "/friends"); + friendsPage.buttonCopyID.rightclick(); + friendsPage.contextOptionCopyID.click(); + chatsMainPage.goToSettings(); + + // Obtain the clipboard text and store it in a Cypress alias + cy.window().then(async (win) => { + const text = await win.navigator.clipboard.readText(); + const statusText = String(text); + // Extract the last 8 characters + const last8Chars = statusText.slice(-8); + // Store the last 8 characters in a Cypress alias + cy.wrap(last8Chars).as("last8CharsDid"); + }); + + // Click on UsernameID to copy userID to clipboard + settingsProfile.copyShortID(); + + // Obtain the clipboard text and store it in a Cypress alias + cy.window().then(async (win) => { + const text = await win.navigator.clipboard.readText(); + const usernameText = String(text); + // Extract the last 13 characters + const copiedUsername = usernameText.slice(-13); + // Store the last 8 characters in a Cypress alias + cy.wrap(copiedUsername).as("copiedUsername"); + }); + + // Username displayed will be equal to the username assigned randomly when creating account + cy.get("@newUser").then((newUser) => { + const { username }: any = newUser; + cy.get("@last8CharsDid").then((last8Chars) => { + cy.get("@copiedUsername").should( + "include", + username.slice(-4) + "#" + last8Chars, + ); + }); + }); + }); + + it("I9, I10 - User should be able to change username and see toast notification of change", () => { + // User types into username and change value + settingsProfile.inputSettingsProfileUsername + .click() + .clear() + .type("newUsername"); + + // Save modal is displayed, user selects cancel and username is not changed + settingsProfile.saveControls.should("exist"); + settingsProfile.saveControlsButtonCancel.click(); + + // Username displayed will be equal to the username assigned randomly when creating account + cy.get("@newUser").then((newUser) => { + const { username }: any = newUser; + settingsProfile.inputSettingsProfileUsername.should( + "have.value", + username, + ); + }); + + // User types into username and change value + settingsProfile.inputSettingsProfileUsername + .click() + .clear() + .type("newUsername"); + + // Save modal is displayed, user selects save and username is changed + settingsProfile.saveControls.should("exist"); + settingsProfile.saveControlsButtonSave.click(); + chatsMainPage.toastNotification.should("exist"); + settingsProfile.inputSettingsProfileUsername.should( + "have.value", + "newUsername", + ); + + // User goes to another page and returns to settings profile, username is still changed + chatsMainPage.buttonFriends.click(); + cy.location("href").should("include", "/friends"); + chatsMainPage.goToSettings(); + settingsProfile.inputSettingsProfileUsername.should( + "have.value", + "newUsername", + ); + }); + + // Skipped since this is not working in Uplink Web as expected per test + it.skip("I11 - All text in Username should be selected after clicking into the text field a single time", () => {}); + + it("I12 - Highlighted border should appear when clicked into the username textbox", () => { + // Click on Username textbox and validate border is highlighted + settingsProfile.inputSettingsProfileUsername.focus(); + settingsProfile.inputSettingsProfileUsername + .parent() + .should("have.css", "box-shadow", "rgb(77, 77, 255) 0px 0px 0px 1px"); + }); + + // Skipped since this is not working in Uplink Web as expected per test + it.skip("I13 - Error message should appear if user tries to input chars that are not allowed or exceeds chars amount", () => {}); + + it("I14 - Highlighted border should appear when user is clicked into Status textbox", () => { + // Click on Status textbox and validate border is highlighted + settingsProfile.inputSettingsProfileUsername.focus(); + settingsProfile.inputSettingsProfileUsername + .parent() + .should("have.css", "box-shadow", "rgb(77, 77, 255) 0px 0px 0px 1px"); + }); + + it("I15, I16 - User should be able to change Status Message and see toast notification for update", () => { + // User types into status and change value + settingsProfile.inputSettingsProfileStatus + .click() + .clear() + .type("newStatusTest"); + + // Save modal is displayed, user selects cancel and status is not changed + settingsProfile.saveControls.should("exist"); + settingsProfile.saveControlsButtonCancel.click(); + // Username displayed will be equal to the username assigned randomly when creating account + cy.get("@newUser").then((newUser) => { + const { status }: any = newUser; + settingsProfile.inputSettingsProfileStatus.should("have.value", status); + }); + + // User types into status and change value + settingsProfile.inputSettingsProfileStatus + .click() + .clear() + .type("newStatusTest"); + + // Save modal is displayed, user selects save and status is changed + settingsProfile.saveControls.should("exist"); + settingsProfile.saveControlsButtonSave.click(); + chatsMainPage.toastNotification.should("exist"); + + // Validate status is changed + settingsProfile.inputSettingsProfileStatus.should( + "have.value", + "newStatusTest", + ); + + // User goes to another page and returns to settings profile, status is still changed + chatsMainPage.buttonFriends.click(); + cy.location("href").should("include", "/friends"); + chatsMainPage.goToSettings(); + settingsProfile.inputSettingsProfileStatus.should( + "have.value", + "newStatusTest", + ); + }); + + // Skipped since this is not working in Uplink Web as expected per test + it.skip("I17 - All text in StatusMessage should be selected after clicking into the text field a single time", () => {}); + + // Skipped since this is not working in Uplink Web as expected per test + it.skip("I18 - Error message should appear if user inputs chars that are not allowed or exceeds limit", () => {}); + + it("I19 - Status dropdown should show Online, Offline, Idle, Do not Disturb", () => { + // Validate Settings Section contents + settingsProfile.onlineStatusSectionLabel.should("have.text", "Status"); + settingsProfile.onlineStatusSectionText.should( + "have.text", + "Set status appearance", + ); + + // Default Status selected is Online + settingsProfile.onlineStatusSectionSelectorCurrentlyOnline.should("exist"); + + // Validate list of options + let options = []; + cy.get("[data-cy='selector-current-status-online']") + .find("[data-cy='select-option']") + .each(($option) => { + cy.log("Option: ", $option); + cy.log("Option Val: ", $option.text()); + options.push($option.text()); + }) + .then(() => { + expect(options).to.have.length(4); + // To deep equal to the array of options + expect(options).to.deep.eq([ + "Online", + "Offline", + "Idle", + "Do Not Disturb", + ]); + }); + }); + + it("I20 - Status should show correctly depending on which status user has set", () => { + // Change Status to Offline and validate is displayed correctly + settingsProfile.onlineStatusSectionSelectorCurrentlyOnline + .find("select") + .select("offline"); + settingsProfile.onlineStatusSectionSelectorCurrentlyOffline.should("exist"); + + // Change Status to Idle and validate is displayed correctly + settingsProfile.onlineStatusSectionSelectorCurrentlyOffline + .find("select") + .select("idle"); + settingsProfile.onlineStatusSectionSelectorCurrentlyIdle.should("exist"); + + // Change Status to Do not Disturb and validate is displayed correctly + settingsProfile.onlineStatusSectionSelectorCurrentlyIdle + .find("select") + .select("do-not-disturb"); + settingsProfile.onlineStatusSectionSelectorCurrentlyDoNotDisturb.should( + "exist", + ); + + // Go to friends page and return to Settings Profile and validate status is still the same + chatsMainPage.buttonFriends.click(); + cy.location("href").should("include", "/friends"); + chatsMainPage.goToSettings(); + cy.location("href").should("include", "/settings/profile"); + settingsProfile.onlineStatusSectionSelectorCurrentlyDoNotDisturb.should( + "exist", + ); + }); + + it("I21 - Clicking Reveal Phrase should display the users Recovery Phrases", () => { + // Validate Settings Section contents + settingsProfile.revealPhraseSectionLabel.should( + "have.text", + "Reveal recovery phrase", + ); + settingsProfile.revealPhraseSectionText.should( + "have.text", + "Click the button to reveal your recovery seed, please do not share this with anybody, it is the master-key for your account.", + ); + settingsProfile.storeRecoverySeedText.should( + "have.text", + "Store recovery seed on account (disable for increased security, irriversable)", + ); + + // Show Recovery Phrase and ensure is displayed now + settingsProfile.revealPhraseSectionRevealButton.click().then(() => { + settingsProfile.validateRecoveryPhraseIsShown(); + }); + + // Click on Hide Phrase and validate is hidden + settingsProfile.revealPhraseSectionHideButton.click().then(() => { + settingsProfile.validateRecoveryPhraseIsHidden(); + }); + }); + + // Cannot be automated for now since copy button does not perform any action + it.skip("I22 - Clicking copy should copy the Recovery Phrase to the users clipboard", () => {}); + + // Cannot be automated for now since checkbox checked or not checked works on the same way for now + it.skip("I23 - User should be able to click checkbox to determine wether they want to store Recovery Phrase on account", () => {}); + + it("I24 - Clicking LogOut should log user out of the account", () => { + // Validate Settings Section contents + settingsProfile.logOutSectionLabel.should("have.text", "Log Out"); + settingsProfile.logOutSectionText.should( + "have.text", + "Log out of the current account and return to the unlock page.", + ); + + // Click on Log Out and validate user is redirected to unlock page + settingsProfile.logOutSectionButton.click(); + cy.location("href").should("include", "/auth/unlock"); + }); }); diff --git a/cypress/e2e/PageObjects/AuthNewAccount.ts b/cypress/e2e/PageObjects/AuthNewAccount.ts index 0f872cbe..f6bd8053 100644 --- a/cypress/e2e/PageObjects/AuthNewAccount.ts +++ b/cypress/e2e/PageObjects/AuthNewAccount.ts @@ -44,7 +44,7 @@ class AuthNewAccount { this.typeOnUsername(username); this.typeOnStatus(status); this.buttonNewAccountCreate.click(); - return username; + return { username, status }; } async typeOnStatus(status: string) { diff --git a/cypress/e2e/PageObjects/ChatsMain.ts b/cypress/e2e/PageObjects/ChatsMain.ts index 5920bb2b..bad7b168 100644 --- a/cypress/e2e/PageObjects/ChatsMain.ts +++ b/cypress/e2e/PageObjects/ChatsMain.ts @@ -87,6 +87,18 @@ class ChatsMainPage { return cy.getByTestAttr("slimbar"); } + get toastNotification() { + return cy.getByTestAttr("toast-notification"); + } + + get toastNotificationButton() { + return cy.getByTestAttr("toast-notification-button"); + } + + get toastNotificationText() { + return cy.getByTestAttr("toast-notification-text"); + } + get topbar() { return cy.getByTestAttr("topbar"); } diff --git a/cypress/e2e/PageObjects/Settings/SettingsProfile.ts b/cypress/e2e/PageObjects/Settings/SettingsProfile.ts index 8fac9f1c..ed2e7c77 100644 --- a/cypress/e2e/PageObjects/Settings/SettingsProfile.ts +++ b/cypress/e2e/PageObjects/Settings/SettingsProfile.ts @@ -163,9 +163,27 @@ class SettingsProfile { return this.onlineStatusSection.find('[data-cy="setting-section-label"]'); } - get onlineStatusSectionSelect() { + get onlineStatusSectionSelectorCurrentlyDoNotDisturb() { return this.onlineStatusSection.find( - '[data-cy="settings-profile-status-select"]', + '[data-cy="selector-current-status-do-not-disturb"]', + ); + } + + get onlineStatusSectionSelectorCurrentlyIdle() { + return this.onlineStatusSection.find( + '[data-cy="selector-current-status-idle"]', + ); + } + + get onlineStatusSectionSelectorCurrentlyOffline() { + return this.onlineStatusSection.find( + '[data-cy="selector-current-status-offline"]', + ); + } + + get onlineStatusSectionSelectorCurrentlyOnline() { + return this.onlineStatusSection.find( + '[data-cy="selector-current-status-online"]', ); } @@ -195,6 +213,52 @@ class SettingsProfile { ); } + public copyShortID() { + this.inputSettingsProfileShortIDGroup.parents(".short-id").click(); + } + + public getSelectorOptions(locator: string) { + let options = []; + cy.get(locator) + .find("[data-cy='select-option']") + .each(($option) => { + cy.log("Option: ", $option); + cy.log("Option Val: ", $option.val()); + options.push($option.val()); + }); + return options; + } + + public getRecoveryPhrase() { + this.revealPhraseSectionRevealButton.click(); + let phrase = []; + for (let i = 1; i <= 12; i++) { + cy.getByTestAttr(`ordered-phrase-number-${i}`).should("exist"); + cy.getByTestAttr(`ordered-phrase-word-${i}`).should("exist"); + cy.getByTestAttr(`ordered-phrase-word-${i}`) + .find("p") + .invoke("text") + .then((text) => { + phrase.push(text); + }); + } + return phrase; + } + + public validateRecoveryPhraseIsHidden() { + for (let i = 1; i <= 12; i++) { + cy.getByTestAttr(`ordered-phrase-number-${i}`).should("not.exist"); + cy.getByTestAttr(`ordered-phrase-word-${i}`).should("not.exist"); + } + } + + public validateRecoveryPhraseIsShown() { + for (let i = 1; i <= 12; i++) { + cy.getByTestAttr(`ordered-phrase-number-${i}`).should("exist"); + cy.getByTestAttr(`ordered-phrase-word-${i}`).should("exist"); + } + } + public uploadProfileBanner(file: string) { this.profileBannerInput.selectFile(file, { force: true,