Skip to content

fix: ensure loading spinner stops when marketplace app installation fails#38524

Open
dodaa08 wants to merge 45 commits into
RocketChat:developfrom
dodaa08:fix/Marketplace-Loading
Open

fix: ensure loading spinner stops when marketplace app installation fails#38524
dodaa08 wants to merge 45 commits into
RocketChat:developfrom
dodaa08:fix/Marketplace-Loading

Conversation

@dodaa08
Copy link
Copy Markdown
Contributor

@dodaa08 dodaa08 commented Feb 6, 2026

Proposed changes (including videos or screenshots)

Fixes a UI issue where the Marketplace Install button spinner never stops when an app installation fails.
The loading state is now properly reset on failure so the spinner stops and the UI does not remain stuck.

Screencast.From.2026-02-06.12-41-30.mp4

Issue(s)

Fixes #38523

Also Fixes #35518
A similar issue where spinner doesn't stop.
After:

Screencast.From.2026-02-06.13-12-12.mp4

Steps to test or reproduce

Run server locally

  1. Open Marketplace
  2. Try installing any app
  3. Force installation failure
  4. Spinner should stop and show error state

Further comments

The fix uses a try-finally pattern which is the standard approach for ensuring cleanup code runs regardless of success/failure. We intentionally don't use try-catch because we want errors to propagate to the existing error handling infrastructure (React Query's
onError

handleAPIError()
→ toast notification).

This is a minimal, focused fix that only addresses the loading state management without changing any business logic or error handling behavior.

COMM-130

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling and recovery mechanisms in marketplace app operations, ensuring more reliable and consistent loading state management throughout user interactions and application purchase transactions.
  • Tests

    • Significantly expanded test coverage for marketplace app status operations with comprehensive test scenarios including multiple error handling paths, action workflows, edge cases, and state verification.

@dodaa08 dodaa08 requested a review from a team as a code owner February 6, 2026 08:11
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 6, 2026

🦋 Changeset detected

Latest commit: 3398bac

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/ui-voip Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/abac Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch
@rocket.chat/server-fetch Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot Bot commented Feb 6, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 6, 2026

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

Added centralized error handling to the AppStatus component's confirmAction method using a try-catch-finally pattern with handleAPIError. Expanded test suite from minimal coverage to comprehensive error-handling scenarios covering install, update, and purchase action failures.

Changes

Cohort / File(s) Summary
AppStatus Error Handling
apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx, AppStatus.spec.tsx
Wrapped confirmAction logic in try-catch-finally for centralized error handling; expanded test suite from basic rendering to comprehensive scenarios covering error paths for Install, Update, and Buy actions with mock failures and UI state recovery verification.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit caught errors mid-flight,
With try-catch-finally done right,
Tests multiply, mocks align,
Error paths now gracefully shine,
Marketplace flows work day and night! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: ensure loading spinner stops when marketplace app installation fails' directly and clearly describes the main change in the pull request: fixing a UI bug where the loading spinner remains active on app installation failure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.


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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 6, 2026

Codecov Report

❌ Patch coverage is 76.92308% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.76%. Comparing base (2affa17) to head (3398bac).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #38524      +/-   ##
===========================================
+ Coverage    70.70%   70.76%   +0.06%     
===========================================
  Files         3192     3192              
  Lines       113064   113061       -3     
  Branches     20466    20496      +30     
===========================================
+ Hits         79941    80008      +67     
+ Misses       31080    31009      -71     
- Partials      2043     2044       +1     
Flag Coverage Δ
unit 71.43% <76.92%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@aleksandernsilva aleksandernsilva left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!
Could you also implement some unit tests covering this behavior?

@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 6, 2026

Thanks for the contribution! Could you also implement some unit tests covering this behavior?

Yeah sure, let me try

@dougfabris dougfabris added valid A valid contribution where maintainers will review based on priority area: ui/ux Related to UI/UX, frontend code, accessibility, and user interaction labels Feb 6, 2026
@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 7, 2026

Thanks for the contribution! Could you also implement some unit tests covering this behavior?

Hi, I've added unit tests to cover this behavior. I also made some changes to error handling in another file to gracefully handle errors and clear the loading state. Please review and let me know your thoughts.

Also for the tests I added it for 2-3 places so I used a global wrapper which can be used by all the places for mook app setup.

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

🤖 Fix all issues with AI agents
In
`@apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx`:
- Around line 98-104: The error tests for install/update/purchase use a
try/catch pattern that can pass vacuously; add expect.assertions(1) at the start
of each of those tests to ensure the catch-block assertion runs — update the
three tests that call onSuccessCallback!('install'|'update'|'purchase') inside
act(...) to include expect.assertions(1) before invoking onSuccessCallback so
the expect(err).toBe(...) in the catch is enforced.
🧹 Nitpick comments (2)
apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx (2)

56-73: Smoke test with no explicit assertions.

