Skip to content

E2e test additional#43

Draft
Kzoeps wants to merge 13 commits intohypercerts-org:e2e-testsfrom
Kzoeps:e2e-test-additional
Draft

E2e test additional#43
Kzoeps wants to merge 13 commits intohypercerts-org:e2e-testsfrom
Kzoeps:e2e-test-additional

Conversation

@Kzoeps
Copy link
Copy Markdown
Contributor

@Kzoeps Kzoeps commented Mar 30, 2026

Builds on #42

Summary by CodeRabbit

  • Tests
    • Added end-to-end coverage for automatic account creation, consent screen, and internal API behaviors
    • Improved OTP/email handling, generalized email-subject checks, and made incorrect-OTP handling more robust
    • Extended test timeouts and added email cleanup to reduce flakiness
    • Added API-focused steps to validate handle→DID resolution and session rejection for password attempts
    • Test config updated to opt into internal-api scenarios via a new env variable

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

@Kzoeps is attempting to deploy a commit to the Hypercerts Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@Kzoeps Kzoeps marked this pull request as draft March 30, 2026 16:56
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5f52fa7c-c88b-4ab3-8fbb-363f376d771f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds new end-to-end Cucumber features and step definitions (automatic account creation, consent screen, internal API tests), centralizes OAuth account-creation flow and utilities, expands test runner configuration and environment wiring, and increases timeouts and Mailpit wait/cleanup behavior.

Changes

