Skip to content

Add file upload e2e tests and e2e tests docs for AI agents#8404

Open
pa-lem wants to merge 3 commits intorelease-1.8from
ple-upload-test
Open

Add file upload e2e tests and e2e tests docs for AI agents#8404
pa-lem wants to merge 3 commits intorelease-1.8from
ple-upload-test

Conversation

@pa-lem
Copy link
Contributor

@pa-lem pa-lem commented Feb 17, 2026

Summary by CodeRabbit

  • Documentation

    • Added a comprehensive Playwright E2E testing guide with best practices, test structure, selector and assertion priorities, auth presets, running commands, and a quality checklist.
  • Tests

    • Added a file-upload end-to-end test suite covering auth states, multi-file-type uploads, edit/save flows, validation, download, and per-test isolation.
    • Added test utilities to generate deterministic test files and streamline file-upload interactions.

@pa-lem pa-lem requested a review from a team as a code owner February 17, 2026 14:40
@github-actions github-actions bot added the group/frontend Issue related to the frontend (React) label Feb 17, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

Walkthrough

Adds a Playwright E2E testing guide at dev/guides/frontend/writing-e2e-tests.md and registers it in frontend/app/AGENTS.md. Introduces file upload test helpers at frontend/app/tests/e2e/objects/file-upload/file-upload-helpers.ts (upload utilities, test file generation, form filler) and a comprehensive test suite frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts covering branch-per-test-file setup, multiple authentication states (storageState presets), upload/edit/download workflows, validations, and role-based access.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, leaving the template sections unfilled. Provide a complete description following the repository template, including Why, What changed, How to review, How to test, and Impact sections.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding file upload e2e tests and documentation for AI agents.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
frontend/app/tests/e2e/objects/file-upload/file-upload-helpers.ts (2)

36-44: Several TEST_FILE_TYPES entries are defined but never used.

PDF, PNG, JPEG, and CSV are declared but not referenced anywhere in the helpers or tests. If these are for future use, that's fine — just noting it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload-helpers.ts` around
lines 36 - 44, TEST_FILE_TYPES contains unused entries (PDF, PNG, JPEG, CSV);
either remove these unused entries from the TEST_FILE_TYPES constant to keep the
test helpers minimal, or if they are intentionally reserved for future tests,
add a short comment above TEST_FILE_TYPES noting they are intentionally included
for future use. Update the TEST_FILE_TYPES declaration (the constant named
TEST_FILE_TYPES) to reflect the chosen approach so lint/tests no longer flag
unused exports.

46-61: JSDoc says "random content" but the output is deterministic.

The generated content is always the same repeated line for a given size. Consider updating the doc comment to say "Generate test file content of a given size" instead.

