Skip to content

Commit 5c37184

Browse files
authored
feat: structured file manager (#1423)
## Description ## Linear Ticket ## What type of PR is this? (check all applicable) - [ ] πŸ’‘ (feat) - A new feature (non-breaking change which adds functionality) - [ ] πŸ”„ (refactor) - Code Refactoring - A code change that neither fixes a bug nor adds a feature - [ ] 🐞 (fix) - Bug Fix (non-breaking change which fixes an issue) - [ ] 🏎 (perf) - Optimization - [ ] πŸ“„ (docs) - Documentation - Documentation only changes - [ ] πŸ“„ (test) - Tests - Adding missing tests or correcting existing tests - [ ] βš™οΈ (ci) - Continuous Integrations - Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) - [ ] β˜‘οΈ (chore) - Chores - Other changes that don't modify src or test files - [ ] ↩️ (revert) - Reverts - Reverts a previous commit(s). <!-- For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments. Before submitting a Pull Request, please ensure you've done the following: - πŸ‘·β€β™€οΈ Create small PRs. In most cases this will be possible. - βœ… Provide tests for your changes. - πŸ“ Use descriptive commit messages (as described below). - πŸ“— Update any related documentation and include any relevant screenshots. Commit Message Structure (all lower-case): <type>(optional ticket number): <description> [optional body] -->
1 parent f90ac5f commit 5c37184

File tree

93 files changed

+3329
-744
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+3329
-744
lines changed

β€Ž.gitignoreβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ directory_contents.json
5353
# MCPs
5454
.vscode/mcp.json
5555
.serena/
56+
.taskmaster/
5657

5758
# ACT Run github workflows locally
5859
.vars
5960
.secrets
60-

β€Ž.vscode/settings.jsonβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
"source.fixAll.eslint": "always"
1818
},
1919
"editor.formatOnSave": true,
20+
"window.title": "${rootName}${separator}${activeRepositoryBranchName}${separator}[Branch: ronen/fix/landing]",
2021
"i18n-ally.localesPaths": [
2122
"src/i18n",
2223
"src/locales"
23-
],
24-
"window.title": "${rootName}${separator}${activeRepositoryBranchName}${separator}[Branch: ronen/fix/landing]"
24+
]
2525
}

β€Že2e/fixtures/test-file.txtβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is a test file for E2E testing

β€Že2e/pages/project.tsβ€Ž

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,37 @@ export class ProjectPage {
1414
await this.page.locator('button[aria-label="Project additional actions"]').hover();
1515
await this.page.locator('button[aria-label="Delete project"]').click();
1616
await this.page.locator('button[aria-label="Ok"]').click();
17-
const successToast = await waitForToast(this.page, "Project deletion completed successfully");
18-
await expect(successToast).toBeVisible();
19-
await successToast
20-
.locator("button[aria-label=\"Close 'Project deletion completed successfully' toast\"]")
21-
.click();
17+
18+
let successToast;
19+
try {
20+
successToast = await waitForToast(
21+
this.page,
22+
`Close "Success Project deletion completed successfully" toast`
23+
);
24+
if (await successToast.isVisible()) {
25+
await successToast
26+
.locator("button[aria-label=\"Close 'Project deletion completed successfully' toast\"]")
27+
.click();
28+
} else {
29+
// eslint-disable-next-line no-console
30+
console.warn("Success toast was found but is not visible. Continuing test without closing toast.");
31+
}
32+
} catch (error) {
33+
// eslint-disable-next-line no-console
34+
console.warn(
35+
`Success toast not found: ${error instanceof Error ? error.message : String(error)}. Continuing test without closing toast.`
36+
);
37+
}
38+
39+
await this.page.mouse.move(0, 0);
2240

2341
const loaders = this.page.locator(".loader-cycle-disks").all();
2442
const loadersArray = await loaders;
2543
await Promise.all(loadersArray.map((loader) => loader.waitFor({ state: "detached" })));
2644

27-
await expect(successToast).not.toBeVisible({ timeout: 10000 });
45+
if (successToast) {
46+
await expect(successToast).not.toBeVisible({ timeout: 2000 });
47+
}
2848

2949
const deletedProjectNameCell = this.page.getByRole("cell", { name: projectName });
3050

β€Že2e/pages/webhookSession.tsβ€Ž

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { expect, type APIRequestContext, type Page } from "@playwright/test";
22
import randomatic from "randomatic";
33

44
import { DashboardPage } from "./dashboard";
5-
import { waitForToast } from "e2e/utils";
5+
import { createNetworkListeners, logNetworkDiagnostics, waitForToast, type NetworkCapture } from "e2e/utils";
66
import { waitForLoadingOverlayGone } from "e2e/utils/waitForLoadingOverlayToDisappear";
77

88
export class WebhookSessionPage {
@@ -18,27 +18,74 @@ export class WebhookSessionPage {
1818
this.projectName = `test_${randomatic("Aa", 4)}`;
1919
}
2020

21-
async waitForFirstCompletedSession(timeoutMs = 120000) {
22-
await expect(async () => {
23-
const refreshButton = this.page.locator('button[aria-label="Refresh"]');
24-
const isDisabled = await refreshButton.evaluate((element) => (element as HTMLButtonElement).disabled);
21+
async waitForFirstCompletedSession(timeoutMs = 180000) {
22+
const allNetworkData: NetworkCapture[] = [];
23+
let attemptCounter = 0;
24+
let timePassed = 0;
2525

26-
if (!isDisabled) {
27-
await refreshButton.click();
28-
}
29-
30-
const completedSession = await this.page.getByRole("button", { name: "1 Completed" }).isVisible();
31-
32-
expect(completedSession).toBe(true);
33-
34-
return true;
35-
}).toPass({
36-
timeout: timeoutMs,
37-
intervals: [3000],
38-
});
26+
try {
27+
await expect(async () => {
28+
attemptCounter++;
29+
const refreshButton = this.page.locator('button[aria-label="Refresh"]');
30+
const isDisabled = await refreshButton.evaluate((element) => (element as HTMLButtonElement).disabled);
31+
32+
if (!isDisabled) {
33+
const { requests, responses, startListening, stopListening } = createNetworkListeners(this.page);
34+
35+
startListening();
36+
37+
try {
38+
const clickTimestamp = Date.now();
39+
40+
await refreshButton.click();
41+
42+
try {
43+
await Promise.race([
44+
this.page.waitForResponse(() => true, { timeout: 3000 }),
45+
new Promise((resolve) => setTimeout(resolve, 2000)),
46+
]);
47+
} catch (e) {
48+
// eslint-disable-next-line no-console
49+
console.error(
50+
`No response received after ${timePassed} milliseconds, ${attemptCounter} attempt. Error:`,
51+
e
52+
);
53+
timePassed += 3000;
54+
}
55+
56+
await new Promise((resolve) => setTimeout(resolve, 1000));
57+
58+
allNetworkData.push({
59+
attemptNumber: attemptCounter,
60+
clickTimestamp,
61+
requests: [...requests],
62+
responses: [...responses],
63+
});
64+
} finally {
65+
stopListening();
66+
}
67+
}
68+
69+
const completedSessionDeploymentColumn = this.page.getByRole("button", { name: "1 Completed" });
70+
await expect(completedSessionDeploymentColumn).toBeVisible();
71+
await expect(completedSessionDeploymentColumn).toBeEnabled();
72+
await completedSessionDeploymentColumn.click();
73+
74+
const sessionCompletedLog = this.page.getByText("The session has finished with completed state");
75+
await expect(sessionCompletedLog).toBeVisible();
76+
77+
return true;
78+
}).toPass({
79+
timeout: timeoutMs,
80+
intervals: [3000],
81+
});
82+
} catch (error) {
83+
logNetworkDiagnostics(allNetworkData, attemptCounter, error);
84+
throw error;
85+
}
3986
}
4087

41-
async setupProjectAndTriggerSession() {
88+
async setupProjectAndTriggerSession(skipSessionToBeCompleted = false) {
4289
await this.page.goto("/welcome");
4390

4491
try {
@@ -91,7 +138,7 @@ export class WebhookSessionPage {
91138
await expect(toast).toBeVisible();
92139

93140
const response = await this.request.get(webhookUrl, {
94-
timeout: 5000,
141+
timeout: 1000,
95142
});
96143

97144
if (!response.ok()) {
@@ -108,6 +155,8 @@ export class WebhookSessionPage {
108155
const deploymentId = this.page.getByText(/bld_*/);
109156
await expect(deploymentId).toBeVisible();
110157

111-
await this.waitForFirstCompletedSession();
158+
if (!skipSessionToBeCompleted) {
159+
await this.waitForFirstCompletedSession();
160+
}
112161
}
113162
}

0 commit comments

Comments
Β (0)