Skip to content

Conversation

@imgullu786
Copy link
Collaborator

@imgullu786 imgullu786 commented Jan 14, 2026

Description

This PR introduces the End-to-End testing infrastructure using Playwright.

Changes

  • Configure Playwright
  • Add GitHub Actions workflow for tests

Summary by CodeRabbit

Release Notes

  • Tests

    • Introduced end-to-end test suite with authentication test coverage, including pre-authenticated and fresh login scenarios
    • Configured automated UI testing pipeline via GitHub Actions for continuous validation
  • Chores

    • Added Playwright configuration with browser support and test reporting
    • Updated gitignore to exclude test artifacts, reports, and cache files
    • Installed Playwright testing framework and related development dependencies

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

This PR establishes a comprehensive end-to-end testing infrastructure for a Frappe-based UI using Playwright. It includes a GitHub Actions CI/CD workflow, Playwright configuration, authentication and API helper utilities, page object models, and initial test suites covering login flows and session persistence.

Changes

Cohort / File(s) Summary
CI/CD & Infrastructure
github/workflows/ui-tests.yml, .gitignore
Adds GitHub Actions workflow to run E2E tests on push/PR with Redis and MariaDB services; adds Playwright ignore patterns (test-results, reports, cache, auth files)
Project Configuration
package.json, playwright.config.js
Adds E2E test scripts (test:e2e, test:e2e:ui, test:e2e:headed, test:e2e:debug); adds Playwright and @types/node devDependencies; configures Playwright with testDir="./e2e/tests", parallel execution, retries, reporters, timeouts, and chromium + setup projects
E2E Helper Utilities
e2e/helpers/auth.js, e2e/helpers/frappe.js, e2e/helpers/index.js
Provides authentication helpers (loginViaAPI, loginViaUI, logout, saveAuthState, isLoggedIn); implements CSRF-aware Frappe REST API wrapper with CRUD operations (createDoc, getDoc, updateDoc, deleteDoc, callMethod, getList, docExists); re-exports all helpers via index module
E2E Page Objects
e2e/pages/login.page.js, e2e/pages/index.js
Implements LoginPage class following Page Object Model pattern with locators and methods for navigation, credential input, submission, and assertions; re-exports LoginPage via index
E2E Test Suites
e2e/tests/auth.setup.js, e2e/tests/auth.spec.js
Adds authentication setup script that logs in via API, verifies session, navigates to app to capture CSRF token, and persists credentials; adds test suite covering pre-authenticated access, fresh login flow, invalid credentials, and unauthenticated redirection

Sequence Diagram(s)

sequenceDiagram
    participant Playwright as Playwright Test<br/>(auth.setup.js)
    participant API as Frappe API<br/>(/api/method/login)
    participant AppPage as App Page<br/>(to capture CSRF)
    participant Storage as Local Storage<br/>(e2e/.auth/)
    
    Playwright->>API: loginViaAPI(credentials)
    API-->>Playwright: Session Cookie
    Playwright->>API: isLoggedIn() check
    API-->>Playwright: User confirmation
    Playwright->>AppPage: Navigate to /app
    AppPage-->>Playwright: Page loaded with CSRF token
    Playwright->>Storage: Save CSRF token to csrf.json
    Playwright->>Storage: Save storageState to user.json
    Storage-->>Playwright: Persistence complete
    Note over Storage: Reusable by subsequent tests
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Testing hops through Frappe's door,
E2E tests to explore and explore!
With Playwright's grace and helpers so bright,
Every login leaps pass through the night.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding Playwright-based end-to-end testing infrastructure with GitHub Actions workflow configuration.
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.

✨ Finishing touches
  • 📝 Generate docstrings

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

@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

🤖 Fix all issues with AI agents
In `@dashboard/frappe-ui`:
- Line 1: Update the commit message or PR description to explicitly document the
addition of the dashboard/frappe-ui submodule (commit e239181): state why this
specific commit was chosen (e.g., needed bugfixes or feature set present in
e239181), list the UI components or features from frappe-ui that the dashboard
and E2E tests depend on (identify components by name used in the repo), and
confirm compatibility with the dashboard package.json constraint frappe-ui:
^0.1.254 (state whether e239181 satisfies that semver range or note any
overrides). Include a brief note that the submodule is required for the E2E
testing infrastructure and reference the submodule path dashboard/frappe-ui and
commit hash e239181.

