diff --git a/cypress.config.ts b/cypress.config.ts index 79007a3968c6170b1ccae5e03a57cd5ecae9d2b3..6d85db4b78dfff6f53749b6caff10992b5678356 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -2,14 +2,21 @@ import { defineConfig } from "cypress"; export default defineConfig({ - e2e: { setupNodeEvents(on, config) { // implement node event listeners here + require("ts-node").register({ + project: "tsconfig.json", + }); }, baseUrl: "http://localhost:4200/", - pageLoadTimeout: 8000, + pageLoadTimeout: 16000, viewportWidth: 1500, viewportHeight: 900, + env: { + // protectedRoutes: protectedRoutes, + username: 'admin', + password: 'openslice' + } }, }); diff --git a/cypress/e2e/auth.cy.ts b/cypress/e2e/auth.cy.ts index b0345eeb21dc990df9b1c344d5b2b10ad94fa7b6..606561fc1d0e4c1a9fa6bccecc862b28d04b18b2 100644 --- a/cypress/e2e/auth.cy.ts +++ b/cypress/e2e/auth.cy.ts @@ -1,10 +1,22 @@ describe('user authentication', () => { beforeEach(() => { cy.visit(window.location.origin); + + }) //edit profile bug it('should block unauthenticated user from entering a protected route', () => { - cy.checkProtectedRoutes(); + cy.fixture("routes.json").then((data) => { + cy.log(data.routes); + // cy.wrap(data.routes).as("protectedRoutes"); + for(let route of data.routes) { + cy.intercept(route); + cy.log(route); + cy.visit(route); + cy.location("pathname").should("equal", "/"); + } + }); + }); it('should display login errors when nothing is typed', () => { @@ -39,6 +51,7 @@ describe('user authentication', () => { }); it('should login, logout', () => { + cy.loginPath(':nth-child(2) > .container > .row > :nth-child(2) > a > .btn', '/services'); cy.get('#navbarDropdown2').click(); cy.window().then((win) => { @@ -49,7 +62,7 @@ describe('user authentication', () => { cy.location("pathname").should("equal", "/"); }); - it.skip('forget password should work', () => { + it('forget password should work', () => { cy.get(':nth-child(1) > .nav-link').click(); cy.location("pathname").should("equal", '/services'); cy.get('.btn').should("contain", "Sign In").click(); diff --git a/cypress/fixtures/routes.json b/cypress/fixtures/routes.json new file mode 100644 index 0000000000000000000000000000000000000000..bbbe58893759a74219f77ac07459f2949db2e604 --- /dev/null +++ b/cypress/fixtures/routes.json @@ -0,0 +1,60 @@ +{ + "routes": [ + "resources/resource_catalogs", + "resources/resource_categories", + "resources/resource_categories_update", + "resources/resource_specs", + "resources/resource_spec_update", + "resources/resource_inventory", + "resources/resource_pools", + "resources/resource_pool", + "resources/resource_reservations", + "resources/resource_reservations_calendar", + "resources/resource_reservation_update", + "services/service_catalogs", + "services/service_categories", + "services/service_categories_update", + "services/service_specs", + "services/service_spec_update", + "services/list_nsds", + "services/list_tests", + "services/service_orders", + "services/service_order_checkout", + "services/my_service_orders", + "services/service_orders_calendar", + "services/organizations", + "services/organization_update", + "services/individuals", + "services/individual_update", + "services/service_inventory", + "services/alarms", + "services/action_specs", + "services/action_specs", + "services/action_rules", + "services/action_rule", + "services/service_rule_design", + "testing/service_test_specs", + "testing/service_test_spec", + "testing/service_tests", + "testing/organizations", + "testing/organization_update", + "testing/individuals", + "testing/individual_update", + "products/product_catalogs", + "products/product_catalog_update", + "products/product_categories", + "products/product_category_update", + "products/product_offerings", + "products/product_offering_update", + "products/product_specs", + "products/product_spec_update", + "products/organizations", + "products/organization_update", + "products/individuals", + "products/individual_update", + "/products/individual_update/myuser", + "/testing/individual_update/myuser", + "/services/individual_update/myuser", + "/resources/individual_update/myuser" + ] +} \ No newline at end of file diff --git a/cypress/screenshots/auth.cy.ts/user authentication -- should block unauthenticated user from entering a protected route (failed).png b/cypress/screenshots/auth.cy.ts/user authentication -- should block unauthenticated user from entering a protected route (failed).png index 124174744ad8df08385027dd092c9c75dd7702ee..39627125b131400d361074f3108171aa73198c53 100644 Binary files a/cypress/screenshots/auth.cy.ts/user authentication -- should block unauthenticated user from entering a protected route (failed).png and b/cypress/screenshots/auth.cy.ts/user authentication -- should block unauthenticated user from entering a protected route (failed).png differ diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index ce4b466d11fb847d240aec3f3027baaea08e4a65..05fdab43541fc31fd186f6bbecd7c664414a5396 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -12,25 +12,6 @@ declare namespace Cypress { } } -const protectedRoutes = ['/services/service_catalogs', '/services/service_categories', - '/services/service_specs', '/services/service_spec_update', - '/services/list_nsds', '/services/list_tests', - '/services/service_orders', '/services/service_inventory', - '/services/organizations', '/services/individuals', - '/services/alarms', '/services/action_specs', - '/services/action_rules', '/services/service_order_checkout', - '/services/individual_update/myuser', '/resources/resource_catalogs', - '/resources/resource_categories', '/resources/resource_specs', - '/resources/resource_spec_update', '/resources/resource_inventory', - '/resources/resource_pools', '/resources/resource_reservations', - '/resources/individual_update/myuser', '/testing/service_test_specs', - '/testing/service_tests', '/testing/organizations', '/testing/individuals', - '/testing/individual_update/myuser', '/products/product_catalogs', - '/products/product_categories', '/products/product_offerings', - '/products/product_specs', '/products/organizations', '/products/individuals', - '/products/individual_update/myuser' -]; - Cypress.Commands.add('navigateToServices', (selector) => { cy.get(selector).click(); cy.location("pathname").should("equal", "/services"); @@ -106,8 +87,8 @@ Cypress.Commands.add('authUser', () => { cy.origin('https://portal.openslice.eu', () => { cy.location("pathname").should("equal", "/auth/realms/openslice/protocol/openid-connect/auth"); - cy.get('#username').type('admin'); - cy.get('#password').type('openslice'); + cy.get('#username').type(Cypress.env('username')); + cy.get('#password').type(Cypress.env('password')); cy.get('#kc-login').click(); }); //redirect page @@ -138,7 +119,7 @@ Cypress.Commands.add('manageEntities', (selector, button, scndIndx, numOfItems) }) Cypress.Commands.add('checkProtectedRoutes', () => { - for(let route of protectedRoutes) { + for(let route of Cypress.env('protectedRoutes')) { cy.intercept(route); cy.log(route); cy.visit(route); diff --git a/cypress/support/protected.routes.ts b/cypress/support/protected.routes.ts deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/package-lock.json b/package-lock.json index d9a07562b5d2b0ee18478af7eec8a406048c3c09..c23db8b0d7bd5ec3b9b7a714ee7a0207381c1d4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "angular-oauth2-oidc": "~13.0.1", "blockly": "git://github.com/google/blockly.git#6.20210701.0", "bootstrap": "~4.6.0", + "dotenv": "^16.4.7", "jsoneditor": "^9.10.0", "jwt-decode": "~2.2.0", "ngx-markdown": "~13.1.0", @@ -3254,6 +3255,8 @@ }, "node_modules/@types/node": { "version": "12.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", + "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", "dev": true, "license": "MIT" }, @@ -6053,6 +6056,18 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -13531,6 +13546,8 @@ }, "node_modules/ts-node": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", "dev": true, "license": "MIT", "dependencies": { @@ -16834,6 +16851,8 @@ }, "@types/node": { "version": "12.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", + "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", "dev": true }, "@types/parse-json": { @@ -18686,6 +18705,11 @@ "domhandler": "^4.2.0" } }, + "dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==" + }, "dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -23490,6 +23514,8 @@ }, "ts-node": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", "dev": true, "requires": { "arrify": "^1.0.0", diff --git a/package.json b/package.json index f1a122072cd31fd604f83ac846d4857e28f11d7b..b8a6771a83ffbc68be41d090f174236c10f9e753 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,10 @@ "build": "ng build", "test": "ng test", "lint": "ng lint", - "e2e": "ng e2e" + "e2e": "ng e2e", + "extract-paths": "ts-node scripts/extract.paths.ts", + "cypress:open": "npm run extract-paths && cypress open", + "cypress:run": "npm run extract-paths && cypress run" }, "private": true, "dependencies": { @@ -38,6 +41,7 @@ "angular-oauth2-oidc": "~13.0.1", "blockly": "git://github.com/google/blockly.git#6.20210701.0", "bootstrap": "~4.6.0", + "dotenv": "^16.4.7", "jsoneditor": "^9.10.0", "jwt-decode": "~2.2.0", "ngx-markdown": "~13.1.0", diff --git a/scripts/extract.paths.ts b/scripts/extract.paths.ts new file mode 100644 index 0000000000000000000000000000000000000000..a67ee268f23d374d76f7476522425815b209a2b9 --- /dev/null +++ b/scripts/extract.paths.ts @@ -0,0 +1,58 @@ +import { dirname, join } from "path"; +import { writeFileSync, existsSync, mkdirSync, readFileSync } from "fs"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const routesFilePathResources = join(__dirname, "../src/app/app-resources-routing.module.ts"); +const routesFilePathTesting = join(__dirname, "../src/app/app-testing-routing.module.ts"); +const routesFilePathServices = join(__dirname, "../src/app/app-services-routing.module.ts"); +const routesFilePathProducts = join(__dirname, "../src/app/app-products-routing.module.ts"); + +//read route module files as plaintext and extract paths +function extractRoutesFromFile(filePath: string, parent: string): string[] { + try { + const fileContent = readFileSync(filePath, "utf-8"); + + // Regex to match route paths (excluding those with `/:id`) + const pathRegex = /path:\s*['"]([^'":]+)['"]/g; + let match; + const paths: string[] = []; + + while ((match = pathRegex.exec(fileContent)) !== null) { + if (!match[1].includes("/:id")) { + paths.push(`${parent}/${match[1]}`); + } + } + + return paths; + } catch (error) { + console.error(`⌠Error reading file: ${filePath}`, error); + return []; + } +} + +// Extract paths from every file +let resourceRoutesStr = extractRoutesFromFile(routesFilePathResources, "resources"); +let servicesRoutesStr = extractRoutesFromFile(routesFilePathServices, "services"); +let testingRoutesStr = extractRoutesFromFile(routesFilePathTesting, "testing"); +let productRoutesStr = extractRoutesFromFile(routesFilePathProducts, "products"); + +let allRoutes = resourceRoutesStr.concat(servicesRoutesStr, testingRoutesStr, productRoutesStr); +allRoutes.push('/products/individual_update/myuser', '/testing/individual_update/myuser', '/services/individual_update/myuser', '/resources/individual_update/myuser'); +let protectedRoutes: string[] = allRoutes.filter((el) => { return el!='services/services_marketplace' && el!='products/marketplace' + && el!='resources/resources_marketplace'}) + + +// Ensure `cypress/fixtures` directory exists +const fixturesDir = join(__dirname, "../cypress/fixtures"); +if (!existsSync(fixturesDir)) { + mkdirSync(fixturesDir, { recursive: true }); +} + +// Convert extracted routes to JSON and save to file +const jsonOutput = JSON.stringify({ routes: protectedRoutes }, null, 2); +const outputPath = join(fixturesDir, "routes.json"); +writeFileSync(outputPath, jsonOutput, "utf-8"); + +console.log("✅ Routes JSON file generated successfully!");