diff --git a/cypress/integration/origin-search.spec.js b/cypress/integration/origin-search.spec.js index 0fe6fd5e..ec6982e6 100644 --- a/cypress/integration/origin-search.spec.js +++ b/cypress/integration/origin-search.spec.js @@ -1,429 +1,429 @@ /** * 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 */ const nonExistentText = 'NoMatchExists'; let origin; let url; function doSearch(searchText) { cy.get('#origins-url-patterns') .type(searchText) .get('.swh-search-icon') .click(); } function searchShouldRedirect(searchText, redirectUrl) { doSearch(searchText); cy.location('pathname') .should('equal', redirectUrl); } function searchShouldShowNotFound(searchText, msg) { doSearch(searchText); cy.get('#swh-no-result') .should('be.visible') .and('contain', msg); } function stubOriginVisitLatestRequests() { cy.server(); cy.route({ method: 'GET', url: '**/visit/latest/**', response: { type: 'tar' } }).as('originVisitLatest'); } describe('Test origin-search', function() { before(function() { origin = this.origin[0]; url = this.Urls.browse_search(); }); beforeEach(function() { cy.visit(url); }); it('should show in result when url is searched', function() { cy.get('#origins-url-patterns') .type(origin.url); cy.get('.swh-search-icon') .click(); cy.get('#origin-search-results') .should('be.visible'); cy.contains('tr', origin.url) .should('be.visible') .find('.swh-visit-status') .find('i') .should('have.class', 'fa-check') .and('have.attr', 'title', - 'Origin has at least one full visit by Software Heritage'); + 'Origin has at least one full visit by Software Heritage'); }); it('should show not found message when no repo matches', function() { searchShouldShowNotFound(nonExistentText, - 'No origins matching the search criteria were found.'); + '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() .get('#swh-filter-empty-visits') .check() .get('#swh-search-origin-metadata') .check() .then(() => { const searchText = origin.url; 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 not send request to the resolve endpoint', function() { cy.server(); cy.route({ method: 'GET', - url: `${this.Urls.api_1_resolve()}**`, + url: `${this.Urls.api_1_resolve()}**` }).as('resolvePid'); cy.route({ method: 'GET', - url: `${this.Urls.api_1_origin_search()}**`, + url: `${this.Urls.api_1_origin_search()}**` }).as('searchOrigin'); cy.get('#origins-url-patterns') .type(origin.url); cy.get('.swh-search-icon') .click(); cy.wait('@searchOrigin'); cy.xhrShouldBeCalled('resolvePid', 0); cy.xhrShouldBeCalled('searchOrigin', 1); }); 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() .get('#swh-filter-empty-visits') .uncheck() .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() .get('#swh-filter-empty-visits') .uncheck() .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() .get('#swh-filter-empty-visits') .uncheck() .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() .get('#swh-filter-empty-visits') .uncheck() .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 persistent ids', function() { it('should resolve directory', function() { const redirectUrl = this.Urls.browse_directory(origin.content[0].directory); const persistentId = `swh:1:dir:${origin.content[0].directory}`; searchShouldRedirect(persistentId, redirectUrl); }); it('should resolve revision', function() { const redirectUrl = this.Urls.browse_revision(origin.revisions[0]); const persistentId = `swh:1:rev:${origin.revisions[0]}`; searchShouldRedirect(persistentId, redirectUrl); }); it('should resolve snapshot', function() { const redirectUrl = this.Urls.browse_snapshot_directory(origin.snapshot); const persistentId = `swh:1:snp:${origin.snapshot}`; searchShouldRedirect(persistentId, redirectUrl); }); it('should resolve content', function() { const redirectUrl = this.Urls.browse_content(`sha1_git:${origin.content[0].sha1git}`); const persistentId = `swh:1:cnt:${origin.content[0].sha1git}`; searchShouldRedirect(persistentId, redirectUrl); }); it('should not send request to the search endpoint', function() { cy.server(); const persistentId = `swh:1:rev:${origin.revisions[0]}`; cy.route({ method: 'GET', - url: `${this.Urls.api_1_resolve()}**`, + url: `${this.Urls.api_1_resolve()}**` }).as('resolvePid'); cy.route({ method: 'GET', - url: `${this.Urls.api_1_origin_search()}**`, + url: `${this.Urls.api_1_origin_search()}**` }).as('searchOrigin'); cy.get('#origins-url-patterns') .type(persistentId); cy.get('.swh-search-icon') .click(); cy.wait('@resolvePid'); cy.xhrShouldBeCalled('resolvePid', 1); cy.xhrShouldBeCalled('searchOrigin', 0); }); }); context('Test invalid persistent ids', function() { it('should show not found for directory', function() { const persistentId = `swh:1:dir:${this.unarchivedRepo.rootDirectory}`; const msg = `Directory with sha1_git ${this.unarchivedRepo.rootDirectory} not found`; searchShouldShowNotFound(persistentId, msg); }); it('should show not found for snapshot', function() { const persistentId = `swh:1:snp:${this.unarchivedRepo.snapshot}`; const msg = `Snapshot with id ${this.unarchivedRepo.snapshot} not found!`; searchShouldShowNotFound(persistentId, msg); }); it('should show not found for revision', function() { const persistentId = `swh:1:rev:${this.unarchivedRepo.revision}`; const msg = `Revision with sha1_git ${this.unarchivedRepo.revision} not found.`; searchShouldShowNotFound(persistentId, msg); }); it('should show not found for content', function() { const persistentId = `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(persistentId, msg); }); }); -}); \ No newline at end of file +}); diff --git a/package.json b/package.json index 904f3416..8755791c 100644 --- a/package.json +++ b/package.json @@ -1,137 +1,137 @@ { "name": "swh-web", "version": "0.0.224", "description": "Static assets management for swh-web", "scripts": { "build-dev": "NODE_ENV=development webpack --config ./swh/web/assets/config/webpack.config.development.js --colors", "build-test": "NODE_ENV=test webpack --config ./swh/web/assets/config/webpack.config.development.js --colors", "start-dev": "NODE_ENV=development nodemon --watch swh/web/api --watch swh/web/browse --watch swh/web/templates --watch swh/web/common --watch swh/web/settings --watch swh/web/assets/config --ext py,html,js --exec \"webpack-dev-server --info=false --config ./swh/web/assets/config/webpack.config.development.js --colors\"", "build": "NODE_ENV=production webpack --config ./swh/web/assets/config/webpack.config.production.js --colors", "mochawesome": "mochawesome-merge cypress/mochawesome/results/*.json > cypress/mochawesome/mochawesome.json && marge -o cypress/mochawesome/report cypress/mochawesome/mochawesome.json", - "eslint": "eslint -c swh/web/assets/config/.eslintrc --fix swh/web/assets/**", + "eslint": "eslint -c swh/web/assets/config/.eslintrc --fix swh/web/assets/** cypress/integration/** cypress/plugins/** cypress/support/**", "preinstall": "npm -v || (SWH_WEB=$PWD && cd /tmp && yarn add npm && cd node_modules/npm && yarn link && cd $SWH_WEB && yarn link npm)", "nyc-report": "nyc report --reporter=lcov" }, "repository": { "type": "git", "url": "https://forge.softwareheritage.org/source/swh-web" }, "author": "The Software Heritage developers", "license": "AGPL-3.0-or-later", "dependencies": { "@babel/runtime-corejs3": "^7.8.3", "@sentry/browser": "^5.11.1", "admin-lte": "^3.0.2", "ansi_up": "^4.0.4", "bootstrap": "^4.4.1", "chosen-js": "^1.8.7", "clipboard": "^2.0.4", "core-js": "^3.6.4", "d3": "^5.15.0", "datatables.net-responsive-bs4": "^2.2.3", "dompurify": "^2.0.7", "font-awesome": "^4.7.0", "highlight.js": "^9.18.0", "highlightjs-line-numbers.js": "^2.7.0", "html-encoder-decoder": "^1.3.8", "iframe-resizer": "^4.2.9", "jquery": "^3.4.1", "js-cookie": "^2.2.1", "js-year-calendar": "^1.0.0-alpha.7", "notebookjs": "^0.4.2", "object-fit-images": "^3.2.4", "octicons": "^8.5.0", "org": "^0.2.0", "pdfjs-dist": "^2.2.228", "popper.js": "^1.16.0", "showdown": "^1.9.1", "typeface-alegreya": "0.0.69", "typeface-alegreya-sans": "^0.0.72", "validate.js": "^0.13.1", "waypoints": "^4.0.1", "whatwg-fetch": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.8.3", "@babel/preset-env": "^7.8.3", "@cypress/code-coverage": "^1.10.4", "autoprefixer": "^9.7.4", "axios": "^0.19.2", "babel-eslint": "^10.0.3", "babel-loader": "^8.0.6", "babel-plugin-istanbul": "^6.0.0", "bootstrap-loader": "^3.0.4", "cache-loader": "^4.1.0", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^5.1.1", "css-loader": "^3.4.2", "cypress": "^3.8.2", "cypress-multi-reporters": "^1.2.3", "ejs": "^3.0.1", "eslint": "^6.8.0", "eslint-loader": "^3.0.3", "eslint-plugin-chai-friendly": "^0.5.0", "eslint-plugin-cypress": "^2.8.1", "eslint-plugin-import": "^2.20.0", "eslint-plugin-node": "^11.0.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", "exports-loader": "^0.7.0", "expose-loader": "^0.7.5", "file-loader": "^5.0.2", "imports-loader": "^0.8.0", "istanbul-lib-coverage": "^3.0.0", "less": "^3.10.3", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^0.9.0", "mocha": "^7.0.0", "mochawesome": "^4.1.0", "mochawesome-merge": "^4.0.0", "mochawesome-report-generator": "^4.1.0", "node-sass": "^4.13.1", "nodemon": "^2.0.2", "nyc": "^15.0.0", "optimize-css-assets-webpack-plugin": "^5.0.3", "postcss-loader": "^3.0.0", "postcss-normalize": "^8.0.1", "postcss-reporter": "^6.0.1", "progress-bar-webpack-plugin": "^2.1.0", "resolve-url-loader": "^3.1.1", "robotstxt-webpack-plugin": "^7.0.0", "sass-loader": "^8.0.2", "schema-utils": "^2.6.4", "script-loader": "^0.7.2", "spdx-expression-parse": "^3.0.0", "style-loader": "^1.1.3", "stylelint": "^13.0.0", "stylelint-config-standard": "^19.0.0", "terser-webpack-plugin": "^2.3.2", "url-loader": "^3.0.0", "webpack": "^4.41.5", "webpack-bundle-tracker": "^0.4.3", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.10.1" }, "browserslist": [ "cover 99.5%", "not dead" ], "postcss": { "plugins": { "autoprefixer": {}, "postcss-normalize": {} } }, "nyc": { "report-dir": "cypress/coverage", "exclude": [ "swh/web/assets/src/bundles/vendors/index.js", "swh/web/assets/src/thirdparty/**/*.js" ] }, "engines": { "node": ">=8.9.0" } }