Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit cc06b14

Browse files
feat: add target for cypress e2e tests into BUCK
Co-authored-by: John Obelenus <jobelenus@systeminit.com>
1 parent 6034186 commit cc06b14

File tree

21 files changed

+562
-105
lines changed

21 files changed

+562
-105
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ vendor/automerge
1414
/support/dev/k8s/**/web-htpasswd
1515
/tmp/
1616
deploy/docker-compose.env.yml
17+
app/web/cypress/downloads/
1718
app/web/cypress/screenshots/
1819
app/web/cypress/videos/
1920
bin/si/src/version.txt

app/web/BUCK

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ load(
22
"@prelude-si//:macros.bzl",
33
"docker_image",
44
"eslint",
5+
"e2e_test",
56
"export_file",
67
"package_node_modules",
78
"shellcheck",
@@ -167,3 +168,7 @@ pnpm_task_test(
167168
path = "app/web",
168169
visibility = ["PUBLIC"],
169170
)
171+
172+
e2e_test(
173+
name = "e2e-test",
174+
)

app/web/cypress/e2e/authentication/login.cy.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VITE_SI_CYPRESS_MULTIPLIER : 1, () => {
1+
const SI_CYPRESS_MULTIPLIER = Cypress.env('VITE_SI_CYPRESS_MULTIPLIER') || import.meta.env.VITE_SI_CYPRESS_MULTIPLIER || 1;
2+
const AUTH0_USERNAME = Cypress.env('VITE_AUTH0_USERNAME') || import.meta.env.VITE_AUTH0_USERNAME;
3+
const AUTH0_PASSWORD = Cypress.env('VITE_AUTH0_PASSWORD') || import.meta.env.VITE_AUTH0_PASSWORD;
4+
const AUTH_API_URL = Cypress.env('VITE_AUTH_API_URL') || import.meta.env.VITE_AUTH_API_URL;
5+
const SI_WORKSPACE_ID = Cypress.env('VITE_SI_WORKSPACE_ID') || import.meta.env.VITE_SI_WORKSPACE_ID;
6+
const UUID = Cypress.env('VITE_UUID') || import.meta.env.VITE_UUID || "local";
7+
8+
Cypress._.times(SI_CYPRESS_MULTIPLIER, () => {
29
describe("login", () => {
310
beforeEach(() => {
411
cy.visit("/");
512
});
613

714
it("log_in", () => {
8-
cy.loginToAuth0(import.meta.env.VITE_AUTH0_USERNAME, import.meta.env.VITE_AUTH0_PASSWORD);
9-
cy.visit("/");
10-
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
15+
cy.loginToAuth0(AUTH0_USERNAME, AUTH0_PASSWORD);
16+
cy.visit(AUTH_API_URL + '/workspaces/' + SI_WORKSPACE_ID + '/go');
17+
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", UUID);
1118
// check that you're on head i.e. that you were redirected correctly
12-
cy.url().should("contain", "head");
19+
cy.wait(4000)
20+
cy.url().should("contain", SI_WORKSPACE_ID);
1321
});
1422

1523
});
Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1-
Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VITE_SI_CYPRESS_MULTIPLIER : 1, () => {
1+
const SI_CYPRESS_MULTIPLIER = Cypress.env('VITE_SI_CYPRESS_MULTIPLIER') || import.meta.env.VITE_SI_CYPRESS_MULTIPLIER || 1;
2+
const AUTH0_USERNAME = Cypress.env('VITE_AUTH0_USERNAME') || import.meta.env.VITE_AUTH0_USERNAME;
3+
const AUTH0_PASSWORD = Cypress.env('VITE_AUTH0_PASSWORD') || import.meta.env.VITE_AUTH0_PASSWORD;
4+
const AUTH_PORTAL_URL = Cypress.env('VITE_AUTH_PORTAL_URL') || import.meta.env.VITE_AUTH_PORTAL_URL;
5+
const UUID = Cypress.env('VITE_UUID') || import.meta.env.VITE_UUID || "local";
6+
7+
Cypress._.times(SI_CYPRESS_MULTIPLIER, () => {
28
describe("logout", () => {
39
beforeEach(() => {
410
cy.visit("/");
5-
cy.loginToAuth0(import.meta.env.VITE_AUTH0_USERNAME, import.meta.env.VITE_AUTH0_PASSWORD);
11+
cy.loginToAuth0(AUTH0_USERNAME, AUTH0_PASSWORD);
612
});
713

814
it("log_out", () => {
915
cy.visit("/");
10-
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
11-
cy.contains('Create change set', { timeout: 10000 }).should('be.visible').click();
16+
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", UUID);
17+
cy.contains('Create change set', { timeout: 10000 }).should('be.visible');
18+
cy.get('.modal-close-button').should('exist').click();
1219
cy.get('[aria-label="Profile"]').should('exist').click();
1320
cy.get('#dropdown-menu-item-1').should('exist').should('be.visible').click({ force: true });
1421

1522
// There is a bug currently where you log out of the product & it just logs you out to the dashboard page
1623
// of the UI in auth portal
17-
cy.url().should("contain", import.meta.env.VITE_AUTH_PORTAL_URL + '/dashboard');
18-
24+
cy.url().should("contain", AUTH_PORTAL_URL + '/dashboard');
1925
});
2026
});
21-
});
27+
});
Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,48 @@
11
// @ts-check
22
///<reference path="../global.d.ts"/>
33

4-
Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VITE_SI_CYPRESS_MULTIPLIER : 1, () => {
4+
const SI_CYPRESS_MULTIPLIER = Cypress.env('VITE_SI_CYPRESS_MULTIPLIER') || import.meta.env.VITE_SI_CYPRESS_MULTIPLIER || 1;
5+
const AUTH0_USERNAME = Cypress.env('VITE_AUTH0_USERNAME') || import.meta.env.VITE_AUTH0_USERNAME;
6+
const AUTH0_PASSWORD = Cypress.env('VITE_AUTH0_PASSWORD') || import.meta.env.VITE_AUTH0_PASSWORD;
7+
const AUTH_API_URL = Cypress.env('VITE_AUTH_API_URL') || import.meta.env.VITE_AUTH_API_URL;
8+
const SI_WORKSPACE_ID = Cypress.env('VITE_SI_WORKSPACE_ID') || import.meta.env.VITE_SI_WORKSPACE_ID;
9+
const UUID = Cypress.env('VITE_UUID') || import.meta.env.VITE_UUID || "local";
10+
11+
Cypress._.times(SI_CYPRESS_MULTIPLIER, () => {
512
describe('component', () => {
613
beforeEach(function () {
7-
cy.loginToAuth0(import.meta.env.VITE_AUTH0_USERNAME, import.meta.env.VITE_AUTH0_PASSWORD);
14+
//cy.setupVariables();
15+
cy.loginToAuth0(AUTH0_USERNAME, AUTH0_PASSWORD);
816
});
917

1018
it('create', () => {
11-
cy.visit('/')
12-
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
19+
cy.visit(AUTH_API_URL + '/workspaces/' + SI_WORKSPACE_ID + '/go');
20+
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", UUID);
1321

1422
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', 'Change Set 1');
1523

16-
cy.get('#vorm-input-3').clear().type(import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
24+
cy.get('#vorm-input-3').clear().type(UUID);
1725

18-
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
26+
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', UUID);
1927

2028
cy.contains('Create change set', { timeout: 30000 }).click();
2129

2230
// Give time to redirect onto the new changeset
2331
cy.url().should('not.include', 'head', { timeout: 10000 });
2432

25-
// Find the AWS Credential
26-
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('AWS Credential').should('be.visible').as('awsCred')
33+
// Find the AWS Region
34+
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('Region').as('region');
2735

2836
// Find the canvas to get a location to drag to
2937
cy.get('canvas').first().as('konvaStage');
3038

3139
// drag to the canvas
32-
cy.dragTo('@awsCred', '@konvaStage');
40+
cy.dragTo('@region', '@konvaStage');
41+
42+
cy.wait(5000);
3343

3444
//check to make sure a component has been added to the outliner
35-
cy.get('[class="component-outline-node"]', { timeout: 30000 }).contains('AWS Credential', { timeout: 30000 }).should('be.visible');
45+
cy.get('[class="component-outline-node"]', { timeout: 30000 }).contains('Region', { timeout: 30000 }).should('be.visible');
3646

3747
// Click the button to destroy changeset
3848
cy.get('nav.navbar button.vbutton.--variant-ghost.--size-sm.--tone-action')
@@ -46,7 +56,6 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
4656
cy.get('button.vbutton.--variant-solid.--size-md.--tone-destructive')
4757
.click();
4858

49-
})
50-
})
51-
52-
});
59+
});
60+
});
61+
});
Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
// @ts-check
22
///<reference path="../global.d.ts"/>
33