📝 Suggested doc fix
-/**
- * Generate a test file with random content
- */
+/**
+ * Generate deterministic test file content of a given size
+ */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload-helpers.ts` around
lines 46 - 61, Update the JSDoc for generateTestFileContent to accurately
describe its behavior: replace "Generate a test file with random content" with
something like "Generate test file content of an approximate size (deterministic
repeated line)"; reference the function name generateTestFileContent and
optionally mention sizes, targetSize, and line to clarify the docstring change
so it no longer claims randomness.
dev/guides/frontend/writing-e2e-tests.md (1)

286-292: Polling example lacks a note about timeout protection.

The while loop has no explicit exit condition beyond the text disappearing. It works because Playwright's test timeout will eventually kill the test, but this isn't mentioned. A reader unfamiliar with the framework may not realize the safeguard, or may copy this pattern into a context without a timeout.

Consider adding a brief note:

 ### Polling for Async Backend Processing
 
+> The test's built-in timeout (60s default, 180s in CI) will terminate the loop if the condition never resolves.
+
 ```typescript
 while (await page.getByText("No activity found").isVisible()) {

Based on learnings: "prefer using the framework's built-in test timeout mechanism (60 seconds default, 180 seconds with CI=true) rather than implementing custom retry counters in polling loops."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev/guides/frontend/writing-e2e-tests.md` around lines 286 - 292, The polling
example uses a bare while loop with page.getByText("No activity
found").isVisible() and page.reload() but lacks any note about relying on
Playwright's built-in test timeout for safety; update the documentation around
this snippet (referencing page.getByText, isVisible, page.reload, and
expect(...).toBeHidden()) to explicitly state that the loop relies on the
framework test timeout (default 60s, 180s in CI) and recommend preferring that
built-in timeout over custom retry counters, or alternatively show how to add an
explicit timeout/abort mechanism if readers need one.
frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts (2)

203-216: Overly broad selector and implicit data dependency make this test fragile.

page.getByRole("link").first() (Line 207) matches any link on the page — navigation, breadcrumbs, etc. — not necessarily a file object link. Additionally, this test silently passes if no link is visible, giving a false green.

Consider scoping the selector to the list container and asserting that at least one item exists:

♻️ Suggested improvement
     await test.step("navigate to an existing file object", async () => {
       await page.goto(`/objects/InfraCircuitContract?branch=${BRANCH_NAME}`);

-      const fileLink = page.getByRole("link").first();
-      if (await fileLink.isVisible()) {
-        await fileLink.click();
-      }
+      const listContainer = page.getByTestId("object-items");
+      const fileLink = listContainer.getByRole("link").first();
+      await expect(fileLink).toBeVisible();
+      await fileLink.click();
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts` around lines
203 - 216, The test "should not be able to edit existing file" uses an overly
broad selector page.getByRole("link").first() and silently skips clicking if no
link is visible; update the test to scope the file link lookup to the file list
container (e.g., a locator like page.getByTestId("file-list") or a
container-specific selector) and then assert that at least one file item exists
before interacting (use an expectation like expect(locator.count() or
locator.first()).toBeGreaterThan(0) / toBeVisible()), then click the scoped
link; keep the final assertion on getByTestId("edit-button") toBeDisabled
unchanged.

29-38: "Not logged in" test silently passes when create button is absent.

If the button isn't rendered at all, the if branch is skipped and the test asserts nothing. Consider asserting a concrete expectation — e.g., that the button is either not visible or disabled:

♻️ Suggested improvement
   test("should not be able to create file object", async ({ page }) => {
     await page.goto(`/objects/InfraCircuitContract?branch=${BRANCH_NAME}`);

-    // Create button should not be visible or enabled
     const createButton = page.getByTestId("create-object-button");
-    if (await createButton.isVisible()) {
-      await expect(createButton).toBeDisabled();
-    }
+    // Button should either be absent or disabled
+    await expect(createButton).not.toBeVisible();
   });

If the UI may render it as disabled instead of hidden, use a conditional with an explicit fallback assertion to ensure the test never silently passes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts` around lines
29 - 38, The test "should not be able to create file object" currently does
nothing when createButton (getByTestId("create-object-button")) is absent;
change it to assert a concrete condition by checking visibility and then
asserting either not visible OR disabled: e.g., evaluate
createButton.isVisible() and assert false if visible then assert
createButton.isDisabled(), so the test fails if the button is present and
enabled; update the assertions in that test body (referencing createButton and
the test name) to guarantee a deterministic expectation instead of a silent
pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts`:
- Around line 8-19: The outer test.describe "File Upload - InfraCircuitContract"
has dependent nested describes but no execution mode set; add a serial
configuration to that describe to enforce ordering (e.g., call
test.describe.configure({ mode: "serial" }) at the top of the describe block
that defines BRANCH_NAME/TEST_FILE_NAME/TEST_FILE_CONTENT) so the Admin-created
data (used by the Read-Only tests) is available when those tests run; update the
describe block containing BRANCH_NAME, TEST_FILE_NAME, TEST_FILE_CONTENT and the
beforeAll/afterAll hooks to include this configuration.
- Around line 249-261: The test currently skips assertions when the download
button is missing because the logic is wrapped in an if check; remove that
conditional and instead assert the button is present/visible (use the test
runner's expect on downloadButton or expect(await
downloadButton.isVisible()).toBeTruthy()) before attempting the download, then
proceed to call page.waitForEvent("download"), click the downloadButton, await
the download, and assert download.suggestedFilename() matches fileName; update
the block around downloadButton, page.waitForEvent, and
download.suggestedFilename to reflect this change.

---

