diff --git a/cypress/e2e/add-forge-now-request-create.cy.js b/cypress/e2e/add-forge-now-request-create.cy.js
index e1414ff7..763e463f 100644
--- a/cypress/e2e/add-forge-now-request-create.cy.js
+++ b/cypress/e2e/add-forge-now-request-create.cy.js
@@ -1,258 +1,258 @@
/**
* Copyright (C) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
function populateForm(type, url, contact, email, consent, comment) {
cy.get('#swh-input-forge-type').select(type);
- cy.get('#swh-input-forge-url').clear().type(url, {delay: 0, force: true});
- cy.get('#swh-input-forge-contact-name').clear().type(contact, {delay: 0, force: true});
- cy.get('#swh-input-forge-contact-email').clear().type(email, {delay: 0, force: true});
+ cy.get('#swh-input-forge-url').clear().type(url);
+ cy.get('#swh-input-forge-contact-name').clear().type(contact);
+ cy.get('#swh-input-forge-contact-email').clear().type(email);
if (comment) {
- cy.get('#swh-input-forge-comment').clear().type(comment, {delay: 0, force: true});
+ cy.get('#swh-input-forge-comment').clear().type(comment);
}
cy.get('#swh-input-consent-check').click({force: consent === 'on'});
}
describe('Browse requests list tests', function() {
beforeEach(function() {
this.addForgeNowUrl = this.Urls.forge_add_create();
this.listAddForgeRequestsUrl = this.Urls.add_forge_request_list_datatables();
});
it('should not show user requests filter checkbox for anonymous users', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#swh-add-forge-user-filter').should('not.exist');
});
it('should show user requests filter checkbox for authenticated users', function() {
cy.userLogin();
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#swh-add-forge-user-filter').should('exist').should('be.checked');
});
it('should only display user requests when filter is activated', function() {
// Clean up previous state
cy.task('db:add_forge_now:delete');
// 'user2' logs in and create requests
cy.user2Login();
cy.visit(this.addForgeNowUrl);
// create requests for the user 'user'
populateForm('gitlab', 'gitlab.org', 'admin', 'admin@example.org', 'on', '');
cy.get('#requestCreateForm').submit();
// user requests filter checkbox should be in the DOM
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#swh-add-forge-user-filter').should('exist').should('be.checked');
// check unfiltered user requests
cy.get('tbody tr').then(rows => {
expect(rows.length).to.eq(1);
});
// user1 logout
cy.contains('a', 'logout').click();
// user logs in
cy.userLogin();
cy.visit(this.addForgeNowUrl);
populateForm('gitea', 'gitea.org', 'admin', 'admin@example.org', 'on', '');
cy.get('#requestCreateForm').submit();
populateForm('cgit', 'cgit.org', 'admin', 'admin@example.org', 'on', '');
cy.get('#requestCreateForm').submit();
// user requests filter checkbox should be in the DOM
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#swh-add-forge-user-filter').should('exist').should('be.checked');
// check unfiltered user requests
cy.get('tbody tr').then(rows => {
expect(rows.length).to.eq(2);
});
cy.get('#swh-add-forge-user-filter')
.uncheck({force: true});
// Users now sees everything
cy.get('tbody tr').then(rows => {
expect(rows.length).to.eq(2 + 1);
});
});
});
describe('Test add-forge-request creation', function() {
beforeEach(function() {
this.addForgeNowUrl = this.Urls.forge_add_create();
});
it('should show all the tabs for every user', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-tab')
.should('have.class', 'nav-link');
cy.get('#swh-add-forge-requests-list-tab')
.should('have.class', 'nav-link');
cy.get('#swh-add-forge-requests-help-tab')
.should('have.class', 'nav-link');
});
it('should show create forge tab by default', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-tab')
.should('have.class', 'active');
cy.get('#swh-add-forge-requests-list-tab')
.should('not.have.class', 'active');
});
it('should show login link for anonymous user', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#loginLink')
.should('be.visible')
.should('contain', 'log in');
});
it('should bring back after login', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#loginLink')
.should('have.attr', 'href')
.and('include', `${this.Urls.login()}?next=${this.Urls.forge_add_create()}`);
});
it('should change tabs on click', function() {
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#swh-add-forge-tab')
.should('not.have.class', 'active');
cy.get('#swh-add-forge-requests-list-tab')
.should('have.class', 'active');
cy.get('#swh-add-forge-requests-help-tab')
.should('not.have.class', 'active');
cy.url()
.should('include', `${this.Urls.forge_add_list()}`);
cy.get('#swh-add-forge-requests-help-tab').click();
cy.get('#swh-add-forge-tab')
.should('not.have.class', 'active');
cy.get('#swh-add-forge-requests-list-tab')
.should('not.have.class', 'active');
cy.get('#swh-add-forge-requests-help-tab')
.should('have.class', 'active');
cy.url()
.should('include', `${this.Urls.forge_add_help()}`);
cy.get('#swh-add-forge-tab').click();
cy.get('#swh-add-forge-tab')
.should('have.class', 'active');
cy.get('#swh-add-forge-requests-list-tab')
.should('not.have.class', 'active');
cy.get('#swh-add-forge-requests-help-tab')
.should('not.have.class', 'active');
cy.url()
.should('include', `${this.Urls.forge_add_create()}`);
});
it('should show create form elements to authenticated user', function() {
cy.userLogin();
cy.visit(this.addForgeNowUrl);
cy.get('#swh-input-forge-type')
.should('be.visible');
cy.get('#swh-input-forge-url')
.should('be.visible');
cy.get('#swh-input-forge-contact-name')
.should('be.visible');
cy.get('#swh-input-consent-check')
.should('be.visible');
cy.get('#swh-input-forge-comment')
.should('be.visible');
cy.get('#swh-input-form-submit')
.should('be.visible');
});
it('should show browse requests table for every user', function() {
// testing only for anonymous
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#add-forge-request-browse')
.should('be.visible');
cy.get('#loginLink')
.should('not.exist');
});
it('should update browse list on successful submission', function() {
cy.userLogin();
cy.visit(this.addForgeNowUrl);
populateForm('bitbucket', 'gitlab.com', 'test', 'test@example.com', 'on', 'test comment');
cy.get('#requestCreateForm').submit();
cy.visit(this.addForgeNowUrl);
cy.get('#swh-add-forge-requests-list-tab').click();
cy.get('#add-forge-request-browse')
.should('be.visible')
.should('contain', 'gitlab.com');
cy.get('#add-forge-request-browse')
.should('be.visible')
.should('contain', 'Pending');
});
it('should show error message on conflict', function() {
cy.userLogin();
cy.visit(this.addForgeNowUrl);
populateForm('bitbucket', 'gitlab.com', 'test', 'test@example.com', 'on', 'test comment');
cy.get('#requestCreateForm').submit();
cy.get('#requestCreateForm').submit(); // Submitting the same data again
cy.get('#userMessage')
.should('have.class', 'badge-danger')
.should('contain', 'already exists');
});
it('should show error message', function() {
cy.userLogin();
cy.intercept('POST', `${this.Urls.api_1_add_forge_request_create()}**`,
{
body: {
'exception': 'BadInputExc',
'reason': '{"add-forge-comment": ["This field is required"]}'
},
statusCode: 400
}).as('errorRequest');
cy.visit(this.addForgeNowUrl);
populateForm(
'bitbucket', 'gitlab.com', 'test', 'test@example.com', 'off', 'comment'
);
cy.get('#requestCreateForm').submit();
cy.wait('@errorRequest').then((xhr) => {
cy.get('#userMessage')
.should('have.class', 'badge-danger')
.should('contain', 'field is required');
});
});
});
diff --git a/cypress/e2e/deposit-admin.cy.js b/cypress/e2e/deposit-admin.cy.js
index a79daa4e..5b4c6890 100644
--- a/cypress/e2e/deposit-admin.cy.js
+++ b/cypress/e2e/deposit-admin.cy.js
@@ -1,239 +1,239 @@
/**
* Copyright (C) 2020-2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
// data to use as request query response
let responseDeposits;
let expectedOrigins;
let depositModerationUrl;
let depositListUrl;
const $ = Cypress.$;
describe('Test moderation deposit Login/logout', function() {
before(function() {
depositModerationUrl = this.Urls.admin_deposit();
});
it('should not display deposit moderation link in sidebar when anonymous', function() {
cy.visit(depositModerationUrl);
cy.get(`.sidebar a[href="${depositModerationUrl}"]`)
.should('not.exist');
});
it('should not display deposit moderation link when connected as unprivileged user', function() {
cy.userLogin();
cy.visit(depositModerationUrl);
cy.get(`.sidebar a[href="${depositModerationUrl}"]`)
.should('not.exist');
});
it('should display deposit moderation link in sidebar when connected as privileged user', function() {
cy.depositLogin();
cy.visit(depositModerationUrl);
cy.get(`.sidebar a[href="${depositModerationUrl}"]`)
.should('exist');
});
it('should display deposit moderation link in sidebar when connected as staff member', function() {
cy.adminLogin();
cy.visit(depositModerationUrl);
cy.get(`.sidebar a[href="${depositModerationUrl}"]`)
.should('exist');
});
});
describe('Test admin deposit page', function() {
before(function() {
depositModerationUrl = this.Urls.admin_deposit();
depositListUrl = this.Urls.admin_deposit_list();
});
beforeEach(() => {
responseDeposits = [
{
'id': 614,
'type': 'code',
'external_id': 'ch-de-1',
'reception_date': '2020-05-18T13:48:27Z',
'status': 'done',
'status_detail': null,
'swhid': 'swh:1:dir:ef04a768',
'swhid_context': 'swh:1:dir:ef04a768;origin=https://w.s.o/c-d-1;visit=swh:1:snp:b234be1e;anchor=swh:1:rev:d24a75c9;path=/',
'raw_metadata': 'bar',
'uri': 'https://w.s.o/c-d-1'
},
{
'id': 613,
'type': 'code',
'external_id': 'ch-de-2',
'reception_date': '2020-05-18T11:20:16Z',
'status': 'done',
'status_detail': null,
'swhid': 'swh:1:dir:181417fb',
'swhid_context': 'swh:1:dir:181417fb;origin=https://w.s.o/c-d-2;visit=swh:1:snp:8c32a2ef;anchor=swh:1:rev:3d1eba04;path=/',
'raw_metadata': null,
'uri': 'https://w.s.o/c-d-2'
},
{
'id': 612,
'type': 'code',
'external_id': 'ch-de-3',
'reception_date': '2020-05-18T11:20:16Z',
'status': 'rejected',
'status_detail': 'incomplete deposit!',
'swhid': null,
'swhid_context': null,
'raw_metadata': null,
'uri': null
}
];
// those are computed from the
expectedOrigins = {
614: 'https://w.s.o/c-d-1',
613: 'https://w.s.o/c-d-2',
612: ''
};
});
it('Should properly display entries', function() {
cy.adminLogin();
const testDeposits = responseDeposits;
cy.intercept(`${depositListUrl}**`, {
body: {
'draw': 10,
'recordsTotal': testDeposits.length,
'recordsFiltered': testDeposits.length,
'data': testDeposits
}
}).as('listDeposits');
cy.visit(depositModerationUrl);
cy.location('pathname')
.should('be.equal', depositModerationUrl);
cy.get('#swh-admin-deposit-list')
.should('exist');
cy.wait('@listDeposits').then((xhr) => {
cy.log('response:', xhr.response);
cy.log(xhr.response.body);
const deposits = xhr.response.body.data;
cy.log('Deposits: ', deposits);
expect(deposits.length).to.equal(testDeposits.length);
cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows');
// only 2 entries
cy.get('@rows').each((row, idx, collection) => {
const cells = row[0].cells;
const deposit = deposits[idx];
const responseDeposit = testDeposits[idx];
assert.isNotNull(deposit);
assert.isNotNull(responseDeposit);
expect(deposit.id).to.be.equal(responseDeposit['id']);
expect(deposit.uri).to.be.equal(responseDeposit['uri']);
expect(deposit.type).to.be.equal(responseDeposit['type']);
expect(deposit.external_id).to.be.equal(responseDeposit['external_id']);
expect(deposit.status).to.be.equal(responseDeposit['status']);
expect(deposit.status_detail).to.be.equal(responseDeposit['status_detail']);
expect(deposit.swhid).to.be.equal(responseDeposit['swhid']);
expect(deposit.swhid_context).to.be.equal(responseDeposit['swhid_context']);
const expectedOrigin = expectedOrigins[deposit.id];
// ensure it's in the dom
cy.contains(deposit.id).should('be.visible');
if (deposit.status !== 'rejected') {
expect(row).to.not.contain(deposit.external_id);
cy.contains(expectedOrigin).should('be.visible');
}
if (deposit.uri && deposit.swhid_context) {
let html = `${deposit.uri}`;
html += ` `;
html += '';
expect($(cells[2]).html()).to.contain(html);
} else if (!deposit.uri) {
expect($(cells[2]).text().trim()).to.equal('');
}
cy.contains(deposit.status).should('be.visible');
// those are hidden by default, so now visible
if (deposit.status_detail !== null) {
cy.contains(deposit.status_detail).should('not.exist');
}
// those are hidden by default
if (deposit.swhid !== null) {
cy.contains(deposit.swhid).should('not.exist');
cy.contains(deposit.swhid_context).should('not.exist');
}
if (deposit.raw_metadata !== null) {
cy.get('button.metadata', {withinSubject: row})
.should('exist')
.should('have.text', 'display')
.click({force: true});
cy.get('#swh-web-modal-html code.xml').should('be.visible');
// Dismiss the modal
- cy.get('body').wait(500).type('{esc}');
+ cy.wait(500).get('#swh-web-modal-html .close').click();
cy.get('#swh-web-modal-html code.xml').should('not.be.visible');
} else {
cy.get('button.metadata', {withinSubject: row}).should('not.exist');
cy.get('#swh-web-modal-html code.xml').should('not.be.visible');
}
});
// toggling all links and ensure, the previous checks are inverted
cy.get('a.toggle-col').click({'multiple': true}).then(() => {
cy.get('#swh-admin-deposit-list').find('tbody > tr').as('rows');
cy.get('@rows').each((row, idx, collection) => {
const deposit = deposits[idx];
const expectedOrigin = expectedOrigins[deposit.id];
// ensure it's in the dom
expect(row).to.not.contain(deposit.id);
if (deposit.status !== 'rejected') {
expect(row).to.not.contain(deposit.external_id);
expect(row).to.contain(expectedOrigin);
}
expect(row).to.not.contain(deposit.status);
// those are hidden by default, so now visible
if (deposit.status_detail !== null) {
cy.contains(deposit.status_detail).should('be.visible');
}
// those are hidden by default, so now they should be visible
if (deposit.swhid !== null) {
cy.contains(deposit.swhid).should('be.visible');
cy.contains(deposit.swhid_context).should('be.visible');
// check SWHID link text formatting
cy.contains(deposit.swhid_context).then(elt => {
expect(elt[0].innerHTML).to.equal(deposit.swhid_context.replace(/;/g, ';
'));
});
}
});
});
cy.get('#swh-admin-deposit-list-error')
.should('not.contain',
'An error occurred while retrieving the list of deposits');
});
});
});
diff --git a/cypress/e2e/mailmap.cy.js b/cypress/e2e/mailmap.cy.js
index d9ee1fde..10c350ab 100644
--- a/cypress/e2e/mailmap.cy.js
+++ b/cypress/e2e/mailmap.cy.js
@@ -1,226 +1,226 @@
/**
* Copyright (C) 2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
const $ = Cypress.$;
function fillFormAndSubmitMailmap(fromEmail, displayName, activated) {
if (fromEmail) {
cy.get('#swh-mailmap-from-email')
.clear()
- .type(fromEmail, {delay: 0, force: true});
+ .type(fromEmail);
}
if (displayName) {
cy.get('#swh-mailmap-display-name')
.clear()
- .type(displayName, {delay: 0, force: true});
+ .type(displayName);
}
if (activated) {
cy.get('#swh-mailmap-display-name-activated')
.check({force: true});
} else {
cy.get('#swh-mailmap-display-name-activated')
.uncheck({force: true});
}
cy.get('#swh-mailmap-form-submit')
.click();
}
function addNewMailmap(fromEmail, displayName, activated) {
cy.get('#swh-add-new-mailmap')
.click();
fillFormAndSubmitMailmap(fromEmail, displayName, activated);
}
function updateMailmap(fromEmail, displayName, activated) {
cy.contains('Edit')
.click();
fillFormAndSubmitMailmap(fromEmail, displayName, activated);
}
function checkMailmapRow(fromEmail, displayName, activated,
processed = false, row = 1, nbRows = 1) {
cy.get('tbody tr').then(rows => {
assert.equal(rows.length, 1);
const cells = rows[0].cells;
assert.equal($(cells[0]).text(), fromEmail);
assert.include($(cells[1]).html(), 'mdi-check-bold');
assert.equal($(cells[2]).text(), displayName);
assert.include($(cells[3]).html(), activated ? 'mdi-check-bold' : 'mdi-close-thick');
assert.notEqual($(cells[4]).text(), '');
assert.include($(cells[5]).html(), processed ? 'mdi-check-bold' : 'mdi-close-thick');
});
}
describe('Test mailmap administration', function() {
before(function() {
this.url = this.Urls.admin_mailmap();
});
beforeEach(function() {
cy.task('db:user_mailmap:delete');
cy.intercept('POST', this.Urls.profile_mailmap_add())
.as('mailmapAdd');
cy.intercept('POST', this.Urls.profile_mailmap_update())
.as('mailmapUpdate');
cy.intercept(`${this.Urls.profile_mailmap_list_datatables()}**`)
.as('mailmapList');
});
it('should not display mailmap admin link in sidebar when anonymous', function() {
cy.visit(this.url);
cy.get('.swh-mailmap-admin-item')
.should('not.exist');
});
it('should not display mailmap admin link when connected as unprivileged user', function() {
cy.userLogin();
cy.visit(this.url);
cy.get('.swh-mailmap-admin-item')
.should('not.exist');
});
it('should display mailmap admin link in sidebar when connected as privileged user', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
cy.get('.swh-mailmap-admin-item')
.should('exist');
});
it('should not create a new mailmap when input data are empty', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
addNewMailmap('', '', true);
cy.get('#swh-mailmap-form :invalid').should('exist');
cy.get('#swh-mailmap-form')
.should('be.visible');
});
it('should not create a new mailmap when from email is invalid', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
addNewMailmap('invalid_email', 'display name', true);
cy.get('#swh-mailmap-form :invalid').should('exist');
cy.get('#swh-mailmap-form')
.should('be.visible');
});
it('should create a new mailmap when input data are valid', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
const fromEmail = 'user@example.org';
const displayName = 'New user display name';
addNewMailmap(fromEmail, displayName, true);
cy.wait('@mailmapAdd');
cy.get('#swh-mailmap-form :invalid').should('not.exist');
// ensure table redraw before next check
cy.contains(fromEmail);
cy.get('#swh-mailmap-form')
.should('not.be.visible');
checkMailmapRow(fromEmail, displayName, true);
});
it('should not create a new mailmap for an email already mapped', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
const fromEmail = 'user@example.org';
const displayName = 'New user display name';
addNewMailmap(fromEmail, displayName, true);
cy.wait('@mailmapAdd');
addNewMailmap(fromEmail, displayName, true);
cy.wait('@mailmapAdd');
cy.get('#swh-mailmap-form')
.should('not.be.visible');
cy.contains('Error')
.should('be.visible');
checkMailmapRow(fromEmail, displayName, true);
});
it('should update a mailmap', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
const fromEmail = 'user@example.org';
const displayName = 'New display name';
addNewMailmap(fromEmail, displayName, false);
cy.wait('@mailmapAdd');
cy.get('#swh-mailmap-form :invalid').should('not.exist');
// ensure table redraw before next check
cy.contains(fromEmail);
cy.get('#swh-mailmap-form')
.should('not.be.visible');
checkMailmapRow(fromEmail, displayName, false);
const newDisplayName = 'Updated display name';
updateMailmap('', newDisplayName, true);
cy.wait('@mailmapUpdate');
cy.get('#swh-mailmap-form :invalid').should('not.exist');
// ensure table redraw before next check
cy.contains(fromEmail);
cy.get('#swh-mailmap-form')
.should('not.be.visible');
checkMailmapRow(fromEmail, newDisplayName, true);
});
it('should indicate when a mailmap has been processed', function() {
cy.mailmapAdminLogin();
cy.visit(this.url);
const fromEmail = 'user@example.org';
const displayName = 'New user display name';
addNewMailmap(fromEmail, displayName, true);
cy.wait('@mailmapAdd');
// ensure table redraw before next check
cy.contains(fromEmail);
checkMailmapRow(fromEmail, displayName, true, false);
cy.task('db:user_mailmap:mark_processed');
cy.visit(this.url);
checkMailmapRow(fromEmail, displayName, true, true);
});
});
diff --git a/cypress/e2e/origin-search.cy.js b/cypress/e2e/origin-search.cy.js
index 3e56ca82..d9934c96 100644
--- a/cypress/e2e/origin-search.cy.js
+++ b/cypress/e2e/origin-search.cy.js
@@ -1,653 +1,653 @@
/**
* Copyright (C) 2019-2021 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
const nonExistentText = 'NoMatchExists';
let origin;
let url;
function doSearch(searchText, searchInputElt = '#swh-origins-url-patterns') {
if (searchText.startsWith('swh:')) {
cy.intercept('**/api/1/resolve/**')
.as('swhidResolve');
}
cy.get(searchInputElt)
// to avoid sending too much SWHID validation requests
// as cypress insert character one by one when using type
.invoke('val', searchText.slice(0, -1))
.type(searchText.slice(-1))
.get('.swh-search-icon')
.click({force: true});
if (searchText.startsWith('swh:')) {
cy.wait('@swhidResolve');
}
}
function searchShouldRedirect(searchText, redirectUrl) {
doSearch(searchText);
cy.location('pathname')
.should('equal', redirectUrl);
}
function searchShouldShowNotFound(searchText, msg) {
doSearch(searchText);
if (searchText.startsWith('swh:')) {
cy.get('.invalid-feedback')
.should('be.visible')
.and('contain', msg);
}
}
function stubOriginVisitLatestRequests(status = 200, response = {type: 'tar'}, aliasSuffix = '') {
cy.intercept({url: '**/visit/latest/**'}, {
body: response,
statusCode: status
}).as(`originVisitLatest${aliasSuffix}`);
}
describe('Test origin-search', function() {
before(function() {
origin = this.origin[0];
url = this.Urls.browse_search();
});
beforeEach(function() {
cy.visit(url);
});
it('should have focus on search form after page load', function() {
cy.get('#swh-origins-url-patterns')
.should('have.attr', 'autofocus');
// for some reason, autofocus is not honored when running cypress tests
// while it is in non controlled browsers
// .should('have.focus');
});
it('should redirect to browse when archived URL is searched', function() {
cy.get('#swh-origins-url-patterns')
.type(origin.url);
cy.get('.swh-search-icon')
.click();
cy.location('pathname')
.should('eq', this.Urls.browse_origin_directory());
cy.location('search')
.should('eq', `?origin_url=${origin.url}`);
});
it('should not redirect for non valid URL', function() {
cy.get('#swh-origins-url-patterns')
.type('www.example'); // Invalid URL
cy.get('.swh-search-icon')
.click();
cy.location('pathname')
.should('eq', this.Urls.browse_search()); // Stay in the current page
});
it('should not redirect for valid non archived URL', function() {
cy.get('#swh-origins-url-patterns')
.type('http://eaxmple.com/test/'); // Valid URL, but not archived
cy.get('.swh-search-icon')
.click();
cy.location('pathname')
.should('eq', this.Urls.browse_search()); // Stay in the current page
});
it('should remove origin URL with no archived content', function() {
stubOriginVisitLatestRequests(404);
// Using a non full origin URL here
// This is because T3354 redirects to the origin in case of a valid, archived URL
cy.get('#swh-origins-url-patterns')
.type(origin.url.slice(0, -1));
cy.get('.swh-search-icon')
.click();
cy.wait('@originVisitLatest');
cy.get('#origin-search-results')
.should('be.visible')
.find('tbody tr').should('have.length', 0);
stubOriginVisitLatestRequests(200, {}, '2');
cy.get('.swh-search-icon')
.click();
cy.wait('@originVisitLatest2');
cy.get('#origin-search-results')
.should('be.visible')
.find('tbody tr').should('have.length', 0);
});
it('should filter origins by visit type', function() {
cy.intercept('**/visit/latest/**').as('checkOriginVisits');
cy.get('#swh-origins-url-patterns')
.type('http');
for (const visitType of ['git', 'tar']) {
cy.get('#swh-search-visit-type')
.select(visitType);
cy.get('.swh-search-icon')
.click();
cy.wait('@checkOriginVisits');
cy.get('#origin-search-results')
.should('be.visible');
cy.get('tbody tr td.swh-origin-visit-type').then(elts => {
for (const elt of elts) {
cy.get(elt).should('have.text', visitType);
}
});
}
});
it('should show not found message when no repo matches', function() {
searchShouldShowNotFound(nonExistentText,
'No origins matching the search criteria were found.');
});
it('should add appropriate URL parameters', function() {
// Check all three checkboxes and check if
// correct url params are added
cy.get('#swh-search-origins-with-visit')
.check({force: true})
.get('#swh-filter-empty-visits')
.check({force: true})
.get('#swh-search-origin-metadata')
.check({force: true})
.then(() => {
const searchText = origin.url.slice(0, -1);
doSearch(searchText);
cy.location('search').then(locationSearch => {
const urlParams = new URLSearchParams(locationSearch);
const query = urlParams.get('q');
const withVisit = urlParams.has('with_visit');
const withContent = urlParams.has('with_content');
const searchMetadata = urlParams.has('search_metadata');
assert.strictEqual(query, searchText);
assert.strictEqual(withVisit, true);
assert.strictEqual(withContent, true);
assert.strictEqual(searchMetadata, true);
});
});
});
it('should search in origin intrinsic metadata', function() {
cy.intercept('GET', '**/origin/metadata-search/**').as(
'originMetadataSearch'
);
cy.get('#swh-search-origins-with-visit')
.check({force: true})
.get('#swh-filter-empty-visits')
.check({force: true})
.get('#swh-search-origin-metadata')
.check({force: true})
.then(() => {
const searchText = 'plugin';
doSearch(searchText);
cy.wait('@originMetadataSearch').then((req) => {
expect(req.response.body[0].metadata.metadata.description).to.equal(
'Line numbering plugin for Highlight.js'
// metadata is defined in _TEST_ORIGINS variable in swh/web/tests/data.py
);
});
});
});
it('should not send request to the resolve endpoint', function() {
cy.intercept(`${this.Urls.api_1_resolve_swhid('').slice(0, -1)}**`)
.as('resolveSWHID');
cy.intercept(`${this.Urls.api_1_origin_search(origin.url.slice(0, -1))}**`)
.as('searchOrigin');
cy.get('#swh-origins-url-patterns')
- .type(origin.url.slice(0, -1), {delay: 0, force: true});
+ .type(origin.url.slice(0, -1));
cy.get('.swh-search-icon')
.click();
cy.wait('@searchOrigin');
cy.xhrShouldBeCalled('resolveSWHID', 0);
cy.xhrShouldBeCalled('searchOrigin', 1);
});
it('should add query language support for staff users', function() {
cy.get('#swh-search-use-ql')
.should('not.exist');
cy.adminLogin();
cy.visit(url);
cy.get('#swh-search-use-ql')
.should('exist');
});
it('should show error messages when using the query language', function() {
cy.adminLogin();
cy.visit(url);
cy.intercept('GET', `${this.Urls.api_1_origin_search('**')}**`,
{
body: {
'exception': 'BadInputExc',
'reason': 'Syntax error in search query: Invalid query'
},
statusCode: 400
})
.as('searchOrigin');
cy.get('#swh-search-use-ql')
.should('exist')
.click({force: true}); // Covered by label
cy.get('#swh-origins-url-patterns')
.type('this is not a valid query')
.type('{enter}');
cy.wait('@searchOrigin').then((xhr) => {
cy.get('#swh-no-result')
.should('contain', 'Syntax error in search query');
});
});
function checkSearchHasResults() {
cy.get('.swh-search-icon')
.click();
cy.wait('@checkOriginVisits');
cy.get('#origin-search-results')
.should('be.visible');
cy.get('tbody tr td.swh-origin-visit-type')
.should('exist');
}
it('should search all origins when no pattern is provided', function() {
cy.intercept('**/visit/latest/**').as('checkOriginVisits');
// with default filters
checkSearchHasResults();
// remove filters
cy.get('#swh-search-origins-with-visit')
.uncheck({force: true})
.get('#swh-filter-empty-visits')
.uncheck({force: true});
checkSearchHasResults();
});
it('should search all origins for a visit type', function() {
cy.intercept('**/visit/latest/**').as('checkOriginVisits');
for (const visitType of ['git', 'tar']) {
cy.get('#swh-search-visit-type')
.select(visitType);
checkSearchHasResults();
cy.get('tbody tr td.swh-origin-visit-type').then(elts => {
for (const elt of elts) {
cy.get(elt).should('have.text', visitType);
}
});
}
});
context('Test pagination', function() {
it('should not paginate if there are not many results', function() {
// Setup search
cy.get('#swh-search-origins-with-visit')
.uncheck({force: true})
.get('#swh-filter-empty-visits')
.uncheck({force: true})
.then(() => {
const searchText = 'libtess';
// Get first page of results
doSearch(searchText);
cy.get('.swh-search-result-entry')
.should('have.length', 1);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://github.com/memononen/libtess2');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('have.class', 'disabled');
});
});
it('should paginate forward when there are many results', function() {
stubOriginVisitLatestRequests();
// Setup search
cy.get('#swh-search-origins-with-visit')
.uncheck({force: true})
.get('#swh-filter-empty-visits')
.uncheck({force: true})
.then(() => {
const searchText = 'many.origins';
// Get first page of results
doSearch(searchText);
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 100);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/1');
cy.get('.swh-search-result-entry#origin-99 td a')
.should('have.text', 'https://many.origins/100');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get second page of results
cy.get('#origins-next-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 100);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/101');
cy.get('.swh-search-result-entry#origin-99 td a')
.should('have.text', 'https://many.origins/200');
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get third (and last) page of results
cy.get('#origins-next-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 50);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/201');
cy.get('.swh-search-result-entry#origin-49 td a')
.should('have.text', 'https://many.origins/250');
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('have.class', 'disabled');
});
});
it('should paginate backward from a middle page', function() {
stubOriginVisitLatestRequests();
// Setup search
cy.get('#swh-search-origins-with-visit')
.uncheck({force: true})
.get('#swh-filter-empty-visits')
.uncheck({force: true})
.then(() => {
const searchText = 'many.origins';
// Get first page of results
doSearch(searchText);
cy.wait('@originVisitLatest');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get second page of results
cy.get('#origins-next-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get first page of results again
cy.get('#origins-prev-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 100);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/1');
cy.get('.swh-search-result-entry#origin-99 td a')
.should('have.text', 'https://many.origins/100');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
});
});
it('should paginate backward from the last page', function() {
stubOriginVisitLatestRequests();
// Setup search
cy.get('#swh-search-origins-with-visit')
.uncheck({force: true})
.get('#swh-filter-empty-visits')
.uncheck({force: true})
.then(() => {
const searchText = 'many.origins';
// Get first page of results
doSearch(searchText);
cy.wait('@originVisitLatest');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get second page of results
cy.get('#origins-next-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get third (and last) page of results
cy.get('#origins-next-results-button a')
.click();
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('have.class', 'disabled');
// Get second page of results again
cy.get('#origins-prev-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 100);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/101');
cy.get('.swh-search-result-entry#origin-99 td a')
.should('have.text', 'https://many.origins/200');
cy.get('#origins-prev-results-button')
.should('not.have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
// Get first page of results again
cy.get('#origins-prev-results-button a')
.click();
cy.wait('@originVisitLatest');
cy.get('.swh-search-result-entry')
.should('have.length', 100);
cy.get('.swh-search-result-entry#origin-0 td a')
.should('have.text', 'https://many.origins/1');
cy.get('.swh-search-result-entry#origin-99 td a')
.should('have.text', 'https://many.origins/100');
cy.get('#origins-prev-results-button')
.should('have.class', 'disabled');
cy.get('#origins-next-results-button')
.should('not.have.class', 'disabled');
});
});
});
context('Test valid SWHIDs', function() {
it('should resolve directory', function() {
const redirectUrl = this.Urls.browse_directory(origin.content[0].directory);
const swhid = `swh:1:dir:${origin.content[0].directory}`;
searchShouldRedirect(swhid, redirectUrl);
});
it('should resolve revision', function() {
const redirectUrl = this.Urls.browse_revision(origin.revisions[0]);
const swhid = `swh:1:rev:${origin.revisions[0]}`;
searchShouldRedirect(swhid, redirectUrl);
});
it('should resolve snapshot', function() {
const redirectUrl = this.Urls.browse_snapshot_directory(origin.snapshot);
const swhid = `swh:1:snp:${origin.snapshot}`;
searchShouldRedirect(swhid, redirectUrl);
});
it('should resolve content', function() {
const redirectUrl = this.Urls.browse_content(`sha1_git:${origin.content[0].sha1git}`);
const swhid = `swh:1:cnt:${origin.content[0].sha1git}`;
searchShouldRedirect(swhid, redirectUrl);
});
it('should not send request to the search endpoint', function() {
const swhid = `swh:1:rev:${origin.revisions[0]}`;
cy.intercept(this.Urls.api_1_resolve_swhid(swhid))
.as('resolveSWHID');
cy.intercept(`${this.Urls.api_1_origin_search('').slice(0, -1)}**`)
.as('searchOrigin');
cy.get('#swh-origins-url-patterns')
- .type(swhid, {delay: 0, force: true});
+ .type(swhid);
cy.get('.swh-search-icon')
.click();
cy.wait('@resolveSWHID');
cy.xhrShouldBeCalled('resolveSWHID', 1);
cy.xhrShouldBeCalled('searchOrigin', 0);
});
});
context('Test invalid SWHIDs', function() {
it('should show not found for directory', function() {
const swhid = `swh:1:dir:${this.unarchivedRepo.rootDirectory}`;
const msg = `Directory with sha1_git ${this.unarchivedRepo.rootDirectory} not found`;
searchShouldShowNotFound(swhid, msg);
});
it('should show not found for snapshot', function() {
const swhid = `swh:1:snp:${this.unarchivedRepo.snapshot}`;
const msg = `Snapshot with id ${this.unarchivedRepo.snapshot} not found!`;
searchShouldShowNotFound(swhid, msg);
});
it('should show not found for revision', function() {
const swhid = `swh:1:rev:${this.unarchivedRepo.revision}`;
const msg = `Revision with sha1_git ${this.unarchivedRepo.revision} not found.`;
searchShouldShowNotFound(swhid, msg);
});
it('should show not found for content', function() {
const swhid = `swh:1:cnt:${this.unarchivedRepo.content[0].sha1git}`;
const msg = `Content with sha1_git checksum equals to ${this.unarchivedRepo.content[0].sha1git} not found!`;
searchShouldShowNotFound(swhid, msg);
});
function checkInvalidSWHIDReport(url, searchInputElt, swhidInput, validationMessagePattern = '') {
cy.visit(url);
doSearch(swhidInput, searchInputElt);
cy.get(searchInputElt)
.then($el => $el[0].checkValidity()).should('be.false');
cy.get(searchInputElt)
.invoke('prop', 'validationMessage')
.should('not.equal', '')
.should('contain', validationMessagePattern);
}
it('should report invalid SWHID in search page input', function() {
const swhidInput =
`swh:1:cnt:${this.unarchivedRepo.content[0].sha1git};lines=45-60/`;
checkInvalidSWHIDReport(this.Urls.browse_search(), '#swh-origins-url-patterns', swhidInput);
cy.get('.invalid-feedback')
.should('be.visible');
});
it('should report invalid SWHID in top right search input', function() {
const swhidInput =
`swh:1:cnt:${this.unarchivedRepo.content[0].sha1git};lines=45-60/`;
checkInvalidSWHIDReport(this.Urls.browse_help(), '#swh-origins-search-top-input', swhidInput);
});
it('should report SWHID with uppercase chars in search page input', function() {
const swhidInput =
`swh:1:cnt:${this.unarchivedRepo.content[0].sha1git}`.toUpperCase();
checkInvalidSWHIDReport(this.Urls.browse_search(), '#swh-origins-url-patterns', swhidInput, swhidInput.toLowerCase());
cy.get('.invalid-feedback')
.should('be.visible');
});
it('should report SWHID with uppercase chars in top right search input', function() {
let swhidInput =
`swh:1:cnt:${this.unarchivedRepo.content[0].sha1git}`.toUpperCase();
swhidInput += ';lines=45-60/';
checkInvalidSWHIDReport(this.Urls.browse_help(), '#swh-origins-search-top-input', swhidInput.toLowerCase());
});
});
});
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
index e703ec17..e6d417f8 100644
--- a/cypress/support/e2e.js
+++ b/cypress/support/e2e.js
@@ -1,110 +1,116 @@
/**
* Copyright (C) 2019-2022 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
import 'cypress-hmr-restarter';
import '@cypress/code-coverage/support';
Cypress.Screenshot.defaults({
screenshotOnRunFailure: false
});
Cypress.Commands.add('xhrShouldBeCalled', (alias, timesCalled) => {
const testRoutes = cy.state('routes');
const aliasRoute = Cypress._.find(testRoutes, {alias});
expect(Object.keys(aliasRoute.requests || {})).to.have.length(timesCalled);
});
function loginUser(username, password) {
const url = '/admin/login/';
return cy.request({
url: url,
method: 'GET'
}).then(() => {
cy.getCookie('sessionid').should('not.exist');
cy.getCookie('csrftoken').its('value').then((token) => {
cy.request({
url: url,
method: 'POST',
form: true,
followRedirect: false,
body: {
username: username,
password: password,
csrfmiddlewaretoken: token
}
}).then(() => {
cy.getCookie('sessionid').should('exist');
return cy.getCookie('csrftoken').its('value');
});
});
});
}
Cypress.Commands.add('adminLogin', () => {
return loginUser('admin', 'admin');
});
Cypress.Commands.add('userLogin', () => {
return loginUser('user', 'user');
});
Cypress.Commands.add('user2Login', () => {
return loginUser('user2', 'user2');
});
Cypress.Commands.add('ambassadorLogin', () => {
return loginUser('ambassador', 'ambassador');
});
Cypress.Commands.add('depositLogin', () => {
return loginUser('deposit', 'deposit');
});
Cypress.Commands.add('addForgeModeratorLogin', () => {
return loginUser('add-forge-moderator', 'add-forge-moderator');
});
function mockCostlyRequests() {
cy.intercept('https://status.softwareheritage.org/**', {
body: {
'result': {
'status': [
{
'id': '5f7c4c567f50b304c1e7bd5f',
'name': 'Save Code Now',
'updated': '2020-11-30T13:51:21.151Z',
'status': 'Operational',
'status_code': 100
}
]
}
}}).as('swhPlatformStatus');
cy.intercept('/coverage', {
body: ''
}).as('swhCoverageWidget');
}
Cypress.Commands.add('mailmapAdminLogin', () => {
return loginUser('mailmap-admin', 'mailmap-admin');
});
before(function() {
mockCostlyRequests();
cy.task('getSwhTestsData').then(testsData => {
Object.assign(this, testsData);
});
cy.visit('/').window().then(async win => {
this.Urls = win.Urls;
});
});
beforeEach(function() {
mockCostlyRequests();
});
+
+Cypress.Commands.overwrite('type', (originalFn, subject, text, options = {}) => {
+ options.delay = options.delay || 0;
+ options.force = options.force || true;
+ return originalFn(subject, text, options);
+});