4-
Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VITE_SI_CYPRESS_MULTIPLIER : 1, () => {
4+
const SI_CYPRESS_MULTIPLIER = Cypress.env('VITE_SI_CYPRESS_MULTIPLIER') || import.meta.env.VITE_SI_CYPRESS_MULTIPLIER || 1;
5+
const AUTH0_USERNAME = Cypress.env('VITE_AUTH0_USERNAME') || import.meta.env.VITE_AUTH0_USERNAME;
6+
const AUTH0_PASSWORD = Cypress.env('VITE_AUTH0_PASSWORD') || import.meta.env.VITE_AUTH0_PASSWORD;
7+
const AUTH_API_URL = Cypress.env('VITE_AUTH_API_URL') || import.meta.env.VITE_AUTH_API_URL;
8+
const SI_WORKSPACE_ID = Cypress.env('VITE_SI_WORKSPACE_ID') || import.meta.env.VITE_SI_WORKSPACE_ID;
9+
const UUID = Cypress.env('VITE_UUID') || import.meta.env.VITE_UUID || "local";
10+
11+
Cypress._.times(SI_CYPRESS_MULTIPLIER, () => {
512
describe('component', () => {
613
beforeEach(function () {
7-
cy.loginToAuth0(import.meta.env.VITE_AUTH0_USERNAME, import.meta.env.VITE_AUTH0_PASSWORD);
14+
cy.loginToAuth0(AUTH0_USERNAME, AUTH0_PASSWORD);
815
});
916

1017
it('delete', () => {
11-
cy.visit('/')
12-
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
18+
cy.visit(AUTH_API_URL + '/workspaces/' + SI_WORKSPACE_ID + '/go');
19+
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", UUID);
1320
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', 'Change Set 1');
1421

15-
cy.get('#vorm-input-3').clear().type(import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
22+
cy.get('#vorm-input-3').clear().type(UUID);
1623

17-
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
24+
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', UUID);
1825

1926
cy.contains('Create change set', { timeout: 30000 }).click();
2027

2128
// Give time to redirect onto the new changeset
2229
cy.url().should('not.include', 'head', { timeout: 10000 });
2330

2431
// Find the AWS Credential
25-
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('AWS Credential').should('be.visible').as('awsCred')
32+
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('AWS Credential').as('awsCred');
2633

2734
// Find the canvas to get a location to drag to
2835
cy.get('canvas').first().as('konvaStage');
@@ -31,8 +38,8 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
3138
cy.dragTo('@awsCred', '@konvaStage');
3239

3340
// Check to make sure a component has been added to the outliner
34-
cy.get('[class="component-outline-node"]', { timeout: 30000 }).
35-
contains('AWS Credential', { timeout: 30000 })
41+
cy.get('[class="component-outline-node"]', { timeout: 30000 })
42+
.contains('AWS Credential', { timeout: 30000 })
3643
.should('be.visible')
3744
.rightclick();
3845

@@ -43,7 +50,7 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
4350
cy.get('button.vbutton.--variant-solid.--size-md.--tone-destructive')
4451
.click();
4552

46-
//check to make sure a component has been added to the outliner
53+
// Check to make sure a component has been added to the outliner
4754
cy.get('[class="component-outline-node"]', { timeout: 30000 }).contains('AWS Credential', { timeout: 30000 }).should('be.visible');
4855

4956
// Click the button to destroy changeset
@@ -58,6 +65,6 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
5865
cy.get('button.vbutton.--variant-solid.--size-md.--tone-destructive')
5966
.click();
6067

61-
})
62-
})
63-
});
68+
});
69+
});
70+
});
Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,107 @@
11
// @ts-check
22
///<reference path="../global.d.ts"/>
33