Nitpick comments:
In `@dev/guides/frontend/writing-e2e-tests.md`:
- Around line 286-292: The polling example uses a bare while loop with
page.getByText("No activity found").isVisible() and page.reload() but lacks any
note about relying on Playwright's built-in test timeout for safety; update the
documentation around this snippet (referencing page.getByText, isVisible,
page.reload, and expect(...).toBeHidden()) to explicitly state that the loop
relies on the framework test timeout (default 60s, 180s in CI) and recommend
preferring that built-in timeout over custom retry counters, or alternatively
show how to add an explicit timeout/abort mechanism if readers need one.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload-helpers.ts`:
- Around line 36-44: TEST_FILE_TYPES contains unused entries (PDF, PNG, JPEG,
CSV); either remove these unused entries from the TEST_FILE_TYPES constant to
keep the test helpers minimal, or if they are intentionally reserved for future
tests, add a short comment above TEST_FILE_TYPES noting they are intentionally
included for future use. Update the TEST_FILE_TYPES declaration (the constant
named TEST_FILE_TYPES) to reflect the chosen approach so lint/tests no longer
flag unused exports.
- Around line 46-61: Update the JSDoc for generateTestFileContent to accurately
describe its behavior: replace "Generate a test file with random content" with
something like "Generate test file content of an approximate size (deterministic
repeated line)"; reference the function name generateTestFileContent and
optionally mention sizes, targetSize, and line to clarify the docstring change
so it no longer claims randomness.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts`:
- Around line 203-216: The test "should not be able to edit existing file" uses
an overly broad selector page.getByRole("link").first() and silently skips
clicking if no link is visible; update the test to scope the file link lookup to
the file list container (e.g., a locator like page.getByTestId("file-list") or a
container-specific selector) and then assert that at least one file item exists
before interacting (use an expectation like expect(locator.count() or
locator.first()).toBeGreaterThan(0) / toBeVisible()), then click the scoped
link; keep the final assertion on getByTestId("edit-button") toBeDisabled
unchanged.
- Around line 29-38: The test "should not be able to create file object"
currently does nothing when createButton (getByTestId("create-object-button"))
is absent; change it to assert a concrete condition by checking visibility and
then asserting either not visible OR disabled: e.g., evaluate
createButton.isVisible() and assert false if visible then assert
createButton.isDisabled(), so the test fails if the button is present and
enabled; update the assertions in that test body (referencing createButton and
the test name) to guarantee a deterministic expectation instead of a silent
pass.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts (1)

21-27: 500-response guard produces a confusing failure message.

When a 500 is caught, the assertion expect(response.url()).toBe("This URL responded with a 500 status") will always fail — by design — but the test report will show a string-comparison diff rather than clearly saying "server returned 500". This makes debugging harder.

A clearer alternative:

Suggested improvement
     page.on("response", async (response) => {
       if (response.status() === 500) {
-        await expect(response.url()).toBe("This URL responded with a 500 status");
+        throw new Error(`Server returned 500 for: ${response.url()}`);
       }
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts` around lines
21 - 27, The response handler in test.beforeEach currently uses
expect(response.url()).toBe(...) which always fails and produces a confusing
string-diff; instead, update the page.on("response") callback (the handler that
checks response.status()) to surface a clear error when a 500 is seen — e.g.,
throw a descriptive Error (or call the test failure helper) with a message like
"Server returned 500 for <url>" referencing response.url(), so replace the
failing expect(...) in the response.status() === 500 branch with a throw/new
Error that includes response.url().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts`:
- Around line 8-19: The suite currently risks parallel/nested ordering and
multiple beforeAll/afterAll runs because nested describes may use different
storageState values; add test.describe.configure({ mode: "serial" }) at the top
of the "File Upload - InfraCircuitContract" describe block to enforce serial
execution, and verify/adjust any nested test.use(...) that changes storageState
(or move branch creation into a global setup) so Playwright does not spawn
multiple workers and invoke test.beforeAll/test.afterAll per worker; check
Playwright config for fullyParallel/workers settings to ensure a single worker
or use a globalSetup to create/delete BRANCH_NAME instead of per-worker hooks.

---

Nitpick comments:
In `@frontend/app/tests/e2e/objects/file-upload/file-upload.spec.ts`:
- Around line 21-27: The response handler in test.beforeEach currently uses
expect(response.url()).toBe(...) which always fails and produces a confusing
string-diff; instead, update the page.on("response") callback (the handler that
checks response.status()) to surface a clear error when a 500 is seen — e.g.,
throw a descriptive Error (or call the test failure helper) with a message like
"Server returned 500 for <url>" referencing response.url(), so replace the
failing expect(...) in the response.status() === 500 branch with a throw/new
Error that includes response.url().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

group/frontend Issue related to the frontend (React)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant