{t(($) => $.goToInit, { ns: 'login' })}
diff --git a/web/app/__tests__/error.spec.tsx b/web/app/__tests__/error.spec.tsx
new file mode 100644
index 00000000000..02f70aba22a
--- /dev/null
+++ b/web/app/__tests__/error.spec.tsx
@@ -0,0 +1,39 @@
+import { QueryErrorResetBoundary } from '@tanstack/react-query'
+import { render, screen } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import { afterEach, describe, expect, it, vi } from 'vitest'
+import CommonLayoutError from '@/app/(commonLayout)/error'
+import AppError from '@/app/error'
+
+describe('route error recovery', () => {
+ afterEach(() => {
+ vi.restoreAllMocks()
+ })
+
+ it.each([
+ {
+ name: 'root error',
+ renderError: (retry: () => void) =>
,
+ },
+ {
+ name: 'common layout error',
+ renderError: (retry: () => void) => (
+
+ ),
+ },
+ ])('resets failed queries before retrying the $name', async ({ renderError }) => {
+ const user = userEvent.setup()
+ const retry = vi.fn()
+ vi.spyOn(console, 'error').mockImplementation(() => {})
+
+ render(
+
+ {({ isReset }) => renderError(() => retry(isReset()))}
+ ,
+ )
+
+ await user.click(screen.getByRole('button', { name: 'common.errorBoundary.tryAgain' }))
+
+ expect(retry).toHaveBeenCalledWith(true)
+ })
+})
diff --git a/web/app/__tests__/layout.spec.tsx b/web/app/__tests__/layout.spec.tsx
new file mode 100644
index 00000000000..bfddd400f02
--- /dev/null
+++ b/web/app/__tests__/layout.spec.tsx
@@ -0,0 +1,71 @@
+import { QueryClient } from '@tanstack/react-query'
+
+let queryClient: QueryClient
+
+const mocks = vi.hoisted(() => ({
+ getSystemFeatures: vi.fn(),
+ requestHeaders: new Headers(),
+}))
+
+vi.mock('@/context/query-client-server', () => ({
+ getQueryClientServer: () => queryClient,
+}))
+
+vi.mock('@/env', async (importOriginal) => {
+ const actual = await importOriginal
()
+
+ return {
+ ...actual,
+ getDatasetMap: () => ({}),
+ }
+})
+
+vi.mock('@/service/server', () => ({
+ serverConsoleQuery: {
+ systemFeatures: {
+ get: {
+ queryOptions: () => ({
+ queryKey: ['console', 'system-features'],
+ queryFn: mocks.getSystemFeatures,
+ retry: false,
+ }),
+ },
+ },
+ },
+}))
+
+vi.mock('@/i18n-config/server', () => ({
+ getLocaleOnServer: async () => 'en-US',
+}))
+
+vi.mock('@/next/headers', () => ({
+ headers: async () => mocks.requestHeaders,
+}))
+
+describe('Root layout System Features bootstrap', () => {
+ beforeEach(() => {
+ vi.clearAllMocks()
+ queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
+ })
+
+ it('caches the resolved System Features for dehydration', async () => {
+ mocks.getSystemFeatures.mockResolvedValue({ deployment_edition: 'CLOUD' })
+ const { default: RootLayout } = await import('../layout')
+
+ await expect(RootLayout({ children: App
})).resolves.toBeDefined()
+
+ expect(mocks.getSystemFeatures).toHaveBeenCalledTimes(1)
+ expect(queryClient.getQueryData(['console', 'system-features'])).toEqual({
+ deployment_edition: 'CLOUD',
+ })
+ })
+
+ it('renders the client recovery path when the server prefetch fails', async () => {
+ mocks.getSystemFeatures.mockRejectedValue(new Error('system features unavailable'))
+ const { default: RootLayout } = await import('../layout')
+
+ await expect(RootLayout({ children: App
})).resolves.toBeDefined()
+
+ expect(queryClient.getQueryData(['console', 'system-features'])).toBeUndefined()
+ })
+})
diff --git a/web/app/account/(commonLayout)/account-page/index.tsx b/web/app/account/(commonLayout)/account-page/index.tsx
index 5415c56e5b7..219bdc47c03 100644
--- a/web/app/account/(commonLayout)/account-page/index.tsx
+++ b/web/app/account/(commonLayout)/account-page/index.tsx
@@ -12,7 +12,7 @@ import AppIcon from '@/app/components/base/app-icon'
import Input from '@/app/components/base/input'
import PremiumBadge from '@/app/components/base/premium-badge'
import Collapse from '@/app/components/header/account-setting/collapse'
-import { IS_CE_EDITION, validPassword } from '@/config'
+import { validPassword } from '@/config'
import { useProviderContext } from '@/context/provider-context'
import { userProfileQueryOptions } from '@/features/account-profile/client'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
@@ -243,7 +243,7 @@ export default function AccountPage() {
wrapperClassName="mt-2"
/>
)}
- {!IS_CE_EDITION && (
+ {systemFeatures.deployment_edition === 'CLOUD' && (