diff --git a/cypress.config.ts b/cypress.config.ts
new file mode 100644
index 0000000..2547b9b
--- /dev/null
+++ b/cypress.config.ts
@@ -0,0 +1,29 @@
+import { defineConfig } from 'cypress';
+
+// Populate process.env with values from .env file
+require('dotenv').config();
+
+export default defineConfig({
+ projectId: 'cf7icg',
+ env: {
+ googleRefreshToken: process.env.GOOGLE_REFRESH_TOKEN,
+ googleClientId: process.env.GOOGLE_CLIENT_ID,
+ googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
+ },
+
+ e2e: {
+ chromeWebSecurity: false,
+ experimentalSourceRewriting: false,
+ numTestsKeptInMemory: 1,
+ defaultCommandTimeout: 30000,
+ requestTimeout: 30000,
+ responseTimeout: 30000,
+ taskTimeout: 30000,
+ pageLoadTimeout: 30000,
+ screenshotOnRunFailure: true,
+ video: false,
+ viewportHeight: 1080,
+ viewportWidth: 1920,
+ waitForAnimations: true,
+ },
+});
diff --git a/cypress/e2e/e2e.cy.ts b/cypress/e2e/e2e.cy.ts
new file mode 100644
index 0000000..8336e0a
--- /dev/null
+++ b/cypress/e2e/e2e.cy.ts
@@ -0,0 +1,31 @@
+import '../support/commands';
+import '../support/index';
+import user from '../fixtures/user.json';
+
+describe('Deployment User story', function () {
+ beforeEach(function () {
+ cy.OAuthlogin();
+ const localStorageItem = localStorage.getItem('token');
+ if (localStorageItem) {
+ const item = JSON.parse(localStorageItem);
+
+ user.backstageIdentity.token = item.body.access_token;
+ user.backstageIdentity.identity.refreshToken = item.body.refresh_token;
+ user.providerInfo.idToken = item.body.id_token;
+ user.providerInfo.accessToken = item.body.access_token;
+ user.providerInfo.scope = item.body.scope;
+ }
+ });
+
+ it('User should be able to login and deploy an express application to cluster on google cloud', function () {
+ cy.intercept('GET', '**/api/auth/**', req => {
+ req.reply(user);
+ });
+
+ cy.visit('http://localhost:3000/catalog');
+
+ expect(cy.contains('Create')).not.to.be.null;
+
+ cy.contains('Create').click();
+ });
+});
diff --git a/cypress/fixtures/user.json b/cypress/fixtures/user.json
new file mode 100644
index 0000000..2a30cbb
--- /dev/null
+++ b/cypress/fixtures/user.json
@@ -0,0 +1,23 @@
+{
+ "profile": {
+ "email": "user_test@code.berlin",
+ "picture": "https://lh3.googleusercontent.com/a/ACg8ocKSdZA_ZVY7tLtdvoZJZW6Utob_xwLX_mDuN6SUFVQj9yA5nQ=s96-c",
+ "displayName": "User Test"
+ },
+ "providerInfo": {
+ "idToken": "",
+ "accessToken": "",
+ "scope": "",
+ "expiresInSeconds": 100000
+ },
+ "backstageIdentity": {
+ "token": "",
+ "expiresInSeconds": 100000,
+ "identity": {
+ "type": "user",
+ "userEntityRef": "user:default/user_test",
+ "ownershipEntityRefs": ["user:default/user_test"],
+ "refreshToken": "1%2F%2F090g8Mm1yA7mCCgYIARAAGAkSNwF-L9IrmTyVW_yCSVLYROtwsCz4SF-Lk-CS74Kbo3NaM3lOkvqVVYjuJWekFXZchSiD1iIqlw4"
+ }
+ }
+}
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
new file mode 100644
index 0000000..c52bdc5
--- /dev/null
+++ b/cypress/support/commands.ts
@@ -0,0 +1,64 @@
+///
+///
+import jwt from 'jsonwebtoken';
+import user from '../fixtures/user.json';
+
+Cypress.Commands.add('OAuthlogin', () => {
+ Cypress.log({
+ name: 'loginViaAuth0',
+ });
+ const audience = Cypress.env('auth_audience');
+ const client_id = Cypress.env('auth_client_id');
+ const scope = 'openid email profile offline_access';
+
+ const options = {
+ method: 'POST',
+ url: Cypress.env('http://localhost:3000/catalog'),
+ body: {
+ grant_type: 'http://auth0.com/oauth/grant-type/password-realm',
+ realm: 'Username-Password-Authentication',
+ username: 'user_test',
+ password: 'test',
+ audience,
+ scope,
+ client_id,
+ client_secret: Cypress.env('auth_client_secret'),
+ },
+ };
+
+ cy.request('http://localhost:3000/', options).then(({ body }) => {
+ const claims = jwt.decode(body.id_token);
+ const { access_token, id_token, token_type, expires_in, refresh_token } =
+ body;
+
+ const item = {
+ body: {
+ access_token,
+ audience,
+ client_id,
+ id_token,
+ oauthTokenScope: scope,
+ expires_in,
+ refresh_token,
+ scope,
+ token_type,
+ decodedToken: {
+ claims,
+ user: {
+ email: 'user_test@code.berlin',
+ picture:
+ 'https://lh3.googleusercontent.com/a/ACg8ocKSdZA_ZVY7tLtdvoZJZW6Utob_xwLX_mDuN6SUFVQj9yA5nQ=s96-c',
+ displayName: 'User Test',
+ },
+ },
+ },
+ expiresAt: user.backstageIdentity.expiresInSeconds,
+ };
+
+ window.localStorage.setItem('token', JSON.stringify(item));
+ window.localStorage.setItem(
+ '@backstage/core:SignInPage:provider',
+ 'google-auth-provider',
+ );
+ });
+});
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts
new file mode 100644
index 0000000..eca539d
--- /dev/null
+++ b/cypress/support/e2e.ts
@@ -0,0 +1,16 @@
+// ***********************************************************
+// This example support/e2e.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
new file mode 100644
index 0000000..c081e7e
--- /dev/null
+++ b/cypress/support/index.ts
@@ -0,0 +1,7 @@
+///
+
+declare namespace Cypress {
+ interface Chainable {
+ OAuthlogin(): Chainable;
+ }
+}
diff --git a/package.json b/package.json
index 6f1a8d9..3b6685e 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"test": "backstage-cli repo test && playwright test",
"test:all": "backstage-cli repo test --coverage",
"test:e2e": "playwright test",
+ "test:cypress": "cypress run --browser chrome --record --key f55bbed2-731e-4dbc-9a89-e6f69a3edd9a --headed",
"test:no-e2e": "backstage-cli repo test",
"fix": "backstage-cli repo fix",
"lint": "backstage-cli repo lint --since origin/master",
@@ -41,18 +42,24 @@
]
},
"devDependencies": {
+ "@babel/core": "^7.24.5",
+ "@babel/preset-env": "^7.24.5",
"@backstage/cli": "^0.25.1",
"@backstage/e2e-test-utils": "^0.1.0",
"@playwright/test": "^1.32.3",
"@spotify/prettier-config": "^12.0.0",
+ "@testing-library/dom": "^10.1.0",
+ "babel-loader": "^9.1.3",
"canvas": "^2.11.2",
"concurrently": "^8.0.0",
+ "cypress": "^13.9.0",
"jest-canvas-mock": "^2.5.2",
"jsdom": "^24.0.0",
"lerna": "^7.3.0",
"node-gyp": "^10.0.1",
"prettier": "^2.3.2",
- "typescript": "~5.2.0"
+ "ts-loader": "^9.5.1",
+ "typescript": "^5.4.5"
},
"resolutions": {
"@types/react": "^18",
diff --git a/packages/app/package.json b/packages/app/package.json
index 97624b1..4c37250 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -43,6 +43,7 @@
"@circleci/backstage-plugin": "^0.1.1",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
+ "cypress": "^13.9.0",
"history": "^5.0.0",
"react": "^18.0.2",
"react-dom": "^18.0.2",
@@ -75,4 +76,4 @@
"files": [
"dist"
]
-}
+}
\ No newline at end of file