diff --git a/Makefile.local b/Makefile.local --- a/Makefile.local +++ b/Makefile.local @@ -37,7 +37,7 @@ .PHONY: run-migrations-test run-migrations-test: - rm -f swh-web-test.sqlite3 + rm -f swh-web-test*.sqlite3* django-admin migrate --settings=$(SETTINGS_TEST) -v0 add-users-test: run-migrations-test diff --git a/cypress.config.js b/cypress.config.js --- a/cypress.config.js +++ b/cypress.config.js @@ -1,6 +1,7 @@ const {defineConfig} = require('cypress'); module.exports = defineConfig({ + projectId: 'swh-web', video: false, viewportWidth: 1920, viewportHeight: 1080, diff --git a/cypress/e2e/add-forge-now-request-create.cy.js b/cypress/e2e/add-forge-now-request-create.cy.js --- a/cypress/e2e/add-forge-now-request-create.cy.js +++ b/cypress/e2e/add-forge-now-request-create.cy.js @@ -67,10 +67,15 @@ populateForm('cgit', 'https://cgit.org', 'admin', 'admin@example.org', 'on', ''); cy.get('#requestCreateForm').submit(); + cy.intercept(this.Urls.add_forge_request_list_datatables() + '**') + .as('addForgeRequestsList'); + // 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'); + cy.wait('@addForgeRequestsList'); + // check unfiltered user requests cy.get('tbody tr').then(rows => { expect(rows.length).to.eq(2); @@ -79,6 +84,8 @@ cy.get('#swh-add-forge-user-filter') .uncheck({force: true}); + cy.wait('@addForgeRequestsList'); + // Users now sees everything cy.get('tbody tr').then(rows => { expect(rows.length).to.eq(2 + 1); diff --git a/cypress/e2e/admin.cy.js b/cypress/e2e/admin.cy.js --- a/cypress/e2e/admin.cy.js +++ b/cypress/e2e/admin.cy.js @@ -226,6 +226,9 @@ const originUrl = `https://example.org/${Date.now()}`; const rejectionNote = 'The provided URL does not target a git repository.'; + const rejectUrl = this.Urls.admin_origin_save_request_reject('git', originUrl); + cy.intercept('POST', rejectUrl).as('rejectSaveRequest'); + // anonymous user creates a request put in pending state cy.visit(this.Urls.origin_save()); @@ -257,6 +260,8 @@ cy.get('#swh-web-modal-confirm-ok-btn') .click(); + cy.wait('@rejectSaveRequest'); + // checks rejection note has been saved to swh-web database cy.request(this.Urls.api_1_save_origin('git', originUrl)) .then(response => { diff --git a/cypress/e2e/origin-save.cy.js b/cypress/e2e/origin-save.cy.js --- a/cypress/e2e/origin-save.cy.js +++ b/cypress/e2e/origin-save.cy.js @@ -98,6 +98,15 @@ }; }; +function loadSaveRequestsListPage() { + // click on tab to visit requests list page + cy.get('#swh-origin-save-requests-list-tab').click(); + // two XHR requests are sent by datatables when initializing requests table + cy.wait(['@saveRequestsList', '@saveRequestsList']); + // ensure datatable got rendered + cy.wait(100); +} + describe('Origin Save Tests', function() { before(function() { url = this.Urls.origin_save(); @@ -277,8 +286,11 @@ }); it('should display origin save info in the requests table', function() { - cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}); - cy.get('#swh-origin-save-requests-list-tab').click(); + cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}) + .as('saveRequestsList'); + + loadSaveRequestsListPage(); + cy.get('tbody tr').then(rows => { let i = 0; for (const row of rows) { @@ -320,10 +332,12 @@ 'recordsFiltered': 1, 'data': [saveRequestData] }; + cy.intercept('/save/requests/list/**', {body: saveRequestsListData}) .as('saveRequestsList'); - cy.get('#swh-origin-save-requests-list-tab').click(); - cy.wait('@saveRequestsList'); + + loadSaveRequestsListPage(); + cy.get('tbody tr').then(rows => { const firstRowCells = rows[0].cells; const browseOriginUrl = `${this.Urls.browse_origin()}?origin_url=${encodeURIComponent(originUrl)}`; @@ -349,8 +363,9 @@ }; cy.intercept('/save/requests/list/**', {body: saveRequestsListData}) .as('saveRequestsList'); - cy.get('#swh-origin-save-requests-list-tab').click(); - cy.wait('@saveRequestsList'); + + loadSaveRequestsListPage(); + cy.get('tbody tr').then(rows => { const firstRowCells = rows[0].cells; const tooltip = 'origin was successfully loaded, waiting for data to be available in database'; @@ -360,14 +375,18 @@ }); it('should display/close task info popover when clicking on the info button', function() { - cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}); - cy.intercept('/save/task/info/**', {fixture: 'save-task-info'}); + cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}) + .as('saveRequestsList'); + cy.intercept('/save/task/info/**', {fixture: 'save-task-info'}) + .as('saveTaskInfo'); + + loadSaveRequestsListPage(); - cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-request-info') .eq(0) .click(); + cy.wait('@saveTaskInfo'); cy.get('.swh-save-request-info-popover') .should('be.visible'); @@ -380,14 +399,18 @@ }); it('should hide task info popover when clicking on the close button', function() { - cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}); - cy.intercept('/save/task/info/**', {fixture: 'save-task-info'}); + cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}) + .as('saveRequestsList'); + cy.intercept('/save/task/info/**', {fixture: 'save-task-info'}) + .as('saveTaskInfo'); + + loadSaveRequestsListPage(); - cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-request-info') .eq(0) .click(); + cy.wait('@saveTaskInfo'); cy.get('.swh-save-request-info-popover') .should('be.visible'); @@ -399,9 +422,11 @@ }); it('should fill save request form when clicking on "Save again" button', function() { - cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}); + cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}) + .as('saveRequestsList'); + + loadSaveRequestsListPage(); - cy.get('#swh-origin-save-requests-list-tab').click(); cy.get('.swh-save-origin-again') .eq(0) .click(); @@ -419,7 +444,8 @@ const originUrl = 'https://gitlab.inria.fr/solverstack/maphys/maphys/'; const badVisitType = 'hg'; const goodVisitType = 'git'; - cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}); + cy.intercept('/save/requests/list/**', {fixture: 'origin-save'}) + .as('saveRequestsList'); stubSaveRequest({requestUrl: this.Urls.api_1_save_origin(badVisitType, originUrl), visitType: badVisitType, saveRequestStatus: 'accepted', @@ -431,7 +457,8 @@ makeOriginSaveRequest(badVisitType, originUrl); - cy.get('#swh-origin-save-requests-list-tab').click(); + loadSaveRequestsListPage(); + cy.wait('@saveRequest').then(() => { cy.get('.swh-save-origin-again') .eq(0) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -10,6 +10,11 @@ const fs = require('fs'); const sqlite3 = require('sqlite3').verbose(); +let buildId = process.env.CYPRESS_PARALLEL_BUILD_ID; +if (buildId === undefined) { + buildId = ''; +} + async function httpGet(url) { const response = await axios.get(url); return response.data; @@ -35,7 +40,7 @@ }; function getDatabase() { - const db = new sqlite3.Database('./swh-web-test.sqlite3'); + const db = new sqlite3.Database(`./swh-web-test${buildId}.sqlite3`); // to prevent "database is locked" error when running tests db.run('PRAGMA journal_mode = WAL;'); return db; diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.7.1", + "cy2": "^2.0.0", "cypress": "^10.6.0", "cypress-hmr-restarter": "^2.0.3", "cypress-multi-reporters": "^1.6.1", @@ -170,4 +171,4 @@ "engines": { "node": ">=14.0.0" } -} \ No newline at end of file +} diff --git a/swh/web/settings/tests.py b/swh/web/settings/tests.py --- a/swh/web/settings/tests.py +++ b/swh/web/settings/tests.py @@ -126,8 +126,12 @@ ) # using sqlite3 for frontend tests + build_id = os.environ.get("CYPRESS_PARALLEL_BUILD_ID", "") settings.DATABASES["default"].update( - {"ENGINE": "django.db.backends.sqlite3", "NAME": "swh-web-test.sqlite3"} + { + "ENGINE": "django.db.backends.sqlite3", + "NAME": f"swh-web-test{build_id}.sqlite3", + } ) # to prevent "database is locked" error when running cypress tests diff --git a/yarn.lock b/yarn.lock --- a/yarn.lock +++ b/yarn.lock @@ -2761,7 +2761,7 @@ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commander@^2.19.0, commander@^2.20.0: +commander@^2.19.0, commander@^2.20.0, commander@^2.9.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -3074,6 +3074,15 @@ dependencies: cssom "~0.3.6" +cy2@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cy2/-/cy2-2.0.0.tgz#c4697c62c939375966ab1f5ec3872a59d8f1c82f" + integrity sha512-Vo2fMKda/XzEGt4yPsYzpuXscCe031dwZ2LcTo3FFTS4BZ4dzHdRFrSEG/sPARDUJMryEqc/55qkmgIOR/WRZQ== + dependencies: + debug "^4.3.2" + js-yaml "^4.0.0" + npm-which "^3.0.1" + cypress-hmr-restarter@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/cypress-hmr-restarter/-/cypress-hmr-restarter-2.0.3.tgz#63220e372c0660d89472887b54b0feccf05d398b" @@ -6345,7 +6354,7 @@ argparse "^1.0.7" esprima "^4.0.0" -js-yaml@4.1.0, js-yaml@^4.1.0: +js-yaml@4.1.0, js-yaml@^4.0.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -7356,6 +7365,13 @@ jsdom "^16.6.0" marked "^4.0.10" +npm-path@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/npm-path/-/npm-path-2.0.4.tgz#c641347a5ff9d6a09e4d9bce5580c4f505278e64" + integrity sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw== + dependencies: + which "^1.2.10" + npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -7363,6 +7379,15 @@ dependencies: path-key "^3.0.0" +npm-which@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" + integrity sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A== + dependencies: + commander "^2.9.0" + npm-path "^2.0.2" + which "^1.2.10" + npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -10213,7 +10238,7 @@ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.3.1: +which@^1.2.10, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==