This test only verifies the component doesn't crash on render and click. Consider adding at least one explicit assertion (e.g., button is visible) to make the test's intent clearer and prevent it from silently passing if the component changes.


86-90: The onSuccessCallback capture relies on useAppInstallationHandler being called during render.

The onSuccessCallback! non-null assertion on lines 100, 134, and 169 will throw a confusing runtime error if the hook mock isn't invoked before the callback is used (e.g., due to a conditional render path change). This is acceptable in tests but worth noting — expect.assertions() (from the previous comment) would also help catch this scenario more gracefully.

Also applies to: 120-124, 155-159

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4ce436 and 473ea06.

📒 Files selected for processing (3)
  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx
  • apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx
  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
🧠 Learnings (13)
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Follow Page Object Model pattern consistently in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.beforeAll()` and `test.afterAll()` for setup/teardown in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/page-objects/**/*.ts : Utilize existing page objects pattern from `apps/meteor/tests/e2e/page-objects/`

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure clean state for each test execution in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-10-06T20:30:45.540Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/storage/storage.ts:101-122
Timestamp: 2025-10-06T20:30:45.540Z
Learning: In `packages/apps-engine/tests/test-data/storage/storage.ts`, the stub methods (updatePartialAndReturnDocument, updateStatus, updateSetting, updateAppInfo, updateMarketplaceInfo) intentionally throw "Method not implemented." Tests using these methods must stub them using `SpyOn` from the test library rather than relying on actual implementations.

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Implement proper wait strategies for dynamic content in Playwright tests

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
📚 Learning: 2025-12-16T17:29:45.163Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37834
File: apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts:12-22
Timestamp: 2025-12-16T17:29:45.163Z
Learning: In page object files under `apps/meteor/tests/e2e/page-objects/`, always import `expect` from `../../utils/test` (Playwright's async expect), not from Jest. Jest's `expect` has a synchronous signature and will cause TypeScript errors when used with web-first assertions like `toBeVisible()`.

Applied to files:

  • apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 📦 Meteor Build (coverage)
🔇 Additional comments (4)
apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx (2)

83-86: LGTM — dismissing on API error correctly resets UI state.

The onDismiss() call after handleAPIError ensures the loading spinner stops and the modal closes when the external URL purchase flow fails.


117-120: Consistent error-handling pattern for the request flow.

Same approach as the purchase path — looks good.

apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppStatus/AppStatus.spec.tsx (2)

1-14: LGTM — mock setup is clean and follows standard patterns.


15-54: Well-structured test scaffolding with reusable wrapper factory.

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

@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 8, 2026

Thanks for the contribution! Could you also implement some unit tests covering this behavior?

Hi, I've added them but this change feels a little big and I need some feedback on weather the tests seems fine, let me know once you review, thanks.

@dodaa08 dodaa08 closed this Feb 8, 2026
@dodaa08 dodaa08 reopened this Feb 8, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/meteor/client/views/marketplace/hooks/useAppInstallationHandler.tsx">

<violation number="1">
P2: Error handling no longer calls `onDismiss`, so failures from `buildExternalUrl` / `buildExternalAppRequest` leave loading state/modal open (callers rely on `onDismiss` to reset loading).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 11, 2026

Thanks @aleksandernsilva for all the suggestions, Ran locally Screenshot From 2026-02-12 01-06-37 Commited!, Let me know your thoughts, once you review.

@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 12, 2026

@aleksandernsilva I tried a few times but the tests are failing

Screenshot From 2026-02-13 00-05-30

I think they were fine yesterday, but after a few merge they doesn't seem to pass.

@dodaa08 dodaa08 force-pushed the fix/Marketplace-Loading branch from 286bdce to e13ff25 Compare February 12, 2026 20:13
@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 15, 2026

Hi @aleksandernsilva , the checks are passing now, let me know if anything else is needed here, once you review.

@dodaa08
Copy link
Copy Markdown
Contributor Author

dodaa08 commented Feb 23, 2026

Hey, @dodaa08 . Thanks for your patience, sometimes implementing the tests takes a lot of effort, but it's worth it in the long run.

I noticed tests are suffering because the onSuccess typing and implementation is inconsistent. So let's update AppInstallationHandlerParams so onSuccess matches the implementation and returns Promise<void>.

After that, you can use the suggestions I highlighted as a guide. In the end things should look similar to your initial implementation (try/catch) with a few additions.

After these adjustments we should be good to go 🚀

PS.: Do not commit the suggestions blindly. Use them as a guide and test locally.

Hi @aleksandernsilva , I waiting for your response.

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

Labels

area: ui/ux Related to UI/UX, frontend code, accessibility, and user interaction valid A valid contribution where maintainers will review based on priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Install spinner stuck after failed marketplace install fix: Loading Stays Active When Clicking Outside Iframe Popup.

3 participants