From e2c05e7dd60fddc72adfde0e0f60659f14b24e31 Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Sun, 5 Dec 2021 16:03:29 +0100 Subject: [PATCH] Add new tests for login (#1580) * always run critical * tests for login * tests for login --- .github/workflows/e2e.yml | 41 +++++++++++++++++++ cypress/elements/account/login-selectors.js | 5 ++- .../configuration/plugins/plugins.js | 14 +++++-- cypress/integration/login.js | 22 +++++----- cypress/integration/staffMembers.js | 35 ++++++++++++++++ cypress/support/api/requests/Plugins.js | 16 ++++++++ cypress/support/api/utils/users.js | 38 ++++++++++++++++- src/auth/components/LoginPage/LoginPage.tsx | 6 ++- .../ResetPasswordPage/ResetPasswordPage.tsx | 1 + 9 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 cypress/support/api/requests/Plugins.js diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index d3928612e..cac6f1169 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -69,3 +69,44 @@ jobs: with: name: cypress-videos path: cypress/videos + + cypress-run-critical: + if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard' && ((github.event.label.name != 'run e2e') || !(contains(github.event.pull_request.labels.*.name, 'run e2e'))) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + + - name: Get API_URI + id: api_uri + # Search for CYPRESS_API_URI in PR description and use default if not defined + env: + pull_request_body: ${{ github.event.pull_request.body }} + prefix: CYPRESS_API_URI= + pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/? + fallback_uri: ${{ secrets.CYPRESS_API_URI }} + run: | + echo "::set-output name=custom_api_uri::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1 | { read custom_uri; if [ -z "$custom_uri" ]; then echo "$fallback_uri"; else echo "$custom_uri"; fi })" + + - name: Cypress run critical + if: ${{ steps.api_uri.outputs.custom_api_uri != 'https://qa.staging.saleor.cloud/graphql/' }} + uses: cypress-io/github-action@v2 + env: + API_URI: ${{ steps.api_uri.outputs.custom_api_uri }} + APP_MOUNT_URI: ${{ secrets.APP_MOUNT_URI }} + CYPRESS_baseUrl: ${{ secrets.CYPRESS_BASEURL }} + CYPRESS_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }} + CYPRESS_SECOND_USER_NAME: ${{ secrets.CYPRESS_SECOND_USER_NAME }} + CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }} + CYPRESS_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }} + with: + build: npm run build + start: npx local-web-server --spa index.html + wait-on: http://localhost:9000/ + wait-on-timeout: 120 + command: npm run cy:run:critical + - uses: actions/upload-artifact@v1 + if: ${{ failure() }} + with: + name: cypress-videos + path: cypress/videos diff --git a/cypress/elements/account/login-selectors.js b/cypress/elements/account/login-selectors.js index 388f6b458..d14245082 100644 --- a/cypress/elements/account/login-selectors.js +++ b/cypress/elements/account/login-selectors.js @@ -5,5 +5,8 @@ export const LOGIN_SELECTORS = { signInButton: "[data-test=submit]", userMenu: "[data-test=userMenu]", warningCredentialMessage: "[data-test=loginErrorMessage]", - welcomePage: "[data-test=welcomeHeader]" + welcomePage: "[data-test=welcomeHeader]", + logOutButton: "[data-test='logOutButton']", + resetPasswordLink: "[data-test-id='reset-password-link']", + confirmPassword: "[name='confirmPassword']" }; diff --git a/cypress/integration/configuration/plugins/plugins.js b/cypress/integration/configuration/plugins/plugins.js index 51b426d18..94e9cf2c4 100644 --- a/cypress/integration/configuration/plugins/plugins.js +++ b/cypress/integration/configuration/plugins/plugins.js @@ -17,7 +17,10 @@ import { deleteChannelsStartsWith, getDefaultChannel } from "../../../support/api/utils/channelsUtils"; -import { getMailsForUser } from "../../../support/api/utils/users"; +import { + getMailActivationLinkForUserAndSubject, + getMailsForUser +} from "../../../support/api/utils/users"; import filterTests from "../../../support/filterTests"; filterTests({ definedTags: ["stagedOnly"], version: "3.1.1" }, () => { @@ -76,10 +79,13 @@ filterTests({ definedTags: ["stagedOnly"], version: "3.1.1" }, () => { .confirmationMessageShouldDisappear(); requestPasswordReset(Cypress.env("USER_NAME"), defaultChannel.slug) .then(() => { - getMailsForUser(customerEmail); + getMailActivationLinkForUserAndSubject( + Cypress.env("USER_NAME"), + randomName + ); }) - .then(mails => { - expect(mails[0].Content.Headers.Subject[0]).to.eq(randomName); + .then(link => { + expect(link).to.be.ok; }); }); }); diff --git a/cypress/integration/login.js b/cypress/integration/login.js index 3445e6406..d0c26bd99 100644 --- a/cypress/integration/login.js +++ b/cypress/integration/login.js @@ -14,7 +14,7 @@ filterTests({ definedTags: ["all"] }, () => { it("should successfully log in an user", () => { cy.visit(urlList.homePage); cy.loginUser(); - cy.get(LOGIN_SELECTORS.welcomePage); + cy.get(LOGIN_SELECTORS.welcomePage).should("be.visible"); }); it("should fail for wrong password", () => { @@ -25,20 +25,20 @@ filterTests({ definedTags: ["all"] }, () => { .type("wrong-password") .get(LOGIN_SELECTORS.signInButton) .click() - .get(LOGIN_SELECTORS.warningCredentialMessage); + .get(LOGIN_SELECTORS.warningCredentialMessage) + .should("be.visible"); }); it("should successfully log out an user", () => { - cy.window().then(win => { - win.sessionStorage.clear(); - }); - cy.visit(urlList.homePage); - cy.loginUser(); - cy.get(LOGIN_SELECTORS.userMenu) + cy.clearSessionData() + .loginUserViaRequest() + .visit(urlList.homePage) + .get(LOGIN_SELECTORS.userMenu) .click() - .get(LOGIN_SELECTORS.accountSettings) - .click(); - cy.location("pathname").should("contains", "/staff/"); + .get(LOGIN_SELECTORS.logOutButton) + .click() + .get(LOGIN_SELECTORS.emailAddressInput) + .should("be.visible"); }); }); }); diff --git a/cypress/integration/staffMembers.js b/cypress/integration/staffMembers.js index 37164c436..e008fb9d6 100644 --- a/cypress/integration/staffMembers.js +++ b/cypress/integration/staffMembers.js @@ -4,16 +4,19 @@ import faker from "faker"; import { LEFT_MENU_SELECTORS } from "../elements/account/left-menu/left-menu-selectors"; +import { LOGIN_SELECTORS } from "../elements/account/login-selectors"; import { BUTTON_SELECTORS } from "../elements/shared/button-selectors"; import { STAFF_MEMBER_DETAILS } from "../elements/staffMembers/staffMemberDetails"; import { STAFF_MEMBERS_LIST } from "../elements/staffMembers/staffMembersList"; import { urlList, userDetailsUrl } from "../fixtures/urlList"; +import { updatePlugin } from "../support/api/requests/Plugins"; import { deleteStaffMembersStartsWith, updateStaffMember } from "../support/api/requests/StaffMembers"; import { getMailActivationLinkForUser, + getMailActivationLinkForUserAndSubject, inviteStaffMemberWithFirstPermission } from "../support/api/utils/users"; import filterTests from "../support/filterTests"; @@ -115,5 +118,37 @@ filterTests({ definedTags: ["stagedOnly"] }, () => { ); }); }); + + it("should reset password", () => { + const newPassword = faker.random.alphaNumeric(8); + updatePlugin( + "mirumee.notifications.admin_email", + "staff_password_reset_subject", + "Reset" + ) + .then(() => { + cy.clearSessionData() + .visit(urlList.homePage) + .get(LOGIN_SELECTORS.resetPasswordLink) + .click() + .get(LOGIN_SELECTORS.emailAddressInput) + .type(email) + .get(BUTTON_SELECTORS.submit) + .click(); + getMailActivationLinkForUserAndSubject(email, "Reset"); + }) + .then(link => { + cy.visit(link) + .get(LOGIN_SELECTORS.emailPasswordInput) + .type(newPassword) + .get(LOGIN_SELECTORS.confirmPassword) + .type(newPassword) + .get(BUTTON_SELECTORS.confirm) + .click() + .get(LOGIN_SELECTORS.welcomePage) + .should("be.visible") + .loginUserViaRequest({ email, password: newPassword }); + }); + }); }); }); diff --git a/cypress/support/api/requests/Plugins.js b/cypress/support/api/requests/Plugins.js new file mode 100644 index 000000000..b4e952627 --- /dev/null +++ b/cypress/support/api/requests/Plugins.js @@ -0,0 +1,16 @@ +export function updatePlugin(id, name, value) { + const mutation = `mutation{ + pluginUpdate(id:"${id}", input:{ + configuration:{ + name:"${name}" + value:"${value}" + } + }){ + errors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); +} diff --git a/cypress/support/api/utils/users.js b/cypress/support/api/utils/users.js index 78a3afad9..1a9505da3 100644 --- a/cypress/support/api/utils/users.js +++ b/cypress/support/api/utils/users.js @@ -44,6 +44,40 @@ export function getMailActivationLinkForUser(email, i = 0) { }); } +export function getMailActivationLinkForUserAndSubject(email, subject, i = 0) { + if (i > 3) { + throw new Error(`There is no email invitation for user ${email}`); + } + return cy.mhGetMailsByRecipient(email).should(mails => { + if (!mails.length) { + cy.wait(10000); + getMailActivationLinkForUserAndSubject(email, subject, i + 1); + } else { + cy.wrap(mails) + .mhGetMailsBySubject(subject) + .should(mailsWithSubject => { + if (!mailsWithSubject.length) { + cy.wait(10000); + getMailActivationLinkForUserAndSubject(email, subject, i + 1); + } else { + cy.wrap(mailsWithSubject) + .mhFirst() + .should("not.eq", undefined) + .mhGetBody() + .then(body => { + const urlRegex = /\[([^\]]*)\]/; + const bodyWithoutWhiteSpaces = body.replace( + /(\r\n|\n|\r|\s)/gm, + "" + ); + return urlRegex.exec(bodyWithoutWhiteSpaces)[1]; + }); + } + }); + } + }); +} + export function getMailsForUser(email, i = 0) { if (i > 3) { throw new Error(`There is no email invitation for user ${email}`); @@ -51,9 +85,9 @@ export function getMailsForUser(email, i = 0) { return cy.mhGetMailsByRecipient(email).should(mails => { if (!mails.length) { cy.wait(10000); - getEmailForUser(email, i + 1); + getMailsForUser(email, i + 1); } else { - return mails[0].Content.Headers.Subject[0]; + return mails; } }); } diff --git a/src/auth/components/LoginPage/LoginPage.tsx b/src/auth/components/LoginPage/LoginPage.tsx index ff3678ef6..a8bf81b3e 100644 --- a/src/auth/components/LoginPage/LoginPage.tsx +++ b/src/auth/components/LoginPage/LoginPage.tsx @@ -150,7 +150,11 @@ const LoginCard: React.FC = props => { description="description" values={{ resetPasswordLink: ( - + = props => { />