In `@package.json`:
- Around line 27-30: The devDependencies entry pins "@types/node" to a
non-existent 25.0.8; update the package.json devDependencies to use a valid 24.x
version (e.g., change "@types/node": "^25.0.8" to "@types/node": "^24.3.1") so
npm install succeeds; keep "@playwright/test" as-is.
🧹 Nitpick comments (2)
e2e/tests/login.spec.js (2)

6-7: Hardcoded default credentials in test file.

While these are test/development credentials and match the workflow's site setup (admin-password admin), having hardcoded passwords in source code is generally discouraged. Consider documenting that these defaults are only for local development or CI environments.


15-19: Consider adding an assertion on the logged-in user.

The test retrieves frappe.session.user but only logs it without asserting. Adding an assertion would make the test more robust by verifying the actual authenticated user matches expectations.

💡 Suggested improvement
 	await expect(page).not.toHaveURL(/.*login.*/);
 	await page.waitForLoadState("networkidle");

 	const loggedInUser = await page.evaluate(() => frappe.session.user);
-	console.log(`Verified Session User: ${loggedInUser}`);
+	console.log(`Verified Session User: ${loggedInUser}`);
+	expect(loggedInUser).toBe(username);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 718162c and 18fdc70.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • .github/workflows/ui-tests.yml
  • .gitignore
  • dashboard/frappe-ui
  • e2e/tests/login.spec.js
  • package.json
  • playwright.config.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: Server
🔇 Additional comments (7)
.gitignore (1)

60-66: LGTM!

The Playwright-related ignore patterns correctly cover standard artifact directories (test-results/, playwright-report/, blob-report/) and internal cache/auth directories. These align well with Playwright's default output locations.

package.json (1)

10-14: LGTM!

Good selection of test scripts covering various execution modes: headless (test:e2e), interactive UI (test:e2e:ui), headed browser (test:e2e:headed), and debug mode (test:e2e:debug).

playwright.config.js (2)

15-41: LGTM!

Well-structured Playwright configuration with sensible defaults:

  • CI-aware settings for forbidOnly, retries, and workers
  • Appropriate timeouts for actions (15s) and navigation (30s)
  • Good debugging aids with trace/video/screenshot on failure
  • baseURL correctly defaults to match the workflow environment

44-79: Consider enabling additional browsers in the future.

Starting with Chromium-only is a reasonable approach for initial E2E setup. The commented-out configurations for Firefox, WebKit, and mobile viewports provide a good template for future cross-browser testing expansion.

.github/workflows/ui-tests.yml (3)

113-126: Good approach for starting the Frappe server in CI.

The workflow correctly:

  • Disables watch and schedule processes to reduce resource usage
  • Runs bench in the background with output redirected to a log file
  • Uses a timeout-wrapped curl loop to wait for server readiness

140-164: LGTM!

Excellent debugging setup:

  • Playwright report uploaded on all runs (if: always())
  • Test results uploaded only on failure to save storage
  • Bench and Frappe logs printed on failure for troubleshooting

41-50: The workflow configuration is correct. Both Python 3.14 and Node.js 24 are valid, stable versions as of January 2026:

  • Python 3.14.2 was released on December 5, 2025, and is the current stable version.
  • Node.js v24.13.0 is the current LTS release as of January 2026.

