Skip to content

verify staging checkout converts the installed app to Pro - #8939

Open
atavism wants to merge 16 commits into
mainfrom
atavism/issue-3723-payment-conversion
Open

verify staging checkout converts the installed app to Pro#8939
atavism wants to merge 16 commits into
mainfrom
atavism/issue-3723-payment-conversion

Conversation

@atavism

@atavism atavism commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Complete checkout through the staging-only E2E provider in the installed Windows app. Verify the normal payment callback, server and local Pro state, success UI, and run-scoped cleanup.

For https://github.com/getlantern/engineering/issues/3723

Summary by CodeRabbit

  • New Features

    • Added desktop payment checkout support for the staging payment flow.
    • Added payment conversion testing to verify successful account upgrades to Pro.
    • Added selectable payment smoke-test suites with checkout and conversion reporting.
    • Improved checkout handling across desktop platforms.
  • Bug Fixes

    • Improved account-status checking with bounded retries and timeout handling.
    • Prevented stale account data from being updated after unsuccessful or interrupted checks.
    • Automatically handles unexpected macOS system-extension prompts during testing.

Copilot AI review requested due to automatic review settings July 30, 2026 11:00
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds desktop payment checkout and conversion smoke modes. It introduces bounded account polling, WebView JavaScript evaluation, staging E2E payment handling, reusable payment-test utilities, Windows smoke parameters, workflow selection, and artifact uploads.

Changes

Payment smoke coverage

Layer / File(s) Summary
Polling and Pro-status validation
lib/core/utils/bounded_poll.dart, lib/core/common/common.dart, test/core/utils/bounded_poll_test.dart
Adds bounded asynchronous polling. Account status checks now use a configurable timeout and update local data after a successful Pro status result.
Payment UI and conversion flow
lib/core/widgets/app_webview.dart, lib/features/auth/choose_payment_method.dart, integration_test/payment/desktop_stripe_checkout_smoke_test.dart, integration_test/utils/payment_robot.dart, integration_test/utils/app_robot.dart
Adds desktop E2E payment handling, WebView JavaScript evaluation, reusable payment helpers, screenshot capture, conversion tracking, and macOS prompt dismissal.
Smoke runners
.github/scripts/windows_smoke_suite.ps1, .github/scripts/macos_payment_checkout_smoke.sh
Adds Flutter Dart defines, checkout render execution, Windows conversion execution, separate screenshot paths, disabled-test logging, and CI-only macOS smoke setup.
Smoke workflow integration
.github/workflows/app-smoke-tests.yml, .github/workflows/build-windows.yml
Adds the payment-smoke suite, platform conditions, Windows conversion execution, and checkout and conversion artifact uploads.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SmokeTest
  participant PaymentRobot
  participant AppWebViewObserver
  participant WebViewController
  participant AccountStatus
  SmokeTest->>PaymentRobot: load plan and open payment route
  PaymentRobot->>AppWebViewObserver: start checkout observation
  AppWebViewObserver->>WebViewController: evaluate completion JavaScript
  SmokeTest->>AccountStatus: poll account status
  AccountStatus-->>SmokeTest: return Pro status
Loading

Possibly related PRs

Suggested reviewers: jigar-f

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: verifying that staging checkout converts the installed app to Pro.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 atavism/issue-3723-payment-conversion

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.

Copilot AI left a comment

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.

Pull request overview

Adds a Windows nightly “payment conversion” smoke path that completes a staging-only E2E checkout in the installed app, then verifies the callback, server/local Pro state, success UI, and run-scoped cleanup via CI artifacts/log markers.

Changes:

  • Introduces a boundedPoll utility and migrates checkUserAccountStatus to poll until the server reports userLevel=pro (with structured logging for smoke validation).
  • Enables an e2e checkout provider in Windows nightly smoke mode (including a staging-only provider injection when absent from normal plan responses).
  • Extends Windows GitHub Actions + PowerShell smoke harness to run the conversion flow end-to-end, capture artifacts, and invoke remote cleanup.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/core/utils/bounded_poll_test.dart Adds unit coverage for boundedPoll success + stall/timeout behavior.
test/core/smoke/payment_checkout_smoke_test.dart Verifies CLI parsing accepts the staging-only e2e provider.
lib/lantern_app.dart Injects the e2e provider into desktop plans for smoke sessions when missing.
lib/features/auth/choose_payment_method.dart Routes e2e provider through the desktop redirect flow; adds smoke logging markers.
lib/core/widgets/app_webview.dart Logs purchase callback result for conversion smoke verification.
lib/core/utils/bounded_poll.dart New polling helper that bounds each fetch by remaining overall timeout.
lib/core/smoke/payment_checkout_smoke.dart Adds e2e to supported providers and exposes usesE2EProvider.
lib/core/common/common.dart Reworks Pro status check to poll + update local user data on success.
lib/core/common/app_dialog.dart Adds a semantics label to the Pro success logo for UI automation targeting.
.github/workflows/build-windows.yml Adds workflow input + artifact upload for payment conversion smoke.
.github/workflows/app-smoke-tests.yml Plumbs new conversion smoke toggle into the Windows smoke job.
.github/scripts/windows_smoke_suite.ps1 Runs the new conversion smoke mode and uploads its artifacts.
.github/scripts/windows_payment_checkout_smoke.ps1 Implements conversion assertions, captures screenshots/results, and calls staging cleanup endpoint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/core/utils/bounded_poll.dart
Comment thread lib/core/common/common.dart
@atavism
atavism force-pushed the atavism/issue-3723 branch from 3368f58 to 886043e Compare August 3, 2026 20:17
@jigar-f

jigar-f commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@atavism Is this ready for review?

@atavism
atavism requested a review from jigar-f August 9, 2026 06:57
@atavism
atavism force-pushed the atavism/issue-3723 branch from 152415a to 80f2b89 Compare August 9, 2026 07:49
@atavism
atavism force-pushed the atavism/issue-3723-payment-conversion branch from 3373297 to fead90c Compare August 9, 2026 07:49
Base automatically changed from atavism/issue-3723 to main August 10, 2026 10:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (10)
lib/lantern_app.dart (1)

118-125: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a machine-readable failure marker.

The bootstrap swallows every error and logs event=bootstrap_error. The app then stays on the default route with no visible indication. If the Windows runner waits for event=ready, it can only detect the failure through a timeout, which produces a slow and unclear result. Log an explicit terminal marker, or surface the error in the UI, so the runner can fail fast with the cause.

🤖 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 `@lib/lantern_app.dart` around lines 118 - 125, The bootstrap error path in the
payment checkout smoke flow must emit an explicit terminal failure marker after
logging the exception, such as a machine-readable event containing the error
details, so the Windows runner can fail fast instead of waiting for event=ready.
Update the catch block around the bootstrap logic while preserving the existing
error and stack-trace logging.
test/core/smoke/payment_checkout_smoke_test.dart (1)

48-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the non-Windows path.

The gate in parse rejects on !isWindows || buildType != 'nightly'. This test only exercises the buildType half. Add a case with isWindows: false so a future change cannot drop the platform half of the gate silently.

💚 Proposed additional test
     test('rejects the hook outside a Windows nightly build', () {
       expect(
         () => PaymentCheckoutSmokeConfig.parse(
           const [
             '--payment-checkout-smoke=stripe',
             '--payment-checkout-run-id=9a1632f8-5b33-4d6f-8a42-7a8a4f77d829',
           ],
           isWindows: true,
           buildType: 'production',
         ),
         throwsFormatException,
       );
+      expect(
+        () => PaymentCheckoutSmokeConfig.parse(
+          const [
+            '--payment-checkout-smoke=stripe',
+            '--payment-checkout-run-id=9a1632f8-5b33-4d6f-8a42-7a8a4f77d829',
+          ],
+          isWindows: false,
+          buildType: 'nightly',
+        ),
+        throwsFormatException,
+      );
     });
🤖 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 `@test/core/smoke/payment_checkout_smoke_test.dart` around lines 48 - 60, Add a
separate assertion in the test covering PaymentCheckoutSmokeConfig.parse where
isWindows is false and buildType is nightly, using the same hook arguments and
expecting a FormatException. Keep the existing production-on-Windows case to
retain coverage of the build-type condition.
test/core/utils/bounded_poll_test.dart (1)

22-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider covering the non-positive timeout guard.

boundedPoll returns null immediately when timeout <= Duration.zero, and it never calls fetch. No test covers that branch. Add a small case so the guard stays intact.

