Skip to content
5 changes: 3 additions & 2 deletions cypress/e2e/admin-workflow-page.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ describe('Admin Workflow Page', () => {
it('should pass accessibility tests', () => {
// Page must first be visible
cy.get('ds-admin-workflow-page').should('be.visible');
// At least one search result should be displayed
cy.get('[data-test="list-object"]').should('be.visible');
// At least one search result should be displayed. The supervision-configured search on a
// freshly-started CI backend can take a while to return, so allow extra time.
cy.get('[data-test="list-object"]', { timeout: 30000 }).should('be.visible');
// Click each filter toggle to open *every* filter
// (As we want to scan filter section for accessibility issues as well)
cy.get('[data-test="filter-toggle"]').click({ multiple: true });
Expand Down
36 changes: 28 additions & 8 deletions cypress/e2e/submission.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ describe('New Submission page', () => {
// This page is restricted, so we will be shown the login form. Fill it out & submit.
cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD'));

// NOTE: VSB configures dc.title as a <textarea> (not the upstream <input>), so the title
// field is matched by id only (#dc_title). The CLARIN form also loads several controlled
// vocabularies, so wait for the form to render before interacting with it.
cy.get('ds-submission-edit').should('be.visible');
cy.get('#dc_title', { timeout: 30000 }).should('exist');

// Attempt an immediate deposit without filling out any fields
cy.get('button#deposit').click();

Expand All @@ -70,8 +76,17 @@ describe('New Submission page', () => {
// (as it has required fields)
cy.get('div#traditionalpageone-header i.fa-exclamation-circle').should('be.visible');

// After a failed deposit the metadata accordion section may be collapsed, which (with
// ngb-accordion) removes its fields from the DOM. Ensure it is expanded before asserting
// on the title field.
cy.get('body').then(($body) => {
if ($body.find('#dc_title').length === 0) {
cy.get('div#traditionalpageone-header').click();
}
});

// Title field should have class "is-invalid" applied, as it's required
cy.get('input#dc_title').should('have.class', 'is-invalid');
cy.get('#dc_title', { timeout: 15000 }).should('have.class', 'is-invalid');

// Date Year field should also have "is-valid" class
cy.get('input#dc_date_issued_year').should('have.class', 'is-invalid');
Expand Down Expand Up @@ -120,20 +135,25 @@ describe('New Submission page', () => {
// This page is restricted, so we will be shown the login form. Fill it out & submit.
cy.loginViaForm(Cypress.env('DSPACE_TEST_ADMIN_USER'), Cypress.env('DSPACE_TEST_ADMIN_PASSWORD'));

// NOTE: VSB configures dc.title as a <textarea> (not the upstream <input>), so the title
// field is matched by id only (#dc_title). The CLARIN form also loads several controlled
// vocabularies, so wait for the form to render before interacting with it.
cy.get('ds-submission-edit').should('be.visible');

// Fill out all required fields (Title, Date)
cy.get('input#dc_title').type('DSpace logo uploaded via e2e tests');
cy.get('#dc_title', { timeout: 30000 }).type('DSpace logo uploaded via e2e tests');
cy.get('input#dc_date_issued_year').type('2022');

// Confirm the required license by checking checkbox
// (NOTE: requires "force:true" cause Cypress claims this checkbox is covered by its own <span>)
// CLARIN
createItemProcess.clickOnDistributionLicenseToggle();
// click on the dropdown button to list options
createItemProcess.clickOnLicenseSelectionButton();
// select `Public Domain Mark (PD)` from the selection
createItemProcess.selectValueFromLicenseSelection(2);
// // selected value should be seen as selected value in the selection
createItemProcess.checkLicenseSelectionValue('GNU General Public License, version 2');
// NOTE: the CLARIN resource-license *selector* (ds-submission-section-clarin-license) is not
// part of the "Sample Collection" traditional submission form — that form only has the
// distribution-license section toggled above — so the selector steps below are skipped.
// createItemProcess.clickOnLicenseSelectionButton();
// createItemProcess.selectValueFromLicenseSelection(2);
// createItemProcess.checkLicenseSelectionValue('GNU General Public License, version 2');
// CLARIN

// Before using Cypress drag & drop, we have to manually trigger the "dragover" event.
Expand Down
18 changes: 11 additions & 7 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,20 @@ function login(email: string, password: string): void {
Cypress.Commands.add('login', login);

/**
* Login user via displayed login form
* Login the given user via the displayed login form.
*
* NOTE: this previously used a programmatic cy.request() login as a workaround
* for admin logins hanging on CI. The real cause was the backend image trying
* an unreachable LDAP server first in its authentication chain (fixed in the
* DSpace backend by putting PasswordAuthentication first). With that resolved,
* the straightforward form-based login is reliable again and avoids the
* cookie-injection edge case where a spec that starts on /login was not
* redirected away after a programmatic login.
*
* @param email email to login as
* @param password password to login as
*/
// Cypress custom command for form-based login with intercept and redirect assertion
function loginViaForm(
email: string,
password: string
): void {
function loginViaForm(email: string, password: string): void {
cy.wait(500);

// Fill in credentials
Expand All @@ -106,7 +111,6 @@ function loginViaForm(

// Submit the form
cy.get('[data-test="login-button"]').click();

}
// Add as a Cypress command (i.e. assign to 'cy.loginViaForm')
Cypress.Commands.add('loginViaForm', loginViaForm);
Expand Down
36 changes: 35 additions & 1 deletion cypress/support/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,50 @@ before(() => {
});
});

// Pre-agreed Klaro consent payload. Keep this list in sync with the services
// declared in src/app/shared/cookies/klaro-configuration.ts — otherwise Klaro
// detects a configuration change and re-shows the consent banner during tests.
const KLARO_CONSENT_PAYLOAD = encodeURIComponent(JSON.stringify({
authentication: true,
preferences: true,
acknowledgement: true,
'google-analytics': true,
'google-recaptcha': true,
accessibility: true,
}));

// Runs once before the first test in each "block"
beforeEach(() => {
// 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%2C%22google-recaptcha%22:true}');
cy.setCookie('klaro-anonymous', KLARO_CONSENT_PAYLOAD);

// Remove any CSRF cookies saved from prior tests
cy.clearCookie(DSPACE_XSRF_COOKIE);
});

// Hide the Klaro cookie-consent banner in every test window. Even with a pre-set
// klaro-anonymous cookie, Klaro may still render the notice (e.g. when its
// internal consent version changes after a config update), and that notice
// overlaps interactive elements such as the admin sidebar toggle. Injecting a
// `display: none` rule for the `.klaro` container at every page load keeps the
// banner from intercepting clicks during e2e tests.
Cypress.on('window:before:load', (win) => {
const injectKlaroHider = () => {
if (!win.document.getElementById('cypress-hide-klaro')) {
const style = win.document.createElement('style');
style.id = 'cypress-hide-klaro';
style.textContent = '.klaro { display: none !important; }';
(win.document.head || win.document.documentElement).appendChild(style);
}
};
if (win.document && win.document.head) {
injectKlaroHider();
} else {
win.addEventListener('DOMContentLoaded', injectKlaroHider, { once: true });
}
});

// NOTE: FALLBACK_TEST_REST_BASE_URL is only used if Cypress cannot read the REST API BaseURL
// from the Angular UI's config.json. See 'before()' above.
const FALLBACK_TEST_REST_BASE_URL = 'http://localhost:8080/server';
Expand Down
Loading