Cohort / File(s) Summary
Test runner & CI
e2e/cucumber.mjs, .github/workflows/e2e-pr.yml, e2e/.env.example
Included additional feature files in Cucumber paths; tightened tags to exclude @manual and @docker-only; added E2E_EPDS_INTERNAL_SECRET to CI/env example.
Timeouts & Mailpit hooks
e2e/support/hooks.ts, e2e/support/mailpit.ts
Increased Cucumber step timeout (60s→120s); Mailpit wait default 15s→60s; added Mailpit cleanup BeforeAll and After hooks.
World & env
e2e/support/world.ts, e2e/support/env.ts
Added userHandle, lastHttpStatus, lastApiResponse, lastRequestUri to EpdsWorld and skipIfNoInternalSecret(); exposed testEnv.internalSecret from env.
Support utilities & flows
e2e/support/utils.ts, e2e/support/flows.ts
New helpers: getPage(world), callInternalApi(path, secret); centralized createAccountViaOAuth(world, email) to perform browser-driven OAuth sign-up, OTP retrieval, DID/handle extraction, and inbox clearing.
Step definitions — auth & common
e2e/step-definitions/auth.steps.ts, e2e/step-definitions/common.steps.ts
Added returning-user Given steps; updated OTP handling to derive incorrect codes and wait for error messages; replaced .btn-approve with role-based Approve click; removed some OAuth helpers from common and added a generic When('the user clicks {string}') step.
Step definitions — consent & email
e2e/step-definitions/consent.steps.ts, e2e/step-definitions/email.steps.ts
New consent step defs to assert consent UI, demo client name, denial redirect, and no-consent navigation; consolidated email-subject checks into one generalized step.
Step definitions — pds & internal API
e2e/step-definitions/pds.steps.ts, e2e/step-definitions/internal-api.steps.ts
Added PDS-oriented steps for registration flow, handle/DID verification, createSession attempts and expected failures; added internal-api steps that call /_internal/* endpoints, handle auth error cases, and skip when internal secret is absent.
Feature files
features/automatic-account-creation.feature, features/consent-screen.feature, features/internal-api.feature, features/passwordless-authentication.feature
Added consent and internal-api features; updated automatic-account-creation and consent flows to use demo-client registration flow, added handle/DID resolution checks, reworked internal-api scenarios to depend on internal secret and registered users, and simplified passwordless/email assertions.

Sequence Diagram

sequenceDiagram
    actor Browser as Browser/Client
    participant Demo as Demo OAuth Server
    participant PDS as PDS Server
    participant Mailpit as Mailpit (Email)

    rect rgba(100, 150, 200, 0.5)
    Note over Browser,Mailpit: OAuth Account Creation & Consent Flow
    Browser->>Demo: Initiate OAuth login (demo client)
    Demo->>Browser: Show email entry form
    Browser->>Demo: Submit email
    Demo->>Mailpit: Send OTP email
    Mailpit->>Browser: Email available in trap
    Browser->>Mailpit: Retrieve OTP
    Browser->>Demo: Enter OTP
    Demo->>Browser: Show consent screen
    Browser->>Demo: Click "Approve"
    Demo->>PDS: Exchange token / create session
    PDS->>Demo: Return session + DID
    Demo->>Browser: Redirect to /welcome (render DID & handle)
    end

    rect rgba(150, 200, 100, 0.5)
    Note over Browser,PDS: Post-Creation Validation
    Browser->>PDS: resolveHandle(handle)
    PDS->>Browser: Return DID (verify matches stored DID)
    Browser->>PDS: GET https://<handle>/.well-known/atproto-did
    PDS->>Browser: Return DID text (verify format)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • aspiers

Poem

🐰 I hopped through mail and browser light,
Fetched codes by moon and tested night,
Consent approved and DIDs aligned,
E2E hops now pass — the trees, they chimed! 🌿

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

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.
Title check ❓ Inconclusive The title 'E2e test additional' is vague and lacks specificity about what tests are being added or modified. Revise the title to be more descriptive of the main changes, such as 'Add E2E tests for internal API, automatic account creation, and consent flows' or 'Expand E2E test coverage with additional feature scenarios'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@Kzoeps
Copy link
Copy Markdown
Contributor Author

Kzoeps commented Mar 30, 2026

@coderabbitai please review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

@Kzoeps: Sure! I'll start reviewing the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

@Kzoeps: Sure! I'll start reviewing the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

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

🧹 Nitpick comments (4)
e2e/step-definitions/pds.steps.ts (2)

147-150: Document why this step is a no-op.

The empty function body is intentional per the comment, but a brief inline comment inside the function would make this clearer for future maintainers.

Proposed fix
 Then(
   'the only way to authenticate is through the ePDS OAuth flow',
-  function (this: EpdsWorld) {},
+  function (this: EpdsWorld) {
+    // No-op: assertion is implicit from preceding createSession rejection
+  },
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/step-definitions/pds.steps.ts` around lines 147 - 150, Add a brief inline
comment inside the empty step-definition function for the step "the only way to
authenticate is through the ePDS OAuth flow" (the Then(...) handler using
EpdsWorld) to document that the no-op is intentional and why it exists; update
the anonymous function body to contain a one-line comment explaining it's
intentionally empty (e.g., authentication is validated elsewhere or handled by
shared fixtures) so future maintainers understand the purpose.

53-56: Use replaceAll for cleaner regex escaping.

SonarCloud suggests using replaceAll here. While the current code works correctly, replaceAll is more idiomatic in modern JS.

Proposed fix
     const pdsDomain = new URL(testEnv.pdsUrl).hostname
     // Handle must be <short-alphanumeric>.<pds-domain>
     const pattern = new RegExp(
-      `^[a-z0-9]{4,20}\\.${pdsDomain.replace(/\./g, '\\.')}$`,
+      `^[a-z0-9]{4,20}\\.${pdsDomain.replaceAll('.', '\\.')}$`,
     )

Note: The ast-grep ReDoS warning is a false positive here—pdsDomain comes from controlled test infrastructure (testEnv.pdsUrl), not user input.

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

In `@e2e/step-definitions/pds.steps.ts` around lines 53 - 56, The regex
construction uses pdsDomain.replace(/\./g, '\\.') — replaceAll is preferred for
readability; change the call to pdsDomain.replaceAll('.', '\\.') when building
the pattern variable so the RegExp remains `new
RegExp(\`^[a-z0-9]{4,20}\\.${escaped}\\$\`)` (use the escaped value of
pdsDomain), keeping the same validation logic in the code that defines pattern
and references pdsDomain.
e2e/support/flows.ts (1)

32-33: Consider reusing getPage from utils.ts.

The page null-check here duplicates the logic in getPage(world). Using the shared helper improves consistency.

Proposed fix
+import { getPage } from './utils.js'
 import { waitForEmail, extractOtp, clearMailpit } from './mailpit.js'
 
 ...
 
 export async function createAccountViaOAuth(
   world: EpdsWorld,
   email: string,
 ): Promise<{ did: string; handle: string | undefined }> {
-  const page = world.page
-  if (!page) throw new Error('page is not initialised')
+  const page = getPage(world)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/support/flows.ts` around lines 32 - 33, Replace the direct access and
null-check of page in e2e/support/flows.ts with the shared helper getPage(world)
from utils.ts: find where you do "const page = world.page" and "if (!page) throw
..." and instead call getPage(world) to obtain the Page instance (importing
getPage if not already), removing the duplicated null-check and ensuring you use
the returned Page object for subsequent operations.
e2e/support/hooks.ts (1)

27-32: Consider adding error handling for the BeforeAll Mailpit cleanup.

The fetch to wipe leftover emails doesn't check res.ok. If Mailpit is unreachable or returns an error, the suite proceeds silently. This could lead to flaky tests from stale emails, with no indication of the root cause.

Proposed fix
   // Wipe any emails left over from previous runs
   if (testEnv.mailpitPass) {
-    await fetch(`${testEnv.mailpitUrl}/api/v1/messages`, {
+    const res = await fetch(`${testEnv.mailpitUrl}/api/v1/messages`, {
       method: 'DELETE',
       headers: { Authorization: mailpitAuthHeader() },
     })
+    if (!res.ok) {
+      console.warn(`Mailpit cleanup failed: ${res.status} — stale emails may cause flaky tests`)
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/support/hooks.ts` around lines 27 - 32, The BeforeAll Mailpit cleanup
fetch call (inside the block checking testEnv.mailpitPass) does not verify the
response; update the code around the fetch to check the returned Response (res)
from the DELETE to `${testEnv.mailpitUrl}/api/v1/messages` and handle non-OK
responses by throwing or logging an error with the status and body so the test
run fails or reports the failure; ensure you still include the Authorization
header from mailpitAuthHeader() and propagate or surface the error (or retry if
desired) so stale emails won't be ignored silently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/step-definitions/auth.steps.ts`:
- Around line 257-266: Replace the hardcoded '00000000' in the When step handler
with a dynamically generated wrong OTP using the active OTP settings: if
this.otpCode is available, mutate or derive a wrong value from it; otherwise
build a bogus code using OTP_LENGTH and OTP_CHARSET (ensure length matches
OTP_LENGTH and characters are drawn from OTP_CHARSET but differ from a valid
code) and use that for page.fill('#code', ...); apply the same fix to the
single-attempt helper referenced above so the test exercises the retry logic
regardless of numeric/alphanumeric or length configuration.

In `@e2e/step-definitions/consent.steps.ts`:
- Around line 24-34: The test currently asserts any non-empty text in the
.subtitle but should verify the actual client name; update the Then("it shows
the demo client's name", async function (this: EpdsWorld) { ... }) step to
target the client name element (e.g. use the locator '.subtitle strong' instead
of '.subtitle') and assert its trimmed innerText equals the expected client name
(load/compare against the value in client-metadata.json) using getPage(...) and
the subtitle locator so the test fails if the <strong> client name is missing or
incorrect.

In `@features/consent-screen.feature`:
- Around line 12-20: The step "Then the browser is redirected back to the demo
client with a valid session" only checks the URL (via the shared auth step that
waits for **/welcome) and thus duplicates "Then no consent screen is shown"
without asserting session validity; update the step (or the shared step
implementation used by it) to explicitly verify authentication state after
redirect by asserting a real session artifact — e.g., check for the demo
client's session cookie (name used by the app), an access/id token in
localStorage, or call the demo client's session endpoint (e.g., /api/session) to
confirm the user is authenticated — and apply the same stronger assertion to the
other consent-success scenarios and the shared step referenced by "Then no
consent screen is shown".

