diff --git a/CHANGELOG.md b/CHANGELOG.md index dd03e53..b1d5725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.0] - 2022-08-25 + +- Added login command for cypress and SSO protected pages + ## [0.6.2] - 2022-08-15 - Added CypressStrictMode diff --git a/cypress.config.ts b/cypress.config.ts index c065935..2395085 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -13,4 +13,13 @@ export default defineConfig({ mochaFile: "dist-tests/test-results/cypress/[hash].xml", outputs: true, }, + env: { + oidcUrl: "https://sso.mastermindzh.tech/realms/public-tests/protocol/openid-connect/token", + oidcClientId: "demo", + oidcClientSecret: "lhlPHFUd3fC1Ky0Uwyb2ssC0XiAFeGGF", + oidcGrantType: "client_credentials", + oidcScope: "openid profile email", + oidcToken: "", + oidcCallbackUrl: "http://localhost:3000/authentication/callback", + }, }); diff --git a/cypress/e2e/tenders.cy.ts b/cypress/e2e/tenders.cy.ts new file mode 100644 index 0000000..753ace1 --- /dev/null +++ b/cypress/e2e/tenders.cy.ts @@ -0,0 +1,13 @@ +describe("Tenders page", () => { + beforeEach(() => { + cy.oidcLogin(); + // you can check that the user is logged in on this page: + cy.visit("http://localhost:3000"); + }); + + it("Should navigate to tenders when clicking on Tenders", () => { + cy.get('[data-testid="nav.tenders"]').click(); + cy.contains("tenders"); + cy.contains("page_count"); + }); +}); diff --git a/cypress/support/auth/commands.ts b/cypress/support/auth/commands.ts new file mode 100644 index 0000000..b63343a --- /dev/null +++ b/cypress/support/auth/commands.ts @@ -0,0 +1,41 @@ +/// +/* eslint-disable camelcase */ +import jwt_decode from "jwt-decode"; +import "./../index"; + +Cypress.Commands.add("oidcLogin", () => { + const options = { + method: "POST", + url: Cypress.env("oidcUrl"), + form: true, + body: { + grant_type: Cypress.env("oidcGrantType"), + client_id: Cypress.env("oidcClientId"), + client_secret: Cypress.env("oidcClientSecret"), + scope: Cypress.env("oidcScope"), + }, + }; + + return cy.request(options).then((response) => { + const { access_token, expires_in, id_token, token_type, scope } = response.body; + const accessTokenPayload = jwt_decode(access_token); + // stub email on the result, as service accounts don't generally have them but we use it in the UI + (accessTokenPayload as any).email = "cypress@e2e.email"; + + window.sessionStorage.setItem( + `oidc.default:${Cypress.env("oidcCallbackUrl")}`, + JSON.stringify({ + tokens: { + accessToken: access_token, + expiresIn: expires_in, + idToken: id_token, + tokenType: token_type, + idTokenPayload: jwt_decode(id_token), + accessTokenPayload, + scope, + }, + }), + ); + return response; + }); +}); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts deleted file mode 100644 index 698b01a..0000000 --- a/cypress/support/commands.ts +++ /dev/null @@ -1,37 +0,0 @@ -/// -// *********************************************** -// This example commands.ts shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) -// -// declare global { -// namespace Cypress { -// interface Chainable { -// login(email: string, password: string): Chainable -// drag(subject: string, options?: Partial): Chainable -// dismiss(subject: string, options?: Partial): Chainable -// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable -// } -// } -// } \ No newline at end of file diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index f80f74f..746ea33 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -14,7 +14,5 @@ // *********************************************************** // Import commands.js using ES2015 syntax: -import './commands' - -// Alternatively you can use CommonJS syntax: -// require('./commands') \ No newline at end of file +import "./index"; +import "./auth/commands"; diff --git a/cypress/support/index.ts b/cypress/support/index.ts new file mode 100644 index 0000000..fdb72fb --- /dev/null +++ b/cypress/support/index.ts @@ -0,0 +1,14 @@ +/* eslint-disable no-unused-vars */ +// load type definitions that come with Cypress module +/// +export {}; +declare global { + namespace Cypress { + interface Chainable { + /** + * Login to the oidc provider + */ + oidcLogin(): Chainable>; + } + } +} diff --git a/package-lock.json b/package-lock.json index cfddb35..77dc302 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-starter-kit", - "version": "0.6.1", + "version": "0.7.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-starter-kit", - "version": "0.6.1", + "version": "0.7.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -32,6 +32,7 @@ "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^14.3.0", "@types/jest": "^28.1.6", + "@types/jwt-decode": "^3.1.0", "@types/luxon": "^3.0.0", "@types/node": "^18.6.1", "@types/react": "^18.0.15", @@ -73,6 +74,7 @@ "jest-junit": "^14.0.0", "jest-resolve": "^27.4.2", "jest-watch-typeahead": "^1.0.0", + "jwt-decode": "^3.1.2", "lint-staged": "^13.0.3", "mini-css-extract-plugin": "^2.6.1", "mocha-junit-reporter": "^2.0.2", @@ -4279,6 +4281,16 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jwt-decode": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz", + "integrity": "sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w==", + "deprecated": "This is a stub types definition. jwt-decode provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "jwt-decode": "*" + } + }, "node_modules/@types/luxon": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.0.tgz", @@ -13992,6 +14004,12 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "dev": true + }, "node_modules/keypress": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", @@ -24254,6 +24272,15 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "@types/jwt-decode": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz", + "integrity": "sha512-tthwik7TKkou3mVnBnvVuHnHElbjtdbM63pdBCbZTirCt3WAdM73Y79mOri7+ljsS99ZVwUFZHLMxJuJnv/z1w==", + "dev": true, + "requires": { + "jwt-decode": "*" + } + }, "@types/luxon": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.0.tgz", @@ -31486,6 +31513,12 @@ "object.assign": "^4.1.2" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "dev": true + }, "keypress": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", diff --git a/package.json b/package.json index a2a7b37..9c53a35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-starter-kit", - "version": "0.6.2", + "version": "0.7.0", "description": "A modern, create-react-app-based, starter kit for React projects", "keywords": [ "react", @@ -67,6 +67,7 @@ "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^14.3.0", "@types/jest": "^28.1.6", + "@types/jwt-decode": "^3.1.0", "@types/luxon": "^3.0.0", "@types/node": "^18.6.1", "@types/react": "^18.0.15", @@ -108,6 +109,7 @@ "jest-junit": "^14.0.0", "jest-resolve": "^27.4.2", "jest-watch-typeahead": "^1.0.0", + "jwt-decode": "^3.1.2", "lint-staged": "^13.0.3", "mini-css-extract-plugin": "^2.6.1", "mocha-junit-reporter": "^2.0.2",