From cb91ccbc33f7ed28f3bbdecffd3e51471ed93c86 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 21 Dec 2021 17:14:27 -0600 Subject: [PATCH] Refactor to use custom commands for login/logout & make admin user configurable --- cypress.json | 2 + cypress/integration/login-modal.spec.ts | 53 +++++++++------ cypress/support/commands.ts | 88 +++++++++++++------------ cypress/support/index.ts | 14 +++- 4 files changed, 93 insertions(+), 64 deletions(-) diff --git a/cypress.json b/cypress.json index 2f3a1e8fe1..104a672377 100644 --- a/cypress.json +++ b/cypress.json @@ -11,6 +11,8 @@ "openMode": 0 }, "env": { + "DSPACE_TEST_ADMIN_USER": "dspacedemo+admin@gmail.com", + "DSPACE_TEST_ADMIN_PASSWORD": "dspace", "DSPACE_TEST_COMMUNITY": "0958c910-2037-42a9-81c7-dca80e3892b4", "DSPACE_TEST_COLLECTION": "282164f5-d325-4740-8dd1-fa4d6d3e7200", "DSPACE_TEST_ENTITY_PUBLICATION": "e98b0f27-5c19-49a0-960d-eb6ad5287067" diff --git a/cypress/integration/login-modal.spec.ts b/cypress/integration/login-modal.spec.ts index da0eb4802a..a71101e591 100644 --- a/cypress/integration/login-modal.spec.ts +++ b/cypress/integration/login-modal.spec.ts @@ -1,34 +1,27 @@ -import { TEST_ENTITY_PUBLICATION } from 'cypress/support'; +import { TEST_ADMIN_PASSWORD, TEST_ADMIN_USER, TEST_ENTITY_PUBLICATION } from 'cypress/support'; const page = { openLoginMenu() { // Click the closed "Log In" dropdown menu (to open Login menu) cy.get('ds-auth-nav-menu.navbar-collapsed').click(); }, - submitLoginAndPassword() { - // In opened Login modal, fill out email & password, then click submit - cy.get('ds-themed-navbar ds-log-in-password input[type = "email"]').type('dspacedemo+admin@gmail.com'); - cy.get('ds-themed-navbar ds-log-in-password input[type = "password"]').type('dspace'); - cy.get('ds-themed-navbar ds-log-in-password button[type = "submit"]').click(); - }, - submitLoginAndPasswordByPressingEnter() { + submitLoginAndPasswordByPressingEnter(email, password) { // In opened Login modal, fill out email & password, then click Enter - cy.get('ds-themed-navbar ds-log-in-password input[type = "email"]').type('dspacedemo+admin@gmail.com'); - cy.get('ds-themed-navbar ds-log-in-password input[type = "password"]').type('dspace'); + cy.get('ds-themed-navbar ds-log-in-password input[type = "email"]').type(email); + cy.get('ds-themed-navbar ds-log-in-password input[type = "password"]').type(password); cy.get('ds-themed-navbar ds-log-in-password input[type = "password"]').type('{enter}'); - }, + } }; describe('Login Modal', () => { it('should login when clicking button', () => { cy.visit('/'); - // Open login menu in header & verify tag is visible - page.openLoginMenu(); - cy.get('ds-log-in').should('be.visible'); + // Login menu should exist + cy.get('ds-log-in').should('exist'); // Login, and the tag should no longer exist - page.submitLoginAndPassword(); + cy.login(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); cy.get('ds-log-in').should('not.exist'); // Open login menu again, verify user menu & logout button now available @@ -37,7 +30,7 @@ describe('Login Modal', () => { cy.get('ds-log-out').should('be.visible'); }); - it('should login when clicking enter', () => { + it('should login when clicking enter key', () => { cy.visit('/'); // Open login menu in header & verify tag is visible @@ -45,7 +38,7 @@ describe('Login Modal', () => { cy.get('.form-login').should('be.visible'); // Login, and the tag should no longer exist - page.submitLoginAndPasswordByPressingEnter(); + page.submitLoginAndPasswordByPressingEnter(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); cy.get('.form-login').should('not.exist'); // Open login menu again, verify user menu & logout button now available @@ -58,12 +51,11 @@ describe('Login Modal', () => { const ENTITYPAGE = '/entities/publication/' + TEST_ENTITY_PUBLICATION; cy.visit(ENTITYPAGE); - // Open login menu in header & verify tag is visible - page.openLoginMenu(); - cy.get('ds-log-in').should('be.visible'); + // Login menu should exist + cy.get('ds-log-in').should('exist'); // Login, and the tag should no longer exist - page.submitLoginAndPassword(); + cy.login(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); cy.get('ds-log-in').should('not.exist'); // Verify we are still on the same page @@ -74,4 +66,23 @@ describe('Login Modal', () => { cy.get('ds-user-menu').should('be.visible'); cy.get('ds-log-out').should('be.visible'); }); + + it('logout should work', () => { + cy.visit('/'); + + cy.get('ds-log-in').should('exist'); + cy.get('ds-log-out').should('not.exist'); + + // Click login + cy.login(TEST_ADMIN_USER, TEST_ADMIN_PASSWORD); + + cy.get('ds-log-in').should('not.exist'); + cy.get('ds-log-out').should('exist'); + + // Click logout + cy.logout(); + + cy.get('ds-log-in').should('exist'); + cy.get('ds-log-out').should('not.exist'); + }); }); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index af1f44a0fc..b1994299fb 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,43 +1,49 @@ // *********************************************** -// This example namespace declaration will help -// with Intellisense and code completion in your -// IDE or Text Editor. +// This File is for Custom Cypress commands. +// See docs at https://docs.cypress.io/api/cypress-api/custom-commands // *********************************************** -// declare namespace Cypress { -// interface Chainable { -// customCommand(param: any): typeof customCommand; -// } -// } -// -// function customCommand(param: any): void { -// console.warn(param); -// } -// -// NOTE: You can use it like so: -// Cypress.Commands.add('customCommand', customCommand); -// -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add("login", (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) +// Declare Cypress namespace to help with Intellisense & code completion in IDEs +// ALL custom commands MUST be listed here for code completion to work +// tslint:disable-next-line:no-namespace +declare namespace Cypress { + interface Chainable { + login(email: string, password: string): typeof login; + logout(): typeof logout; + } +} + +/** + * Login from any page via DSpace's header menu + * @param email email to login as + * @param password password to login as + */ +function login(email: string, password: string): void { + // Click the closed "Log In" dropdown menu (to open Login menu) + cy.get('ds-auth-nav-menu.navbar-collapsed').click(); + // Enter email + cy.get('ds-themed-navbar ds-log-in-password input[type = "email"]').type(email); + // Enter password + cy.get('ds-themed-navbar ds-log-in-password input[type = "password"]').type(password); + // Click login button + cy.get('ds-themed-navbar ds-log-in-password button[type = "submit"]').click(); +} +// Add as a Cypress command (i.e. assign to 'cy.login') +Cypress.Commands.add('login', login); + + +/** + * Logout from any page via DSpace's header menu. + * NOTE: Also waits until logout completes before next command will be run. + */ + function logout(): void { + // Click the closed User dropdown menu (to open user menu in header) + cy.get('ds-auth-nav-menu.navbar-collapsed').click(); + // This is the POST command that will actually log us out + cy.intercept('POST', '/server/api/authn/logout').as('logout'); + // Click logout button + cy.get('ds-themed-navbar ds-log-out button').click(); + // Wait until above POST command responds before continuing + cy.wait('@logout'); +} +// Add as a Cypress command (i.e. assign to 'cy.logout') +Cypress.Commands.add('logout', logout); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index de00a33534..9c29d45e3e 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -13,18 +13,28 @@ // https://on.cypress.io/configuration // *********************************************************** -// When a command from ./commands is ready to use, import with `import './commands'` syntax -// import './commands'; +// Import all custom Commands (from commands.ts) for all tests +import './commands'; // Import Cypress Axe tools for all tests // https://github.com/component-driven/cypress-axe import 'cypress-axe'; +// Runs once before the first test in each "block" +before(() => { + // Pre-agree to all Klaro cookies by setting the klaro-anonymous cookie + // This just ensures it doesn't get in the way of matching other objects in the page. + cy.setCookie('klaro-anonymous', '{%22authentication%22:true%2C%22preferences%22:true%2C%22acknowledgement%22:true%2C%22google-analytics%22:true}'); +}); + + // Global constants used in tests // May be overridden in our cypress.json config file using specified environment variables. // Default UUIDs listed here are all in the Demo Entities Data set available at // https://github.com/DSpace-Labs/AIP-Files/releases/tag/demo-entities-data // (This is the data set used in our CI environment) +export const TEST_ADMIN_USER = Cypress.env('DSPACE_TEST_ADMIN_USER') || 'dspacedemo+admin@gmail.com'; +export const TEST_ADMIN_PASSWORD = Cypress.env('DSPACE_TEST_ADMIN_PASSWORD') || 'dspace'; export const TEST_COLLECTION = Cypress.env('DSPACE_TEST_COLLECTION') || '282164f5-d325-4740-8dd1-fa4d6d3e7200'; export const TEST_COMMUNITY = Cypress.env('DSPACE_TEST_COMMUNITY') || '0958c910-2037-42a9-81c7-dca80e3892b4'; export const TEST_ENTITY_PUBLICATION = Cypress.env('DSPACE_TEST_ENTITY_PUBLICATION') || 'e98b0f27-5c19-49a0-960d-eb6ad5287067';