♻️ Proposed additional test
     test('bounds a stalled fetch by the overall timeout', () async {

Add after the existing tests:

    test('returns null without fetching when the timeout is not positive', () async {
      var calls = 0;
      final result = await boundedPoll<String>(
        timeout: Duration.zero,
        fetch: (_) async {
          calls++;
          return 'pro';
        },
      );

      expect(result, isNull);
      expect(calls, 0);
    });
🤖 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 `@test/core/utils/bounded_poll_test.dart` around lines 22 - 35, Add a test
alongside the existing boundedPoll tests covering a zero or otherwise
non-positive timeout. Assert boundedPoll<String> returns null and the fetch
callback is never invoked, preserving the guard behavior.
lib/core/common/app_dialog.dart (1)

117-142: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The automation token is announced to screen-reader users.

label here does not replace the child semantics, because excludeSemantics is not set. Assistive technology reads payment-conversion-success in addition to the localized title and description of a production success dialog.

identifier carries the same value to Windows UI Automation as AutomationId without changing the spoken label. See the consolidated comment for the full change across the payment screens.

🤖 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 `@lib/core/common/app_dialog.dart` around lines 117 - 142, Update the Semantics
widget in the payment-conversion-success dialog to replace the spoken label
property with the identifier property, preserving the existing value and child
semantics so screen readers announce only the localized title and description
while Windows UI Automation retains the automation ID.
.github/workflows/app-smoke-tests.yml (1)

151-151: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider gating the conversion smoke behind its own opt-in input.

This line enables the payment-to-Pro conversion smoke on every run where tests is all or empty. That run creates a disposable local Windows user, drives the installed app through a real staging checkout, and depends on cross-user UI Automation. See the comment on .github/scripts/windows_payment_checkout_smoke.ps1 Lines 502-528.

Until that path is proven on hosted runners, keep it opt-in so a failure does not turn every nightly run red.

♻️ Proposed change
-      run_payment_conversion_smoke: ${{ (inputs.tests || 'all') == 'all' }}
+      run_payment_conversion_smoke: ${{ inputs.tests == 'payment_conversion' }}
🤖 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 @.github/workflows/app-smoke-tests.yml at line 151, Update the
run_payment_conversion_smoke condition so the payment-to-Pro conversion smoke
runs only when its dedicated opt-in input is explicitly enabled, while
preserving the existing tests selection behavior for other smoke tests. Define
or reuse the workflow input symbol for this opt-in rather than enabling the
conversion smoke whenever tests is all or empty.
lib/features/auth/choose_payment_method.dart (2)

657-673: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The onTap handler duplicates the button callback.

PrimaryButton already calls onSubscribe in onPressed. The Semantics.onTap handler adds a second path to the same callback. beginPaymentRedirect guards against a concurrent second run, so this is not a correctness defect, but the extra handler is redundant. Removing it also keeps a single owner of the tap action.

Note: excludeSemantics: true also hides the localized subscribe / checkout label from assistive technology. See the consolidated comment on this file.

♻️ Proposed change
               Semantics(
                 container: true,
-                excludeSemantics: true,
-                label: 'payment-checkout-${method.providers.name}',
+                identifier: 'payment-checkout-${method.providers.name}',
                 button: true,
                 enabled: !isSubmitting,
-                onTap: isSubmitting ? null : () => onSubscribe.call(method),
                 child: PrimaryButton(
🤖 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 `@lib/features/auth/choose_payment_method.dart` around lines 657 - 673, Remove
the redundant Semantics.onTap handler and its isSubmitting conditional from the
Semantics wrapping PrimaryButton; keep PrimaryButton.onPressed as the sole
caller of onSubscribe.call(method), while preserving the existing enabled state
and other semantics properties.

559-572: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Semantics.identifier for automation names. Put the automation tokens on identifier instead of Semantics.label at the payment provider row, checkout button, and conversion-success dialog. Update the corresponding Windows smoke script UIA lookups to search AutomationIdProperty for "payment-provider-$Provider", "payment-checkout-$Provider", and "payment-conversion-success".

🤖 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 `@lib/features/auth/choose_payment_method.dart` around lines 559 - 572, Replace
the automation tokens currently assigned through Semantics.label with
Semantics.identifier for the payment-provider row in
lib/features/auth/choose_payment_method.dart lines 559-572, the checkout button
in lib/features/auth/choose_payment_method.dart lines 657-673, and the
conversion-success dialog in lib/core/common/app_dialog.dart lines 117-142.
Update the corresponding Windows smoke script UIA lookups to use
AutomationIdProperty with "payment-provider-$Provider",
"payment-checkout-$Provider", and "payment-conversion-success".
.github/scripts/windows_payment_checkout_smoke.ps1 (3)

343-353: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename $profile; it shadows a PowerShell automatic variable.

$profile holds the path of the current profile script. Use a distinct name such as $userProfile.

♻️ Proposed change
   for ($i = 0; $i -lt 15; $i++) {
-    $profile = Get-CimInstance Win32_UserProfile -Filter "SID='$SID'" -ErrorAction SilentlyContinue
-    if (-not $profile) { return }
-    if (-not $profile.Loaded) {
-      Remove-CimInstance $profile
+    $userProfile = Get-CimInstance Win32_UserProfile -Filter "SID='$SID'" -ErrorAction SilentlyContinue
+    if (-not $userProfile) { return }
+    if (-not $userProfile.Loaded) {
+      Remove-CimInstance $userProfile
       return
     }
🤖 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 @.github/scripts/windows_payment_checkout_smoke.ps1 around lines 343 - 353,
Rename the local `$profile` variable in the disposable-profile cleanup loop to a
distinct name such as `$userProfile`, and update its checks and
`Remove-CimInstance` call consistently without changing the cleanup behavior.

Source: Linters/SAST tools


262-301: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Any single main-frame error fails the whole case, even after a successful load.

Wait-CheckoutDocument scans the complete log text on each iteration. One event=navigation_error line anywhere in the log throws, including an aborted navigation that the redirect chain supersedes and errors that occur after the checkout page already rendered. The same applies to Wait-PaymentConversion at Line 312.

Scope the error check to the target host, or evaluate the success match before the error match so a rendered checkout page is not discarded.

♻️ Proposed change
-      if ($logText -match 'PAYMENT_WEBVIEW_SMOKE event=navigation_error') {
-        throw "The checkout WebView reported a main-frame navigation error"
-      }
-      if ($logText -match 'PAYMENT_WEBVIEW_SMOKE event=document_error') {
-        throw "The checkout WebView could not inspect the loaded document"
-      }
       if ($logText -match 'PAYMENT_CHECKOUT_SMOKE event=(rejected|bootstrap_error)') {
         throw "Lantern could not prepare the requested checkout smoke"
       }
       foreach ($match in [regex]::Matches($logText, $linePattern)) {

Then re-check navigation_error and document_error for the expected host only after the success loop finds no match.

🤖 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 @.github/scripts/windows_payment_checkout_smoke.ps1 around lines 262 - 301,
Update Wait-CheckoutDocument and Wait-PaymentConversion so successful
checkout/conversion matches are evaluated before failure markers, and only treat
navigation_error or document_error events for the expected host as fatal.
Preserve unrelated-host errors and stale errors after a rendered target page,
allowing the successful result to return before any subsequent error check.

396-406: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

The transcript starts before the credential is created; document the plaintext password.

Start-Transcript at Line 396 is active while the script builds $passwordText and calls ConvertTo-SecureString -AsPlainText. The transcript is uploaded as a workflow artifact. PowerShell transcripts record commands and output rather than variable values, so the generated password should not appear, but the margin is thin. PSScriptAnalyzer also reports PSAvoidUsingConvertToSecureStringWithPlainText as an error here.

Create the credential before Start-Transcript, and add a short comment plus a scoped suppression so the analyzer error is intentional rather than ignored.

🤖 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 @.github/scripts/windows_payment_checkout_smoke.ps1 around lines 396 - 406,
Move the `$passwordText`, `$securePassword`, and `$credential` initialization
before `Start-Transcript` in the surrounding setup flow, while preserving their
existing values and usage. Add a brief comment documenting the intentional
plaintext conversion and apply a narrowly scoped suppression for
`PSAvoidUsingConvertToSecureStringWithPlainText`; keep transcript startup and
subsequent local-user creation behavior unchanged.

Source: Linters/SAST tools

🤖 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 @.github/scripts/windows_payment_checkout_smoke.ps1:
- Around line 111-137: Update Use-StagingService to explicitly stop and delete
the existing LanternSvc service before invoking InstalledDaemonPath install for
staging. Ensure the cleanup handles an absent service safely, then preserve the
existing installation, wait, and PathName validation flow.

In @.github/scripts/windows_smoke_suite.ps1:
- Around line 389-392: The payment checkout switch is incorrectly shared by
pre-installer and installed-app suites. In
.github/scripts/windows_smoke_suite.ps1 lines 389-392, add and use a distinct
RunInstalledPaymentCheckoutSmoke switch for the installer-gated block; in
.github/workflows/build-windows.yml lines 331-343, pass it only from the
installer smoke step while leaving the pre-installer step on
RunPaymentCheckoutSmoke.
- Around line 389-419: Remove the $LASTEXITCODE validation blocks after both
invocations of windows_payment_checkout_smoke.ps1 in the RunPaymentCheckoutSmoke
and RunPaymentConversionSmoke branches. Continue relying on the child script’s
propagated terminating exceptions for failure handling, while preserving the
existing arguments and step messages.

In `@lib/core/common/common.dart`:
- Around line 142-186: In checkUserAccountStatus, check that the BuildContext is
still mounted immediately before
ref.read(homeProvider.notifier).updateUserData(proUser). Return false without
reading or updating homeProvider when the context has been disposed, while
preserving the existing successful update path for mounted contexts.

In `@lib/core/smoke/payment_checkout_smoke.dart`:
- Around line 27-42: Change the argument-processing flow around
`_singleArgument` so the presence of payment-checkout-smoke prefixes is detected
without validating their values first; apply the Windows nightly gate before
calling `_singleArgument` for `_providerPrefix` and `_runIDPrefix`. Preserve the
null-mode behavior for absent prefixes, and ensure malformed or empty values
still throw on Windows nightly builds.

In `@lib/core/widgets/app_webview.dart`:
- Around line 210-235: Update the WebView load-completion flow around
_logSmokeEvent and _notifyPageLoaded so document inspection and the load_stop
smoke event run even when observer is null. Only call _notifyPageLoaded when an
observer exists, and guard the catch-path observer.onPageLoadFailed callback
similarly while retaining error logging and document_error smoke reporting.

In `@lib/features/auth/choose_payment_method.dart`:
- Around line 490-492: Update the account-status polling path after purchase
completion, near the existing success_ui logger in choose payment flow, to emit
both required conversion markers before success_ui: server_user with the attempt
number and userLevel=pro, followed by local_user with userLevel=pro. Preserve
the existing success_ui event and ensure the markers are emitted on the
successful pro-account path.

In `@lib/lantern_app.dart`:
- Around line 64-90: The synthetic E2E provider added in
_openPaymentCheckoutSmoke must also reach checkout state, not remain only in
matchingProviders. Persist the updated provider list through
PlansNotifier.updatePlans() or pass it explicitly into ChoosePaymentMethod,
ensuring PaymentCheckoutMethods receives the injected provider while preserving
normal provider handling.

In `@lib/main.dart`:
- Around line 44-50: Update the Windows diagnostic logging block in main to
avoid emitting LOCALAPPDATA or other user-identifying paths in app logs. Gate
the existing WEBVIEW2 diagnostic behind the nightly-build condition, or replace
path logging with only the smoke-test facts needed, such as whether each folder
is set and writable.

---

Nitpick comments:
In @.github/scripts/windows_payment_checkout_smoke.ps1:
- Around line 343-353: Rename the local `$profile` variable in the
disposable-profile cleanup loop to a distinct name such as `$userProfile`, and
update its checks and `Remove-CimInstance` call consistently without changing
the cleanup behavior.
- Around line 262-301: Update Wait-CheckoutDocument and Wait-PaymentConversion
so successful checkout/conversion matches are evaluated before failure markers,
and only treat navigation_error or document_error events for the expected host
as fatal. Preserve unrelated-host errors and stale errors after a rendered
target page, allowing the successful result to return before any subsequent
error check.
- Around line 396-406: Move the `$passwordText`, `$securePassword`, and
`$credential` initialization before `Start-Transcript` in the surrounding setup
flow, while preserving their existing values and usage. Add a brief comment
documenting the intentional plaintext conversion and apply a narrowly scoped
suppression for `PSAvoidUsingConvertToSecureStringWithPlainText`; keep
transcript startup and subsequent local-user creation behavior unchanged.

In @.github/workflows/app-smoke-tests.yml:
- Line 151: Update the run_payment_conversion_smoke condition so the
payment-to-Pro conversion smoke runs only when its dedicated opt-in input is
explicitly enabled, while preserving the existing tests selection behavior for
other smoke tests. Define or reuse the workflow input symbol for this opt-in
rather than enabling the conversion smoke whenever tests is all or empty.

In `@lib/core/common/app_dialog.dart`:
- Around line 117-142: Update the Semantics widget in the
payment-conversion-success dialog to replace the spoken label property with the
identifier property, preserving the existing value and child semantics so screen
readers announce only the localized title and description while Windows UI
Automation retains the automation ID.

In `@lib/features/auth/choose_payment_method.dart`:
- Around line 657-673: Remove the redundant Semantics.onTap handler and its
isSubmitting conditional from the Semantics wrapping PrimaryButton; keep
PrimaryButton.onPressed as the sole caller of onSubscribe.call(method), while
preserving the existing enabled state and other semantics properties.
- Around line 559-572: Replace the automation tokens currently assigned through
Semantics.label with Semantics.identifier for the payment-provider row in
lib/features/auth/choose_payment_method.dart lines 559-572, the checkout button
in lib/features/auth/choose_payment_method.dart lines 657-673, and the
conversion-success dialog in lib/core/common/app_dialog.dart lines 117-142.
Update the corresponding Windows smoke script UIA lookups to use
AutomationIdProperty with "payment-provider-$Provider",
"payment-checkout-$Provider", and "payment-conversion-success".

In `@lib/lantern_app.dart`:
- Around line 118-125: The bootstrap error path in the payment checkout smoke
flow must emit an explicit terminal failure marker after logging the exception,
such as a machine-readable event containing the error details, so the Windows
runner can fail fast instead of waiting for event=ready. Update the catch block
around the bootstrap logic while preserving the existing error and stack-trace
logging.

In `@test/core/smoke/payment_checkout_smoke_test.dart`:
- Around line 48-60: Add a separate assertion in the test covering
PaymentCheckoutSmokeConfig.parse where isWindows is false and buildType is
nightly, using the same hook arguments and expecting a FormatException. Keep the
existing production-on-Windows case to retain coverage of the build-type
condition.

In `@test/core/utils/bounded_poll_test.dart`:
- Around line 22-35: Add a test alongside the existing boundedPoll tests
covering a zero or otherwise non-positive timeout. Assert boundedPoll<String>
returns null and the fetch callback is never invoked, preserving the guard
behavior.
🪄 Autofix

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 Plus

Run ID: 86c98dca-5e7f-4a4b-980d-49c5b99871d9

📥 Commits

Reviewing files that changed from the base of the PR and between 1a331d2 and f6c2d4a.

📒 Files selected for processing (14)
  • .github/scripts/windows_payment_checkout_smoke.ps1
  • .github/scripts/windows_smoke_suite.ps1
  • .github/workflows/app-smoke-tests.yml
  • .github/workflows/build-windows.yml
  • lib/core/common/app_dialog.dart
  • lib/core/common/common.dart
  • lib/core/smoke/payment_checkout_smoke.dart
  • lib/core/utils/bounded_poll.dart
  • lib/core/widgets/app_webview.dart
  • lib/features/auth/choose_payment_method.dart
  • lib/lantern_app.dart
  • lib/main.dart
  • test/core/smoke/payment_checkout_smoke_test.dart
  • test/core/utils/bounded_poll_test.dart

Comment thread .github/scripts/windows_payment_checkout_smoke.ps1 Outdated
Comment thread .github/scripts/windows_smoke_suite.ps1 Outdated
Comment thread .github/scripts/windows_smoke_suite.ps1 Outdated
Comment thread lib/core/common/common.dart
Comment thread lib/core/smoke/payment_checkout_smoke.dart Outdated
Comment thread lib/core/widgets/app_webview.dart Outdated
Comment thread lib/features/auth/choose_payment_method.dart Outdated
Comment thread lib/lantern_app.dart Outdated
Comment thread lib/main.dart Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
lib/core/widgets/app_webview.dart (1)

128-128: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the empty onWebViewCreated callback.

The callback body is empty. The controller is now taken from onLoadStop and the error callbacks. Drop the parameter to keep the widget configuration minimal.

♻️ Proposed cleanup
-      onWebViewCreated: (controller) {},
🤖 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 `@lib/core/widgets/app_webview.dart` at line 128, Remove the empty
onWebViewCreated callback from the widget configuration, leaving controller
acquisition through onLoadStop and the error callbacks unchanged.
.github/scripts/windows_smoke_suite.ps1 (1)

147-160: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename $args to avoid the automatic variable.

PSScriptAnalyzer flags the assignment at Line 159. $args is an automatic variable inside a PowerShell function. The assignment works here, but it shadows the automatic variable and the warning stays in the pipeline output. Rename the local variable.

♻️ Proposed rename
-  $args = @(
+  $flutterArgs = @(
     "test",
     $Path,
     "-d",
     "windows",
     "--reporter=expanded",
     "--dart-define=DISABLE_SYSTEM_TRAY=true"
   )
 
-  $args += "--dart-define=RADIANCE_ENV=$RadianceEnvironment"
+  $flutterArgs += "--dart-define=RADIANCE_ENV=$RadianceEnvironment"
 
   foreach ($define in $DartDefines) {
-    $args += "--dart-define=$define"
+    $flutterArgs += "--dart-define=$define"
   }

Update the remaining $args references at Lines 162-171 in the same way.

🤖 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 @.github/scripts/windows_smoke_suite.ps1 around lines 147 - 160, Rename the
local `$args` collection in the smoke-test argument construction to a
non-reserved name, and update all subsequent `+=` and command-invocation
references consistently. Preserve the existing test path, Dart defines, and
argument ordering.

Source: Linters/SAST tools

lib/features/auth/choose_payment_method.dart (1)

193-207: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider gating the e2e provider case to non-production builds.

The e2e case lives in production code. It runs whenever the backend returns a provider named e2e, not only under the integration test. A build-time or environment guard keeps the test-only path unreachable in release builds. The comment documents the intent, but it does not enforce it.

🤖 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 `@lib/features/auth/choose_payment_method.dart` around lines 193 - 207, Gate
the `e2e` provider branch in the provider-selection flow so it is available only
in non-production or explicitly enabled integration-test builds. Ensure release
builds cannot enter the `paymentRedirectFlow` path for `e2e`, while preserving
the existing desktop test behavior and normal handling for other providers.
.github/workflows/app-smoke-tests.yml (1)

152-153: 📐 Maintainability & Code Quality | 🔵 Trivial

Confirm the nightly all tier should run the conversion smoke.

contains(fromJSON('["all", "payment-smoke"]'), ...) enables the conversion smoke in the nightly run. Each run creates a staging account and converts it to Pro, and the step budget is 15 minutes. If the intent is on-demand coverage only, restrict conversion to payment-smoke.

🤖 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 @.github/workflows/app-smoke-tests.yml around lines 152 - 153, Confirm the
intended tier for run_payment_conversion_smoke in the workflow: either retain
all in its contains list so nightly all runs execute conversion, or restrict the
list to payment-smoke for on-demand coverage only. Update only that condition
and leave run_payment_checkout_smoke unchanged.
integration_test/payment/desktop_stripe_checkout_smoke_test.dart (1)

437-461: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

_completionStarted blocks retries on later E2E page loads.

The guard is set on the first page load from _e2eHost. If that page is an interstitial or redirect that never renders a control labeled complete, the observer polls the wrong document for 30 s, sets failure, and never inspects the following E2E page load. Track completion instead of "started", so a later load can retry.

♻️ Proposed change
-    if (uri.host != _e2eHost || _completionStarted) return;
-    _completionStarted = true;
+    if (uri.host != _e2eHost || completeClicked || _inProgress) return;
+    _inProgress = true;
     this.uri = uri;
     this.documentLength = documentLength;
 
     try {
       screenshot = await _waitForRenderedScreenshot(captureScreenshot);
       await _saveScreenshot(screenshot!);
 
       final deadline = DateTime.now().add(const Duration(seconds: 30));
       while (DateTime.now().isBefore(deadline)) {
         final result = await evaluateJavaScript(
           _clickCompleteScript,
         ).timeout(const Duration(seconds: 5));
         if (_isJavaScriptTrue(result)) {
           completeClicked = true;
           return;
         }
         await Future<void>.delayed(_screenshotPollInterval);
       }
-      failure = 'The staging E2E completion control was not found';
     } catch (error) {
       failure = 'Unable to complete the staging checkout: $error';
+    } finally {
+      _inProgress = false;
     }

Then let the outer _waitFor at Lines 166-171 provide the timeout, and rename _completionStarted to _inProgress.

🤖 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 `@integration_test/payment/desktop_stripe_checkout_smoke_test.dart` around
lines 437 - 461, Update the completion observer around `_completionStarted` to
track only whether completion handling is currently in progress, renaming it to
`_inProgress` and clearing it when the attempt finishes or fails. Do not
permanently block subsequent `_e2eHost` page loads; allow each later load to
retry until the outer `_waitFor` timeout, and remove the inner 30-second polling
deadline and failure path that prematurely ends the retry flow.
🤖 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 @.github/scripts/windows_smoke_suite.ps1:
- Around line 355-367: Update the $RunPaymentConversionSmoke branch before
Invoke-FlutterSmokeTest to validate that $ServiceEnvironment equals staging;
fail fast with a clear error message when it does not, and only construct or run
the conversion smoke test after the validation passes.

In `@integration_test/payment/desktop_stripe_checkout_smoke_test.dart`:
- Around line 42-69: The testWidgets timeout around the desktop Stripe smoke
test is too short for the conversion flow’s combined waits. Increase the outer
timeout beyond the conversion budget so staging delays do not trigger the
generic timeout before _runPaymentConversionSmoke completes, while preserving
the existing render and conversion behavior.

---

Nitpick comments:
In @.github/scripts/windows_smoke_suite.ps1:
- Around line 147-160: Rename the local `$args` collection in the smoke-test
argument construction to a non-reserved name, and update all subsequent `+=` and
command-invocation references consistently. Preserve the existing test path,
Dart defines, and argument ordering.

In @.github/workflows/app-smoke-tests.yml:
- Around line 152-153: Confirm the intended tier for
run_payment_conversion_smoke in the workflow: either retain all in its contains
list so nightly all runs execute conversion, or restrict the list to
payment-smoke for on-demand coverage only. Update only that condition and leave
run_payment_checkout_smoke unchanged.

In `@integration_test/payment/desktop_stripe_checkout_smoke_test.dart`:
- Around line 437-461: Update the completion observer around
`_completionStarted` to track only whether completion handling is currently in
progress, renaming it to `_inProgress` and clearing it when the attempt finishes
or fails. Do not permanently block subsequent `_e2eHost` page loads; allow each
later load to retry until the outer `_waitFor` timeout, and remove the inner
30-second polling deadline and failure path that prematurely ends the retry
flow.

In `@lib/core/widgets/app_webview.dart`:
- Line 128: Remove the empty onWebViewCreated callback from the widget
configuration, leaving controller acquisition through onLoadStop and the error
callbacks unchanged.

In `@lib/features/auth/choose_payment_method.dart`:
- Around line 193-207: Gate the `e2e` provider branch in the provider-selection
flow so it is available only in non-production or explicitly enabled
integration-test builds. Ensure release builds cannot enter the
`paymentRedirectFlow` path for `e2e`, while preserving the existing desktop test
behavior and normal handling for other providers.
🪄 Autofix

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 Plus

Run ID: 9319af7b-c2f2-49ce-8836-1ad87c473aa1

📥 Commits

Reviewing files that changed from the base of the PR and between f6c2d4a and 1da858b.

📒 Files selected for processing (8)
  • .github/scripts/windows_smoke_suite.ps1
  • .github/workflows/app-smoke-tests.yml
  • .github/workflows/build-windows.yml
  • integration_test/payment/desktop_stripe_checkout_smoke_test.dart
  • lib/core/common/common.dart
  • lib/core/widgets/app_webview.dart
  • lib/features/auth/choose_payment_method.dart
  • test/core/utils/bounded_poll_test.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/core/common/common.dart
  • test/core/utils/bounded_poll_test.dart

Comment thread .github/scripts/windows_smoke_suite.ps1
Comment thread integration_test/payment/desktop_stripe_checkout_smoke_test.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@lib/features/plans/provider/plans_notifier.dart`:
- Line 18: Update the refresh tracking around _pendingBackgroundRefresh,
build(), and waitForPendingRefresh() so every active background refresh is
awaited or coalesced rather than allowing a newer future to replace an older
one. Ensure refresh completion cannot overwrite plans after
waitForPendingRefresh() returns, and add a regression test covering invalidation
during an in-progress refresh.
🪄 Autofix

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 Plus

Run ID: 8bbbc9a7-84df-401b-932c-3a8a035e9bec

📥 Commits

Reviewing files that changed from the base of the PR and between 1da858b and 20beabe.

📒 Files selected for processing (2)
  • integration_test/payment/desktop_stripe_checkout_smoke_test.dart
  • lib/features/plans/provider/plans_notifier.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • integration_test/payment/desktop_stripe_checkout_smoke_test.dart

Comment thread lib/features/plans/provider/plans_notifier.dart Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 @.github/scripts/macos_payment_checkout_smoke.sh:
- Around line 29-41: Create LANTERN_DATA_DIR with mkdir -p after it is removed
and before touching .radiance_env, preserving the existing marker creation and
Flutter test flow.
🪄 Autofix

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 Plus

Run ID: 95c89c5e-98c3-4a96-aa0c-da6a6617f39d

📥 Commits

Reviewing files that changed from the base of the PR and between 123a4c4 and dfde689.

📒 Files selected for processing (5)
  • .github/scripts/macos_payment_checkout_smoke.sh
  • .github/workflows/build-windows.yml
  • integration_test/payment/desktop_stripe_checkout_smoke_test.dart
  • integration_test/utils/app_robot.dart
  • integration_test/utils/payment_robot.dart
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/build-windows.yml
  • integration_test/payment/desktop_stripe_checkout_smoke_test.dart

Comment on lines 29 to +41
rm -rf "$LANTERN_DATA_DIR"
mkdir -p "$LANTERN_LOG_DIR"
mkdir -p "$ARTIFACT_DIR"

# The debug test build reads this marker before initializing Radiance.
touch "$LANTERN_DATA_DIR/.radiance_env"

flutter test \
"$TEST_PATH" \
-d macos \
--reporter=expanded \
--dart-define=DISABLE_SYSTEM_TRAY=true \
--dart-define=PAYMENT_SMOKE_SCREENSHOT_PATH="$SCREENSHOT_PATH" \
--dart-define=RADIANCE_ENV=staging
--dart-define=PAYMENT_SMOKE_SCREENSHOT_PATH="$SCREENSHOT_PATH"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Create LANTERN_DATA_DIR before creating the marker.

Line 29 deletes LANTERN_DATA_DIR. Line 34 then runs touch in that deleted directory. This command fails unless another process recreates the directory. Create the directory before touch.

Proposed fix
 rm -rf "$LANTERN_DATA_DIR"
+mkdir -p "$LANTERN_DATA_DIR"
 mkdir -p "$LANTERN_LOG_DIR"
 mkdir -p "$ARTIFACT_DIR"

 # The debug test build reads this marker before initializing Radiance.
 touch "$LANTERN_DATA_DIR/.radiance_env"
📝 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
rm -rf "$LANTERN_DATA_DIR"
mkdir -p "$LANTERN_LOG_DIR"
mkdir -p "$ARTIFACT_DIR"
# The debug test build reads this marker before initializing Radiance.
touch "$LANTERN_DATA_DIR/.radiance_env"
flutter test \
"$TEST_PATH" \
-d macos \
--reporter=expanded \
--dart-define=DISABLE_SYSTEM_TRAY=true \
--dart-define=PAYMENT_SMOKE_SCREENSHOT_PATH="$SCREENSHOT_PATH" \
--dart-define=RADIANCE_ENV=staging
--dart-define=PAYMENT_SMOKE_SCREENSHOT_PATH="$SCREENSHOT_PATH"
rm -rf "$LANTERN_DATA_DIR"
mkdir -p "$LANTERN_DATA_DIR"
mkdir -p "$LANTERN_LOG_DIR"
mkdir -p "$ARTIFACT_DIR"
# The debug test build reads this marker before initializing Radiance.
touch "$LANTERN_DATA_DIR/.radiance_env"
flutter test \
"$TEST_PATH" \
-d macos \
--reporter=expanded \
--dart-define=DISABLE_SYSTEM_TRAY=true \
--dart-define=PAYMENT_SMOKE_SCREENSHOT_PATH="$SCREENSHOT_PATH"
🤖 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 @.github/scripts/macos_payment_checkout_smoke.sh around lines 29 - 41, Create
LANTERN_DATA_DIR with mkdir -p after it is removed and before touching
.radiance_env, preserving the existing marker creation and Flutter test flow.

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.

3 participants