No changes are needed.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@e2e/tests/login.spec.js`:
- Around line 15-19: The test currently reads frappe.session.user into
loggedInUser and only logs it; replace or supplement that log with an assertion
that validates loggedInUser equals the expected test account (e.g., the known
username used by the test or an env/fixture value), using the test framework's
expect to fail the test on mismatch; locate the page.evaluate call that reads
frappe.session.user and add an assertion like
expect(loggedInUser).toBe(expectedUser) (or the appropriate matcher) and ensure
expectedUser is sourced from the test's existing credentials/fixture or an env
var.
🧹 Nitpick comments (2)
e2e/tests/login.spec.js (1)

9-13: Consider removing or reducing debug logging.

The console.log on line 12 may be a debug artifact. If intentional for CI visibility, consider using Playwright's built-in tracing or test annotations instead for cleaner test output.

.github/workflows/ui-tests.yml (1)

84-87: Minor: Use consistent apt commands.

Mixing apt update with apt-get install works but is inconsistent.

🧹 Proposed fix for consistency
       - name: Install MariaDB Client
         run: |
-          sudo apt update
-          sudo apt-get install mariadb-client
+          sudo apt-get update
+          sudo apt-get install -y mariadb-client
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d298186 and a69cb70.

📒 Files selected for processing (2)
  • .github/workflows/ui-tests.yml
  • e2e/tests/login.spec.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Server
  • GitHub Check: Playwright E2E Tests
🔇 Additional comments (7)
e2e/tests/login.spec.js (1)

1-7: LGTM on test setup and credential handling.

Environment variable fallbacks for credentials are appropriate for CI/local flexibility.

.github/workflows/ui-tests.yml (6)

1-12: LGTM on workflow triggers and concurrency.

Good use of concurrency grouping with cancel-in-progress: true to avoid wasted CI resources on superseded commits.


20-35: LGTM on service configuration.

Redis and MariaDB services are properly configured with health checks for MariaDB, ensuring the database is ready before tests proceed.


96-106: LGTM on app installation order.

Installing payments before buzz aligns with the dependency requirements mentioned in the commit message.


114-127: LGTM on server startup with timeout-based readiness check.

The approach of disabling watch/schedule to reduce resource usage and using a timeout-based curl check for server readiness is solid for CI environments.


141-155: LGTM on artifact handling.

Uploading the report unconditionally (if: always()) and test results only on failure is a practical balance between debugging capability and storage efficiency.


41-50: No action required. Python 3.14 and Node.js 24 are stable versions (released October 2025 and May 2025 respectively) and are officially recommended by Frappe v16/develop. These are the intended dependency versions for current Frappe development, not a compatibility risk.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@NagariaHussain
Copy link
Contributor

Check hazelnode for how Logins are handled.

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@e2e/.auth/user.json`:
- Around line 1-95: The committed user.json contains real session/localStorage
(including the sid cookie and user identifiers); remove sensitive runtime state
and replace user.json with a sanitized placeholder fixture, update the test
bootstrap (auth.setup) to generate the required cookies/localStorage at runtime
instead of relying on committed state, and ensure generated auth JSON files are
ignored by adding the auth JSON pattern to .gitignore so e2e auth artifacts are
not committed.
🧹 Nitpick comments (5)
e2e/helpers/auth.js (1)

23-33: Keep UI login selectors in sync with the LoginPage object.
loginViaUI uses data-fieldname selectors while e2e/pages/login.page.js uses #login_email/#login_password; consider delegating to LoginPage (or shared selectors) to avoid drift and please verify the current DOM exposes both. As per coding guidelines, use absolute imports.

e2e/helpers/index.js (1)

1-2: Switch re-exports to absolute paths to match import policy.
Using relative paths here conflicts with the absolute-import guideline; please confirm the resolver supports e2e/* and then swap to absolute paths. As per coding guidelines, use absolute imports.

♻️ Proposed refactor
-export * from "./auth";
-export * from "./frappe";
+export * from "e2e/helpers/auth";
+export * from "e2e/helpers/frappe";
e2e/tests/auth.setup.js (1)

37-49: CSRF token extraction could be more robust with an explicit wait.

The comment mentions "Wait for frappe to be defined," but the code only uses optional chaining without actually waiting. If frappe initializes after networkidle, the token won't be captured. Consider adding a retry or explicit wait:

♻️ Suggested improvement
-	// Wait for frappe to initialize and extract CSRF token
-	const csrfToken = await page.evaluate(() => {
-		// Wait for frappe to be defined
-		return window.frappe?.csrf_token;
-	});
+	// Wait for frappe to initialize and extract CSRF token
+	const csrfToken = await page.evaluate(async () => {
+		// Wait for frappe to be defined (up to 5 seconds)
+		for (let i = 0; i < 50; i++) {
+			if (window.frappe?.csrf_token) {
+				return window.frappe.csrf_token;
+			}
+			await new Promise((r) => setTimeout(r, 100));
+		}
+		return null;
+	});
e2e/tests/auth.spec.js (2)

33-40: Consider using environment variables for test credentials.

The setup file (auth.setup.js) uses process.env.FRAPPE_USER || "Administrator" for credentials, but this test hardcodes them. For consistency and flexibility across environments:

♻️ Suggested change
 	test("should login via UI", async ({ page }) => {
 		const loginPage = new LoginPage(page);

-		await loginPage.login("Administrator", "admin");
+		await loginPage.login(
+			process.env.FRAPPE_USER || "Administrator",
+			process.env.FRAPPE_PASSWORD || "admin"
+		);

 		// Should be redirected away from login
 		await expect(page).not.toHaveURL(/.*login.*/);
 	});

42-51: Consider also asserting the error message is displayed.

The LoginPage class provides expectLoginError() which verifies the error message is visible. Adding this assertion would make the test more thorough:

♻️ Suggested addition
 	test("should show error for invalid credentials", async ({ page }) => {
 		const loginPage = new LoginPage(page);

 		await loginPage.goto();
 		await loginPage.fillCredentials("invalid@example.com", "wrongpassword");
 		await loginPage.submit();

+		// Should show error message
+		await loginPage.expectLoginError();
+
 		// Should stay on login page
 		await loginPage.expectToBeOnLoginPage();
 	});

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@e2e/helpers/frappe.js`:
- Around line 170-176: The docExists function currently catches all errors which
can hide auth/network issues; change it to only return false when the error
indicates a 404/not-found from getDoc and rethrow any other errors. Locate
docExists and the call to getDoc(request, doctype, name), inspect the thrown
error (e.g., error.response?.status === 404 or a known NotFoundError
class/message) and return false in that case, otherwise throw the original error
so auth/network failures bubble up.
🧹 Nitpick comments (3)
e2e/pages/login.page.js (1)

43-48: Consider env-driven defaults for credentials.
Hardcoding admin defaults can make CI/environment setup brittle. Prefer env overrides with safe fallbacks.

♻️ Proposed adjustment
-	async login(email = "Administrator", password = "admin") {
+	async login(
+		email = process.env.E2E_USER ?? "Administrator",
+		password = process.env.E2E_PASSWORD ?? "admin"
+	) {
e2e/helpers/frappe.js (2)

14-33: Optional: avoid noisy console warnings.
Consider throwing (or using a test logger) instead of console.warn so CSRF file issues fail fast and are easier to trace.


140-165: Handle limit = 0 explicitly.
The current truthy check skips 0, which may be a valid limit.

♻️ Proposed fix
-	if (options.limit) {
+	if (options.limit !== undefined && options.limit !== null) {
 		params.set("limit_page_length", options.limit.toString());
 	}

Comment on lines +170 to +176
export async function docExists(request, doctype, name) {
try {
await getDoc(request, doctype, name);
return true;
} catch {
return false;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don’t swallow non-404 failures in docExists.
Catching all errors can hide auth or network regressions. Consider only returning false on a known “not found” case and rethrow otherwise.

💡 Safer pattern
 export async function docExists(request, doctype, name) {
 	try {
 		await getDoc(request, doctype, name);
 		return true;
-	} catch {
-		return false;
+	} catch (error) {
+		if (error?.message?.includes("404")) return false;
+		throw error;
 	}
 }
🤖 Prompt for AI Agents
In `@e2e/helpers/frappe.js` around lines 170 - 176, The docExists function
currently catches all errors which can hide auth/network issues; change it to
only return false when the error indicates a 404/not-found from getDoc and
rethrow any other errors. Locate docExists and the call to getDoc(request,
doctype, name), inspect the thrown error (e.g., error.response?.status === 404
or a known NotFoundError class/message) and return false in that case, otherwise
throw the original error so auth/network failures bubble up.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants