Skip to content

fix(ci): fix failing unit tests and Playwright global setup#2457

Open
mikib0 wants to merge 6 commits into
developmentfrom
fix/ci-unit-and-e2e-test-failures
Open

fix(ci): fix failing unit tests and Playwright global setup#2457
mikib0 wants to merge 6 commits into
developmentfrom
fix/ci-unit-and-e2e-test-failures

Conversation

@mikib0
Copy link
Copy Markdown
Collaborator

@mikib0 mikib0 commented May 20, 2026

Summary

  • passwordResetService.test.ts: Mock for timingSafeEqual used positional args (a, b) but the real function takes { a, b } — the mock always returned false, making all OTP-comparison-dependent tests unreachable
  • embeddingHelper.test.ts: 7 fallback tests called getEmbeddingText(item, existingItem) as positional args instead of the { item, existingItem } object form, causing TypeError: Cannot read properties of undefined (reading 'name')
  • getRelativeTime.test.ts: 3 i18n tests called getRelativeTime(date, t) positionally instead of { dateValue, t }, so the translate spy was never invoked
  • globalSetup.ts (Playwright): Login endpoint /api/auth/login was removed in the Better Auth migration — replaced with /api/auth/sign-in/email and updated response destructuring to read session.token as the access token

Test plan

  • bun test:api:unit — 299 tests pass (was: 12 failures in passwordResetService + embeddingHelper)
  • bun test (Expo) — 357 tests pass (was: 1 failure in getRelativeTime)
  • Web E2E (Playwright) — will validate in CI; global setup now hits the correct login endpoint

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a web-specific API client for improved web auth behavior.
    • Web providers now include bottom-sheet modal support.
  • Bug Fixes / UX

    • Trip creation no longer blocks when location is missing.
    • Confirmation dialog’s destructive button now labeled “Delete” and styled destructively.
  • Tests

    • Many tests updated to object-style args, with stronger assertions and expanded E2E auth/context handling.
  • Chores

    • Increased Playwright/CI timeouts and adjusted lint/test tooling.

Review Change Stack

- passwordResetService.test.ts: mock timingSafeEqual with object arg
  ({ a, b }) to match actual function signature — positional mock caused
  OTP comparison to always fail, masking the 'User not found' path
- embeddingHelper.test.ts: fix 7 fallback tests that called
  getEmbeddingText(item, existingItem) as positional args instead of
  the { item, existingItem } object form, causing TypeError on item.name
- getRelativeTime.test.ts: fix 3 i18n tests calling
  getRelativeTime(date, t) positionally instead of { dateValue, t }
- globalSetup.ts: replace removed /api/auth/login with Better Auth's
  /api/auth/sign-in/email and read session.token as the access token
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Walkthrough

Refactors tests to object-style args, adds a web PackRat API client, updates Playwright E2E auth seeding (DB session insertion or HTTP sign-in) and token parsing, widens fixture auth shapes, increases Playwright/CI timeouts, updates Expo web providers and small UI behaviors, and adds a lint exclusion.

Changes

Test and Playwright E2E changes