---

Nitpick comments:
In `@e2e/step-definitions/pds.steps.ts`:
- Around line 147-150: Add a brief inline comment inside the empty
step-definition function for the step "the only way to authenticate is through
the ePDS OAuth flow" (the Then(...) handler using EpdsWorld) to document that
the no-op is intentional and why it exists; update the anonymous function body
to contain a one-line comment explaining it's intentionally empty (e.g.,
authentication is validated elsewhere or handled by shared fixtures) so future
maintainers understand the purpose.
- Around line 53-56: The regex construction uses pdsDomain.replace(/\./g, '\\.')
— replaceAll is preferred for readability; change the call to
pdsDomain.replaceAll('.', '\\.') when building the pattern variable so the
RegExp remains `new RegExp(\`^[a-z0-9]{4,20}\\.${escaped}\\$\`)` (use the
escaped value of pdsDomain), keeping the same validation logic in the code that
defines pattern and references pdsDomain.

In `@e2e/support/flows.ts`:
- Around line 32-33: Replace the direct access and null-check of page in
e2e/support/flows.ts with the shared helper getPage(world) from utils.ts: find
where you do "const page = world.page" and "if (!page) throw ..." and instead
call getPage(world) to obtain the Page instance (importing getPage if not
already), removing the duplicated null-check and ensuring you use the returned
Page object for subsequent operations.

