diff --git a/e2e-tests/cypress/tests/.eslintignore b/e2e-tests/cypress/tests/.eslintignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/e2e-tests/cypress/tests/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/e2e-tests/cypress/tests/.eslintrc.js b/e2e-tests/cypress/tests/.eslintrc.js new file mode 100644 index 000000000..157454287 --- /dev/null +++ b/e2e-tests/cypress/tests/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + root: true, + env: { + node: true, + }, + parser: "@typescript-eslint/parser", + plugins: ["cypress", "prettier", "@typescript-eslint"], + extends: [ + "standard", + "eslint:recommended", + "plugin:prettier/recommended", + "plugin:@typescript-eslint/recommended", + ], + rules: { + "no-console": ["error"], + "no-debugger": "error", + "prettier/prettier": [ + "error", + { + htmlWhitespaceSensitivity: "ignore", + }, + ], + }, +}; diff --git a/e2e-tests/cypress/tests/cypress.config.ts b/e2e-tests/cypress/tests/cypress.config.ts index 73f53636e..e82ee586f 100644 --- a/e2e-tests/cypress/tests/cypress.config.ts +++ b/e2e-tests/cypress/tests/cypress.config.ts @@ -15,10 +15,11 @@ async function setupNodeEvents( }) ); - on('after:run', (results) => { + on("after:run", (results) => { if (results) { // results will be undefined in interactive mode - console.log(results.status) + // eslint-disable-next-line no-console + console.log(results.status); } }); @@ -29,19 +30,20 @@ export default defineConfig({ e2e: { specPattern: "**/*.feature", excludeSpecPattern: "*.js", - baseUrl: 'http://localhost:3000', + baseUrl: "http://localhost:3000", chromeWebSecurity: false, - supportFile: 'cypress/support/index.ts', + supportFile: "cypress/support/index.ts", viewportHeight: 720, viewportWidth: 1280, retries: { runMode: 2, - openMode: 0 + openMode: 0, }, env: { - backendURL: 'http://localhost:4000', - loginQuery: 'query ($email: String!, $password: String!, $publisherId: Int) {\n login(email: $email, password: $password, publisherId: $publisherId) {\n email\n firstName\n lastName\n language\n klickTipp {\n newsletterState\n __typename\n }\n hasElopage\n publisherId\n isAdmin\n creation\n __typename\n }\n}\n' + backendURL: "http://localhost:4000", + loginQuery: + "query ($email: String!, $password: String!, $publisherId: Int) {\n login(email: $email, password: $password, publisherId: $publisherId) {\n email\n firstName\n lastName\n language\n klickTipp {\n newsletterState\n __typename\n }\n hasElopage\n publisherId\n isAdmin\n creation\n __typename\n }\n}\n", }, - setupNodeEvents - } -}) + setupNodeEvents, + }, +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts index c1c1084fd..21fda4b19 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts @@ -1,11 +1,11 @@ import { When } from "@badeball/cypress-cucumber-preprocessor"; import { ProfilePage } from "../models/ProfilePage"; -When("the user fills the password form with:", table => { +When("the user fills the password form with:", (table) => { table = table.rowsHash(); const profilePage = new ProfilePage(); profilePage.enterOldPassword(table["Old password"]); profilePage.enterNewPassword(table["New password"]); profilePage.enterRepeatPassword(table["Repeat new password"]); - cy.get(profilePage.submitNewPasswordBtn).should('be.enabled'); -}); \ No newline at end of file + cy.get(profilePage.submitNewPasswordBtn).should("be.enabled"); +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts index 79b63e499..9fa90bd02 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts @@ -2,7 +2,10 @@ import { When } from "@badeball/cypress-cucumber-preprocessor"; import { Toasts } from "../models/Toasts"; When("the user is presented a {string} message", (type: string) => { - const toast = new Toasts(); - cy.get(toast.toastTitle).should('contain.text', 'Success'); - cy.get(toast.toastMessage).should('contain.text', 'Your password has been changed.'); -}); \ No newline at end of file + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Success"); + cy.get(toast.toastMessage).should( + "contain.text", + "Your password has been changed." + ); +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts index 78e6cdfe0..dcfed3c71 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts @@ -2,8 +2,8 @@ import { And } from "@badeball/cypress-cucumber-preprocessor"; import { ProfilePage } from "../models/ProfilePage"; And("the user opens the change password menu", () => { - const profilePage = new ProfilePage(); - cy.get(profilePage.openChangePassword).click(); - cy.get(profilePage.newPasswordRepeatInput).should('be.visible'); - cy.get(profilePage.submitNewPasswordBtn).should('be.disabled'); -}); \ No newline at end of file + const profilePage = new ProfilePage(); + cy.get(profilePage.openChangePassword).click(); + cy.get(profilePage.newPasswordRepeatInput).should("be.visible"); + cy.get(profilePage.submitNewPasswordBtn).should("be.disabled"); +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts index 7730f04fc..5752c94fa 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts @@ -2,6 +2,6 @@ import { And } from "@badeball/cypress-cucumber-preprocessor"; import { ProfilePage } from "../models/ProfilePage"; And("the user submits the password form", () => { - const profilePage = new ProfilePage(); - profilePage.submitPasswordForm(); -}); \ No newline at end of file + const profilePage = new ProfilePage(); + profilePage.submitPasswordForm(); +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts index 27be5f22d..a16b93a11 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts @@ -2,14 +2,14 @@ export class LoginPage { // selectors - emailInput = '#Email-input-field'; - passwordInput = '#Password-input-field'; - submitBtn = '[type=submit]'; - emailHint = '#vee_Email'; - passwordHint = '#vee_Password'; + emailInput = "#Email-input-field"; + passwordInput = "#Password-input-field"; + submitBtn = "[type=submit]"; + emailHint = "#vee_Email"; + passwordHint = "#vee_Password"; goto() { - cy.visit('/'); + cy.visit("/"); return this; } diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts index 1de37abe2..426c2b8b3 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts @@ -3,8 +3,8 @@ export class OverviewPage { navbarName = '[data-test="navbar-item-username"]'; - goto() { - cy.visit('/overview'); - return this; - } -} \ No newline at end of file + goto() { + cy.visit("/overview"); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts index f7a243a40..51fba2b90 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts @@ -2,17 +2,17 @@ export class ProfilePage { // selectors - openChangePassword = '[data-test=open-password-change-form]'; - oldPasswordInput = '#password-input-field'; - newPasswordInput = '#Neues-Passwort-input-field'; - newPasswordRepeatInput = '#Neues-Passwort-wiederholen-input-field'; - submitNewPasswordBtn = '[data-test=submit-new-password-btn]'; + openChangePassword = "[data-test=open-password-change-form]"; + oldPasswordInput = "#password-input-field"; + newPasswordInput = "#Neues-Passwort-input-field"; + newPasswordRepeatInput = "#Neues-Passwort-wiederholen-input-field"; + submitNewPasswordBtn = "[data-test=submit-new-password-btn]"; goto() { - cy.visit('/profile'); + cy.visit("/profile"); return this; } - + enterOldPassword(password: string) { cy.get(this.oldPasswordInput).clear().type(password); return this; diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts b/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts index 6770fe6ff..3dd9d6914 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts @@ -1,17 +1,17 @@ /// export class SideNavMenu { - // selectors - profileMenu = '[data-test=profile-menu]'; - logoutMenu = '[data-test=logout-menu]'; + // selectors + profileMenu = "[data-test=profile-menu]"; + logoutMenu = "[data-test=logout-menu]"; - openUserProfile() { - cy.get(this.profileMenu).click(); - return this; - } + openUserProfile() { + cy.get(this.profileMenu).click(); + return this; + } - logout() { - cy.get(this.logoutMenu).click(); - return this; - } - } \ No newline at end of file + logout() { + cy.get(this.logoutMenu).click(); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts index 86fed8933..b2198bc8d 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts @@ -1,7 +1,7 @@ /// export class Toasts { - // selectors - toastTitle = '.gdd-toaster-title'; - toastMessage = '.gdd-toaster-body'; -} \ No newline at end of file + // selectors + toastTitle = ".gdd-toaster-title"; + toastMessage = ".gdd-toaster-body"; +} diff --git a/e2e-tests/cypress/tests/cypress/support/e2e.ts b/e2e-tests/cypress/tests/cypress/support/e2e.ts index 689d0919e..16cc474bf 100644 --- a/e2e-tests/cypress/tests/cypress/support/e2e.ts +++ b/e2e-tests/cypress/tests/cypress/support/e2e.ts @@ -1,39 +1,38 @@ -import jwtDecode from 'jwt-decode' +import jwtDecode from "jwt-decode"; -Cypress.Commands.add('login', (email, password) => { - Cypress.LocalStorage.clear - - cy.request({ - method: 'POST', - url: Cypress.env('backendURL'), - body: { - "operationName": null, - "variables": { - "email": email, - "password": password - }, - "query": Cypress.env('loginQuery') - } - }) - .then(async (response) => { - const token = response.headers.token - let tokenTime +Cypress.Commands.add("login", (email, password) => { + cy.clearLocalStorage("vuex"); - // to avoid JWT InvalidTokenError, the decoding of the token is wrapped - // in a try-catch block (see - // https://github.com/auth0/jwt-decode/issues/65#issuecomment-395493807) - try { - tokenTime = jwtDecode(token).exp - } catch (tokenDecodingError) { - cy.log('JWT decoding error: ', tokenDecodingError) - } + cy.request({ + method: "POST", + url: Cypress.env("backendURL"), + body: { + operationName: null, + variables: { + email: email, + password: password, + }, + query: Cypress.env("loginQuery"), + }, + }).then(async (response) => { + const token = response.headers.token; + let tokenTime; - let vuexToken = { - token : token, - tokenTime : tokenTime - }; + // to avoid JWT InvalidTokenError, the decoding of the token is wrapped + // in a try-catch block (see + // https://github.com/auth0/jwt-decode/issues/65#issuecomment-395493807) + try { + tokenTime = jwtDecode(token).exp; + } catch (tokenDecodingError) { + cy.log("JWT decoding error: ", tokenDecodingError); + } - cy.visit('/') - window.localStorage.setItem('vuex', JSON.stringify(vuexToken)) - }) -}) \ No newline at end of file + const vuexToken = { + token: token, + tokenTime: tokenTime, + }; + + cy.visit("/"); + window.localStorage.setItem("vuex", JSON.stringify(vuexToken)); + }); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/index.ts b/e2e-tests/cypress/tests/cypress/support/index.ts index b5db7da24..99ab0efc2 100644 --- a/e2e-tests/cypress/tests/cypress/support/index.ts +++ b/e2e-tests/cypress/tests/cypress/support/index.ts @@ -1,11 +1,14 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + /// -import './e2e'; +import "./e2e"; declare global { - namespace Cypress { - interface Chainable { - login(email: string, password: string): Chainable - } + namespace Cypress { + interface Chainable { + login(email: string, password: string): Chainable; } -} \ No newline at end of file + } +} diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts index 19973a9c2..cd397080d 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts @@ -2,4 +2,4 @@ import { Given } from "@badeball/cypress-cucumber-preprocessor"; Given("the browser navigates to page {string}", (page: string) => { cy.visit(page); -}); \ No newline at end of file +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts index 9f7607565..bec4e5f30 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts @@ -2,7 +2,10 @@ import { Then } from "@badeball/cypress-cucumber-preprocessor"; import { Toasts } from "../../e2e/models/Toasts"; Then("the user cannot login", () => { - const toast = new Toasts(); - cy.get(toast.toastTitle).should('contain.text', 'Fehler!'); // 'Error!' - cy.get(toast.toastMessage).should('contain.text', 'Kein Benutzer mit diesen Anmeldedaten.'); // 'No user with this credentials.' + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Fehler!"); // 'Error!' + cy.get(toast.toastMessage).should( + "contain.text", + "Kein Benutzer mit diesen Anmeldedaten." + ); // 'No user with this credentials.' }); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts index e8692da38..145ece1b1 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts @@ -1,5 +1,8 @@ import { Given } from "@badeball/cypress-cucumber-preprocessor"; -Given("the user is logged in as {string} {string}", (email: string, password: string) => { +Given( + "the user is logged in as {string} {string}", + (email: string, password: string) => { cy.login(email, password); -}); \ No newline at end of file + } +); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts index 4a01a988f..64741d122 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts @@ -2,9 +2,7 @@ import { Then } from "@badeball/cypress-cucumber-preprocessor"; import { OverviewPage } from "../../e2e/models/OverviewPage"; Then("the user is logged in with username {string}", (username: string) => { - const overviewPage = new OverviewPage(); - cy.url().should('include', '/overview') - cy.get(overviewPage.navbarName).should('contain', username); + const overviewPage = new OverviewPage(); + cy.url().should("include", "/overview"); + cy.get(overviewPage.navbarName).should("contain", username); }); - - diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts index 2822fce78..62766f7bd 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts @@ -2,6 +2,6 @@ import { Then } from "@badeball/cypress-cucumber-preprocessor"; import { SideNavMenu } from "../../e2e/models/SideNavMenu"; Then("the user logs out", () => { - const sideNavMenu = new SideNavMenu; - sideNavMenu.logout(); -}); \ No newline at end of file + const sideNavMenu = new SideNavMenu(); + sideNavMenu.logout(); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts index d6766f837..6aef84797 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts @@ -1,9 +1,12 @@ import { When } from "@badeball/cypress-cucumber-preprocessor"; import { LoginPage } from "../../e2e/models/LoginPage"; -When("the user submits the credentials {string} {string}", (email: string, password: string) => { - const loginPage = new LoginPage; +When( + "the user submits the credentials {string} {string}", + (email: string, password: string) => { + const loginPage = new LoginPage(); loginPage.enterEmail(email); loginPage.enterPassword(password); loginPage.submitLogin(); -}); \ No newline at end of file + } +);