4-
Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VITE_SI_CYPRESS_MULTIPLIER : 1, () => {
4+
const SI_CYPRESS_MULTIPLIER = Cypress.env('VITE_SI_CYPRESS_MULTIPLIER') || import.meta.env.VITE_SI_CYPRESS_MULTIPLIER || 1;
5+
const AUTH0_USERNAME = Cypress.env('VITE_AUTH0_USERNAME') || import.meta.env.VITE_AUTH0_USERNAME;
6+
const AUTH0_PASSWORD = Cypress.env('VITE_AUTH0_PASSWORD') || import.meta.env.VITE_AUTH0_PASSWORD;
7+
const AUTH_API_URL = Cypress.env('VITE_AUTH_API_URL') || import.meta.env.VITE_AUTH_API_URL;
8+
const SI_WORKSPACE_ID = Cypress.env('VITE_SI_WORKSPACE_ID') || import.meta.env.VITE_SI_WORKSPACE_ID;
9+
const SI_WORKSPACE_URL = Cypress.env('VITE_SI_WORKSPACE_URL') || import.meta.env.VITE_SI_WORKSPACE_URL;
10+
const UUID = Cypress.env('VITE_UUID') || import.meta.env.VITE_UUID || "local";
11+
12+
Cypress._.times(SI_CYPRESS_MULTIPLIER, () => {
513
describe('component', () => {
614
beforeEach(function () {
7-
cy.loginToAuth0(import.meta.env.VITE_AUTH0_USERNAME, import.meta.env.VITE_AUTH0_PASSWORD);
15+
cy.loginToAuth0(AUTH0_USERNAME, AUTH0_PASSWORD);
816
});
917

1018
it('value_propagation', () => {
11-
12-
console.log(import.meta.env.VITE_UUID);
13-
cy.log(import.meta.env.VITE_UUID);
19+
console.log(UUID);
20+
cy.log(UUID);
1421

1522
// Go to the Synthetic Workspace
16-
cy.visit(import.meta.env.VITE_SI_WORKSPACE_URL + '/w/' + import.meta.env.VITE_SI_WORKSPACE_ID + '/head')
17-
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
18-
23+
cy.visit(SI_WORKSPACE_URL + '/w/' + SI_WORKSPACE_ID + '/head');
24+
cy.sendPosthogEvent(Cypress.currentTest.titlePath.join("/"), "test_uuid", UUID);
1925
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', 'Change Set 1');
2026

21-
cy.get('#vorm-input-3').clear().type(import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
27+
cy.get('#vorm-input-3').clear().type(UUID);
2228

23-
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', import.meta.env.VITE_UUID ? import.meta.env.VITE_UUID: "local");
29+
cy.get('#vorm-input-3', { timeout: 30000 }).should('have.value', UUID);
2430

2531
cy.contains('Create change set', { timeout: 30000 }).click();
2632

2733
// Give time to redirect onto the new changeset
2834
cy.url().should('not.include', 'head', { timeout: 10000 });
2935

36+
// Find the AWS Credential
37+
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('Region').as('awsRegion');
38+
39+
// Find the canvas to get a location to drag to
40+
cy.get('canvas').first().as('konvaStage');
41+
42+
cy.intercept('POST', '/api/diagram/create_component').as('componentA');
43+
let componentIDA, componentIDB, bearertoken;
44+
45+
// drag to the canvas
46+
cy.dragTo('@awsRegion', '@konvaStage');
47+
cy.wait('@componentA', {timeout: 60000}).then(async (interception) => {
48+
componentIDA = interception.response?.body.componentId;
49+
});
50+
51+
cy.wait(5000);
52+
53+
cy.get('div[class="tree-node"]', { timeout: 30000 }).contains('EC2 Instance').as('awsEC2');
54+
55+
cy.intercept('POST', '/api/diagram/create_component').as('componentB');
56+
cy.dragTo('@awsEC2', '@konvaStage', 0, 75);
57+
58+
cy.wait('@componentB', {timeout: 60000}).then(async (interception) => {
59+
bearertoken = interception.request.headers.authorization;
60+
componentIDB = interception.response?.body.componentId;
61+
});
62+
63+
// WE CANNOT FORCE A HOVER STATE INSIDE CANVAS
64+
// SO THE "PARENT" IS NOT SET DESPITE COMPONENT B BEING INSIDE THE FRAME
65+
// HACK
66+
cy.url().then(currentUrl => {
67+
const parts = currentUrl.split('/');
68+
parts.pop(); // c
69+
const changeset = parts.pop();
70+
cy.request({
71+
method: 'POST',
72+
url: '/api/diagram/connect_component_to_frame',
73+
body: JSON.stringify({
74+
childId: componentIDB,
75+
parentId: componentIDA,
76+
visibility_change_set_pk: changeset,
77+
workspaceId: SI_WORKSPACE_ID
78+
}),
79+
headers: { Authorization: bearertoken, "Content-Type": 'application/json' }
80+
});
81+
});
82+
83+
cy.wait(2000);
84+
3085
cy.url().then(currentUrl => {
3186
// Construct a new URL with desired query parameters for selecting
3287
// the attribute panel for a known component
3388
let newUrl = new URL(currentUrl);
34-
newUrl.searchParams.set('s', import.meta.env.VITE_SI_PROPAGATION_COMPONENT_A);
89+
newUrl.searchParams.set('s', 'c_'+componentIDA);
3590
newUrl.searchParams.set('t', 'attributes');
3691

3792
// Visit the new URL
93+
console.log(newUrl.href);
3894
cy.visit(newUrl.href);
3995
});
4096

4197
// Give the page a few seconds to load
4298
cy.wait(2000);
4399

44-
// Generate a random number between 1 and 100 to insert into the
45-
// attribute value for Integer
46-
const randomNumber = Math.floor(Math.random() * 100) + 1;
47-
48100
cy.intercept('POST', '/api/component/update_property_editor_value').as('updatePropertyEditorValue');
49101

50102
// Find the attribute for the Integer Input
51-
cy.get('.attributes-panel-item__input-wrap input[type="number"]')
52-
.clear()
53-
.type(randomNumber.toString() + '{enter}') // type the new value
103+
cy.get('.attributes-panel-item__input-wrap select:first')
104+
.select('us-east-1');
54105

55106
// Intercept the API call and alias it
56107
cy.wait('@updatePropertyEditorValue', { timeout: 60000 }).its('response.statusCode').should('eq', 200);
@@ -59,17 +110,17 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
59110
// Construct a new URL with desired query parameters for selecting
60111
// the attribute panel for a known connected component
61112
let newUrl = new URL(currentUrl);
62-
newUrl.searchParams.set('s', import.meta.env.VITE_SI_PROPAGATION_COMPONENT_B);
113+
newUrl.searchParams.set('s', 'c_'+componentIDB);
63114
newUrl.searchParams.set('t', 'attributes');
64115
cy.visit(newUrl.href);
65116
});
66117

67118
// Wait for the values to propagate
68-
cy.wait(60000);
119+
cy.wait(1000);
69120

70-
// Validate that the value has propogated through the system
71-
cy.get('.attributes-panel-item__input-wrap input[type="number"]', { timeout: 30000 })
72-
.should('have.value', randomNumber.toString(), { timeout: 30000 });
121+
// Validate that the value has propagated through the system
122+
cy.get('.attributes-panel-item__input-wrap input.region')
123+
.should('have.value', 'us-east-1');
73124

74125
// Click the button to destroy changeset
75126
cy.get('nav.navbar button.vbutton.--variant-ghost.--size-sm.--tone-action')
@@ -83,6 +134,6 @@ Cypress._.times(import.meta.env.VITE_SI_CYPRESS_MULTIPLIER ? import.meta.env.VIT
83134
cy.get('button.vbutton.--variant-solid.--size-md.--tone-destructive')
84135
.click();
85136

86-
})
87-
})
88-
});
137+
});
138+
});
139+
});

0 commit comments

Comments
 (0)