In `@e2e/support/hooks.ts`:
- Around line 27-32: The BeforeAll Mailpit cleanup fetch call (inside the block
checking testEnv.mailpitPass) does not verify the response; update the code
around the fetch to check the returned Response (res) from the DELETE to
`${testEnv.mailpitUrl}/api/v1/messages` and handle non-OK responses by throwing
or logging an error with the status and body so the test run fails or reports
the failure; ensure you still include the Authorization header from
mailpitAuthHeader() and propagate or surface the error (or retry if desired) so
stale emails won't be ignored silently.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0181e006-a423-405f-a75a-daa1f669c937

📥 Commits

Reviewing files that changed from the base of the PR and between b73cb1f and 3aa4220.

📒 Files selected for processing (14)
  • e2e/cucumber.mjs
  • e2e/step-definitions/auth.steps.ts
  • e2e/step-definitions/common.steps.ts
  • e2e/step-definitions/consent.steps.ts
  • e2e/step-definitions/email.steps.ts
  • e2e/step-definitions/pds.steps.ts
  • e2e/support/flows.ts
  • e2e/support/hooks.ts
  • e2e/support/mailpit.ts
  • e2e/support/utils.ts
  • e2e/support/world.ts
  • features/automatic-account-creation.feature
  • features/consent-screen.feature
  • features/passwordless-authentication.feature