Layer / File(s) Summary
getRelativeTime signature migration
apps/expo/lib/utils/__tests__/getRelativeTime.test.ts
Test invocations refactored to call getRelativeTime({ dateValue, t }) across minutes, sub-minute, and invalid-date cases and assert translation usage and return value.
timingSafeEqual mock update
packages/api/src/services/__tests__/passwordResetService.test.ts
Mock for timingSafeEqual changed to accept a single { a, b } object and still performs strict equality; inline comment updated.
getEmbeddingText signature migration and fallback assertions
packages/api/src/utils/__tests__/embeddingHelper.test.ts
All getEmbeddingText calls rewritten to { item, existingItem } form across fallback tests; reviews/qas tests add explicit typing; adjusted variant/color-size-material assertions.
overpass client test helper & assertions
packages/overpass/src/client.test.ts
makeResponse helper now accepts { body, status }; tests updated to use it, header assertions clarified, and error/success cases strengthened.
web PackRat API client
apps/expo/lib/api/packrat.web.ts
Adds a web-specific PackRat API client (apiClient) using clientEnvs.EXPO_PUBLIC_API_URL; token retrieval uses authClient.getSession() and onNeedsReauth sets needsReauthAtom.
Playwright globalSetup, fixtures, config, workflow
apps/expo/playwright/tests/globalSetup.ts, apps/expo/playwright/tests/fixtures.ts, apps/expo/playwright/playwright.config.ts, .github/workflows/web-e2e-tests.yml
Resilient Priority-1 token handling (try/catch for /api/auth/me), adds DB-session seeding for TEST_EMAIL (writes session token with refreshToken: null), falls back to /api/auth/sign-in/email seeded HTTP login or /api/auth/sign-up/email for local dev, widens fixtures to accept `refreshToken: string
Expo web providers, trips, and UI tests
apps/expo/providers/index.web.tsx, apps/expo/features/trips/store/trips.ts, apps/expo/features/trips/utils/getTripDetailOptions.tsx, apps/expo/playwright/tests/core.spec.ts
Adds BottomSheetModalProvider to web providers, removes createTrip location precondition, updates delete confirmation button to common.delete/destructive, and adjusts Playwright UI tests (sequential key presses and broader app/version regex).
lint exclusion update
scripts/lint/no-owned-max-params.ts
Adds apps/trails/scripts/generate-og-images.ts to the exclusion list for the owned-params lint rule.
  • Sequence Diagram(s):
sequenceDiagram
  participant GlobalSetup
  participant Database
  participant API
  participant FS as FileSystem
  GlobalSetup->>Database: lookup user by TEST_EMAIL (if NEON_DATABASE_URL)
  Database-->>GlobalSetup: returns user?
  alt user found
    GlobalSetup->>Database: insert session row (generate token)
    Database-->>GlobalSetup: session.token
    GlobalSetup->>FS: write .auth-tokens.json { accessToken: session.token, refreshToken: null, user }
  else no DB session
    GlobalSetup->>API: POST /api/auth/sign-in/email (seed creds)
    API-->>GlobalSetup: { session: { token }, user, maybe refreshToken }
    GlobalSetup->>FS: write .auth-tokens.json { accessToken: session.token, refreshToken: maybeNull, user }
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

web

Suggested reviewers

  • andrew-bierman
  • Isthisanmol
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main purpose of the PR: fixing unit test failures and Playwright global setup issues across multiple test files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ci-unit-and-e2e-test-failures
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/ci-unit-and-e2e-test-failures

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

Coverage Report for API Unit Tests Coverage (./packages/api)

Status Category Percentage Covered / Total
🔵 Lines 98.37% (🎯 95%) 726 / 738
🔵 Statements 98.37% (🎯 95%) 726 / 738
🔵 Functions 100% (🎯 97%) 43 / 43
🔵 Branches 95.43% (🎯 92%) 293 / 307
File CoverageNo changed files found.
Generated in workflow #1372 for commit 6435354 by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 20, 2026

Coverage Report for Expo Unit Tests Coverage (./apps/expo)

Status Category Percentage Covered / Total
🔵 Lines 97.56% (🎯 95%) 560 / 574
🔵 Statements 97.56% (🎯 95%) 560 / 574
🔵 Functions 100% (🎯 97%) 51 / 51
🔵 Branches 95% (🎯 92%) 190 / 200
File CoverageNo changed files found.
Generated in workflow #1372 for commit 6435354 by the Vitest Coverage Report Action

Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/expo/playwright/tests/globalSetup.ts (1)

44-61: ⚠️ Potential issue | 🔴 Critical

Fix incorrect response destructuring at lines 53–60.

The /api/auth/sign-in/email endpoint returns { token: string; user: {...} } (verified in auth.test.ts), not { session: { token }, refreshToken?, user }. The current code will fail at runtime when trying to access session.token.

Update line 53 to:

const { token, user } = (await loginRes.json()) as {
  token: string;
  user: Record<string, unknown>;
};

Then update line 60 to use token directly instead of session.token:

JSON.stringify({ accessToken: token, refreshToken: null, user }),

Also verify that /api/auth/verify-email (Priority 3, line 98) returns the expected { accessToken, refreshToken, user } structure — if it doesn't match, the same fix applies there.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo/playwright/tests/globalSetup.ts` around lines 44 - 61, The response
destructuring for the sign-in call is wrong: replace extracting { session,
refreshToken, user } from the /api/auth/sign-in/email JSON with { token, user }
and then write accessToken using token (and set refreshToken to null) when
writing TOKENS_FILE; update the variables used in the fs.writeFileSync call
accordingly. Also check the verify-email response handling (the code that
expects { accessToken, refreshToken, user }) and adjust its destructuring to
match the actual API shape if it differs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/expo/playwright/tests/globalSetup.ts`:
- Around line 44-61: The response destructuring for the sign-in call is wrong:
replace extracting { session, refreshToken, user } from the
/api/auth/sign-in/email JSON with { token, user } and then write accessToken
using token (and set refreshToken to null) when writing TOKENS_FILE; update the
variables used in the fs.writeFileSync call accordingly. Also check the
verify-email response handling (the code that expects { accessToken,
refreshToken, user }) and adjust its destructuring to match the actual API shape
if it differs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 52de98cb-3f77-4c27-b894-8bb80dcfbb2d

📥 Commits

Reviewing files that changed from the base of the PR and between 406845b and 674263b.

📒 Files selected for processing (4)
  • apps/expo/lib/utils/__tests__/getRelativeTime.test.ts
  • apps/expo/playwright/tests/globalSetup.ts
  • packages/api/src/services/__tests__/passwordResetService.test.ts
  • packages/api/src/utils/__tests__/embeddingHelper.test.ts

mikib0 added 3 commits May 20, 2026 08:29
- no-owned-max-params: add apps/trails/scripts/generate-og-images.ts to
  EXCLUDED_FILES (same globalThis.fetch override pattern as landing/guides)
- overpass/client.test.ts: convert makeResponse(body, status) to object
  param form to satisfy the one-parameter rule
- globalSetup.ts: add Priority 2 DB-direct session creation — when
  NEON_DATABASE_URL is available, insert a session row and write the
  token directly, bypassing the HTTP login that 404s when
  EXPO_PUBLIC_API_URL is a same-origin URL without a local API server
The DB-session path in globalSetup writes refreshToken: null when
creating a session directly in the DB (no HTTP auth). Playwright's
storageState requires all localStorage values to be strings, so passing
null caused every test to fail with "expected string, got object".

Guard refresh_token the same way user already is, and type refreshToken
as string | null to match what globalSetup actually writes.
Per-test: 30s → 60s, assertion: 10s → 15s, CI job: 30min → 60min.
@github-actions github-actions Bot added the ci/cd label May 20, 2026
Two root causes prevented every test from passing:

1. authClient.getSession() on web uses browser cookies, not SecureStore.
   The test browser has no valid Better Auth session cookie, so getSession
   returns null and useAuthInit redirects every page to /auth.  Fix: add a
   context-level Playwright route mock for **/api/auth/get-session that
   returns the seeded user + a synthetic session holding the real DB token.

2. packrat.ts reads the session token from SecureStore via the packrat_cookie
   key.  On web, ExpoSecureStore.web.js is an empty object so getItemAsync
   throws at runtime, leaving every API call without a Bearer token.  Fix:
   add packrat.web.ts that Metro auto-selects for web builds; it calls
   getActiveToken() which reads from the (now-intercepted) getSession.

Also seeds auth_version=v2 in localStorage so the startup migration in
useAuthInit does not delete access_token / refresh_token on first boot.
Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/expo/lib/api/packrat.web.ts`:
- Around line 18-22: onNeedsReauth currently calls authClient.getSession() and
sets needsReauthAtom without checking for an error; change it to examine the
returned { data, error } from authClient.getSession() and return early if error
is present (do not set store.set(needsReauthAtom, true)) so transient failures
don't force reauth. Locate the onNeedsReauth handler and update the logic to:
await authClient.getSession(), check error first, then check data?.session and
only set needsReauthAtom when there is no error and no session (mirroring the
pattern used in useAuthInit and the similar logic in packrat.ts).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f39037a8-0140-44d0-9404-5f2389ab44d8

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1419f and 6435354.

📒 Files selected for processing (2)
  • apps/expo/lib/api/packrat.web.ts
  • apps/expo/playwright/tests/fixtures.ts

Comment on lines +18 to +22
onNeedsReauth: async () => {
const { data } = await authClient.getSession();
if (data?.session) return;
store.set(needsReauthAtom, true);
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify authClient.getSession() return shape and existing usage patterns before applying.
set -euo pipefail

echo "== Locate authClient definition =="
fd -i "auth-client" apps | sed -n '1,20p'

echo "== Inspect getSession call sites with context =="
rg -n -C3 --type=ts --type=tsx '\bauthClient\.getSession\s*\('

echo "== Inspect createApiClient auth hooks typing/contracts =="
rg -n -C3 --type=ts --type=tsx '\bonNeedsReauth\b|getAccessToken|getRefreshToken|onAccessTokenRefreshed' apps packages

Repository: PackRat-AI/PackRat

Length of output: 280


🏁 Script executed:

# Read the auth-client.ts to understand getSession return type
cat -n apps/expo/lib/auth-client.ts | head -50

Repository: PackRat-AI/PackRat

Length of output: 1036


🏁 Script executed:

# Read the packrat.web.ts file to see the complete context
cat -n apps/expo/lib/api/packrat.web.ts

Repository: PackRat-AI/PackRat

Length of output: 1340


🏁 Script executed:

# Search for all getSession usages in the codebase (fixing the file type issue)
rg -n -C3 'getSession\s*\(' apps packages --type ts -A 5 -B 2

Repository: PackRat-AI/PackRat

Length of output: 13294


🏁 Script executed:

# Check if there's a better-auth package and its version
fd package.json apps packages | head -5 | xargs grep -l "better-auth" 2>/dev/null || echo "Checking root package.json"
cat package.json | grep -A5 -B5 "better-auth" 2>/dev/null || echo "No better-auth found in root"

Repository: PackRat-AI/PackRat

Length of output: 405


Handle errors from authClient.getSession() before setting reauth state.

onNeedsReauth ignores the error field from authClient.getSession(). If the call fails transiently (network issue, service error), the code sets needsReauthAtom = true and bounces the user to login unnecessarily. The codebase already acknowledges this risk in a similar call at apps/expo/lib/api/packrat.ts line 42–46. The auth initialization code in useAuthInit.ts shows the correct pattern: check error first and return early if present.

Suggested fix
 onNeedsReauth: async () => {
-  const { data } = await authClient.getSession();
-  if (data?.session) return;
+  const { data, error } = await authClient.getSession();
+  if (error) return;
+  if (data?.session) return;
   store.set(needsReauthAtom, true);
 },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo/lib/api/packrat.web.ts` around lines 18 - 22, onNeedsReauth
currently calls authClient.getSession() and sets needsReauthAtom without
checking for an error; change it to examine the returned { data, error } from
authClient.getSession() and return early if error is present (do not set
store.set(needsReauthAtom, true)) so transient failures don't force reauth.
Locate the onNeedsReauth handler and update the logic to: await
authClient.getSession(), check error first, then check data?.session and only
set needsReauthAtom when there is no error and no session (mirroring the pattern
used in useAuthInit and the similar logic in packrat.ts).

…lSetup

- Remove mandatory location check before trip sync (trips.ts)
- Use destructive style on delete confirmation button (getTripDetailOptions)
- Switch globalSetup to Better Auth sign-in/sign-up endpoints; drop OTP
  verification step now that requireEmailVerification=false + autoSignIn=true
  returns a token directly
- Wrap API fetch calls in try/catch with actionable error messages
- Re-add BottomSheetModalProvider to web providers (providers/index.web.tsx)
- Use pressSequentially for search input to trigger React onChangeText;
  broaden version string regex in settings test
Copy link
Copy Markdown
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/expo/playwright/tests/globalSetup.ts (1)

54-59: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Table name mismatch: users should be user.

The query references FROM users but the auth schema defines the table as user (singular):

// packages/api/auth-schema.ts:4
export const user = pgTable('user', { ... });

This will fail with "relation 'users' does not exist" when the Priority 2 DB-seeding path runs in CI.

Proposed fix
     const rows = await sql`
       SELECT id, email, name, role, first_name AS "firstName", last_name AS "lastName"
-      FROM users
+      FROM "user"
       WHERE email = ${process.env.TEST_EMAIL.toLowerCase()}
       LIMIT 1
     `;

Note: Quote "user" since it's a reserved word in PostgreSQL.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo/playwright/tests/globalSetup.ts` around lines 54 - 59, The SQL
query uses the wrong table name "users"; change the FROM clause in the sql call
that selects id,email,name,role,... to reference the auth table name "user"
(quoted as "user" because user is a reserved PostgreSQL word) so the SELECT
executes against the defined pgTable; keep the rest of the query intact
(including the WHERE using process.env.TEST_EMAIL.toLowerCase()) and only update
the table identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/expo/playwright/tests/globalSetup.ts`:
- Around line 54-59: The SQL query uses the wrong table name "users"; change the
FROM clause in the sql call that selects id,email,name,role,... to reference the
auth table name "user" (quoted as "user" because user is a reserved PostgreSQL
word) so the SELECT executes against the defined pgTable; keep the rest of the
query intact (including the WHERE using process.env.TEST_EMAIL.toLowerCase())
and only update the table identifier.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d1e26a84-6cef-474e-9d25-44c746817b7a

📥 Commits

Reviewing files that changed from the base of the PR and between 6435354 and de6a3cb.

📒 Files selected for processing (5)
  • apps/expo/features/trips/store/trips.ts
  • apps/expo/features/trips/utils/getTripDetailOptions.tsx
  • apps/expo/playwright/tests/core.spec.ts
  • apps/expo/playwright/tests/globalSetup.ts
  • apps/expo/providers/index.web.tsx
💤 Files with no reviewable changes (1)
  • apps/expo/features/trips/store/trips.ts

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant