diff --git a/apps/datahub-e2e/src/support/commands.ts b/apps/datahub-e2e/src/support/commands.ts index 38595569a8..d9ccb51a63 100644 --- a/apps/datahub-e2e/src/support/commands.ts +++ b/apps/datahub-e2e/src/support/commands.ts @@ -7,114 +7,4 @@ // commands please read more here: // https://on.cypress.io/custom-commands // *********************************************** - -// eslint-disable-next-line @typescript-eslint/no-namespace -declare namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - login(): void - clearFavorites(): void - - // interaction with gn-ui-dropdown-selector - openDropdown(): Chainable> - selectDropdownOption(value: string): void - getActiveDropdownOption(): Chainable> - } -} - -Cypress.Commands.add('login', () => { - // ignore error coming from GN - Cypress.on('uncaught:exception', (err) => { - if (err.message.includes('Jsonix')) return false - if (err.message.includes('postMessage')) return false - }) - - cy.visit('/geonetwork/srv/eng/catalog.signin?debug&redirect=blargz') // this will point to a 404 - cy.get('#inputUsername').type('admin', { force: true }) - cy.get('#inputPassword').type('admin', { force: true }) - cy.get('[name="gnSigninForm"]').submit() -}) - -/** - * This will most likely fail if the user is not logged in! - */ -Cypress.Commands.add('clearFavorites', () => { - cy.request({ - url: '/geonetwork/srv/api/me', - headers: { accept: 'application/json' }, - }) - .its('body') - .its('id') - .as('myId') - - cy.window().then(function () { - cy.request({ - url: `/geonetwork/srv/api/userselections/0/${this.myId}`, - headers: { accept: 'application/json' }, - }) - .its('body') - .as('favoritesId') - }) - - cy.getCookie('XSRF-TOKEN') - .its('value') - .then(function (token) { - const favoritesId = this.favoritesId || [] - cy.request({ - url: `/geonetwork/srv/api/userselections/0/${ - this.myId - }?uuid=${favoritesId.join('&uuid=')}`, - method: 'DELETE', - headers: { accept: 'application/json', 'X-XSRF-TOKEN': token }, - }) - }) -}) - -// previous value should be a component -Cypress.Commands.add( - 'openDropdown', - { prevSubject: true }, - (dropdownElement) => { - cy.get('body').click() // first click on the document to close other dropdowns - const width = dropdownElement.width() - const height = dropdownElement.height() - cy.wrap(dropdownElement).click(width - 10, height / 2) // click on the right size to avoid the label - return cy.get('.cdk-overlay-container').find('[role=listbox]') - } -) - -// previous value should be a component -Cypress.Commands.add( - 'selectDropdownOption', - { prevSubject: true }, - (dropdownElement, value: string) => { - cy.wrap(dropdownElement) - .openDropdown() - .find(`[data-cy-value="${value}"]`) - .click() - } -) - -// previous value should be a component -Cypress.Commands.add( - 'getActiveDropdownOption', - { prevSubject: true }, - (dropdownElement) => { - return cy.wrap(dropdownElement).openDropdown().find(`[data-cy-active]`) - } -) - -// -- 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) => { ... }) +import '../../../../tools/e2e/commands' diff --git a/apps/metadata-editor-e2e/src/e2e/home.cy.ts b/apps/metadata-editor-e2e/src/e2e/home.cy.ts index 2587cd057d..02e60f9d03 100644 --- a/apps/metadata-editor-e2e/src/e2e/home.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/home.cy.ts @@ -11,7 +11,7 @@ const gnBaseUrl = 'http://localhost:8080/geonetwork/srv/eng/' describe('avatar', () => { describe('display avatar for user without gravatar hash', () => { it('should display placeholder url', () => { - cy.loginGN('admin', 'admin', false) + cy.login('admin', 'admin', false) cy.visit(`${gnBaseUrl}admin.console#/organization`) cy.get('#gn-btn-user-add').click() cy.get('#username').type(fakeUser.username) @@ -33,7 +33,7 @@ describe('avatar', () => { .should('eq', 'https://www.gravatar.com/avatar/?d=mp') }) it('should display monsterid', () => { - cy.loginGN('admin', 'admin', false) + cy.login('admin', 'admin', false) cy.visit(`${gnBaseUrl}admin.console#/settings`) cy.get('[id="system/users/identicon"]').type( '{selectAll}gravatar:monsterid' @@ -49,7 +49,7 @@ describe('avatar', () => { }) describe('display avatar for user with hash', () => { it('should display the correct profile picture', () => { - cy.loginGN(fakeUser.username, fakeUser.password) + cy.login(fakeUser.username, fakeUser.password) cy.get('gn-ui-avatar') .children('img') .should('have.attr', 'src') diff --git a/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts b/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts index 5d93e32ec0..ff578d8b68 100644 --- a/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts @@ -1,6 +1,6 @@ describe('my-org', () => { beforeEach(() => { - cy.loginGN('barbie', 'p4ssworD_', false) + cy.login('barbie', 'p4ssworD_', false) cy.intercept({ method: 'GET', url: '/geonetwork/srv/api/userselections/0/101', diff --git a/apps/metadata-editor-e2e/src/support/app.po.ts b/apps/metadata-editor-e2e/src/support/app.po.ts deleted file mode 100644 index 00f556e103..0000000000 --- a/apps/metadata-editor-e2e/src/support/app.po.ts +++ /dev/null @@ -1 +0,0 @@ -export const getGreeting = () => cy.get('h1') diff --git a/apps/metadata-editor-e2e/src/support/commands.ts b/apps/metadata-editor-e2e/src/support/commands.ts index fa04f99e13..d9ccb51a63 100644 --- a/apps/metadata-editor-e2e/src/support/commands.ts +++ b/apps/metadata-editor-e2e/src/support/commands.ts @@ -7,55 +7,4 @@ // commands please read more here: // https://on.cypress.io/custom-commands // *********************************************** - -/* eslint-disable cypress/no-unnecessary-waiting */ -// eslint-disable-next-line @typescript-eslint/no-namespace -declare namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Chainable { - loginGN(username: string, password: string, redirect?: boolean): void - signOutGN(): void - } -} - -Cypress.Commands.add( - 'loginGN', - (username: string, password: string, redirect = true) => { - // first request to get the XSRF cookie - cy.request({ - method: 'GET', - url: '/geonetwork/srv/api/me', - headers: { - Accept: 'application/json, text/plain, */*', - }, - }) - cy.getCookie('XSRF-TOKEN').then((xsrfTokenCookie) => { - cy.request({ - method: 'POST', - url: '/geonetwork/signin', - body: `username=${username}&password=${password}&_csrf=${xsrfTokenCookie.value}`, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }) - }) - if (redirect) cy.visit('/') - } -) - -Cypress.Commands.add('signOutGN', () => { - cy.visit('http://localhost:8080/geonetwork/srv/eng/catalog.search#/home') - cy.get('a[title="User details"]').click() - cy.get('a[title="Sign out"]').click() -}) -// -// -- 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) => { ... }) +import '../../../../tools/e2e/commands' diff --git a/tools/e2e/.eslintrc.json b/tools/e2e/.eslintrc.json new file mode 100644 index 0000000000..696cb8b121 --- /dev/null +++ b/tools/e2e/.eslintrc.json @@ -0,0 +1,10 @@ +{ + "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/tools/e2e/README.md b/tools/e2e/README.md new file mode 100644 index 0000000000..b42c5a4992 --- /dev/null +++ b/tools/e2e/README.md @@ -0,0 +1,4 @@ +# End-to-end testing utils + +This folder contains useful Cypress commands to be used in the E2E tests of +various applications. diff --git a/tools/e2e/commands.ts b/tools/e2e/commands.ts new file mode 100644 index 0000000000..0c2e85d3c2 --- /dev/null +++ b/tools/e2e/commands.ts @@ -0,0 +1,139 @@ +// *********************************************** +// 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 +// *********************************************** + +// eslint-disable-next-line @typescript-eslint/no-namespace +declare namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Chainable { + login(username?: string, password?: string, redirect?: boolean): void + signOut(): void + clearFavorites(): void + + // interaction with gn-ui-dropdown-selector + openDropdown(): Chainable> + selectDropdownOption(value: string): void + getActiveDropdownOption(): Chainable> + } +} + +Cypress.Commands.add( + 'login', + (username = 'admin', password = 'password', redirect = true) => { + // first request to get the XSRF cookie + cy.request({ + method: 'GET', + url: '/geonetwork/srv/api/me', + headers: { + Accept: 'application/json, text/plain, */*', + }, + }) + cy.getCookie('XSRF-TOKEN').then((xsrfTokenCookie) => { + cy.request({ + method: 'POST', + url: '/geonetwork/signin', + body: `username=${username}&password=${password}&_csrf=${xsrfTokenCookie.value}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + }) + }) + if (redirect) cy.visit('/') + } +) + +Cypress.Commands.add('signOut', () => { + cy.visit('/geonetwork/srv/eng/catalog.search#/home') + cy.get('a[title="User details"]').click() + cy.get('a[title="Sign out"]').click() +}) + +/** + * This will most likely fail if the user is not logged in! + */ +Cypress.Commands.add('clearFavorites', () => { + cy.request({ + url: '/geonetwork/srv/api/me', + headers: { accept: 'application/json' }, + }) + .its('body') + .its('id') + .as('myId') + + cy.window().then(function () { + cy.request({ + url: `/geonetwork/srv/api/userselections/0/${this.myId}`, + headers: { accept: 'application/json' }, + }) + .its('body') + .as('favoritesId') + }) + + cy.getCookie('XSRF-TOKEN') + .its('value') + .then(function (token) { + const favoritesId = this.favoritesId || [] + cy.request({ + url: `/geonetwork/srv/api/userselections/0/${ + this.myId + }?uuid=${favoritesId.join('&uuid=')}`, + method: 'DELETE', + headers: { accept: 'application/json', 'X-XSRF-TOKEN': token }, + }) + }) +}) + +// previous value should be a component +Cypress.Commands.add( + 'openDropdown', + { prevSubject: true }, + (dropdownElement) => { + cy.get('body').click() // first click on the document to close other dropdowns + const width = dropdownElement.width() + const height = dropdownElement.height() + cy.wrap(dropdownElement).click(width - 10, height / 2) // click on the right size to avoid the label + return cy.get('.cdk-overlay-container').find('[role=listbox]') + } +) + +// previous value should be a component +Cypress.Commands.add( + 'selectDropdownOption', + { prevSubject: true }, + (dropdownElement, value: string) => { + cy.wrap(dropdownElement) + .openDropdown() + .find(`[data-cy-value="${value}"]`) + .click() + } +) + +// previous value should be a component +Cypress.Commands.add( + 'getActiveDropdownOption', + { prevSubject: true }, + (dropdownElement) => { + return cy.wrap(dropdownElement).openDropdown().find(`[data-cy-active]`) + } +) + +// -- 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) => { ... }) diff --git a/tools/e2e/tsconfig.json b/tools/e2e/tsconfig.json new file mode 100644 index 0000000000..1a77b2819a --- /dev/null +++ b/tools/e2e/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "sourceMap": false, + "outDir": "../../dist/out-tsc", + "allowJs": true, + "types": ["cypress", "node"] + }, + "include": ["*.ts", "*.js", "cypress.config.ts"] +}