Comment on lines +24 to +34
Then("it shows the demo client's name", async function (this: EpdsWorld) {
// The consent page renders "<client_name> wants to access your account"
// in the .subtitle element. Assert it contains non-trivial text (not blank).
const page = getPage(this)
const subtitle = page.locator('.subtitle')
await expect(subtitle).toBeVisible()
const text = await subtitle.innerText()
if (!text.trim()) {
throw new Error('Consent screen subtitle is empty — expected client name')
}
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Assert the rendered client name, not just any subtitle text.

This still passes if the <strong> containing the client name disappears and only the static wants to access your account copy remains. Please target .subtitle strong at minimum, or compare against the value from client-metadata.json.

🎯 Tighten the assertion
 Then("it shows the demo client's name", async function (this: EpdsWorld) {
-  // The consent page renders "<client_name> wants to access your account"
-  // in the .subtitle element. Assert it contains non-trivial text (not blank).
   const page = getPage(this)
-  const subtitle = page.locator('.subtitle')
-  await expect(subtitle).toBeVisible()
-  const text = await subtitle.innerText()
-  if (!text.trim()) {
-    throw new Error('Consent screen subtitle is empty — expected client name')
-  }
+  const clientName = page.locator('.subtitle strong')
+  await expect(clientName).toBeVisible()
+  await expect(clientName).not.toHaveText(/^\s*$/)
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Then("it shows the demo client's name", async function (this: EpdsWorld) {
// The consent page renders "<client_name> wants to access your account"
// in the .subtitle element. Assert it contains non-trivial text (not blank).
const page = getPage(this)
const subtitle = page.locator('.subtitle')
await expect(subtitle).toBeVisible()
const text = await subtitle.innerText()
if (!text.trim()) {
throw new Error('Consent screen subtitle is empty — expected client name')
}
})
Then("it shows the demo client's name", async function (this: EpdsWorld) {
const page = getPage(this)
const clientName = page.locator('.subtitle strong')
await expect(clientName).toBeVisible()
await expect(clientName).not.toHaveText(/^\s*$/)
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/step-definitions/consent.steps.ts` around lines 24 - 34, The test
currently asserts any non-empty text in the .subtitle but should verify the
actual client name; update the Then("it shows the demo client's name", async
function (this: EpdsWorld) { ... }) step to target the client name element (e.g.
use the locator '.subtitle strong' instead of '.subtitle') and assert its
trimmed innerText equals the expected client name (load/compare against the
value in client-metadata.json) using getPage(...) and the subtitle locator so
the test fails if the <strong> client name is missing or incorrect.

Comment on lines +12 to 20
Given a returning user has a PDS account
When the demo client initiates an OAuth login
And the user enters the test email on the login page
Then an OTP email arrives in the mail trap
When the user enters the OTP code
Then a consent screen is displayed
And it shows the demo client's name and requested permissions
And it shows the demo client's name
When the user clicks "Approve"
Then the browser is redirected back to the demo client with a valid session
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

The “valid session” assertion is weaker than the scenario text.

Then the browser is redirected back to the demo client with a valid session currently just waits for **/welcome in the shared auth step. On Lines 33-44, that makes it effectively the same check as Then no consent screen is shown, so the session/token part is never asserted explicitly.

🔍 Make the session check explicit
-    Then the browser is redirected back to the demo client with a valid session
+    Then the browser is redirected back to the demo client
+    And the demo client has a valid OAuth access token

Apply the same change to the other consent-success scenarios here, or strengthen the shared step implementation instead.

Also applies to: 33-39, 42-44

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

In `@features/consent-screen.feature` around lines 12 - 20, The step "Then the
browser is redirected back to the demo client with a valid session" only checks
the URL (via the shared auth step that waits for **/welcome) and thus duplicates
"Then no consent screen is shown" without asserting session validity; update the
step (or the shared step implementation used by it) to explicitly verify
authentication state after redirect by asserting a real session artifact — e.g.,
check for the demo client's session cookie (name used by the app), an access/id
token in localStorage, or call the demo client's session endpoint (e.g.,
/api/session) to confirm the user is authenticated — and apply the same stronger
assertion to the other consent-success scenarios and the shared step referenced
by "Then no consent screen is shown".

@Kzoeps Kzoeps force-pushed the e2e-test-additional branch from 149cb11 to 8b9d00b Compare March 31, 2026 11:35
@Kzoeps
Copy link
Copy Markdown
Contributor Author

Kzoeps commented Apr 1, 2026

@coderabbitai please review this

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

@Kzoeps: Sure! I'll start reviewing the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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)
e2e/step-definitions/auth.steps.ts (1)

50-55: Consider extracting the nested ternary for readability.

The charset detection logic works correctly but the nested ternary is dense. Extracting to a helper or using early returns would improve clarity.

♻️ Optional refactor to improve readability
-  const otpCharset =
-    inputModeAttr === 'numeric' || patternAttr === `[0-9]{${otpLength}}`
-      ? 'numeric'
-      : patternAttr === `[A-Z0-9]{${otpLength}}`
-        ? 'alphanumeric'
-        : testEnv.otpCharset
+  let otpCharset: 'numeric' | 'alphanumeric'
+  if (inputModeAttr === 'numeric' || patternAttr === `[0-9]{${otpLength}}`) {
+    otpCharset = 'numeric'
+  } else if (patternAttr === `[A-Z0-9]{${otpLength}}`) {
+    otpCharset = 'alphanumeric'
+  } else {
+    otpCharset = testEnv.otpCharset
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/step-definitions/auth.steps.ts` around lines 50 - 55, The nested ternary
that computes otpCharset is hard to read; extract the logic into a small helper
like getOtpCharset(inputModeAttr, patternAttr, otpLength, testEnv) or replace
the ternary with an explicit if/else block: check if inputModeAttr === 'numeric'
or patternAttr matches `[0-9]{${otpLength}}` then return 'numeric', else if
patternAttr matches `[A-Z0-9]{${otpLength}}` return 'alphanumeric', otherwise
return testEnv.otpCharset; update the original assignment to call that helper or
use the clearer control flow and keep the same variable name otpCharset.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/step-definitions/auth.steps.ts`:
- Around line 50-55: The nested ternary that computes otpCharset is hard to
read; extract the logic into a small helper like getOtpCharset(inputModeAttr,
patternAttr, otpLength, testEnv) or replace the ternary with an explicit if/else
block: check if inputModeAttr === 'numeric' or patternAttr matches
`[0-9]{${otpLength}}` then return 'numeric', else if patternAttr matches
`[A-Z0-9]{${otpLength}}` return 'alphanumeric', otherwise return
testEnv.otpCharset; update the original assignment to call that helper or use
the clearer control flow and keep the same variable name otpCharset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab9c56de-0558-4235-a822-2eb6e4c37ff7

📥 Commits

Reviewing files that changed from the base of the PR and between 3aa4220 and fb0eb71.

📒 Files selected for processing (9)
  • .github/workflows/e2e-pr.yml
  • e2e/.env.example
  • e2e/cucumber.mjs
  • e2e/step-definitions/auth.steps.ts
  • e2e/step-definitions/internal-api.steps.ts
  • e2e/support/env.ts
  • e2e/support/utils.ts
  • e2e/support/world.ts
  • features/internal-api.feature
✅ Files skipped from review due to trivial changes (2)
  • e2e/support/env.ts
  • e2e/.env.example
🚧 Files skipped from review as they are similar to previous changes (2)
  • e2e/cucumber.mjs
  • e2e/support/utils.ts

@aspiers aspiers deleted the branch hypercerts-org:e2e-tests April 2, 2026 16:48
@aspiers aspiers closed this Apr 2, 2026
@aspiers
Copy link
Copy Markdown
Contributor

aspiers commented Apr 2, 2026

Oh this was a stacked PR and it gets auto-closed if the target branch is deleted. Restored and reopening.

@aspiers aspiers reopened this Apr 2, 2026
Given "alice@example.com" has a PDS account with DID "did:plc:alice"
When GET /_internal/account-by-email?email=alice@example.com is called with valid x-internal-secret
Then the response is 200 with { "did": "did:plc:alice" }
Scenario: Account lookup by email returns the account's DID
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.

@Kzoeps I'm not sure it's a good idea to be testing internal stuff. These are not part of a feature but rather implementation details, and the point of E2E tests is to test functionality for users in a more black box way. Were there any particular reasons why we need this file?

e2e/cucumber.mjs Outdated
import: ['e2e/step-definitions/**/*.ts', 'e2e/support/**/*.ts'],
format: ['pretty', 'html:reports/e2e.html'],
tags: 'not @manual',
tags: 'not @manual and not @docker-only',
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.

We should have an @email tag for tests involving sending email.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 3, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
C Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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