diff --git a/cypress/integration/origin-save.spec.js b/cypress/integration/origin-save.spec.js index 55690c12..28a00c42 100644 --- a/cypress/integration/origin-save.spec.js +++ b/cypress/integration/origin-save.spec.js @@ -1,294 +1,346 @@ /** * Copyright (C) 2019-2020 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 */ let url; let origin; const $ = Cypress.$; const saveCodeMsg = { 'success': 'The "save code now" request has been accepted and will be processed as soon as possible.', 'warning': 'The "save code now" request has been put in pending state and may be accepted for processing after manual review.', 'rejected': 'The "save code now" request has been rejected because the provided origin url is blacklisted.', 'rateLimit': 'The rate limit for "save code now" requests has been reached. Please try again later.', 'unknownError': 'An unexpected error happened when submitting the "save code now request', 'csrfError': 'CSRF Failed: Referrer checking failed - no Referrer.' }; function makeOriginSaveRequest(originType, originUrl) { cy.get('#swh-input-origin-url') .type(originUrl) .get('#swh-input-visit-type') .select(originType) .get('#swh-save-origin-form') .submit(); } function checkAlertVisible(alertType, msg) { cy.get('#swh-origin-save-request-status') .should('be.visible') .find(`.alert-${alertType}`) .should('be.visible') .and('contain', msg); } // Stub requests to save an origin -function stubSaveRequest(requestUrl, objectType, status, originUrl, taskStatus, - responseStatus = 200, errorMessage = '') { +function stubSaveRequest({ + requestUrl, + visitType = 'git', + saveRequestStatus, + originUrl, + saveTaskStatus, + responseStatus = 200, + errorMessage = '', + saveRequestDate = new Date(), + visitDate = new Date() +} = {}) { let response; if (responseStatus !== 200 && errorMessage) { - response = {'detail': errorMessage}; + response = { + 'detail': errorMessage + }; } else { - response = genOriginSaveResponse(objectType, status, originUrl, Date().toString(), taskStatus); + response = genOriginSaveResponse({visitType: visitType, + saveRequestStatus: saveRequestStatus, + originUrl: originUrl, + saveRequestDate: saveRequestDate, + saveTaskStatus: saveTaskStatus, + visitDate: visitDate}); } cy.route({ method: 'POST', status: responseStatus, url: requestUrl, response: response }).as('saveRequest'); } -// Mocks API response : /save/(:object_type)/(:origin_url) -// object_type : {'git', 'hg', 'svn'} -function genOriginSaveResponse(objectType, saveRequestStatus, originUrl, saveRequestDate, saveTaskStatus, visitDate = Date().toString()) { +// Mocks API response : /save/(:visit_type)/(:origin_url) +// visit_type : {'git', 'hg', 'svn'} +function genOriginSaveResponse({ + visitType = 'git', + saveRequestStatus, + originUrl, + saveRequestDate = new Date(), + saveTaskStatus, + visitDate = new Date() +} = {}) { return { - 'visit_type': objectType, + 'visit_type': visitType, 'save_request_status': saveRequestStatus, 'origin_url': originUrl, 'id': 1, - 'save_request_date': saveRequestDate, + 'save_request_date': saveRequestDate ? saveRequestDate.toISOString() : null, 'save_task_status': saveTaskStatus, - 'visit_date': visitDate + 'visit_date': visitDate ? visitDate.toISOString() : null }; }; describe('Origin Save Tests', function() { before(function() { url = this.Urls.origin_save(); origin = this.origin[0]; this.originSaveUrl = this.Urls.origin_save_request(origin.type, origin.url); }); beforeEach(function() { cy.fixture('origin-save').as('originSaveJSON'); cy.fixture('save-task-info').as('saveTaskInfoJSON'); cy.visit(url); cy.server(); }); it('should display accepted message when accepted', function() { - stubSaveRequest(this.originSaveUrl, origin.type, 'accepted', - origin.url, 'not yet scheduled'); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'accepted', + originUrl: origin.url, + saveTaskStatus: 'not yet scheduled'}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('success', saveCodeMsg['success']); }); }); it('should validate gitlab subproject url', function() { const gitlabSubProjectUrl = 'https://gitlab.com/user/project/sub/'; const originSaveUrl = this.Urls.origin_save_request('git', gitlabSubProjectUrl); - stubSaveRequest(originSaveUrl, 'git', 'accepted', - gitlabSubProjectUrl, 'not yet scheduled'); + + stubSaveRequest({requestUrl: originSaveUrl, + saveRequestStatus: 'accepted', + originurl: gitlabSubProjectUrl, + saveTaskStatus: 'not yet scheduled'}); makeOriginSaveRequest('git', gitlabSubProjectUrl); cy.wait('@saveRequest').then(() => { checkAlertVisible('success', saveCodeMsg['success']); }); }); it('should display warning message when pending', function() { - stubSaveRequest(this.originSaveUrl, origin.type, 'pending', - origin.url, 'not created'); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'pending', + originUrl: origin.url, + saveTaskStatus: 'not created'}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('warning', saveCodeMsg['warning']); }); }); it('should show error when csrf validation failed (status: 403)', function() { - stubSaveRequest(this.originSaveUrl, origin.type, 'rejected', - origin.url, 'not created', 403, saveCodeMsg['csrfError']); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'rejected', + originUrl: origin.url, + saveTaskStatus: 'not created', + responseStatus: 403, + errorMessage: saveCodeMsg['csrfError']}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('danger', saveCodeMsg['csrfError']); }); }); it('should show error when origin is rejected (status: 403)', function() { - stubSaveRequest(this.originSaveUrl, origin.type, 'rejected', - origin.url, 'not created', 403, saveCodeMsg['rejected']); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'rejected', + originUrl: origin.url, + saveTaskStatus: 'not created', + responseStatus: 403, + errorMessage: saveCodeMsg['rejected']}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('danger', saveCodeMsg['rejected']); }); }); it('should show error when rate limited (status: 429)', function() { - stubSaveRequest(this.originSaveUrl, origin.type, - 'Request was throttled. Expected available in 60 seconds.', - origin.url, 'not created', 429); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'Request was throttled. Expected available in 60 seconds.', + originUrl: origin.url, + saveTaskStatus: 'not created', + responseStatus: 429}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('danger', saveCodeMsg['rateLimit']); }); }); it('should show error when unknown error occurs (status other than 200, 403, 429)', function() { - stubSaveRequest(this.originSaveUrl, origin.type, 'Error', - origin.url, 'not created', 406); + stubSaveRequest({requestUrl: this.originSaveUrl, + saveRequestStatus: 'Error', + originUrl: origin.url, + saveTaskStatus: 'not created', + responseStatus: 406}); makeOriginSaveRequest(origin.type, origin.url); cy.wait('@saveRequest').then(() => { checkAlertVisible('danger', saveCodeMsg['unknownError']); }); }); it('should display origin save info in the requests table', function() { cy.route('GET', '/save/requests/list/**', '@originSaveJSON'); cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('tbody tr').then(rows => { let i = 0; for (let row of rows) { const cells = row.cells; const requestDateStr = new Date(this.originSaveJSON.data[i].save_request_date).toLocaleString(); const saveStatus = this.originSaveJSON.data[i].save_task_status; assert.equal($(cells[0]).text(), requestDateStr); assert.equal($(cells[1]).text(), this.originSaveJSON.data[i].visit_type); let html = ''; if (saveStatus === 'succeed') { let browseOriginUrl = `${this.Urls.browse_origin()}?origin_url=${this.originSaveJSON.data[i].origin_url}`; browseOriginUrl += `&timestamp=${encodeURIComponent(this.originSaveJSON.data[i].visit_date)}`; html += `${this.originSaveJSON.data[i].origin_url}`; } else { html += this.originSaveJSON.data[i].origin_url; } html += ` `; html += ''; assert.equal($(cells[2]).html(), html); assert.equal($(cells[3]).text(), this.originSaveJSON.data[i].save_request_status); assert.equal($(cells[4]).text(), saveStatus); ++i; } }); }); it('should not add timestamp to the browse origin URL is no visit date has been found', function() { const originUrl = 'https://git.example.org/example.git'; - const saveRequestData = genOriginSaveResponse('git', 'accepted', originUrl, Date().toString(), 'succeed', null); + const saveRequestData = genOriginSaveResponse({ + saveRequestStatus: 'accepted', + originUrl: originUrl, + saveTaskStatus: 'succeed', + visitDate: null + }); const saveRequestsListData = { 'recordsTotal': 1, 'draw': 2, 'recordsFiltered': 1, 'data': [saveRequestData] }; cy.route('GET', '/save/requests/list/**', saveRequestsListData); cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('tbody tr').then(rows => { const firstRowCells = rows[0].cells; const browseOriginUrl = `${this.Urls.browse_origin()}?origin_url=${originUrl}`; const browseOriginLink = `${originUrl}`; expect($(firstRowCells[2]).html()).to.have.string(browseOriginLink); }); }); it('should display/close task info popover when clicking on the info button', function() { cy.route('GET', '/save/requests/list/**', '@originSaveJSON'); cy.route('GET', '/save/task/info/**', '@saveTaskInfoJSON'); cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-request-info') .eq(0) .click(); cy.get('.swh-save-request-info-popover') .should('be.visible'); cy.get('.swh-save-request-info') .eq(0) .click(); cy.get('.swh-save-request-info-popover') .should('not.be.visible'); }); it('should hide task info popover when clicking on the close button', function() { cy.route('GET', '/save/requests/list/**', '@originSaveJSON'); cy.route('GET', '/save/task/info/**', '@saveTaskInfoJSON'); cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-request-info') .eq(0) .click(); cy.get('.swh-save-request-info-popover') .should('be.visible'); cy.get('.swh-save-request-info-close') .click(); cy.get('.swh-save-request-info-popover') .should('not.be.visible'); }); it('should fill save request form when clicking on "Save again" button', function() { cy.route('GET', '/save/requests/list/**', '@originSaveJSON'); cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-origin-again') .eq(0) .click(); cy.get('tbody tr').eq(0).then(row => { const cells = row[0].cells; cy.get('#swh-input-visit-type') .should('have.value', $(cells[1]).text()); cy.get('#swh-input-origin-url') .should('have.value', $(cells[2]).text().slice(0, -1)); }); }); - it('should select correct origin type if possible when clicking on "Save again" button', function() { + it('should select correct visit type if possible when clicking on "Save again" button', function() { const originUrl = 'https://gitlab.inria.fr/solverstack/maphys/maphys/'; - const badOriginType = 'hg'; - const goodOriginType = 'git'; + const badVisitType = 'hg'; + const goodVisitType = 'git'; cy.route('GET', '/save/requests/list/**', '@originSaveJSON'); - stubSaveRequest(this.Urls.origin_save_request(badOriginType, originUrl), - badOriginType, 'accepted', - originUrl, 'failed', 200, saveCodeMsg['accepted']); + stubSaveRequest({requestUrl: this.Urls.origin_save_request(badVisitType, originUrl), + visitType: badVisitType, + saveRequestStatus: 'accepted', + originUrl: originUrl, + saveTaskStatus: 'failed', + responseStatus: 200, + errorMessage: saveCodeMsg['accepted']}); - makeOriginSaveRequest(badOriginType, originUrl); + makeOriginSaveRequest(badVisitType, originUrl); cy.get('#swh-origin-save-requests-list-tab').click(); cy.wait('@saveRequest').then(() => { cy.get('.swh-save-origin-again') .eq(0) .click(); cy.get('tbody tr').eq(0).then(row => { const cells = row[0].cells; cy.get('#swh-input-visit-type') - .should('have.value', goodOriginType); + .should('have.value', goodVisitType); cy.get('#swh-input-origin-url') .should('have.value', $(cells[2]).text().slice(0, -1)); }); }); }); });