test(web): align test state boundaries (#39239)

This commit is contained in:
yyh 2026-07-20 14:06:17 +08:00 committed by GitHub
parent 9a2d039e93
commit 15674a9db6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
281 changed files with 3881 additions and 7556 deletions

View File

@ -3,12 +3,12 @@ import type { ChatConfig } from '@/app/components/base/chat/types'
import type { AppConversationData, AppData, AppMeta, ConversationItem } from '@/models/share'
import { fireEvent, renderHook, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import ChatWithHistory from '@/app/components/base/chat/chat-with-history'
import { useChatWithHistory } from '@/app/components/base/chat/chat-with-history/hooks'
import { useThemeContext } from '@/app/components/base/chat/embedded-chatbot/theme/theme-context'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import useDocumentTitle from '@/hooks/use-document-title'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
vi.mock('@/app/components/base/chat/chat-with-history/hooks', () => ({
useChatWithHistory: vi.fn(),

View File

@ -1,5 +1,5 @@
import type { UsagePlanInfo, UsageResetInfo } from '@/app/components/billing/type'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import AnnotationFull from '@/app/components/billing/annotation-full'
@ -14,9 +14,10 @@ import TriggerEventsLimitModal from '@/app/components/billing/trigger-events-lim
import { Plan } from '@/app/components/billing/type'
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
import VectorSpaceFull from '@/app/components/billing/vector-space-full'
import { render } from '@/test/console/render'
let mockProviderCtx: Record<string, unknown> = {}
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
const mockSetShowPricingModal = vi.fn()
const mockSetShowAccountSettingModal = vi.fn()
@ -32,31 +33,21 @@ vi.mock('@/context/provider-context', () => ({
useProviderContext: () => mockProviderCtx,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/modal-context', () => ({
@ -149,8 +140,8 @@ const setupProviderContext = (
}
}
const setupAppContext = (overrides: Record<string, unknown> = {}) => {
mockAppCtx = {
const setupConsoleState = (overrides: Record<string, unknown> = {}) => {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.view', 'billing.manage', 'billing.subscription.manage'],
userProfile: { email: 'test@example.com' },
@ -168,7 +159,7 @@ const setupAppContext = (overrides: Record<string, unknown> = {}) => {
describe('Billing Page + Plan Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
// Verify that the billing page renders PlanComp with all 7 usage items
@ -256,7 +247,7 @@ describe('Billing Page + Plan Integration', () => {
describe('Billing URL button', () => {
it('should show billing button when manager has subscription management permission', () => {
setupProviderContext({ type: Plan.sandbox })
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.subscription.manage'],
})
@ -269,7 +260,7 @@ describe('Billing Page + Plan Integration', () => {
it('should hide billing button when subscription management permission is granted without manager role', () => {
setupProviderContext({ type: Plan.sandbox })
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.subscription.manage'],
})
@ -281,7 +272,7 @@ describe('Billing Page + Plan Integration', () => {
it('should hide billing button when subscription management permission is missing', () => {
setupProviderContext({ type: Plan.sandbox })
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.view', 'billing.manage'],
})
@ -301,7 +292,7 @@ describe('Billing Page + Plan Integration', () => {
it('should hide billing button when no billing permissions are granted', () => {
setupProviderContext({ type: Plan.sandbox })
setupAppContext({
setupConsoleState({
workspacePermissionKeys: [],
})
@ -319,7 +310,7 @@ describe('Billing Page + Plan Integration', () => {
describe('Plan Type Display Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
it('should render sandbox plan with upgrade button (premium badge)', () => {
@ -385,7 +376,7 @@ describe('Plan Type Display Integration', () => {
describe('Upgrade Flow Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
setupProviderContext({ type: Plan.sandbox })
})
@ -532,7 +523,7 @@ describe('Upgrade Flow Integration', () => {
describe('Capacity Full Components Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
// AppsFull renders with correct messaging and components
@ -731,7 +722,7 @@ describe('Capacity Full Components Integration', () => {
describe('PriorityLabel Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
it('should display "standard" priority for sandbox plan', () => {
@ -777,7 +768,7 @@ describe('PriorityLabel Integration', () => {
describe('Usage Display Edge Cases', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
// Vector space storage mode behavior
@ -881,7 +872,7 @@ describe('Usage Display Edge Cases', () => {
describe('Cross-Component Upgrade Flow', () => {
beforeEach(() => {
vi.clearAllMocks()
setupAppContext()
setupConsoleState()
})
it('should trigger pricing from AppsFull upgrade button', async () => {

View File

@ -9,47 +9,30 @@
*/
import type { BasicPlan } from '@/app/components/billing/type'
import { toast, ToastHost } from '@langgenius/dify-ui/toast'
import { cleanup, render, screen, waitFor } from '@testing-library/react'
import { cleanup, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { ALL_PLANS } from '@/app/components/billing/config'
import { PlanRange } from '@/app/components/billing/pricing/plan-switcher/plan-range-switcher'
import CloudPlanItem from '@/app/components/billing/pricing/plans/cloud-plan-item'
import { Plan } from '@/app/components/billing/type'
import { render } from '@/test/console/render'
// ─── Mock state ──────────────────────────────────────────────────────────────
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
const mockFetchSubscriptionUrls = vi.fn()
const mockInvoices = vi.fn()
const mockOpenAsyncWindow = vi.fn()
// ─── Context mocks ───────────────────────────────────────────────────────────
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
// ─── Service mocks ───────────────────────────────────────────────────────────
@ -79,8 +62,8 @@ vi.mock('@/next/navigation', () => ({
}))
// ─── Helpers ─────────────────────────────────────────────────────────────────
const setupAppContext = (overrides: Record<string, unknown> = {}) => {
mockAppCtx = {
const setupConsoleState = (overrides: Record<string, unknown> = {}) => {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.view', 'billing.manage', 'billing.subscription.manage'],
...overrides,
@ -116,7 +99,7 @@ describe('Cloud Plan Payment Flow', () => {
vi.clearAllMocks()
cleanup()
toast.dismiss()
setupAppContext()
setupConsoleState()
mockFetchSubscriptionUrls.mockResolvedValue({ url: 'https://pay.example.com/checkout' })
mockInvoices.mockResolvedValue({ url: 'https://billing.example.com/invoices' })
})
@ -295,7 +278,7 @@ describe('Cloud Plan Payment Flow', () => {
// ─── 5. Permission Check ────────────────────────────────────────────────
describe('Permission check', () => {
it('should change plans when billing manage permission is granted without manager role', async () => {
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.manage'],
})
@ -311,7 +294,7 @@ describe('Cloud Plan Payment Flow', () => {
})
it('should show error toast when billing manage permission is missing for plan changes', async () => {
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.view', 'billing.subscription.manage'],
})
@ -328,7 +311,7 @@ describe('Cloud Plan Payment Flow', () => {
})
it('should open billing portal when subscription management permission is granted without manager role', async () => {
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.subscription.manage'],
})
@ -345,7 +328,7 @@ describe('Cloud Plan Payment Flow', () => {
})
it('should show error toast when subscription management permission is missing for current paid plan', async () => {
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.view', 'billing.manage'],
})

View File

@ -8,16 +8,17 @@
* Also covers education button visibility based on context flags.
*/
import type { UsagePlanInfo, UsageResetInfo } from '@/app/components/billing/type'
import { cleanup, render, screen, waitFor } from '@testing-library/react'
import { cleanup, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { defaultPlan } from '@/app/components/billing/config'
import PlanComp from '@/app/components/billing/plan'
import { Plan } from '@/app/components/billing/type'
import { render } from '@/test/console/render'
// ─── Mock state ──────────────────────────────────────────────────────────────
let mockProviderCtx: Record<string, unknown> = {}
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
const mockSetShowPricingModal = vi.fn()
const mockSetShowAccountSettingModal = vi.fn()
const mockRouterPush = vi.fn()
@ -37,31 +38,21 @@ vi.mock('@/context/provider-context', () => ({
useProviderContext: () => mockProviderCtx,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/modal-context', () => ({
@ -164,7 +155,7 @@ const setupContexts = (
allowRefreshEducationVerify: false,
...providerOverrides,
}
mockAppCtx = {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.view', 'billing.manage', 'billing.subscription.manage'],
userProfile: { email: 'student@university.edu' },

View File

@ -8,47 +8,38 @@
* Validates cross-component state propagation when the user switches between
* cloud / self-hosted categories and monthly / yearly plan ranges.
*/
import { cleanup, render, screen } from '@testing-library/react'
import { cleanup, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { ALL_PLANS } from '@/app/components/billing/config'
import Pricing from '@/app/components/billing/pricing'
import { Plan } from '@/app/components/billing/type'
import { render } from '@/test/console/render'
// ─── Mock state ──────────────────────────────────────────────────────────────
let mockProviderCtx: Record<string, unknown> = {}
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
// ─── Context mocks ───────────────────────────────────────────────────────────
vi.mock('@/context/provider-context', () => ({
useProviderContext: () => mockProviderCtx,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/i18n', () => ({
@ -138,7 +129,7 @@ const setupContexts = (
isEducationAccount: false,
allowRefreshEducationVerify: false,
}
mockAppCtx = {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.view', 'billing.manage', 'billing.subscription.manage'],
userProfile: { email: 'test@example.com' },

View File

@ -8,7 +8,7 @@ import { toast, ToastHost } from '@langgenius/dify-ui/toast'
* Covers community/premium/enterprise plan rendering, external URL navigation,
* and workspace manager permission enforcement.
*/
import { cleanup, render, screen, waitFor } from '@testing-library/react'
import { cleanup, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import {
@ -18,37 +18,20 @@ import {
} from '@/app/components/billing/config'
import SelfHostedPlanItem from '@/app/components/billing/pricing/plans/self-hosted-plan-item'
import { SelfHostedPlan } from '@/app/components/billing/type'
import { render } from '@/test/console/render'
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
const originalLocation = window.location
let assignedHref = ''
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/hooks/use-theme', () => ({
@ -69,8 +52,8 @@ vi.mock('@/app/components/billing/pricing/plans/self-hosted-plan-item/list', ()
),
}))
const setupAppContext = (overrides: Record<string, unknown> = {}) => {
mockAppCtx = {
const setupConsoleState = (overrides: Record<string, unknown> = {}) => {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.manage'],
...overrides,
@ -91,7 +74,7 @@ describe('Self-Hosted Plan Flow', () => {
vi.clearAllMocks()
cleanup()
toast.dismiss()
setupAppContext()
setupConsoleState()
// Mock window.location with minimal getter/setter (Location props are non-enumerable)
assignedHref = ''
@ -208,7 +191,7 @@ describe('Self-Hosted Plan Flow', () => {
// ─── 3. Permission Check ────────────────────────────────────────────────
describe('Permission check', () => {
it('should redirect when billing manage permission is granted without manager role', async () => {
setupAppContext({
setupConsoleState({
isCurrentWorkspaceManager: false,
workspacePermissionKeys: ['billing.manage'],
})
@ -222,7 +205,7 @@ describe('Self-Hosted Plan Flow', () => {
})
it('should show error toast when billing manage permission is missing for community button', async () => {
setupAppContext({ workspacePermissionKeys: [] })
setupConsoleState({ workspacePermissionKeys: [] })
const user = userEvent.setup()
renderSelfHostedPlanItem(SelfHostedPlan.community)
@ -237,7 +220,7 @@ describe('Self-Hosted Plan Flow', () => {
})
it('should show error toast when billing manage permission is missing for premium button', async () => {
setupAppContext({ workspacePermissionKeys: [] })
setupConsoleState({ workspacePermissionKeys: [] })
const user = userEvent.setup()
renderSelfHostedPlanItem(SelfHostedPlan.premium)
@ -251,7 +234,7 @@ describe('Self-Hosted Plan Flow', () => {
})
it('should show error toast when billing manage permission is missing for enterprise button', async () => {
setupAppContext({ workspacePermissionKeys: [] })
setupConsoleState({ workspacePermissionKeys: [] })
const user = userEvent.setup()
renderSelfHostedPlanItem(SelfHostedPlan.enterprise)

View File

@ -1,12 +1,9 @@
import { screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import { renderToString } from 'react-dom/server'
import {
createSystemFeaturesWrapper,
renderWithSystemFeatures,
} from '@/__tests__/utils/mock-system-features'
import WebAppStoreProvider, { useWebAppStore } from '@/context/web-app-context'
import { AccessMode } from '@/models/access-control'
import { createConsoleQueryWrapper, renderWithConsoleQuery } from '@/test/console/query-data'
const navigationMocks = vi.hoisted(() => ({
usePathname: vi.fn(() => '/chatbot/sample-app'),
@ -89,7 +86,7 @@ describe('WebAppStoreProvider embedded user id handling', () => {
configurable: true,
value: undefined,
})
const { wrapper: Wrapper } = createSystemFeaturesWrapper()
const { wrapper: Wrapper } = createConsoleQueryWrapper()
try {
expect(() =>
@ -118,7 +115,7 @@ describe('WebAppStoreProvider embedded user id handling', () => {
navigationMocks.useSearchParams.mockReturnValue(params)
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({})
renderWithSystemFeatures(
renderWithConsoleQuery(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,
@ -133,7 +130,7 @@ describe('WebAppStoreProvider embedded user id handling', () => {
navigationMocks.usePathname.mockReturnValue(pathname)
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({})
renderWithSystemFeatures(
renderWithConsoleQuery(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,
@ -149,7 +146,7 @@ describe('WebAppStoreProvider embedded user id handling', () => {
conversation_id: 'conversation-456',
})
renderWithSystemFeatures(
renderWithConsoleQuery(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,
@ -171,7 +168,7 @@ describe('WebAppStoreProvider embedded user id handling', () => {
}))
mockGetProcessedSystemVariablesFromUrlParams.mockResolvedValue({})
renderWithSystemFeatures(
renderWithConsoleQuery(
<WebAppStoreProvider>
<TestConsumer />
</WebAppStoreProvider>,

View File

@ -1,234 +0,0 @@
import type { LangGeniusVersionInfo } from '@/context/app-context-types'
import type { ICurrentWorkspace } from '@/models/common'
const APP_CONTEXT_STATE_ATOM_KIND = Symbol('app-context-state-atom-kind')
export type AppContextStateMockState = {
userProfile?: {
id?: string
name?: string
email?: string
avatar?: string | null
avatar_url?: string | null
is_password_set?: boolean
} | null
currentWorkspace?:
| ({
id?: string
name?: string
} & Partial<ICurrentWorkspace>)
| null
isCurrentWorkspaceManager?: boolean
isCurrentWorkspaceOwner?: boolean
isCurrentWorkspaceEditor?: boolean
isCurrentWorkspaceDatasetOperator?: boolean
isLoadingCurrentWorkspace?: boolean
isLoadingWorkspacePermissionKeys?: boolean
workspacePermissionKeys?: string[]
datasetRbacEnabled?: boolean
langGeniusVersionInfo?: Partial<LangGeniusVersionInfo>
refreshUserProfile?: () => void
refreshCurrentWorkspace?: () => void
mutateUserProfile?: () => void
mutateCurrentWorkspace?: () => void
}
type AppContextStateAtomKind =
| 'userProfile'
| 'userProfileId'
| 'userProfileEmail'
| 'currentWorkspace'
| 'currentWorkspaceId'
| 'isCurrentWorkspaceManager'
| 'isCurrentWorkspaceOwner'
| 'isCurrentWorkspaceEditor'
| 'isCurrentWorkspaceDatasetOperator'
| 'currentWorkspaceLoading'
| 'workspacePermissionKeys'
| 'workspacePermissionKeysLoading'
| 'datasetRbacEnabled'
| 'langGeniusVersionInfo'
| 'langGeniusCurrentVersion'
| 'refreshUserProfile'
| 'refreshCurrentWorkspace'
type AppContextStateMockAtom = {
[APP_CONTEXT_STATE_ATOM_KIND]: AppContextStateAtomKind
}
type AppContextStateMockRegistry = {
getState: () => AppContextStateMockState
}
const defaultUserProfile = {
id: 'user-1',
name: 'User',
email: 'user@example.com',
avatar: '',
avatar_url: '',
is_password_set: true,
}
const defaultCurrentWorkspace = {
id: 'workspace-1',
name: 'Workspace',
plan: '',
status: '',
created_at: 0,
role: 'owner',
providers: [],
trial_credits: 0,
trial_credits_used: 0,
trial_credits_exhausted_at: 0,
next_credit_reset_date: 0,
} satisfies ICurrentWorkspace
const defaultLangGeniusVersionInfo = {
current_env: 'CLOUD',
current_version: '',
latest_version: '',
version: '',
release_date: '',
release_notes: '',
features: {
can_replace_logo: false,
model_load_balancing_enabled: false,
},
can_auto_update: false,
} satisfies LangGeniusVersionInfo
let appContextStateMockRegistry: AppContextStateMockRegistry | undefined
const createMockAtom = (kind: AppContextStateAtomKind): AppContextStateMockAtom => ({
[APP_CONTEXT_STATE_ATOM_KIND]: kind,
})
const isAppContextStateMockAtom = (atom: unknown): atom is AppContextStateMockAtom => {
return typeof atom === 'object' && atom !== null && APP_CONTEXT_STATE_ATOM_KIND in atom
}
const getUserProfile = (state: AppContextStateMockState) => ({
...defaultUserProfile,
...state.userProfile,
})
const getCurrentWorkspace = (state: AppContextStateMockState): ICurrentWorkspace => ({
...defaultCurrentWorkspace,
...state.currentWorkspace,
})
const getLangGeniusVersionInfo = (state: AppContextStateMockState): LangGeniusVersionInfo => ({
...defaultLangGeniusVersionInfo,
...state.langGeniusVersionInfo,
})
export const createAppContextStateAtomMock = async <TModule extends object>(
importOriginal: <T>() => Promise<T>,
getState: () => AppContextStateMockState,
) => {
const actual = await importOriginal<TModule>()
appContextStateMockRegistry = {
getState,
}
return {
...actual,
userProfileAtom: createMockAtom('userProfile'),
userProfileIdAtom: createMockAtom('userProfileId'),
userProfileEmailAtom: createMockAtom('userProfileEmail'),
currentWorkspaceAtom: createMockAtom('currentWorkspace'),
currentWorkspaceIdAtom: createMockAtom('currentWorkspaceId'),
isCurrentWorkspaceManagerAtom: createMockAtom('isCurrentWorkspaceManager'),
isCurrentWorkspaceOwnerAtom: createMockAtom('isCurrentWorkspaceOwner'),
isCurrentWorkspaceEditorAtom: createMockAtom('isCurrentWorkspaceEditor'),
isCurrentWorkspaceDatasetOperatorAtom: createMockAtom('isCurrentWorkspaceDatasetOperator'),
currentWorkspaceLoadingAtom: createMockAtom('currentWorkspaceLoading'),
workspacePermissionKeysAtom: createMockAtom('workspacePermissionKeys'),
workspacePermissionKeysLoadingAtom: createMockAtom('workspacePermissionKeysLoading'),
datasetRbacEnabledAtom: createMockAtom('datasetRbacEnabled'),
langGeniusVersionInfoAtom: createMockAtom('langGeniusVersionInfo'),
langGeniusCurrentVersionAtom: createMockAtom('langGeniusCurrentVersion'),
refreshUserProfileAtom: createMockAtom('refreshUserProfile'),
refreshCurrentWorkspaceAtom: createMockAtom('refreshCurrentWorkspace'),
}
}
export const createAppContextStateJotaiMock = async (importOriginal: <T>() => Promise<T>) => {
const actual = await importOriginal<typeof import('jotai')>()
return {
...actual,
useAtomValue: (atom: unknown) => {
if (!isAppContextStateMockAtom(atom))
return actual.useAtomValue(atom as Parameters<typeof actual.useAtomValue>[0])
if (!appContextStateMockRegistry)
throw new Error('App context state atom mock is not initialized')
const state = appContextStateMockRegistry.getState()
const userProfile = getUserProfile(state)
const currentWorkspace = getCurrentWorkspace(state)
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'userProfile') return userProfile
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'userProfileId') return userProfile.id
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'userProfileEmail') return userProfile.email
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'currentWorkspace') return currentWorkspace
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'currentWorkspaceId') return currentWorkspace.id
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'isCurrentWorkspaceManager')
return state.isCurrentWorkspaceManager ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'isCurrentWorkspaceOwner')
return state.isCurrentWorkspaceOwner ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'isCurrentWorkspaceEditor')
return state.isCurrentWorkspaceEditor ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'isCurrentWorkspaceDatasetOperator')
return state.isCurrentWorkspaceDatasetOperator ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'currentWorkspaceLoading')
return state.isLoadingCurrentWorkspace ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'workspacePermissionKeys')
return state.workspacePermissionKeys ?? []
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'workspacePermissionKeysLoading')
return state.isLoadingWorkspacePermissionKeys ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'datasetRbacEnabled')
return state.datasetRbacEnabled ?? false
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'langGeniusVersionInfo')
return getLangGeniusVersionInfo(state)
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'langGeniusCurrentVersion')
return getLangGeniusVersionInfo(state).current_version
throw new Error(`Unsupported app context state atom: ${atom[APP_CONTEXT_STATE_ATOM_KIND]}`)
},
useSetAtom: (atom: unknown) => {
if (!isAppContextStateMockAtom(atom))
return actual.useSetAtom(atom as Parameters<typeof actual.useSetAtom>[0])
if (!appContextStateMockRegistry)
throw new Error('App context state atom mock is not initialized')
const state = appContextStateMockRegistry.getState()
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'refreshUserProfile')
return state.refreshUserProfile ?? (() => {})
if (atom[APP_CONTEXT_STATE_ATOM_KIND] === 'refreshCurrentWorkspace')
return state.refreshCurrentWorkspace ?? (() => {})
throw new Error(
`Unsupported app context state write atom: ${atom[APP_CONTEXT_STATE_ATOM_KIND]}`,
)
},
}
}

View File

@ -1,9 +1,9 @@
import type { App } from '@/types/app'
import { screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { useStore } from '@/app/components/app/store'
import { usePathname, useRouter } from '@/next/navigation'
import { fetchAppDetailDirect } from '@/service/apps'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import AppDetailLayout from '../layout-main'
@ -11,7 +11,7 @@ import AppDetailLayout from '../layout-main'
const mockReplace = vi.fn()
let mockPathname = '/app/app-1/workflow'
let mockIsRbacEnabled = true
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
isLoadingWorkspacePermissionKeys: false,
@ -19,8 +19,8 @@ const mockAppContextState = vi.hoisted(() => ({
workspacePermissionKeys: [] as string[],
}))
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -35,37 +35,17 @@ vi.mock('@/service/apps', () => ({
fetchAppDetailDirect: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/hooks/use-document-title', () => ({
@ -96,11 +76,11 @@ describe('AppDetailLayout', () => {
vi.clearAllMocks()
mockPathname = '/app/app-1/workflow'
mockIsRbacEnabled = true
mockAppContextState.currentWorkspace = { id: 'workspace-1' }
mockAppContextState.isLoadingCurrentWorkspace = false
mockAppContextState.isLoadingWorkspacePermissionKeys = false
mockAppContextState.userProfile = { id: 'user-1' }
mockAppContextState.workspacePermissionKeys = []
mockConsoleState.currentWorkspace = { id: 'workspace-1' }
mockConsoleState.isLoadingCurrentWorkspace = false
mockConsoleState.isLoadingWorkspacePermissionKeys = false
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = []
mockUsePathname.mockImplementation(() => mockPathname)
mockUseRouter.mockReturnValue({
back: vi.fn(),
@ -266,7 +246,7 @@ describe('AppDetailLayout', () => {
})
it('should wait for workspace permission keys before redirecting restricted pages', async () => {
mockAppContextState.isLoadingWorkspacePermissionKeys = true
mockConsoleState.isLoadingWorkspacePermissionKeys = true
mockPathname = '/app/app-1/overview'
mockFetchAppDetailDirect.mockResolvedValue(
createAppDetail({ permission_keys: [AppACLPermission.ViewLayout] }),
@ -284,7 +264,7 @@ describe('AppDetailLayout', () => {
expect(mockReplace).not.toHaveBeenCalled()
expect(screen.queryByText('App page content')).not.toBeInTheDocument()
mockAppContextState.isLoadingWorkspacePermissionKeys = false
mockConsoleState.isLoadingWorkspacePermissionKeys = false
rerender(
<AppDetailLayout appId="app-1">
<div>App page content</div>

View File

@ -1,6 +1,7 @@
import type { App } from '@/types/app'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { render } from '@/test/console/render'
import CardView from '../card-view'
const mockAppState = vi.hoisted(() => ({
@ -44,58 +45,30 @@ vi.mock('@tanstack/react-query', async (importOriginal) => {
}
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-1' },
currentWorkspace: { id: 'workspace-1' },
workspacePermissionKeys: mockAppState.appDetail.permission_keys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: 'user-1' },
currentWorkspace: { id: 'workspace-1' },
workspacePermissionKeys: mockAppState.appDetail.permission_keys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'user-1' },
currentWorkspace: { id: 'workspace-1' },
workspacePermissionKeys: mockAppState.appDetail.permission_keys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'user-1' },
currentWorkspace: { id: 'workspace-1' },
workspacePermissionKeys: mockAppState.appDetail.permission_keys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'user-1' },
currentWorkspace: { id: 'workspace-1' },
workspacePermissionKeys: mockAppState.appDetail.permission_keys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/app/components/workflow/collaboration/core/collaboration-manager', () => ({
collaborationManager: {

View File

@ -1,4 +1,5 @@
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { AppACLPermission } from '@/utils/permission'
import ChartView from '../chart-view'
@ -14,6 +15,13 @@ const testState = vi.hoisted(() => ({
chartRenderSpy: vi.fn(),
}))
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/app/components/app/store', () => ({
useStore: <T,>(selector: (state: { appDetail: typeof testState.appDetail }) => T): T =>
selector({
@ -84,6 +92,14 @@ vi.mock('../time-range-picker', () => ({
default: () => <button type="button">time range</button>,
}))
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('ChartView monitor permission', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -1,5 +1,6 @@
import type { ReactNode } from 'react'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { AppACLPermission } from '@/utils/permission'
import OverviewView from '../view'
@ -14,6 +15,13 @@ const testState = vi.hoisted(() => ({
workspacePermissionKeys: [] as string[],
}))
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/app/components/app/store', () => ({
useStore: <T,>(selector: (state: { appDetail: typeof testState.appDetail }) => T): T =>
selector({
@ -38,6 +46,14 @@ vi.mock('../tracing/panel', () => ({
default: () => <button type="button">tracing</button>,
}))
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('OverviewView monitor permission', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -1,6 +1,7 @@
import type { ComponentProps, ReactNode } from 'react'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import { fetchTracingConfig, fetchTracingStatus, updateTracingStatus } from '@/service/apps'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { AppACLPermission } from '@/utils/permission'
import Panel from '../panel'
@ -13,6 +14,13 @@ const testState = vi.hoisted(() => ({
}>,
}))
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/next/navigation', () => ({
usePathname: () => '/app/app-1/overview',
}))
@ -91,6 +99,14 @@ const renderPanel = async () => {
await screen.findAllByTestId('config-button')
}
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('Tracing overview panel permissions', () => {
beforeEach(() => {
testState.appPermissionKeys = []

View File

@ -1,15 +1,15 @@
import { screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { usePathname, useRouter } from '@/next/navigation'
import { useDatasetDetail } from '@/service/knowledge/use-dataset'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { DatasetACLPermission } from '@/utils/permission'
import DatasetDetailLayout from '../layout-main'
const mockReplace = vi.fn()
let mockIsRbacEnabled = true
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -24,80 +24,31 @@ vi.mock('@/service/knowledge/use-dataset', () => ({
useDatasetDetail: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}),
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-1' },
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}),
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createWorkspaceStateModuleMock(() => ({}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}),
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}),
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}),
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createSystemFeaturesStateModuleMock(() => ({
datasetRbacEnabled: mockIsRbacEnabled,
}))
})
vi.mock('@/context/event-emitter', () => ({
@ -106,13 +57,6 @@ vi.mock('@/context/event-emitter', () => ({
}),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
vi.mock('@/hooks/use-document-title', () => ({
default: vi.fn(),
}))

View File

@ -1,10 +1,11 @@
import type { ReactNode } from 'react'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from '@/test/console/render'
import DatasetsLayout from './layout'
const mockReplace = vi.fn()
const mockUseAppContext = vi.fn()
const mockConsoleStateReader = vi.fn()
let mockPathname = '/datasets'
let mockExternalKnowledgeApiProviderEnabled: boolean | undefined
@ -15,48 +16,21 @@ vi.mock('@/next/navigation', () => ({
usePathname: () => mockPathname,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockUseAppContext())
return createWorkspaceStateModuleMock(() => mockConsoleStateReader())
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockUseAppContext())
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockUseAppContext())
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockUseAppContext())
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockUseAppContext())
return createPermissionStateModuleMock(() => mockConsoleStateReader())
})
vi.mock('@/context/external-api-panel-context', () => ({
ExternalApiPanelProvider: ({ children }: { children: ReactNode }) => <>{children}</>,
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
vi.mock('@/context/external-knowledge-api-context', () => ({
ExternalKnowledgeApiProvider: ({
children,
@ -70,7 +44,7 @@ vi.mock('@/context/external-knowledge-api-context', () => ({
},
}))
type AppContextMock = {
type ConsoleStateFixture = {
isCurrentWorkspaceEditor: boolean
isCurrentWorkspaceDatasetOperator: boolean
isLoadingCurrentWorkspace: boolean
@ -81,7 +55,7 @@ type AppContextMock = {
}
}
const baseContext: AppContextMock = {
const baseContext: ConsoleStateFixture = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceDatasetOperator: false,
isLoadingCurrentWorkspace: false,
@ -92,8 +66,8 @@ const baseContext: AppContextMock = {
},
}
const setAppContext = (overrides: Partial<AppContextMock> = {}) => {
mockUseAppContext.mockReturnValue({
const setConsoleState = (overrides: Partial<ConsoleStateFixture> = {}) => {
mockConsoleStateReader.mockReturnValue({
...baseContext,
...overrides,
})
@ -104,11 +78,11 @@ describe('DatasetsLayout', () => {
vi.clearAllMocks()
mockPathname = '/datasets'
mockExternalKnowledgeApiProviderEnabled = undefined
setAppContext()
setConsoleState()
})
it('should render loading when workspace is still loading', () => {
setAppContext({
setConsoleState({
isLoadingCurrentWorkspace: true,
currentWorkspace: { id: '' },
})
@ -125,7 +99,7 @@ describe('DatasetsLayout', () => {
})
it('should render loading while workspace permission keys are loading', () => {
setAppContext({
setConsoleState({
isLoadingWorkspacePermissionKeys: true,
workspacePermissionKeys: [],
})
@ -142,7 +116,7 @@ describe('DatasetsLayout', () => {
})
it('should render children without a page-level dataset permission', () => {
setAppContext({
setConsoleState({
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceDatasetOperator: true,
workspacePermissionKeys: ['dataset.create_and_management', 'dataset.external.connect'],
@ -159,7 +133,7 @@ describe('DatasetsLayout', () => {
})
it('should render children on the dataset list route without dataset permissions', () => {
setAppContext({
setConsoleState({
isCurrentWorkspaceEditor: false,
isCurrentWorkspaceDatasetOperator: false,
workspacePermissionKeys: [],
@ -179,7 +153,7 @@ describe('DatasetsLayout', () => {
'should redirect direct dataset creation route to /datasets without dataset.create_and_management: %s',
async (pathname) => {
mockPathname = pathname
setAppContext({
setConsoleState({
workspacePermissionKeys: [],
})
@ -198,7 +172,7 @@ describe('DatasetsLayout', () => {
it('should render direct dataset creation route when workspace has dataset.create_and_management', () => {
mockPathname = '/datasets/create'
setAppContext({
setConsoleState({
workspacePermissionKeys: ['dataset.create_and_management'],
})
@ -214,7 +188,7 @@ describe('DatasetsLayout', () => {
it('should redirect direct external dataset connection route to /datasets without dataset.external.connect', async () => {
mockPathname = '/datasets/connect'
setAppContext({
setConsoleState({
workspacePermissionKeys: [],
})
@ -232,7 +206,7 @@ describe('DatasetsLayout', () => {
it('should render direct external dataset connection route when workspace has dataset.external.connect', () => {
mockPathname = '/datasets/connect'
setAppContext({
setConsoleState({
workspacePermissionKeys: ['dataset.external.connect'],
})
@ -247,7 +221,7 @@ describe('DatasetsLayout', () => {
})
it('should disable external knowledge API queries without dataset.external.connect', () => {
setAppContext({
setConsoleState({
workspacePermissionKeys: [],
})
@ -261,7 +235,7 @@ describe('DatasetsLayout', () => {
})
it('should enable external knowledge API queries with dataset.external.connect', () => {
setAppContext({
setConsoleState({
workspacePermissionKeys: ['dataset.external.connect'],
})

View File

@ -1,6 +1,6 @@
import { waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { AccessMode } from '@/models/access-control'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import WebSSOForm from '../page'
const navigationMocks = vi.hoisted(() => ({
@ -35,7 +35,7 @@ describe('WebSSOForm redirect security', () => {
})
it('should use the login fallback when the redirect target is external', async () => {
renderWithSystemFeatures(<WebSSOForm />, {
renderWithConsoleQuery(<WebSSOForm />, {
systemFeatures: { webapp_auth: { enabled: true } },
})

View File

@ -1,6 +1,6 @@
import { waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { SSOProtocol } from '@/features/system-features/constants'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import ExternalMemberSSOAuth from '../external-member-sso-auth'
const navigationMocks = vi.hoisted(() => ({
@ -34,7 +34,7 @@ describe('ExternalMemberSSOAuth redirect security', () => {
})
it('should use the login fallback without calling SSO when the redirect target is external', async () => {
renderWithSystemFeatures(<ExternalMemberSSOAuth />, {
renderWithConsoleQuery(<ExternalMemberSSOAuth />, {
systemFeatures: {
webapp_auth: { sso_config: { protocol: SSOProtocol.SAML } },
},
@ -58,7 +58,7 @@ describe('ExternalMemberSSOAuth redirect security', () => {
})
serviceMock.mockResolvedValue({ url: 'https://idp.example/authorize' })
renderWithSystemFeatures(<ExternalMemberSSOAuth />, {
renderWithConsoleQuery(<ExternalMemberSSOAuth />, {
systemFeatures: { webapp_auth: { sso_config: { protocol } } },
})

View File

@ -1,5 +1,5 @@
import { screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppACLPermission } from '@/utils/permission'
import AppDetailSection from '../app-detail-section'
@ -7,15 +7,15 @@ let mockAppMode = 'chat'
let mockPathname = '/app/app-1/logs'
let mockAppPermissionKeys: string[] = []
let mockIsRbacEnabled = true
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
},
}))
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -36,31 +36,13 @@ vi.mock('@/app/components/app/store', () => ({
}),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/next/navigation', () => ({

View File

@ -1,6 +1,6 @@
import type { DataSet, RelatedAppResponse } from '@/models/datasets'
import { screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { DatasetACLPermission } from '@/utils/permission'
import DatasetDetailSection from '../dataset-detail-section'
@ -8,15 +8,15 @@ let mockPathname = '/datasets/dataset-1/documents'
let mockDataset: DataSet | undefined
let mockRelatedApps: RelatedAppResponse | undefined
let mockIsRbacEnabled = true
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
},
}))
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -26,31 +26,13 @@ vi.mock('@/next/navigation', () => ({
usePathname: () => mockPathname,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/service/knowledge/use-dataset', () => ({

View File

@ -1,7 +1,8 @@
import type { App, AppSSO } from '@/types/app'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { render } from '@/test/console/render'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import AppInfoDetailPanel from '../app-info-detail-panel'
@ -9,7 +10,7 @@ import AppInfoDetailPanel from '../app-info-detail-panel'
const mockWorkspacePermissionKeys = vi.hoisted(() => ({
value: ['app.create_and_management'] as string[],
}))
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
userProfile: { id: 'user-1' },
get workspacePermissionKeys() {
@ -18,31 +19,13 @@ const mockAppContextState = vi.hoisted(() => ({
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('../../../base/app-icon', () => ({

View File

@ -2,8 +2,8 @@ import type { DataSet } from '@/models/datasets'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { RETRIEVE_METHOD } from '@/types/app'
import { DatasetACLPermission } from '@/utils/permission'
import Dropdown from '../dropdown'
@ -17,15 +17,15 @@ const mockCheckIsUsedInApp = vi.fn()
const mockDeleteDataset = vi.fn()
const mockToast = vi.fn()
let mockIsRbacEnabled = true
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
},
}))
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -106,31 +106,13 @@ vi.mock('@/context/dataset-detail', () => ({
selector({ dataset: mockDataset }),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/service/knowledge/use-dataset', () => ({

View File

@ -2,8 +2,8 @@ import type { DataSet } from '@/models/datasets'
import { createEvent, fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { RETRIEVE_METHOD } from '@/types/app'
import { DatasetACLPermission } from '@/utils/permission'
import DatasetInfo from '..'
@ -21,15 +21,15 @@ const mockCheckIsUsedInApp = vi.fn()
const mockDeleteDataset = vi.fn()
const TestEditIcon = () => <span aria-hidden className="i-ri-edit-line" />
let mockIsRbacEnabled = true
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
},
}))
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -119,31 +119,13 @@ vi.mock('@/context/dataset-detail', () => ({
selector({ dataset: mockDataset }),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/service/knowledge/use-dataset', () => ({

View File

@ -1,8 +1,9 @@
import type { CreateSnippetDialogPayload } from '@/app/components/snippets/create-snippet-dialog'
import type { SnippetDetail } from '@/models/snippet'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { render } from '@/test/console/render'
import SnippetInfoDropdown from '../dropdown'
const mockReplace = vi.fn()
@ -15,7 +16,7 @@ const mockDeleteMutate = vi.fn()
let mockWorkspacePermissionKeys: string[] = ['snippets.create_and_modify', 'snippets.management']
let mockDropdownOpen = false
let mockDropdownOnOpenChange: ((open: boolean) => void) | undefined
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
get workspacePermissionKeys() {
return mockWorkspacePermissionKeys
@ -23,31 +24,9 @@ const mockAppContextState = vi.hoisted(() => ({
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/next/navigation', () => ({

View File

@ -1,23 +1,23 @@
import type { AccessRulesEditorProps } from '@/app/components/access-rules-editor'
import { screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { useStore } from '@/app/components/app/store'
import {
useAppAccessRules,
useAppUserAccessSettings,
} from '@/service/access-control/use-app-access-config'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppACLPermission } from '@/utils/permission'
import AppAccessConfigPage from '../index'
const mockAppContext = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}))
let mockIsRbacEnabled = true
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -44,37 +44,13 @@ const mockMutations = vi.hoisted(() => ({
removeMemberBindings: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/service/access-control/use-app-access-config', () => ({
@ -110,8 +86,8 @@ vi.mock('@/app/components/access-rules-editor', () => ({
describe('AppAccessConfigPage', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContext.userProfile = { id: 'user-1' }
mockAppContext.workspacePermissionKeys = []
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = []
mockIsRbacEnabled = true
mockAppAccessRules.items = []
mockAppAccessRules.isLoading = false
@ -258,8 +234,8 @@ describe('AppAccessConfigPage', () => {
})
it('should allow the app maintainer with app management workspace permission', () => {
mockAppContext.userProfile = { id: 'account-1' }
mockAppContext.workspacePermissionKeys = ['app.create_and_management']
mockConsoleState.userProfile = { id: 'account-1' }
mockConsoleState.workspacePermissionKeys = ['app.create_and_management']
useStore.setState({
appDetail: {
id: 'app-1',

View File

@ -3,9 +3,9 @@ import type { App } from '@/types/app'
import { toast } from '@langgenius/dify-ui/toast'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import useAccessControlStore from '@/context/access-control-store'
import { AccessMode, SubjectType } from '@/models/access-control'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import AccessControlDialog from '../access-control-dialog'
import AccessControlItem from '../access-control-item'
import AddMemberOrGroupDialog from '../add-member-or-group-pop'
@ -30,6 +30,21 @@ vi.mock('@/service/access-control', () => ({
useUpdateAccessMode: () => mockUseUpdateAccessMode(),
}))
vi.mock('@/context/account-state', async () => {
const { atom } = await vi.importActual<typeof import('jotai')>('jotai')
return {
userProfileAtom: atom({
id: 'user-1',
name: 'Test User',
email: 'test@dify.ai',
avatar: '',
avatar_url: null,
is_password_set: false,
timezone: 'UTC',
}),
}
})
vi.mock('ahooks', async (importOriginal) => {
const actual = await importOriginal<typeof import('ahooks')>()
return {

View File

@ -1,8 +1,9 @@
import type { AccessControlAccount, AccessControlGroup, Subject } from '@/models/access-control'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import useAccessControlStore from '@/context/access-control-store'
import { SubjectType } from '@/models/access-control'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import AddMemberOrGroupDialog from '../add-member-or-group-pop'
const mockUseSearchForWhiteListCandidates = vi.fn()

View File

@ -2,9 +2,9 @@ import type { ReactElement } from 'react'
import type { App } from '@/types/app'
import { toast } from '@langgenius/dify-ui/toast'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import useAccessControlStore from '@/context/access-control-store'
import { AccessMode } from '@/models/access-control'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import AccessControl from '../index'
let mockWebappAuth = {
@ -15,7 +15,7 @@ let mockWebappAuth = {
}
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { webapp_auth: mockWebappAuth },
})

View File

@ -1,14 +1,14 @@
/* oxlint-disable typescript/no-explicit-any */
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { AccessMode } from '@/models/access-control'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { basePath } from '@/utils/var'
import { AppPublisher } from '../index'
const render = (ui: React.ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { webapp_auth: { enabled: true } },
})
@ -107,47 +107,20 @@ vi.mock('@/service/use-tools', () => ({
useInvalidateWorkflowToolDetailByAppID: () => vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: true,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@langgenius/dify-ui/toast', () => ({
toast: {
@ -610,7 +583,7 @@ describe('AppPublisher', () => {
})
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null)
renderWithSystemFeatures(<AppPublisher publishedAt={Date.now()} onPublish={mockOnPublish} />, {
renderWithConsoleQuery(<AppPublisher publishedAt={Date.now()} onPublish={mockOnPublish} />, {
systemFeatures: { webapp_auth: { enabled: true }, enable_creators_platform: true },
})
@ -631,7 +604,7 @@ describe('AppPublisher', () => {
it('should show toast error when publish to marketplace fails', async () => {
mockPublishToCreatorsPlatform.mockRejectedValue(new Error('network error'))
renderWithSystemFeatures(<AppPublisher publishedAt={Date.now()} onPublish={mockOnPublish} />, {
renderWithConsoleQuery(<AppPublisher publishedAt={Date.now()} onPublish={mockOnPublish} />, {
systemFeatures: { webapp_auth: { enabled: true }, enable_creators_platform: true },
})
@ -646,7 +619,7 @@ describe('AppPublisher', () => {
})
it('should disable marketplace button when not yet published', () => {
renderWithSystemFeatures(<AppPublisher onPublish={mockOnPublish} />, {
renderWithConsoleQuery(<AppPublisher onPublish={mockOnPublish} />, {
systemFeatures: { webapp_auth: { enabled: true }, enable_creators_platform: true },
})

View File

@ -1,7 +1,7 @@
/* oxlint-disable typescript/no-explicit-any */
import type { DataSet } from '@/models/datasets'
import type { DatasetConfigs } from '@/models/debug'
import { fireEvent, render, screen, within } from '@testing-library/react'
import { fireEvent, screen, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useContext } from 'use-context-selector'
import {
@ -10,6 +10,7 @@ import {
} from '@/app/components/workflow/nodes/knowledge-retrieval/types'
import { getSelectedDatasetsMode } from '@/app/components/workflow/nodes/knowledge-retrieval/utils'
import { DatasetPermission, DataSourceType } from '@/models/datasets'
import { render } from '@/test/console/render'
import { AppModeEnum, ModelModeType, RETRIEVE_TYPE } from '@/types/app'
import { DatasetACLPermission, getDatasetACLCapabilities } from '@/utils/permission'
import DatasetConfig from '../index'
@ -40,53 +41,20 @@ vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', ()
})),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-123' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'user-123' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'user-123' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'user-123' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'user-123' },
workspacePermissionKeys: [],
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/utils/permission', () => ({
DatasetACLPermission: {

View File

@ -1,10 +1,11 @@
/* oxlint-disable typescript/no-explicit-any */
import type { DataSet } from '@/models/datasets'
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import { describe, expect, it, vi } from 'vitest'
import { IndexingType } from '@/app/components/datasets/create/step-two'
import { DatasetPermission } from '@/models/datasets'
import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import SelectDataSet from '../index'
@ -34,48 +35,12 @@ vi.mock('@/service/knowledge/use-dataset', () => ({
let mockWorkspacePermissionKeys = ['dataset.create_and_management']
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/hooks/use-knowledge', () => ({
useKnowledge: () => ({

View File

@ -2,7 +2,7 @@ import type { MockedFunction } from 'vitest'
import type { DataSet } from '@/models/datasets'
import type { RetrievalConfig } from '@/types/app'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { IndexingType } from '@/app/components/datasets/create/step-two'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
@ -17,6 +17,7 @@ import {
} from '@/models/datasets'
import { updateDatasetSetting } from '@/service/datasets'
import { useMembers } from '@/service/use-common'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { RETRIEVE_METHOD } from '@/types/app'
import { DatasetACLPermission } from '@/utils/permission'
import SettingsModal from '../index'

View File

@ -1,12 +1,13 @@
import type { ModelAndParameter } from '../../types'
import type { ChatConfig, ChatItem as ChatItemType, OnSend } from '@/app/components/base/chat/types'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import { TransferMethod } from '@/app/components/base/chat/types'
import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { APP_CHAT_WITH_MULTIPLE_MODEL, APP_CHAT_WITH_MULTIPLE_MODEL_RESTART } from '../../types'
import ChatItem from '../chat-item'
const mockUseAppContext = vi.fn()
const mockConsoleStateReader = vi.fn()
const mockUseDebugConfigurationContext = vi.fn()
const mockUseProviderContext = vi.fn()
const mockUseFeatures = vi.fn()
@ -116,7 +117,7 @@ const createModelAndParameter = (
})
const createDefaultMocks = () => {
mockUseAppContext.mockReturnValue({
mockConsoleStateReader.mockReturnValue({
userProfile: { avatar_url: 'http://avatar.url', name: 'Test User' },
})

View File

@ -6,7 +6,7 @@ import type { FileEntity } from '@/app/components/base/file-uploader/types'
import type { Collection } from '@/app/components/tools/types'
import type { ProviderContextState } from '@/context/provider-context'
import type { DatasetConfigs, ModelConfig } from '@/models/debug'
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import { createRef } from 'react'
import { useStore as useAppStore } from '@/app/components/app/store'
import {
@ -17,6 +17,7 @@ import {
} from '@/app/components/header/account-setting/model-provider-page/declarations'
import { CollectionType } from '@/app/components/tools/types'
import { PromptMode } from '@/models/debug'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { AgentStrategy, AppModeEnum, ModelModeType, Resolution, TransferMethod } from '@/types/app'
import DebugWithSingleModel from '../index'
@ -307,7 +308,7 @@ vi.mock('@/context/provider-context', () => ({
useProviderContext: mockUseProviderContext,
}))
const mockAppContext = {
const mockConsoleState = {
userProfile: {
id: 'user-1',
avatar_url: 'https://example.com/avatar.png',
@ -317,14 +318,14 @@ const mockAppContext = {
isCurrentWorkspaceManager: false,
isCurrentWorkspaceOwner: false,
isCurrentWorkspaceDatasetOperator: false,
mutateUserProfile: vi.fn(),
refreshUserProfile: vi.fn(),
}
const { mockUseAppContext } = vi.hoisted(() => ({
mockUseAppContext: vi.fn(),
const { mockConsoleStateReader } = vi.hoisted(() => ({
mockConsoleStateReader: vi.fn(),
}))
mockUseAppContext.mockReturnValue(mockAppContext)
mockConsoleStateReader.mockReturnValue(mockConsoleState)
type FeatureState = {
moreLikeThis: { enabled: boolean }
@ -602,7 +603,7 @@ describe('DebugWithSingleModel', () => {
// Reset mock implementations using module-level mocks
mockUseDebugConfigurationContext.mockReturnValue(mockDebugConfigContext)
mockUseProviderContext.mockReturnValue(mockProviderContext)
mockUseAppContext.mockReturnValue(mockAppContext)
mockConsoleStateReader.mockReturnValue(mockConsoleState)
mockUseConfigFromDebugContext.mockReturnValue(mockConfigFromDebugContext)
mockUseFormattingChangedSubscription.mockReturnValue(undefined)
mockFeaturesState = { ...defaultFeatures }
@ -936,8 +937,8 @@ describe('DebugWithSingleModel', () => {
})
it('should handle missing user profile', () => {
mockUseAppContext.mockReturnValue({
...mockAppContext,
mockConsoleStateReader.mockReturnValue({
...mockConsoleState,
userProfile: {
id: '',
avatar_url: '',

View File

@ -1,6 +1,7 @@
/* oxlint-disable typescript/no-explicit-any */
import { act, renderHook, waitFor } from '@testing-library/react'
import { act, waitFor } from '@testing-library/react'
import { updateAppModelConfig } from '@/service/apps'
import { renderHook } from '@/test/console/render'
import { AppModeEnum, ModelModeType } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import { useConfiguration } from '../use-configuration'
@ -44,63 +45,33 @@ vi.mock('ahooks', async () => {
}
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: { id: 'workspace-1' },
isLoadingCurrentWorkspace: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/context/modal-context', () => ({
useModalContext: () => ({

View File

@ -2,9 +2,9 @@ import type { App } from '@/models/explore'
import type { AppIconType } from '@/types/app'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { trackEvent } from '@/app/components/base/amplitude'
import AppListContext from '@/context/app-list-context'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import AppCard from '../index'

View File

@ -1,6 +1,6 @@
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { NEED_REFRESH_APP_LIST_KEY } from '@/app/components/apps/storage'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import Apps from '../index'
@ -29,53 +29,21 @@ vi.mock('ahooks', () => ({
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('nuqs', () => ({
useQueryState: () => ['Recommended', vi.fn()],
}))

View File

@ -1,11 +1,11 @@
import type { App } from '@/types/app'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { NEED_REFRESH_APP_LIST_KEY } from '@/app/components/apps/storage'
import { useProviderContext } from '@/context/provider-context'
import { useRouter } from '@/next/navigation'
import { createApp } from '@/service/apps'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { getRedirection } from '@/utils/app-redirection'
import { trackCreateApp } from '@/utils/create-app-tracking'
@ -15,11 +15,11 @@ const ahooksMocks = vi.hoisted(() => ({
keyPressHandlers: [] as Array<() => void>,
}))
const mockInvalidateAppList = vi.hoisted(() => vi.fn())
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'] as string[],
}))
const mockUseAppContext = vi.hoisted(() => vi.fn())
const mockConsoleStateReader = vi.hoisted(() => vi.fn())
vi.mock('ahooks', () => ({
useDebounceFn: <T extends (...args: unknown[]) => unknown>(fn: T) => {
@ -75,37 +75,15 @@ vi.mock('@/utils/app-redirection', () => ({
vi.mock('@/context/provider-context', () => ({
useProviderContext: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/context/i18n', () => ({
useDocLink: () => () => '/guides',
}))
@ -163,12 +141,12 @@ describe('CreateAppModal', () => {
},
enableBilling: true,
} as unknown as ReturnType<typeof useProviderContext>)
mockUseAppContext.mockReturnValue({
mockConsoleStateReader.mockReturnValue({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
})
mockAppContextState.userProfile = { id: 'user-1' }
mockAppContextState.workspacePermissionKeys = ['app.create_and_management']
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = ['app.create_and_management']
mockSetItem.mockClear()
Object.defineProperty(window, 'localStorage', {
value: {

View File

@ -1,8 +1,8 @@
/* oxlint-disable typescript/no-explicit-any */
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { NEED_REFRESH_APP_LIST_KEY } from '@/app/components/apps/storage'
import { DSLImportMode, DSLImportStatus } from '@/models/app'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import CreateFromDSLModal from '../index'
import { CreateFromDSLModalTab } from '../types'
@ -76,53 +76,20 @@ vi.mock('@/app/components/workflow/plugin-dependency/hooks', () => ({
}),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/context/provider-context', () => ({
useProviderContext: () => ({

View File

@ -1,10 +1,11 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, screen } from '@testing-library/react'
import { createMockProviderContextValue } from '@/__mocks__/provider-context'
import { defaultPlan } from '@/app/components/billing/config'
import { Plan } from '@/app/components/billing/type'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import { useModalContextSelector } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { render } from '@/test/console/render'
import { ArchivedLogsNotice } from '../archived-logs-notice'
vi.mock('@/config', async (importOriginal) => {
@ -15,8 +16,13 @@ vi.mock('@/config', async (importOriginal) => {
}
})
vi.mock('@/context/workspace-state', () => ({ isCurrentWorkspaceManagerAtom: {} }))
vi.mock('jotai', () => ({ useAtomValue: () => true }))
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
isCurrentWorkspaceManager: true,
}))
})
vi.mock('@/context/provider-context', async (importOriginal) => {
const actual = await importOriginal<typeof import('@/context/provider-context')>()

View File

@ -1,6 +1,6 @@
import type { App } from '@/types/app'
import { screen } from '@testing-library/react'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import EmptyElement from '../empty-element'

View File

@ -1,10 +1,8 @@
/* oxlint-disable typescript/no-explicit-any */
import type { ReactNode } from 'react'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import {
AccountProfileQueryProvider,
createAccountProfileQueryClient,
} from '@/test/account-profile-query'
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
import { QueryClientTestProvider } from '@/test/console/query-provider'
import { renderWithNuqs } from '@/test/nuqs-testing'
import { AppModeEnum } from '@/types/app'
import ConversationList from '../list'
@ -258,9 +256,9 @@ const renderConversationList = ({
} = {}) => {
const queryClient = createAccountProfileQueryClient({ timezone: 'Asia/Shanghai' })
return renderWithNuqs(
<AccountProfileQueryProvider queryClient={queryClient}>
<QueryClientTestProvider queryClient={queryClient}>
<ConversationList appDetail={appDetail} logs={logs} onRefresh={mockOnRefresh} />
</AccountProfileQueryProvider>,
</QueryClientTestProvider>,
{ searchParams },
)
}

View File

@ -1,9 +1,9 @@
import type { ReactElement } from 'react'
import type { AppDetailResponse } from '@/models/app'
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { InputVarType } from '@/app/components/workflow/types'
import { AccessMode } from '@/models/access-control'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import { basePath } from '@/utils/var'
@ -14,7 +14,7 @@ vi.mock('@/context/i18n', () => ({
}))
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { webapp_auth: { enabled: true } },
})

View File

@ -1,5 +1,6 @@
import type { AppDetailResponse } from '@/models/app'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import TriggerCard from '../trigger-card'

View File

@ -1,10 +1,11 @@
import type { SiteInfo } from '@/models/share'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import copy from 'copy-to-clipboard'
import * as React from 'react'
import { act } from 'react'
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
import { InputVarType } from '@/app/components/workflow/types'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import Embedded from '../index'
vi.mock('../style.module.css', () => ({

View File

@ -2,10 +2,10 @@ import type { App } from '@/types/app'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { useStore as useAppStore } from '@/app/components/app/store'
import { NEED_REFRESH_APP_LIST_KEY } from '@/app/components/apps/storage'
import { Plan } from '@/app/components/billing/type'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import SwitchAppModal from '../index'
@ -284,7 +284,7 @@ describe('SwitchAppModal', () => {
expect(onSuccess).toHaveBeenCalledTimes(1)
expect(onClose).toHaveBeenCalledTimes(1)
expect(notify).toHaveBeenCalledWith({ type: 'success', message: 'app.newApp.appCreated' })
expect(localStorage.setItem).toHaveBeenCalledWith(NEED_REFRESH_APP_LIST_KEY, '1')
expect(localStorage.getItem(NEED_REFRESH_APP_LIST_KEY)).toBe('1')
expect(mockPush).toHaveBeenCalledWith('/app/new-app-001/workflow')
expect(mockReplace).not.toHaveBeenCalled()
})

View File

@ -20,10 +20,10 @@ import type { WorkflowAppLogDetail, WorkflowLogsResponse, WorkflowRunDetail } fr
import type { App, AppIconType, AppModeEnum } from '@/types/app'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { APP_PAGE_LIMIT } from '@/config'
import { WorkflowRunTriggeredFrom } from '@/models/log'
import * as useLogModule from '@/service/use-log'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { TIME_PERIOD_MAPPING } from '../filter'
import Logs from '../index'
@ -93,7 +93,7 @@ const mockedUseWorkflowLogs = useLogModule.useWorkflowLogs as MockedFunction<
// ============================================================================
const renderWithQueryClient = (ui: React.ReactElement) => {
return renderWithSystemFeatures(ui)
return renderWithConsoleQuery(ui)
}
// ============================================================================

View File

@ -2,11 +2,11 @@ import type { Mock } from 'vitest'
import type { App } from '@/types/app'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { AccessMode } from '@/models/access-control'
import * as appsService from '@/service/apps'
import * as exploreService from '@/service/explore'
import * as workflowService from '@/service/workflow'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import { AppCard } from '../app-card'
@ -20,7 +20,7 @@ const mockUserCanAccessApp = vi.hoisted(() => ({
}))
const render = (ui: React.ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: {
webapp_auth: { enabled: mockWebappAuthEnabled },
branding: { enabled: false },
@ -80,7 +80,7 @@ vi.mock('use-context-selector', () => ({
}),
}))
const mockAppContext = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
isCurrentWorkspaceEditor: true,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'] as string[],
@ -88,37 +88,17 @@ const mockAppContext = vi.hoisted(() => ({
// Mock app context
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContext)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
// Mock provider context
@ -545,9 +525,9 @@ describe('AppCard', () => {
mockUserCanAccessApp.isLoading = false
mockDeleteMutationPending = false
mockToggleStarMutationPending = false
mockAppContext.isCurrentWorkspaceEditor = true
mockAppContext.userProfile = { id: 'user-1' }
mockAppContext.workspacePermissionKeys = ['app.create_and_management']
mockConsoleState.isCurrentWorkspaceEditor = true
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = ['app.create_and_management']
})
describe('Rendering', () => {
@ -696,9 +676,9 @@ describe('AppCard', () => {
})
it('should allow app edit permission to bind tags without workspace tag management permission', () => {
mockAppContext.isCurrentWorkspaceEditor = false
mockAppContext.workspacePermissionKeys = []
mockAppContext.userProfile = { id: 'user-2' }
mockConsoleState.isCurrentWorkspaceEditor = false
mockConsoleState.workspacePermissionKeys = []
mockConsoleState.userProfile = { id: 'user-2' }
const editableApp = createMockApp({
maintainer: 'user-1',
tags: [{ id: 'tag1', name: 'Tag 1', type: 'app' as const, binding_count: '' }],
@ -714,9 +694,9 @@ describe('AppCard', () => {
})
it('should allow workspace app tag management permission to bind tags without app edit permission', () => {
mockAppContext.isCurrentWorkspaceEditor = false
mockAppContext.workspacePermissionKeys = ['app.tag.manage']
mockAppContext.userProfile = { id: 'user-2' }
mockConsoleState.isCurrentWorkspaceEditor = false
mockConsoleState.workspacePermissionKeys = ['app.tag.manage']
mockConsoleState.userProfile = { id: 'user-2' }
const tagManageApp = createMockApp({
maintainer: 'user-1',
tags: [{ id: 'tag1', name: 'Tag 1', type: 'app' as const, binding_count: '' }],
@ -732,9 +712,9 @@ describe('AppCard', () => {
})
it('should render existing app tags as readonly without app edit or workspace tag management permission', () => {
mockAppContext.isCurrentWorkspaceEditor = false
mockAppContext.workspacePermissionKeys = []
mockAppContext.userProfile = { id: 'user-2' }
mockConsoleState.isCurrentWorkspaceEditor = false
mockConsoleState.workspacePermissionKeys = []
mockConsoleState.userProfile = { id: 'user-2' }
const readonlyApp = createMockApp({
maintainer: 'user-1',
tags: [{ id: 'tag1', name: 'Tag 1', type: 'app' as const, binding_count: '' }],
@ -948,7 +928,7 @@ describe('AppCard', () => {
})
it('should show switch option when user can edit app without app creation permission', async () => {
mockAppContext.workspacePermissionKeys = []
mockConsoleState.workspacePermissionKeys = []
const editableChatApp = createMockApp({
created_by: 'another-user',
maintainer: 'another-user',

View File

@ -1,50 +1,15 @@
import { fireEvent, render, screen, within } from '@testing-library/react'
import { fireEvent, screen, within } from '@testing-library/react'
import { render } from '@/test/console/render'
import CreatorsFilter from '../creators-filter'
const mockOnChange = vi.hoisted(() => vi.fn())
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: { id: 'member-2' },
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'member-2' },
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'member-2' },
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'member-2' },
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'member-2' },
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/service/use-common', () => ({
useMembers: () => ({

View File

@ -2,12 +2,13 @@ import type { ReactNode } from 'react'
import type { App } from '@/models/explore'
import type { TryAppSelection } from '@/types/try-app'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { useContextSelector } from 'use-context-selector'
import AppListContext from '@/context/app-list-context'
import { fetchAppDetail } from '@/service/explore'
import { render } from '@/test/console/render'
import { AppModeEnum } from '@/types/app'
import Apps from '../index'
@ -71,48 +72,12 @@ vi.mock('@/app/education-apply/hooks', () => ({
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/hooks/use-import-dsl', () => ({
useImportDSL: () => ({

View File

@ -4,7 +4,7 @@ import type { TryAppSelection } from '@/types/try-app'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { createSystemFeaturesWrapper } from '@/__tests__/utils/mock-system-features'
import { createConsoleQueryWrapper } from '@/test/console/query-data'
import { renderWithNuqs } from '@/test/nuqs-testing'
import { AppModeEnum } from '@/types/app'
import List from '../list'
@ -104,53 +104,20 @@ vi.mock('@/service/client', () => ({
const mockIsCurrentWorkspaceDatasetOperator = vi.fn(() => false)
let mockWorkspacePermissionKeys = ['app.create_and_management']
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: { id: 'creator-1' },
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'creator-1' },
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'creator-1' },
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'creator-1' },
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
userProfile: { id: 'creator-1' },
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
const mockOnPlanInfoChanged = vi.fn()
vi.mock('@/context/provider-context', () => ({
@ -527,13 +494,13 @@ type RenderListOptions = {
const renderList = (searchParams = '', options: RenderListOptions = {}) => {
mockSearchParams = new URLSearchParams(searchParams)
const { wrapper: SystemFeaturesWrapper } = createSystemFeaturesWrapper({
const { wrapper: ConsoleQueryWrapper } = createConsoleQueryWrapper({
systemFeatures: { branding: { enabled: false }, ...options.systemFeatures },
})
return renderWithNuqs(
<SystemFeaturesWrapper>
<ConsoleQueryWrapper>
<List onCreateLearnDify={options.onCreateLearnDify} onTryLearnDify={options.onTryLearnDify} />
</SystemFeaturesWrapper>,
</ConsoleQueryWrapper>,
{ searchParams },
)
}

View File

@ -4,8 +4,8 @@ import type { ChatWithHistoryContextValue } from '../context'
import type { AppData, AppMeta } from '@/models/share'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as ReactI18next from 'react-i18next'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { withSelectorKey } from '@/test/i18n-mock'
import { useChatWithHistoryContext } from '../context'
import HeaderInMobile from '../header-in-mobile'

View File

@ -4,8 +4,8 @@ import { screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import * as ReactI18next from 'react-i18next'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { expectLoadingButton } from '@/test/button'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { withSelectorKey } from '@/test/i18n-mock'
import { useChatWithHistoryContext } from '../../context'
import Sidebar from '../index'
@ -16,7 +16,7 @@ let mockBranding: { enabled: boolean; workspace_logo: string } = {
workspace_logo: '',
}
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { branding: { ...mockBranding } },
})

View File

@ -1,50 +1,23 @@
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { render } from '@/test/console/render'
import Tips from '../tips'
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: {
email: 'test@example.com',
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
describe('Tips', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContextState.userProfile.email = 'test@example.com'
mockConsoleState.userProfile.email = 'test@example.com'
})
it('should render email tip in normal mode', () => {

View File

@ -1,9 +1,10 @@
import type { InputVarType } from '@/app/components/workflow/types'
import type { HumanInputFormData } from '@/types/workflow'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, expect, it, vi } from 'vitest'
import { UserActionButtonType } from '@/app/components/workflow/nodes/human-input/types'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { UnsubmittedHumanInputContent } from '../unsubmitted'
describe('UnsubmittedHumanInputContent Integration', () => {

View File

@ -3,14 +3,14 @@ import type { ChatConfig } from '../../types'
import type { AppData, AppMeta, ConversationItem } from '@/models/share'
import { screen } from '@testing-library/react'
import { vi } from 'vitest'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { useEmbeddedChatbot } from '../hooks'
import EmbeddedChatbot from '../index'
let mockBrandingWorkspaceLogo = ''
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: {
branding: { enabled: true, workspace_logo: mockBrandingWorkspaceLogo },
},

View File

@ -3,13 +3,13 @@ import type { EmbeddedChatbotContextValue } from '../../context'
import type { AppData } from '@/models/share'
import { act, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { useEmbeddedChatbotContext } from '../../context'
import Header from '../index'
let mockBranding = { enabled: true, workspace_logo: '' }
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { branding: { ...mockBranding } },
})

View File

@ -1,4 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { render } from '@/test/console/render'
import Billing from '../index'
let currentBillingUrl: string | null = 'https://billing'
@ -34,47 +35,20 @@ vi.mock('@/hooks/use-async-window-open', () => ({
useAsyncWindowOpen: () => openAsyncWindowMock,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
isCurrentWorkspaceManager: isManager,
workspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
isCurrentWorkspaceManager: isManager,
workspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: isManager,
workspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: isManager,
workspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
isCurrentWorkspaceManager: isManager,
workspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/context/provider-context', () => ({
useProviderContext: () => ({

View File

@ -1,9 +1,9 @@
import type { ReactNode } from 'react'
import type { Mock } from 'vitest'
import type { UsagePlanInfo } from '../../type'
import { render } from '@testing-library/react'
import { useGetPricingPageLanguage } from '@/context/i18n'
import { useProviderContext } from '@/context/provider-context'
import { render } from '@/test/console/render'
import { Plan } from '../../type'
import Pricing from '../index'
@ -14,7 +14,7 @@ type DialogProps = {
}
let latestOnOpenChange: DialogProps['onOpenChange']
let mockAppCtx: Record<string, unknown> = {}
let mockConsoleState: Record<string, unknown> = {}
vi.mock('@langgenius/dify-ui/dialog', () => ({
Dialog: ({ children, onOpenChange }: DialogProps) => {
@ -46,31 +46,13 @@ vi.mock('../footer', () => ({
default: () => <div>footer</div>,
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppCtx)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/provider-context', () => ({
@ -95,7 +77,7 @@ describe('Pricing dialog lifecycle', () => {
beforeEach(() => {
vi.clearAllMocks()
latestOnOpenChange = undefined
mockAppCtx = {
mockConsoleState = {
isCurrentWorkspaceManager: true,
workspacePermissionKeys: ['billing.manage'],
}

View File

@ -1,15 +1,13 @@
import type { ReactElement } from 'react'
import type { AppContextStateMockState } from '@/__tests__/utils/mock-app-context-state'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createMockProviderContextValue } from '@/__mocks__/provider-context'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { contactSalesUrl, defaultPlan } from '@/app/components/billing/config'
import { Plan } from '@/app/components/billing/type'
import { initialLangGeniusVersionInfo, initialWorkspaceInfo } from '@/context/app-context-defaults'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import CustomPage from '../index'
vi.mock('@/config', async (importOriginal) => {
@ -21,7 +19,7 @@ vi.mock('@/config', async (importOriginal) => {
})
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: {
branding: {
enabled: true,
@ -42,8 +40,6 @@ const { mockToast } = vi.hoisted(() => {
})
return { mockToast }
})
const mockUseAppContext = vi.hoisted(() => vi.fn())
vi.mock('@/context/provider-context', () => ({
useProviderContext: vi.fn(),
}))
@ -57,15 +53,6 @@ vi.mock('@langgenius/dify-ui/toast', () => ({
const mockUseProviderContext = vi.mocked(useProviderContext)
const mockUseModalContext = vi.mocked(useModalContext)
const testUserProfile = {
id: '',
name: '',
email: '',
avatar: '',
avatar_url: '',
is_password_set: false,
}
const createProviderContext = ({
enableBilling = false,
planType = Plan.professional,
@ -82,26 +69,6 @@ const createProviderContext = ({
})
}
const createAppContextValue = (): AppContextStateMockState => ({
userProfile: testUserProfile,
mutateUserProfile: vi.fn(),
currentWorkspace: {
...initialWorkspaceInfo,
custom_config: {
replace_webapp_logo: 'https://example.com/replace.png',
remove_webapp_brand: false,
},
},
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: false,
isCurrentWorkspaceEditor: false,
isCurrentWorkspaceDatasetOperator: false,
mutateCurrentWorkspace: vi.fn(),
langGeniusVersionInfo: initialLangGeniusVersionInfo,
isLoadingCurrentWorkspace: false,
workspacePermissionKeys: [],
})
describe('CustomPage', () => {
const setShowPricingModal = vi.fn()
@ -112,7 +79,6 @@ describe('CustomPage', () => {
mockUseModalContext.mockReturnValue({
setShowPricingModal,
} as unknown as ReturnType<typeof useModalContext>)
mockUseAppContext.mockReturnValue(createAppContextValue())
})
// Integration coverage for the page and its child custom brand section.

View File

@ -1,22 +1,22 @@
import type { GetSystemFeaturesResponse } from '@dify/contracts/api/console/system-features/types.gen'
import type { ChangeEvent } from 'react'
import type { AppContextStateMockState } from '@/__tests__/utils/mock-app-context-state'
import type { ICurrentWorkspace } from '@/models/common'
import type { ConsoleStateFixture } from '@/test/console/state-fixture'
import { act } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createMockProviderContextValue } from '@/__mocks__/provider-context'
import { renderHookWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { getImageUploadErrorMessage, imageUpload } from '@/app/components/base/image-uploader/utils'
import { defaultPlan } from '@/app/components/billing/config'
import { Plan } from '@/app/components/billing/type'
import { initialLangGeniusVersionInfo, initialWorkspaceInfo } from '@/context/app-context-defaults'
import { useProviderContext } from '@/context/provider-context'
import { updateCurrentWorkspace } from '@/service/common'
import { renderHookWithConsoleQuery } from '@/test/console/query-data'
import useWebAppBrand from '../use-web-app-brand'
let currentBrandingOverrides: Partial<GetSystemFeaturesResponse['branding']> = {}
const renderHook = <Result, Props = void>(callback: (props: Props) => Result) =>
renderHookWithSystemFeatures(callback, {
renderHookWithConsoleQuery(callback, {
systemFeatures: {
branding: {
enabled: true,
@ -39,10 +39,10 @@ const { mockNotify, mockToast } = vi.hoisted(() => {
})
return { mockNotify, mockToast }
})
const appContextStateRef = vi.hoisted(() => ({
value: undefined as AppContextStateMockState | undefined,
const consoleStateRef = vi.hoisted(() => ({
value: undefined as ConsoleStateFixture | undefined,
}))
const mockUseAppContext = vi.hoisted(() => vi.fn())
const mockConsoleStateReader = vi.hoisted(() => vi.fn())
vi.mock('@langgenius/dify-ui/toast', () => ({
toast: mockToast,
@ -50,52 +50,35 @@ vi.mock('@langgenius/dify-ui/toast', () => ({
vi.mock('@/service/common', () => ({
updateCurrentWorkspace: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
...appContextStateRef.value,
refreshCurrentWorkspace: appContextStateRef.value?.mutateCurrentWorkspace,
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
...consoleStateRef.value,
refreshCurrentWorkspace: consoleStateRef.value?.refreshCurrentWorkspace,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
...appContextStateRef.value,
refreshCurrentWorkspace: appContextStateRef.value?.mutateCurrentWorkspace,
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
...consoleStateRef.value,
refreshCurrentWorkspace: consoleStateRef.value?.refreshCurrentWorkspace,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
...appContextStateRef.value,
refreshCurrentWorkspace: appContextStateRef.value?.mutateCurrentWorkspace,
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
...consoleStateRef.value,
refreshCurrentWorkspace: consoleStateRef.value?.refreshCurrentWorkspace,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
...appContextStateRef.value,
refreshCurrentWorkspace: appContextStateRef.value?.mutateCurrentWorkspace,
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => ({
...consoleStateRef.value,
refreshCurrentWorkspace: consoleStateRef.value?.refreshCurrentWorkspace,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
...appContextStateRef.value,
refreshCurrentWorkspace: appContextStateRef.value?.mutateCurrentWorkspace,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/context/provider-context', () => ({
useProviderContext: vi.fn(),
}))
@ -134,11 +117,9 @@ const createProviderContext = ({
})
}
const createAppContextValue = (
overrides: Partial<AppContextStateMockState> = {},
): AppContextStateMockState => {
const createConsoleState = (overrides: Partial<ConsoleStateFixture> = {}): ConsoleStateFixture => {
const { currentWorkspace: currentWorkspaceOverride, ...restOverrides } = overrides
const workspaceOverrides: Partial<AppContextStateMockState['currentWorkspace']> =
const workspaceOverrides: Partial<ConsoleStateFixture['currentWorkspace']> =
currentWorkspaceOverride ?? {}
const currentWorkspace = {
...initialWorkspaceInfo,
@ -152,13 +133,13 @@ const createAppContextValue = (
return {
userProfile: testUserProfile,
mutateUserProfile: vi.fn(),
refreshUserProfile: vi.fn(),
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: false,
isCurrentWorkspaceEditor: false,
isCurrentWorkspaceDatasetOperator: false,
workspacePermissionKeys: ['customization.manage'],
mutateCurrentWorkspace: vi.fn(),
refreshCurrentWorkspace: vi.fn(),
langGeniusVersionInfo: initialLangGeniusVersionInfo,
isLoadingCurrentWorkspace: false,
...restOverrides,
@ -167,22 +148,20 @@ const createAppContextValue = (
}
describe('useWebAppBrand', () => {
let appContextValue: AppContextStateMockState
const setAppContextValue = (nextValue: AppContextStateMockState) => {
appContextValue = nextValue
appContextStateRef.value = nextValue
let consoleState: ConsoleStateFixture
const setConsoleState = (nextValue: ConsoleStateFixture) => {
consoleState = nextValue
consoleStateRef.value = nextValue
}
beforeEach(() => {
vi.clearAllMocks()
setAppContextValue(createAppContextValue())
setConsoleState(createConsoleState())
currentBrandingOverrides = {}
mockUpdateCurrentWorkspace.mockResolvedValue(
appContextValue.currentWorkspace as ICurrentWorkspace,
)
mockUseAppContext.mockImplementation(() => appContextValue)
mockUpdateCurrentWorkspace.mockResolvedValue(consoleState.currentWorkspace as ICurrentWorkspace)
mockConsoleStateReader.mockImplementation(() => consoleState)
mockUseProviderContext.mockReturnValue(createProviderContext())
mockGetImageUploadErrorMessage.mockReturnValue('upload error')
})
@ -200,8 +179,8 @@ describe('useWebAppBrand', () => {
})
it('should disable uploads when customization management permission is missing', () => {
setAppContextValue(
createAppContextValue({
setConsoleState(
createConsoleState({
workspacePermissionKeys: [],
isCurrentWorkspaceManager: true,
}),
@ -214,8 +193,8 @@ describe('useWebAppBrand', () => {
})
it('should allow uploads for non-manager users with customization management permission', () => {
setAppContextValue(
createAppContextValue({
setConsoleState(
createConsoleState({
workspacePermissionKeys: ['customization.manage'],
isCurrentWorkspaceManager: false,
}),
@ -234,8 +213,8 @@ describe('useWebAppBrand', () => {
planType: Plan.sandbox,
}),
)
setAppContextValue(
createAppContextValue({
setConsoleState(
createConsoleState({
currentWorkspace: {
...initialWorkspaceInfo,
custom_config: {
@ -262,8 +241,8 @@ describe('useWebAppBrand', () => {
})
it('should fall back to an empty custom logo when custom config is missing', () => {
setAppContextValue({
...createAppContextValue(),
setConsoleState({
...createConsoleState(),
currentWorkspace: {
...initialWorkspaceInfo,
},
@ -370,9 +349,9 @@ describe('useWebAppBrand', () => {
it('should persist the selected logo and reset transient state on apply', async () => {
const mutateCurrentWorkspace = vi.fn()
setAppContextValue(
createAppContextValue({
mutateCurrentWorkspace,
setConsoleState(
createConsoleState({
refreshCurrentWorkspace: mutateCurrentWorkspace,
}),
)
mockImageUpload.mockImplementation(({ onSuccessCallback }) => {
@ -409,9 +388,9 @@ describe('useWebAppBrand', () => {
it('should restore the default branding configuration', async () => {
const mutateCurrentWorkspace = vi.fn()
setAppContextValue(
createAppContextValue({
mutateCurrentWorkspace,
setConsoleState(
createConsoleState({
refreshCurrentWorkspace: mutateCurrentWorkspace,
}),
)
@ -433,9 +412,9 @@ describe('useWebAppBrand', () => {
it('should persist brand removal changes', async () => {
const mutateCurrentWorkspace = vi.fn()
setAppContextValue(
createAppContextValue({
mutateCurrentWorkspace,
setConsoleState(
createConsoleState({
refreshCurrentWorkspace: mutateCurrentWorkspace,
}),
)

View File

@ -1,136 +0,0 @@
const DATASET_ACCESS_ATOM_KIND = Symbol('dataset-access-atom-kind')
type DatasetAccessMockState = {
userProfile?: {
id?: string
name?: string
email?: string
avatar?: string
avatar_url?: string
is_password_set?: boolean
} | null
currentWorkspace?: {
id?: string
} | null
isCurrentWorkspaceOwner?: boolean
isLoadingCurrentWorkspace?: boolean
isLoadingWorkspacePermissionKeys?: boolean
workspacePermissionKeys?: string[]
}
type DatasetAccessMockOptions = {
isRbacEnabled?: boolean
}
type DatasetAccessAtomKind =
| 'userProfile'
| 'userProfileId'
| 'currentWorkspaceId'
| 'isCurrentWorkspaceOwner'
| 'workspacePermissionKeys'
| 'currentWorkspaceLoading'
| 'workspacePermissionKeysLoading'
| 'datasetRbacEnabled'
type DatasetAccessMockAtom = {
[DATASET_ACCESS_ATOM_KIND]: DatasetAccessAtomKind
}
type DatasetAccessMockRegistry = {
getState: () => DatasetAccessMockState
getOptions: () => DatasetAccessMockOptions
}
const defaultUserProfile = {
id: 'user-1',
name: 'User',
email: 'user@example.com',
avatar: '',
avatar_url: '',
is_password_set: true,
}
let datasetAccessMockRegistry: DatasetAccessMockRegistry | undefined
const createMockAtom = (kind: DatasetAccessAtomKind): DatasetAccessMockAtom => ({
[DATASET_ACCESS_ATOM_KIND]: kind,
})
const isDatasetAccessMockAtom = (atom: unknown): atom is DatasetAccessMockAtom => {
return typeof atom === 'object' && atom !== null && DATASET_ACCESS_ATOM_KIND in atom
}
const getUserProfile = (state: DatasetAccessMockState) => ({
...defaultUserProfile,
...state.userProfile,
})
const getWorkspacePermissionKeys = (state: DatasetAccessMockState) =>
state.workspacePermissionKeys ?? []
export const createDatasetAccessAtomMock = async <TModule extends object>(
importOriginal: <T>() => Promise<T>,
getState: () => DatasetAccessMockState,
getOptions: () => DatasetAccessMockOptions = () => ({}),
) => {
const actual = await importOriginal<TModule>()
datasetAccessMockRegistry = {
getState,
getOptions,
}
return {
...actual,
userProfileAtom: createMockAtom('userProfile'),
userProfileIdAtom: createMockAtom('userProfileId'),
currentWorkspaceIdAtom: createMockAtom('currentWorkspaceId'),
isCurrentWorkspaceOwnerAtom: createMockAtom('isCurrentWorkspaceOwner'),
workspacePermissionKeysAtom: createMockAtom('workspacePermissionKeys'),
currentWorkspaceLoadingAtom: createMockAtom('currentWorkspaceLoading'),
workspacePermissionKeysLoadingAtom: createMockAtom('workspacePermissionKeysLoading'),
datasetRbacEnabledAtom: createMockAtom('datasetRbacEnabled'),
}
}
export const createDatasetAccessJotaiMock = async (importOriginal: <T>() => Promise<T>) => {
const actual = await importOriginal<typeof import('jotai')>()
return {
...actual,
useAtomValue: (atom: unknown) => {
if (!isDatasetAccessMockAtom(atom))
return actual.useAtomValue(atom as Parameters<typeof actual.useAtomValue>[0])
if (!datasetAccessMockRegistry) throw new Error('Dataset access atom mock is not initialized')
const state = datasetAccessMockRegistry.getState()
const options = datasetAccessMockRegistry.getOptions()
const userProfile = getUserProfile(state)
const workspacePermissionKeys = getWorkspacePermissionKeys(state)
if (atom[DATASET_ACCESS_ATOM_KIND] === 'userProfile') return userProfile
if (atom[DATASET_ACCESS_ATOM_KIND] === 'userProfileId') return userProfile.id
if (atom[DATASET_ACCESS_ATOM_KIND] === 'currentWorkspaceId')
return state.currentWorkspace?.id ?? 'workspace-1'
if (atom[DATASET_ACCESS_ATOM_KIND] === 'isCurrentWorkspaceOwner')
return state.isCurrentWorkspaceOwner ?? false
if (atom[DATASET_ACCESS_ATOM_KIND] === 'workspacePermissionKeys')
return workspacePermissionKeys
if (atom[DATASET_ACCESS_ATOM_KIND] === 'currentWorkspaceLoading')
return state.isLoadingCurrentWorkspace ?? false
if (atom[DATASET_ACCESS_ATOM_KIND] === 'workspacePermissionKeysLoading')
return state.isLoadingWorkspacePermissionKeys ?? false
if (atom[DATASET_ACCESS_ATOM_KIND] === 'datasetRbacEnabled')
return options.isRbacEnabled ?? true
throw new Error(`Unsupported dataset access atom: ${atom[DATASET_ACCESS_ATOM_KIND]}`)
},
}
}

View File

@ -1,10 +1,10 @@
import type { AccessRulesEditorProps } from '@/app/components/access-rules-editor'
import { screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import {
useDatasetAccessRules,
useDatasetUserAccessSettings,
} from '@/service/access-control/use-dataset-access-config'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { DatasetACLPermission } from '@/utils/permission'
import DatasetAccessConfigPage from '../index'
@ -23,15 +23,15 @@ const mockDatasetDetail = vi.hoisted(() => ({
dataset: undefined as { maintainer?: string | null; permission_keys?: string[] } | undefined,
}))
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}))
let mockIsRbacEnabled = true
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
@ -82,65 +82,30 @@ vi.mock('@/context/dataset-detail', () => ({
),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
return createSystemFeaturesStateModuleMock(() => ({
...(() => mockConsoleState)(),
datasetRbacEnabled: (() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
}))().isRbacEnabled,
}))
})
vi.mock('@/app/components/access-rules-editor', () => ({
@ -150,13 +115,6 @@ vi.mock('@/app/components/access-rules-editor', () => ({
},
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
describe('DatasetAccessConfigPage', () => {
beforeEach(() => {
vi.clearAllMocks()
@ -169,8 +127,8 @@ describe('DatasetAccessConfigPage', () => {
maintainer: 'maintainer-1',
permission_keys: [DatasetACLPermission.AccessConfig],
}
mockAppContextState.userProfile = { id: 'user-1' }
mockAppContextState.workspacePermissionKeys = []
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = []
mockIsRbacEnabled = true
mockAccessRulesEditor.props = null
})

View File

@ -1,495 +1,158 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import ImagePreviewer from '../index'
// Mock fetch
const mockFetch = vi.fn()
globalThis.fetch = mockFetch
// Mock URL methods
const mockFetch = vi.fn<typeof fetch>()
const mockRevokeObjectURL = vi.fn()
const mockCreateObjectURL = vi.fn(() => 'blob:mock-url')
globalThis.URL.revokeObjectURL = mockRevokeObjectURL
globalThis.URL.createObjectURL = mockCreateObjectURL
class MockImage {
naturalWidth = 800
naturalHeight = 600
onload: (() => void) | null = null
onerror: (() => void) | null = null
_src = ''
private source = ''
get src() {
return this._src
return this.source
}
set src(value: string) {
this._src = value
// Trigger onload after a microtask
setTimeout(() => {
if (this.onload) this.onload()
}, 0)
this.source = value
queueMicrotask(() => this.onload?.())
}
naturalWidth = 800
naturalHeight = 600
}
;(globalThis as unknown as { Image: typeof MockImage }).Image = MockImage
const createMockImages = () => [
const images = [
{ url: 'https://example.com/image1.png', name: 'image1.png', size: 1024 },
{ url: 'https://example.com/image2.png', name: 'image2.png', size: 2048 },
{ url: 'https://example.com/image3.png', name: 'image3.png', size: 3072 },
]
const successfulResponse = () => new Response(new Blob(['test'], { type: 'image/png' }))
const getPreviewButtons = () => {
const [closeButton, previousButton, nextButton] = screen.getAllByRole('button')
expect(closeButton).toBeInTheDocument()
expect(previousButton).toBeInTheDocument()
expect(nextButton).toBeInTheDocument()
return { closeButton: closeButton!, previousButton: previousButton!, nextButton: nextButton! }
}
describe('ImagePreviewer', () => {
beforeEach(() => {
vi.clearAllMocks()
// Default successful fetch mock
mockFetch.mockResolvedValue({
ok: true,
blob: () => Promise.resolve(new Blob(['test'], { type: 'image/png' })),
})
mockFetch.mockReset().mockImplementation(async () => successfulResponse())
mockCreateObjectURL.mockClear()
mockRevokeObjectURL.mockClear()
vi.stubGlobal('fetch', mockFetch)
vi.stubGlobal('Image', MockImage)
vi.spyOn(URL, 'createObjectURL').mockImplementation(mockCreateObjectURL)
vi.spyOn(URL, 'revokeObjectURL').mockImplementation(mockRevokeObjectURL)
})
afterEach(() => {
vi.unstubAllGlobals()
vi.restoreAllMocks()
})
describe('Rendering', () => {
it('should render close button', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('shows the preview and loading state while images are loading', () => {
mockFetch.mockImplementation(() => new Promise(() => {}))
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
render(<ImagePreviewer images={images} onClose={vi.fn()} />)
// Esc text should be visible
// Esc text should be visible
expect(screen.getByText('Esc'))!.toBeInTheDocument()
})
it('should show loading state initially', async () => {
const onClose = vi.fn()
const images = createMockImages()
// Delay fetch to see loading state
mockFetch.mockImplementation(() => new Promise(() => {}))
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
// Loading component should be visible
// Loading component should be visible
expect(document.body.querySelector('.image-previewer'))!.toBeInTheDocument()
})
expect(screen.getByRole('dialog')).toBeInTheDocument()
expect(screen.getByRole('status')).toBeInTheDocument()
expect(screen.getByText('Esc')).toBeInTheDocument()
})
describe('Props', () => {
it('should start at initialIndex', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('loads every image and displays the first image metadata by default', async () => {
render(<ImagePreviewer images={images} onClose={vi.fn()} />)
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={1} onClose={onClose} />)
})
await waitFor(() => {
// Should start at second image
// Should start at second image
expect(screen.getByText('image2.png'))!.toBeInTheDocument()
})
})
it('should default initialIndex to 0', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
})
expect(await screen.findByRole('img', { name: 'image1.png' })).toHaveAttribute(
'src',
'blob:mock-url',
)
expect(screen.getByText(/800.*600/)).toBeInTheDocument()
expect(screen.getByText('1.00 KB')).toBeInTheDocument()
expect(mockFetch).toHaveBeenCalledTimes(3)
expect(mockFetch.mock.calls.map(([url]) => url)).toEqual(images.map(({ url }) => url))
})
describe('User Interactions', () => {
it('should call onClose when close button is clicked', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('starts from the requested image', async () => {
render(<ImagePreviewer images={images} initialIndex={1} onClose={vi.fn()} />)
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
// Find and click close button (the one with RiCloseLine icon)
const closeButton = document.querySelector('.absolute.right-6 button')
if (closeButton) {
fireEvent.click(closeButton)
expect(onClose).toHaveBeenCalledTimes(1)
}
})
it('should navigate to next image when next button is clicked', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
// Find and click next button (right arrow)
const buttons = document.querySelectorAll('button')
const nextButton = Array.from(buttons).find((btn) => btn.className.includes('right-8'))
if (nextButton) {
await act(async () => {
fireEvent.click(nextButton)
})
await waitFor(() => {
expect(screen.getByText('image2.png'))!.toBeInTheDocument()
})
}
})
it('should navigate to previous image when prev button is clicked', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={1} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText('image2.png'))!.toBeInTheDocument()
})
// Find and click prev button (left arrow)
const buttons = document.querySelectorAll('button')
const prevButton = Array.from(buttons).find((btn) => btn.className.includes('left-8'))
if (prevButton) {
await act(async () => {
fireEvent.click(prevButton)
})
await waitFor(() => {
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
}
})
it('should disable prev button at first image', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={0} onClose={onClose} />)
})
const buttons = document.querySelectorAll('button')
const prevButton = Array.from(buttons).find((btn) => btn.className.includes('left-8'))
expect(prevButton)!.toBeDisabled()
})
it('should disable next button at last image', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={2} onClose={onClose} />)
})
const buttons = document.querySelectorAll('button')
const nextButton = Array.from(buttons).find((btn) => btn.className.includes('right-8'))
expect(nextButton)!.toBeDisabled()
})
expect(await screen.findByRole('img', { name: 'image2.png' })).toBeInTheDocument()
})
describe('Image Loading', () => {
it('should fetch images on mount', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('navigates between images and disables navigation at the boundaries', async () => {
const user = userEvent.setup()
render(<ImagePreviewer images={images} onClose={vi.fn()} />)
await screen.findByRole('img', { name: 'image1.png' })
const { previousButton, nextButton } = getPreviewButtons()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
expect(previousButton).toBeDisabled()
expect(nextButton).toBeEnabled()
await waitFor(() => {
expect(mockFetch).toHaveBeenCalled()
})
})
await user.click(nextButton)
expect(screen.getByRole('img', { name: 'image2.png' })).toBeInTheDocument()
expect(previousButton).toBeEnabled()
it('should show error state when fetch fails', async () => {
const onClose = vi.fn()
const images = createMockImages()
await user.click(nextButton)
expect(screen.getByRole('img', { name: 'image3.png' })).toBeInTheDocument()
expect(nextButton).toBeDisabled()
mockFetch.mockRejectedValue(new Error('Network error'))
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText(/Failed to load image/))!.toBeInTheDocument()
})
})
it('should show retry button on error', async () => {
const onClose = vi.fn()
const images = createMockImages()
mockFetch.mockRejectedValue(new Error('Network error'))
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
// Retry button should be visible
const retryButton = document.querySelector('button.rounded-full')
expect(retryButton)!.toBeInTheDocument()
})
})
await user.click(previousButton)
expect(screen.getByRole('img', { name: 'image2.png' })).toBeInTheDocument()
})
describe('Navigation Boundary Cases', () => {
it('should not navigate past first image when prevImage is called at index 0', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('disables both navigation buttons for a single image', async () => {
render(<ImagePreviewer images={[images[0]!]} onClose={vi.fn()} />)
await screen.findByRole('img', { name: 'image1.png' })
const { previousButton, nextButton } = getPreviewButtons()
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={0} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
const buttons = document.querySelectorAll('button')
const prevButton = Array.from(buttons).find((btn) => btn.className.includes('left-8'))
if (prevButton) {
await act(async () => {
fireEvent.click(prevButton)
fireEvent.click(prevButton)
})
// Should still be at first image
await waitFor(() => {
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
}
})
it('should not navigate past last image when nextImage is called at last index', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} initialIndex={2} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText('image3.png'))!.toBeInTheDocument()
})
const buttons = document.querySelectorAll('button')
const nextButton = Array.from(buttons).find((btn) => btn.className.includes('right-8'))
if (nextButton) {
await act(async () => {
fireEvent.click(nextButton)
fireEvent.click(nextButton)
})
// Should still be at last image
await waitFor(() => {
expect(screen.getByText('image3.png'))!.toBeInTheDocument()
})
}
})
expect(previousButton).toBeDisabled()
expect(nextButton).toBeDisabled()
})
describe('Retry Functionality', () => {
it('should retry image load when retry button is clicked', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('keeps the preview open on content clicks and closes from the close button', async () => {
const user = userEvent.setup()
const onClose = vi.fn()
render(<ImagePreviewer images={images} onClose={onClose} />)
await screen.findByRole('img', { name: 'image1.png' })
const { closeButton } = getPreviewButtons()
// First fail, then succeed
let callCount = 0
mockFetch.mockImplementation(() => {
callCount++
if (callCount === 1) {
return Promise.reject(new Error('Network error'))
}
return Promise.resolve({
ok: true,
blob: () => Promise.resolve(new Blob(['test'], { type: 'image/png' })),
})
})
await user.click(screen.getByRole('dialog'))
expect(onClose).not.toHaveBeenCalled()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
// Wait for error state
await waitFor(() => {
expect(screen.getByText(/Failed to load image/))!.toBeInTheDocument()
})
const retryButton = document.querySelector('button.rounded-full')
if (retryButton) {
await act(async () => {
fireEvent.click(retryButton)
})
// Should refetch the image
await waitFor(() => {
expect(mockFetch).toHaveBeenCalledTimes(4) // 3 initial + 1 retry
})
}
})
it('should show retry button and call retryImage when clicked', async () => {
const onClose = vi.fn()
const images = createMockImages()
mockFetch.mockRejectedValue(new Error('Network error'))
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
expect(screen.getByText(/Failed to load image/))!.toBeInTheDocument()
})
// Find and click the retry button (not the nav buttons)
const allButtons = document.querySelectorAll('button')
const retryButton = Array.from(allButtons).find(
(btn) =>
btn.className.includes('rounded-full') &&
!btn.className.includes('left-8') &&
!btn.className.includes('right-8'),
)
expect(retryButton)!.toBeInTheDocument()
if (retryButton) {
mockFetch.mockClear()
mockFetch.mockResolvedValue({
ok: true,
blob: () => Promise.resolve(new Blob(['test'], { type: 'image/png' })),
})
await act(async () => {
fireEvent.click(retryButton)
})
await waitFor(() => {
expect(mockFetch).toHaveBeenCalled()
})
}
})
await user.click(closeButton)
expect(onClose).toHaveBeenCalledOnce()
})
describe('Image Cache', () => {
it('should clean up blob URLs on unmount', async () => {
const onClose = vi.fn()
const images = createMockImages()
it('shows an error and retries the failed image', async () => {
const user = userEvent.setup()
mockFetch.mockRejectedValueOnce(new Error('Network error'))
render(<ImagePreviewer images={images} onClose={vi.fn()} />)
// First render to populate cache
const { unmount } = await act(async () => {
const result = render(<ImagePreviewer images={images} onClose={onClose} />)
return result
})
expect(await screen.findByText(/Failed to load image/)).toHaveTextContent(images[0]!.url)
const [, retryButton] = screen.getAllByRole('button')
expect(retryButton).toBeInTheDocument()
await waitFor(() => {
expect(mockFetch).toHaveBeenCalled()
})
await user.click(retryButton!)
// Store the call count for verification
const _firstCallCount = mockFetch.mock.calls.length
unmount()
// Note: The imageCache is cleared on unmount, so this test verifies
// the cleanup behavior rather than caching across mounts
expect(mockRevokeObjectURL).toHaveBeenCalled()
})
expect(await screen.findByRole('img', { name: 'image1.png' })).toBeInTheDocument()
expect(mockFetch).toHaveBeenCalledTimes(4)
expect(mockFetch).toHaveBeenLastCalledWith(images[0]!.url)
})
describe('Edge Cases', () => {
it('should handle single image', async () => {
const onClose = vi.fn()
const images = [createMockImages()[0]!]
it('revokes loaded blob URLs on unmount', async () => {
const { unmount } = render(<ImagePreviewer images={images} onClose={vi.fn()} />)
await screen.findByRole('img', { name: 'image1.png' })
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
unmount()
// Both navigation buttons should be disabled
const buttons = document.querySelectorAll('button')
const prevButton = Array.from(buttons).find((btn) => btn.className.includes('left-8'))
const nextButton = Array.from(buttons).find((btn) => btn.className.includes('right-8'))
expect(prevButton)!.toBeDisabled()
expect(nextButton)!.toBeDisabled()
})
it('should not close on container click', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
const container = document.querySelector('.image-previewer')
if (container) {
fireEvent.click(container)
expect(onClose).not.toHaveBeenCalled()
}
})
it('should display image dimensions when loaded', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
// Should display dimensions (800 × 600 from MockImage)
// Should display dimensions (800 × 600 from MockImage)
expect(screen.getByText(/800.*600/))!.toBeInTheDocument()
})
})
it('should display file size', async () => {
const onClose = vi.fn()
const images = createMockImages()
await act(async () => {
render(<ImagePreviewer images={images} onClose={onClose} />)
})
await waitFor(() => {
// Should display formatted file size
// Should display formatted file size
expect(screen.getByText('image1.png'))!.toBeInTheDocument()
})
})
await waitFor(() => expect(mockRevokeObjectURL).toHaveBeenCalledTimes(3))
})
})

View File

@ -1,11 +1,11 @@
import type { ReactElement } from 'react'
import { screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import BuiltInPipelineList from '../built-in-pipeline-list'
const render = (ui: ReactElement) =>
renderWithSystemFeatures(ui, {
renderWithConsoleQuery(ui, {
systemFeatures: { enable_marketplace: true },
})

View File

@ -6,10 +6,11 @@ import type { TopBarProps } from '../top-bar'
import type { DataSourceAuth } from '@/app/components/header/account-setting/data-source-page-new/types'
import type { NotionPage } from '@/models/common'
import type { DataSet, FileItem } from '@/models/datasets'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
import { DataSourceProvider } from '@/models/common'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import DatasetUpdateForm from '../index'
@ -41,51 +42,37 @@ let mockCurrentUserId = 'user-1'
let mockWorkspacePermissionKeys = ['dataset.create_and_management']
let mockIsLoadingWorkspacePermissionKeys = false
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createAccountStateModuleMock(() => ({
userProfile: { id: mockCurrentUserId },
workspacePermissionKeys: mockWorkspacePermissionKeys,
isLoadingWorkspacePermissionKeys: mockIsLoadingWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: mockCurrentUserId },
workspacePermissionKeys: mockWorkspacePermissionKeys,
isLoadingWorkspacePermissionKeys: mockIsLoadingWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createPermissionStateModuleMock(() => ({
userProfile: { id: mockCurrentUserId },
workspacePermissionKeys: mockWorkspacePermissionKeys,
isLoadingWorkspacePermissionKeys: mockIsLoadingWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
userProfile: { id: mockCurrentUserId },
workspacePermissionKeys: mockWorkspacePermissionKeys,
isLoadingWorkspacePermissionKeys: mockIsLoadingWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createSystemFeaturesStateModuleMock(() => ({
userProfile: { id: mockCurrentUserId },
workspacePermissionKeys: mockWorkspacePermissionKeys,
isLoadingWorkspacePermissionKeys: mockIsLoadingWorkspacePermissionKeys,
@ -110,13 +97,6 @@ vi.mock('@/context/modal-context', () => ({
},
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
// Mock dataset detail context
let mockDatasetDetail: DataSet | undefined
vi.mock('@/context/dataset-detail', () => ({

View File

@ -1,9 +1,10 @@
import type { DocumentListResponse } from '@/models/datasets'
import { act, fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, screen } from '@testing-library/react'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { useProviderContext } from '@/context/provider-context'
import { DataSourceType } from '@/models/datasets'
import { useDocumentList } from '@/service/knowledge/use-document'
import { render } from '@/test/console/render'
import { useDocumentsPageState } from '../hooks/use-documents-page-state'
import Documents from '../index'
@ -47,47 +48,34 @@ vi.mock('@/context/provider-context', () => ({
})),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createAccountStateModuleMock(() => ({
userProfile: { id: 'test-user' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: 'test-user' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'test-user' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
userProfile: { id: 'test-user' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createSystemFeaturesStateModuleMock(() => ({
userProfile: { id: 'test-user' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
@ -130,13 +118,6 @@ vi.mock('@/service/knowledge/use-document', () => ({
useInvalidDocumentDetail: vi.fn(() => mockInvalidDocumentDetail),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
// Mock segment service hooks
vi.mock('@/service/knowledge/use-segment', () => ({
useSegmentListKey: 'segment-list-key',
@ -629,7 +610,9 @@ describe('Documents', () => {
render(<Documents {...defaultProps} />)
const payload = vi.mocked(useDocumentList).mock.calls.at(-1)?.[0]
const payload = vi
.mocked(useDocumentList)
.mock.calls.find(([options]) => options.query.status === 'indexing')?.[0]
const refetchInterval = payload?.refetchInterval
expect(typeof refetchInterval).toBe('function')
if (typeof refetchInterval !== 'function')

View File

@ -1,6 +1,7 @@
import type { SimpleDocumentDetail } from '@/models/datasets'
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { useDocumentSort } from '../document-list/hooks'
import DocumentList from '../list'
@ -14,6 +15,13 @@ const mockShowEditModal = vi.fn()
const mockHideEditModal = vi.fn()
const mockHandleSave = vi.fn()
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('../document-list/hooks', () => ({
useDocumentSort: vi.fn(() => ({
sortField: null,
@ -133,6 +141,14 @@ const defaultProps = {
onSortChange: vi.fn(),
}
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('DocumentList', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -1,9 +1,11 @@
import type { ReactNode } from 'react'
import type { SimpleDocumentDetail } from '@/models/datasets'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { act, fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ChunkingMode, DataSourceType } from '@/models/datasets'
import { seedAccountProfileQuery } from '@/test/console/account-profile'
import { render } from '@/test/console/render'
import DocumentList from '../../list'
const mockPush = vi.fn()
@ -38,47 +40,34 @@ vi.mock('@/context/dataset-detail', () => ({
}),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createSystemFeaturesStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
}))
@ -94,23 +83,21 @@ vi.mock('@/app/components/datasets/metadata/hooks/use-batch-edit-document-metada
}),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
const createTestQueryClient = () =>
const createConsoleQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false, gcTime: 0 },
queries: {
retry: false,
gcTime: Number.POSITIVE_INFINITY,
staleTime: Number.POSITIVE_INFINITY,
},
mutations: { retry: false },
},
})
const createWrapper = () => {
const queryClient = createTestQueryClient()
const queryClient = createConsoleQueryClient()
seedAccountProfileQuery(queryClient)
return ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)

View File

@ -1,15 +1,24 @@
import type { ReactNode } from 'react'
import type { SimpleDocumentDetail } from '@/models/datasets'
import { CheckboxGroup } from '@langgenius/dify-ui/checkbox-group'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { DataSourceType } from '@/models/datasets'
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
import { createQueryClientWrapper } from '@/test/console/query-client'
import { render } from '@/test/console/render'
import DocumentTableRow from '../document-table-row'
const mockPush = vi.fn()
let mockSearchParams = ''
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/next/navigation', () => ({
useRouter: () => ({
push: mockPush,
@ -17,18 +26,10 @@ vi.mock('@/next/navigation', () => ({
useSearchParams: () => new URLSearchParams(mockSearchParams),
}))
const createTestQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false, gcTime: 0 },
mutations: { retry: false },
},
})
const createWrapper = (value: string[] = [], onValueChange = vi.fn()) => {
const queryClient = createTestQueryClient()
const QueryClientWrapper = createQueryClientWrapper(createAccountProfileQueryClient())
return ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>
<QueryClientWrapper>
<CheckboxGroup
value={value}
onValueChange={(nextValue) => onValueChange(nextValue)}
@ -38,7 +39,7 @@ const createWrapper = (value: string[] = [], onValueChange = vi.fn()) => {
<tbody>{children}</tbody>
</table>
</CheckboxGroup>
</QueryClientProvider>
</QueryClientWrapper>
)
}
@ -83,6 +84,14 @@ const createMockDoc = (overrides: Record<string, unknown> = {}): LocalDoc =>
const getRowCheckbox = () => screen.getByRole('checkbox', { name: 'test-document.txt' })
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('DocumentTableRow', () => {
const defaultProps = {
doc: createMockDoc(),

View File

@ -16,7 +16,7 @@ const mockUseDocumentDelete = vi.mocked(useDocument.useDocumentDelete)
const mockUseDocumentBatchRetryIndex = vi.mocked(useDocument.useDocumentBatchRetryIndex)
const mockUseDocumentDownloadZip = vi.mocked(useDocument.useDocumentDownloadZip)
const createTestQueryClient = () =>
const createConsoleQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false },
@ -25,7 +25,7 @@ const createTestQueryClient = () =>
})
const createWrapper = () => {
const queryClient = createTestQueryClient()
const queryClient = createConsoleQueryClient()
return ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)

View File

@ -1,4 +1,5 @@
import { render, waitFor } from '@testing-library/react'
import { waitFor } from '@testing-library/react'
import { render } from '@/test/console/render'
import CreateFromPipeline from '../index'
let mockDatasetPermissionKeys = ['dataset.acl.use']
@ -15,63 +16,46 @@ vi.mock('@/context/provider-context', () => ({
) => selector({ plan: mockPlan, enableBilling: true }),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
isLoadingWorkspacePermissionKeys: false,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
isLoadingWorkspacePermissionKeys: false,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
isLoadingWorkspacePermissionKeys: false,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createSystemFeaturesStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
isLoadingWorkspacePermissionKeys: false,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.create_and_management'],
isLoadingWorkspacePermissionKeys: false,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
vi.mock('@/context/dataset-detail', () => ({
useDatasetDetailContextWithSelector: (
selector: (state: {

View File

@ -1,5 +1,6 @@
import { act, fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { DatasetACLPermission } from '@/utils/permission'
// --- All hoisted mock fns and state (accessible inside vi.mock factories) ---
@ -29,6 +30,13 @@ const mocks = vi.hoisted(() => {
})
// --- External mocks ---
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/next/navigation', () => ({
useRouter: () => ({ push: mocks.push }),
useSearchParams: () => new URLSearchParams(mocks.state.searchParams),
@ -260,6 +268,14 @@ const createDocumentDetail = (overrides?: Record<string, unknown>) => ({
...overrides,
})
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('DocumentDetail', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -37,7 +37,7 @@ const mockPauseDocIndexing = vi.mocked(datasetsService.pauseDocIndexing)
const mockResumeDocIndexing = vi.mocked(datasetsService.resumeDocIndexing)
const mockUseProcessRule = vi.mocked(useDataset.useProcessRule)
const createTestQueryClient = () =>
const createConsoleQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false, gcTime: 0 },
@ -48,7 +48,7 @@ const createTestQueryClient = () =>
const createWrapper = (
contextValue: DocumentContextValue = { datasetId: 'ds1', documentId: 'doc1' },
) => {
const queryClient = createTestQueryClient()
const queryClient = createConsoleQueryClient()
return ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>
<>

View File

@ -19,7 +19,7 @@ const mockFetchIndexingStatus = vi.mocked(datasetsService.fetchIndexingStatus)
const mockPauseDocIndexing = vi.mocked(datasetsService.pauseDocIndexing)
const mockResumeDocIndexing = vi.mocked(datasetsService.resumeDocIndexing)
const createTestQueryClient = () =>
const createConsoleQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false },
@ -28,7 +28,7 @@ const createTestQueryClient = () =>
})
const createWrapper = () => {
const queryClient = createTestQueryClient()
const queryClient = createConsoleQueryClient()
return ({ children }: { children: ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)

View File

@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import { DatasetACLPermission } from '@/utils/permission'
import Card from '../card'
@ -9,6 +10,13 @@ let mockDatasetPermissionKeys: string[] = [DatasetACLPermission.Edit]
const mockEnableApi = vi.fn()
const mockDisableApi = vi.fn()
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/context/dataset-detail', () => ({
useDatasetDetailContextWithSelector: (selector: (state: Record<string, unknown>) => unknown) =>
selector({
@ -29,6 +37,14 @@ vi.mock('@/hooks/use-api-access-url', () => ({
useDatasetApiAccessUrl: () => 'https://docs.dify.ai/api-reference/datasets',
}))
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('API access card', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -1,15 +1,16 @@
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { render } from '@/test/console/render'
import ServiceApi from '../index'
let mockPermissionKeys = ['dataset.api_key.manage']
vi.mock('jotai', async (importOriginal) => {
const actual = await importOriginal<typeof import('jotai')>()
return {
...actual,
useAtomValue: () => mockPermissionKeys,
}
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mockPermissionKeys,
}))
})
vi.mock('@/app/components/develop/secret-key/secret-key-modal', () => ({

View File

@ -2,9 +2,10 @@ import type { ReactNode } from 'react'
import type { DataSet, HitTesting, HitTestingRecord, HitTestingResponse } from '@/models/datasets'
import type { RetrievalConfig } from '@/types/app'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen, waitFor } from '@testing-library/react'
import { screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, expect, it, vi } from 'vitest'
import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import HitTestingPage from '../index'
@ -117,7 +118,7 @@ const mockDataset = {
permission_keys: ['dataset.acl.retrieval_recall'],
} as Partial<DataSet>
let mockAppContextState = {
let mockConsoleState = {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}
@ -138,35 +139,25 @@ vi.mock('@/context/dataset-detail', () => ({
),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createSystemFeaturesStateModuleMock(() => mockConsoleState)
})
const mockRecordsRefetch = vi.fn()
@ -187,13 +178,6 @@ vi.mock('@/service/knowledge/use-dataset', () => ({
})),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
vi.mock('@/service/knowledge/use-hit-testing', () => ({
useHitTesting: vi.fn(() => ({
mutateAsync: mockHitTestingMutateAsync,
@ -338,7 +322,7 @@ vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', ()
// Test Wrapper with QueryClientProvider
const createTestQueryClient = () =>
const createConsoleQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
@ -352,7 +336,7 @@ const createTestQueryClient = () =>
})
const TestWrapper = ({ children }: { children: ReactNode }) => {
const queryClient = createTestQueryClient()
const queryClient = createConsoleQueryClient()
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
@ -433,7 +417,7 @@ describe('HitTestingPage', () => {
is_multimodal: false,
permission_keys: ['dataset.acl.retrieval_recall'],
})
mockAppContextState = {
mockConsoleState = {
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}

View File

@ -1,11 +1,12 @@
import type { ReactNode } from 'react'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from '@/test/console/render'
import List from '../index'
const mockPush = vi.fn()
const mockReplace = vi.fn()
let mockAppContextState = {
let mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -20,35 +21,25 @@ vi.mock('@/next/navigation', () => ({
// Mock app context
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createSystemFeaturesStateModuleMock(() => mockConsoleState)
})
// Mock external api panel context
@ -60,13 +51,6 @@ vi.mock('@/context/external-api-panel-context', () => ({
}),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
// Mock useDocumentTitle hook
vi.mock('@/hooks/use-document-title', () => ({
default: vi.fn(),
@ -191,7 +175,7 @@ vi.mock('@/app/components/datasets/create/website/base/checkbox-with-label', ()
describe('List', () => {
beforeEach(async () => {
vi.clearAllMocks()
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -224,7 +208,7 @@ describe('List', () => {
})
it('should hide external API panel button without dataset.external.connect', () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -335,7 +319,7 @@ describe('List', () => {
})
it('should render first empty state when dataset.create_and_management is available without the legacy editor role', async () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: false,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -359,7 +343,7 @@ describe('List', () => {
})
it('should not render first empty state for legacy editors without dataset creation permissions', async () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -472,7 +456,7 @@ describe('List', () => {
})
it('should not show ExternalAPIPanel without dataset.external.connect even when panel state is open', async () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: true,
@ -520,7 +504,7 @@ describe('List', () => {
})
it('should not show include all checkbox when not workspace owner', async () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceManager: true,
isCurrentWorkspaceOwner: false,

View File

@ -1,9 +1,10 @@
import type { DataSet } from '@/models/datasets'
import { fireEvent, render, screen } from '@testing-library/react'
import { fireEvent, screen } from '@testing-library/react'
import * as React from 'react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { IndexingType } from '@/app/components/datasets/create/step-two'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { render } from '@/test/console/render'
import { DatasetACLPermission } from '@/utils/permission'
import DatasetCardFooter from '../components/dataset-card-footer'
import Description from '../components/description'
@ -55,41 +56,31 @@ vi.mock('@/next/navigation', () => ({
useRouter: () => ({ push: mockPush }),
}))
let mockAppContextState = {
let mockConsoleState = {
isCurrentWorkspaceDatasetOperator: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => mockAppContextState)
return createSystemFeaturesStateModuleMock(() => mockConsoleState)
})
vi.mock('../hooks/use-dataset-card-state', () => ({
@ -111,13 +102,6 @@ vi.mock('../hooks/use-dataset-card-state', () => ({
}),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
vi.mock('../components/corner-labels', () => ({
default: () => <div data-testid="corner-labels" />,
}))
@ -187,7 +171,7 @@ const createMockDataset = (overrides: Partial<DataSet> = {}): DataSet =>
describe('DatasetCard Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceDatasetOperator: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
@ -336,7 +320,7 @@ describe('DatasetCard Integration', () => {
describe('DatasetCard Component', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceDatasetOperator: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
@ -471,7 +455,7 @@ describe('DatasetCard Component', () => {
})
it('should allow tag binding with workspace dataset tag management permission', () => {
mockAppContextState = {
mockConsoleState = {
isCurrentWorkspaceDatasetOperator: false,
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['dataset.tag.manage'],

View File

@ -1,92 +1,50 @@
import type { DataSet } from '@/models/datasets'
import { fireEvent, screen } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { IndexingType } from '@/app/components/datasets/create/step-two'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { DatasetACLPermission } from '@/utils/permission'
import OperationsDropdown from '../operations-dropdown'
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}))
let mockIsRbacEnabled = true
const render = (ui: Parameters<typeof renderWithSystemFeatures>[0]) =>
renderWithSystemFeatures(ui, {
const render = (ui: Parameters<typeof renderWithConsoleQuery>[0]) =>
renderWithConsoleQuery(ui, {
systemFeatures: {
rbac_enabled: mockIsRbacEnabled,
},
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
return createSystemFeaturesStateModuleMock(() => ({
...(() => mockConsoleState)(),
datasetRbacEnabled: (() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
}))().isRbacEnabled,
}))
})
describe('OperationsDropdown', () => {
@ -129,8 +87,8 @@ describe('OperationsDropdown', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContextState.userProfile = { id: 'user-1' }
mockAppContextState.workspacePermissionKeys = []
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = []
mockIsRbacEnabled = true
})

View File

@ -1,7 +1,7 @@
import type { ReactElement } from 'react'
import { fireEvent, render as rtlRender, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { createAccountProfileQueryWrapper } from '@/test/account-profile-query'
import { createAccountProfileQueryWrapper } from '@/test/console/account-profile'
import WrappedDatePicker from '../date-picker'
type TriggerArgs = {

View File

@ -1,8 +1,9 @@
import type { DataSet } from '@/models/datasets'
import type { RetrievalConfig } from '@/types/app'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { expectLoadingButton } from '@/test/button'
import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import { DatasetACLPermission } from '@/utils/permission'
import { IndexingType } from '../../../create/step-two'
@ -37,80 +38,42 @@ vi.mock('@tanstack/react-query', async (importOriginal) => {
}
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}),
() => ({
isRbacEnabled: false,
}),
)
return createAccountStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}),
() => ({
isRbacEnabled: false,
}),
)
return createWorkspaceStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}),
() => ({
isRbacEnabled: false,
}),
)
return createPermissionStateModuleMock(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
return createSystemFeaturesStateModuleMock(() => ({
...(() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}),
() => ({
}))(),
datasetRbacEnabled: (() => ({
isRbacEnabled: false,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => ({
userProfile: mockUserProfile,
workspacePermissionKeys: mockWorkspacePermissionKeys,
}),
() => ({
isRbacEnabled: false,
}),
)
}))().isRbacEnabled,
}))
})
const createMockDataset = (overrides: Partial<DataSet> = {}): DataSet => ({
@ -197,13 +160,6 @@ vi.mock('@/context/dataset-detail', () => ({
},
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
// Mock services
vi.mock('@/service/datasets', () => ({
updateDatasetSetting: vi.fn().mockResolvedValue({}),

View File

@ -1,8 +1,9 @@
import type { Member } from '@/models/common'
import type { DataSet, IconInfo } from '@/models/datasets'
import type { RetrievalConfig } from '@/types/app'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { ChunkingMode, DatasetPermission, DataSourceType } from '@/models/datasets'
import { render } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import { IndexingType } from '../../../../create/step-two'
import BasicInfoSection from '../basic-info-section'
@ -19,7 +20,7 @@ vi.mock('@tanstack/react-query', async (importOriginal) => {
}
})
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: {
id: 'user-1',
name: 'Current User',
@ -31,65 +32,30 @@ const mockAppContextState = vi.hoisted(() => ({
// Mock app-context
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: false,
}),
)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: false,
}),
)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: false,
}),
)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
return createSystemFeaturesStateModuleMock(() => ({
...(() => mockConsoleState)(),
datasetRbacEnabled: (() => ({
isRbacEnabled: false,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: false,
}),
)
}))().isRbacEnabled,
}))
})
// Mock image uploader hooks for AppIconPicker
@ -109,13 +75,6 @@ vi.mock('@/app/components/base/image-uploader/hooks', () => ({
}),
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
describe('BasicInfoSection', () => {
const mockDataset: DataSet = {
id: 'dataset-1',

View File

@ -1,12 +1,13 @@
import type { DataSet } from '@/models/datasets'
import type { RetrievalConfig } from '@/types/app'
import { act, renderHook, waitFor } from '@testing-library/react'
import { act, waitFor } from '@testing-library/react'
import {
ChunkingMode,
DatasetPermission,
DataSourceType,
WeightedScoreEnum,
} from '@/models/datasets'
import { renderHook } from '@/test/console/render'
import { RETRIEVE_METHOD } from '@/types/app'
import { DatasetACLPermission } from '@/utils/permission'
import { IndexingType } from '../../../../create/step-two'
@ -21,47 +22,34 @@ const { mockToastSuccess, mockToastError } = vi.hoisted(() => ({
const mockMutateDatasets = vi.fn()
const mockInvalidDatasetList = vi.fn()
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createAccountStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createWorkspaceStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createPermissionStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(importOriginal, () => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(importOriginal, () => ({
return createSystemFeaturesStateModuleMock(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [],
}))
@ -150,13 +138,6 @@ vi.mock('@/context/dataset-detail', () => ({
},
}))
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
})
// Mock services
vi.mock('@/service/datasets', () => ({
updateDatasetSetting: vi.fn().mockResolvedValue({}),

View File

@ -1,10 +1,10 @@
import type { Member } from '@/models/common'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { DatasetPermission } from '@/models/datasets'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import PermissionSelector from '../index'
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: {
id: 'user-1',
name: 'Current User',
@ -16,72 +16,30 @@ const mockAppContextState = vi.hoisted(() => ({
let mockIsRbacEnabled = false
vi.mock('@/context/account-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
vi.mock('@/context/system-features-state', async () => {
const { createSystemFeaturesStateModuleMock } = await import('@/test/console/state-fixture')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
return createSystemFeaturesStateModuleMock(() => ({
...(() => mockConsoleState)(),
datasetRbacEnabled: (() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createDatasetAccessAtomMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessAtomMock(
importOriginal,
() => mockAppContextState,
() => ({
isRbacEnabled: mockIsRbacEnabled,
}),
)
})
vi.mock('jotai', async (importOriginal) => {
const { createDatasetAccessJotaiMock } =
await import('@/app/components/datasets/__tests__/mock-dataset-access')
return createDatasetAccessJotaiMock(importOriginal)
}))().isRbacEnabled,
}))
})
describe('PermissionSelector', () => {
@ -151,21 +109,21 @@ describe('PermissionSelector', () => {
describe('Rendering', () => {
it('should render Only Me option when permission is onlyMe', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.onlyMe} />,
)
expect(screen.getByText(/form\.permissionsOnlyMe/))!.toBeInTheDocument()
})
it('should render All Team Members option when permission is allTeamMembers', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.allTeamMembers} />,
)
expect(screen.getByText(/form\.permissionsAllMember/))!.toBeInTheDocument()
})
it('should render selected member names when permission is partialMembers', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
permission={DatasetPermission.partialMembers}
@ -180,7 +138,7 @@ describe('PermissionSelector', () => {
describe('Dropdown Toggle', () => {
it('should open dropdown when clicked', async () => {
renderWithSystemFeatures(<PermissionSelector {...defaultProps} />)
renderWithConsoleQuery(<PermissionSelector {...defaultProps} />)
const trigger = screen.getByText(/form\.permissionsOnlyMe/)
fireEvent.click(trigger)
@ -192,7 +150,7 @@ describe('PermissionSelector', () => {
})
it('should not open dropdown when disabled', () => {
renderWithSystemFeatures(<PermissionSelector {...defaultProps} disabled={true} />)
renderWithConsoleQuery(<PermissionSelector {...defaultProps} disabled={true} />)
const trigger = screen.getByText(/form\.permissionsOnlyMe/)
fireEvent.click(trigger)
@ -205,7 +163,7 @@ describe('PermissionSelector', () => {
describe('Permission Selection', () => {
it('should call onChange with onlyMe when Only Me is selected', async () => {
const handleChange = vi.fn()
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
onChange={handleChange}
@ -226,7 +184,7 @@ describe('PermissionSelector', () => {
it('should call onChange with allTeamMembers when All Team Members is selected', async () => {
const handleChange = vi.fn()
renderWithSystemFeatures(<PermissionSelector {...defaultProps} onChange={handleChange} />)
renderWithConsoleQuery(<PermissionSelector {...defaultProps} onChange={handleChange} />)
const trigger = screen.getByText(/form\.permissionsOnlyMe/)
fireEvent.click(trigger)
@ -242,7 +200,7 @@ describe('PermissionSelector', () => {
it('should call onChange with partialMembers when Invited Members is selected', async () => {
const handleChange = vi.fn()
const handleMemberSelect = vi.fn()
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
onChange={handleChange}
@ -265,7 +223,7 @@ describe('PermissionSelector', () => {
describe('Member Selection', () => {
it('should show member list when partialMembers is selected', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -282,7 +240,7 @@ describe('PermissionSelector', () => {
it('should call onMemberSelect when a member is clicked', async () => {
const handleMemberSelect = vi.fn()
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
permission={DatasetPermission.partialMembers}
@ -303,7 +261,7 @@ describe('PermissionSelector', () => {
it('should deselect member when clicked again', async () => {
const handleMemberSelect = vi.fn()
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
permission={DatasetPermission.partialMembers}
@ -326,7 +284,7 @@ describe('PermissionSelector', () => {
describe('Search Functionality', () => {
it('should allow typing in search input', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -342,7 +300,7 @@ describe('PermissionSelector', () => {
})
it('should render search input in partial members mode', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -355,7 +313,7 @@ describe('PermissionSelector', () => {
})
it('should filter members after debounce completes', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -378,7 +336,7 @@ describe('PermissionSelector', () => {
})
it('should handle clear search functionality', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -402,7 +360,7 @@ describe('PermissionSelector', () => {
})
it('should filter members by email', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -425,7 +383,7 @@ describe('PermissionSelector', () => {
})
it('should show no results message when search matches nothing', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -448,7 +406,7 @@ describe('PermissionSelector', () => {
})
it('should show current user when search matches user name', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -471,7 +429,7 @@ describe('PermissionSelector', () => {
})
it('should show current user when search matches user email', async () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.partialMembers} />,
)
@ -494,7 +452,7 @@ describe('PermissionSelector', () => {
describe('Disabled State', () => {
it('should apply disabled styles when disabled', () => {
const { container } = renderWithSystemFeatures(
const { container } = renderWithConsoleQuery(
<PermissionSelector {...defaultProps} disabled={true} />,
)
// When disabled, the component has cursor-not-allowed! class (escaped in Tailwind)
@ -505,7 +463,7 @@ describe('PermissionSelector', () => {
it('should show access config hint and remain closed when RBAC is enabled', () => {
mockIsRbacEnabled = true
renderWithSystemFeatures(<PermissionSelector {...defaultProps} />, {
renderWithConsoleQuery(<PermissionSelector {...defaultProps} />, {
systemFeatures: {
rbac_enabled: true,
},
@ -521,7 +479,7 @@ describe('PermissionSelector', () => {
describe('Display Variations', () => {
it('should display single avatar when only one member selected', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
permission={DatasetPermission.partialMembers}
@ -535,7 +493,7 @@ describe('PermissionSelector', () => {
})
it('should display two avatars when two or more members selected', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
permission={DatasetPermission.partialMembers}
@ -551,13 +509,13 @@ describe('PermissionSelector', () => {
describe('Edge Cases', () => {
it('should handle empty member list', () => {
renderWithSystemFeatures(<PermissionSelector {...defaultProps} memberList={[]} />)
renderWithConsoleQuery(<PermissionSelector {...defaultProps} memberList={[]} />)
expect(screen.getByText(/form\.permissionsOnlyMe/))!.toBeInTheDocument()
})
it('should handle member list with only current user', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector {...defaultProps} memberList={[mockMemberList[0]!]} />,
)
@ -584,7 +542,7 @@ describe('PermissionSelector', () => {
},
]
renderWithSystemFeatures(
renderWithConsoleQuery(
<PermissionSelector
{...defaultProps}
memberList={memberListWithNormalUser}
@ -600,7 +558,7 @@ describe('PermissionSelector', () => {
describe('Props', () => {
it('should update when permission prop changes', () => {
const { rerender } = renderWithSystemFeatures(
const { rerender } = renderWithConsoleQuery(
<PermissionSelector {...defaultProps} permission={DatasetPermission.onlyMe} />,
)

View File

@ -1,4 +1,5 @@
import { act, fireEvent, render, screen } from '@testing-library/react'
import { act, fireEvent, screen } from '@testing-library/react'
import { render } from '@/test/console/render'
import { DetailSidebarFrame } from '..'
import { DETAIL_SIDEBAR_STORAGE_KEY } from '../storage'
@ -11,7 +12,7 @@ const { hotkeyRegistrations } = vi.hoisted(() => ({
}
>(),
}))
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: {
langGeniusVersionInfo: {
current_env: '',
@ -33,31 +34,9 @@ vi.mock('@tanstack/react-hotkeys', async (importOriginal) => {
}
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState.current)
})
vi.mock('@/app/components/main-nav/components/account-section', () => ({
@ -103,7 +82,7 @@ describe('DetailSidebarFrame', () => {
beforeEach(() => {
localStorage.clear()
hotkeyRegistrations.clear()
mockAppContextState.current = {
mockConsoleState.current = {
langGeniusVersionInfo: {
current_env: '',
},
@ -131,7 +110,7 @@ describe('DetailSidebarFrame', () => {
})
it('collapses detail content from the top toggle and hides environment metadata', () => {
mockAppContextState.current = {
mockConsoleState.current = {
langGeniusVersionInfo: {
current_env: 'TESTING',
},

View File

@ -1,7 +1,15 @@
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import { renderWithAccountProfile as render } from '@/test/console/account-profile'
import DevelopMain from '../index'
const mockAppDetailValue: { current: unknown } = { current: undefined }
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: { id: 'workspace-1' },
}))
})
vi.mock('@/app/components/app/store', () => ({
useStore: (selector: (state: unknown) => unknown) => {
const state = { appDetail: mockAppDetailValue.current }
@ -23,6 +31,14 @@ vi.mock('@/app/components/develop/ApiServer', () => ({
),
}))
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: [],
}))
})
describe('DevelopMain', () => {
beforeEach(() => {
vi.clearAllMocks()

View File

@ -1,6 +1,7 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { afterEach } from 'vitest'
import { render } from '@/test/console/render'
import SecretKeyModal from '../secret-key-modal'
async function renderModal(ui: React.ReactElement) {
@ -27,58 +28,14 @@ const mockCurrentWorkspace = vi.fn().mockReturnValue({
const mockIsCurrentWorkspaceManager = vi.fn().mockReturnValue(true)
const mockIsCurrentWorkspaceEditor = vi.fn().mockReturnValue(true)
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => ({
currentWorkspace: mockCurrentWorkspace(),
isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(),
isCurrentWorkspaceEditor: mockIsCurrentWorkspaceEditor(),
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: mockCurrentWorkspace(),
isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(),
isCurrentWorkspaceEditor: mockIsCurrentWorkspaceEditor(),
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: mockCurrentWorkspace(),
isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(),
isCurrentWorkspaceEditor: mockIsCurrentWorkspaceEditor(),
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: mockCurrentWorkspace(),
isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(),
isCurrentWorkspaceEditor: mockIsCurrentWorkspaceEditor(),
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
currentWorkspace: mockCurrentWorkspace(),
isCurrentWorkspaceManager: mockIsCurrentWorkspaceManager(),
isCurrentWorkspaceEditor: mockIsCurrentWorkspaceEditor(),
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/hooks/use-timestamp', () => ({
default: () => ({

View File

@ -3,8 +3,8 @@ import type { App } from '@/models/explore'
import { fireEvent, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import * as React from 'react'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { trackEvent } from '@/app/components/base/amplitude'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import AppCard from '../index'

View File

@ -6,15 +6,15 @@ import type { App } from '@/models/explore'
import type { App as WorkspaceApp } from '@/types/app'
import { act, fireEvent, screen, waitFor } from '@testing-library/react'
import { createStore, Provider as JotaiProvider } from 'jotai'
import { createSystemFeaturesWrapper } from '@/__tests__/utils/mock-system-features'
import { fetchAppDetail, fetchAppList, fetchBanners } from '@/service/explore'
import { createConsoleQueryWrapper } from '@/test/console/query-data'
import { renderWithNuqs } from '@/test/nuqs-testing'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import { LEARN_DIFY_HIDDEN_STORAGE_KEY } from '../../learn-dify/storage'
import AppList from '../index'
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: [] as string[],
}))
@ -150,37 +150,13 @@ vi.mock('@/service/client', () => ({
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/hooks/use-import-dsl', () => ({
@ -347,9 +323,7 @@ const createBanner = (overrides: Partial<BannerType> = {}): BannerType => ({
})
const mockAppCreatePermission = (hasEditPermission: boolean) => {
mockAppContextState.workspacePermissionKeys = hasEditPermission
? ['app.create_and_management']
: []
mockConsoleState.workspacePermissionKeys = hasEditPermission ? ['app.create_and_management'] : []
}
type RenderOptions = {
@ -370,7 +344,7 @@ const renderAppList = (
) => {
mockConfig.isCloudEdition = options.isCloudEdition ?? false
mockAppCreatePermission(hasEditPermission)
const { wrapper: SystemFeaturesWrapper, queryClient } = createSystemFeaturesWrapper({
const { wrapper: ConsoleQueryWrapper, queryClient } = createConsoleQueryWrapper({
systemFeatures: {
enable_explore_banner: options.enableExploreBanner ?? false,
enable_learn_app: options.enableLearnApp ?? true,
@ -404,7 +378,7 @@ const renderAppList = (
const Wrapped = ({ children }: { children: ReactNode }) => (
<JotaiProvider store={jotaiStore}>
<SystemFeaturesWrapper>{children}</SystemFeaturesWrapper>
<ConsoleQueryWrapper>{children}</ConsoleQueryWrapper>
</JotaiProvider>
)
const rendered = renderWithNuqs(

View File

@ -1,8 +1,9 @@
import type { Banner as BannerType } from '@/models/app'
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { cleanup, fireEvent, screen } from '@testing-library/react'
import * as React from 'react'
import { act } from 'react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { render } from '@/test/console/render'
import { Banner } from '../banner'
const mockTrackEvent = vi.fn()
@ -14,7 +15,7 @@ const mockAutoplayListeners = {
play: new Set<() => void>(),
stop: new Set<() => void>(),
}
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: {
id: 'account-123',
name: 'Evan',
@ -57,15 +58,9 @@ const setMockSelectedIndex = (index: number) => {
mockCarouselListeners.forEach((listener) => listener())
}
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/app/components/base/amplitude', () => ({
@ -178,7 +173,7 @@ describe('Banner', () => {
mockCarouselListeners.clear()
mockAutoplayListeners.play.clear()
mockAutoplayListeners.stop.clear()
mockAppContextState.userProfile = { id: 'account-123', name: 'Evan' }
mockConsoleState.userProfile = { id: 'account-123', name: 'Evan' }
})
afterEach(cleanup)
@ -391,7 +386,7 @@ describe('Banner', () => {
})
it('does not track impressions without an account id', () => {
mockAppContextState.userProfile = { id: '', name: '' }
mockConsoleState.userProfile = { id: '', name: '' }
render(<Banner banners={[createMockBanner('1')]} />)
expect(mockTrackEvent).not.toHaveBeenCalled()

View File

@ -1,13 +1,13 @@
import type { AnchorHTMLAttributes, ReactNode } from 'react'
import type { App } from '@/types/app'
import { fireEvent, screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { AccessMode } from '@/models/access-control'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
import ContinueWorkItem from '../item'
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
userProfile: { id: 'user-1' },
workspacePermissionKeys: ['app.create_and_management'],
}))
@ -18,37 +18,13 @@ const toastMocks = vi.hoisted(() => ({
warning: vi.fn(),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState)
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/hooks/use-format-time-from-now', () => ({
@ -107,16 +83,16 @@ const createApp = (overrides: Partial<App> = {}): App => ({
const renderItem = (
app: App,
systemFeatures: NonNullable<Parameters<typeof renderWithSystemFeatures>[1]>['systemFeatures'] = {
systemFeatures: NonNullable<Parameters<typeof renderWithConsoleQuery>[1]>['systemFeatures'] = {
rbac_enabled: true,
},
) => renderWithSystemFeatures(<ContinueWorkItem app={app} />, { systemFeatures })
) => renderWithConsoleQuery(<ContinueWorkItem app={app} />, { systemFeatures })
describe('ContinueWorkItem', () => {
beforeEach(() => {
vi.clearAllMocks()
mockAppContextState.userProfile = { id: 'user-1' }
mockAppContextState.workspacePermissionKeys = ['app.create_and_management']
mockConsoleState.userProfile = { id: 'user-1' }
mockConsoleState.workspacePermissionKeys = ['app.create_and_management']
mockFormatTimeFromNow.mockReturnValue('5 minutes ago')
})

View File

@ -1,6 +1,6 @@
import type { CreateAppModalProps } from '../index'
import type { UsagePlanInfo } from '@/app/components/billing/type'
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import { act, fireEvent, screen, waitFor, within } from '@testing-library/react'
import * as React from 'react'
import {
createMockPlan,
@ -8,6 +8,7 @@ import {
createMockPlanUsage,
} from '@/__mocks__/provider-context'
import { Plan } from '@/app/components/billing/type'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import { AppModeEnum } from '@/types/app'
import CreateAppModal from '../index'

View File

@ -1,7 +1,7 @@
import type { TryAppInfo } from '@/service/try-app'
import { cleanup, fireEvent, screen, waitFor } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures as render } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery as render } from '@/test/console/query-data'
import TryApp from '../index'
import { TypeEnum } from '../types'

View File

@ -1,6 +1,6 @@
import type { LangGeniusVersionInfo } from '@/context/app-context-types'
import { fireEvent, screen } from '@testing-library/react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import AccountAbout from '../index'
let mockIsCEEdition = false
@ -38,7 +38,7 @@ describe('AccountAbout', () => {
describe('Rendering', () => {
it('should render correctly with version information', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={mockVersionInfo} onCancel={mockOnCancel} />,
{
systemFeatures: { branding: { enabled: false } },
@ -50,7 +50,7 @@ describe('AccountAbout', () => {
})
it('should render branding logo if enabled', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={mockVersionInfo} onCancel={mockOnCancel} />,
{
systemFeatures: { branding: { enabled: true, workspace_logo: 'custom-logo.png' } },
@ -65,7 +65,7 @@ describe('AccountAbout', () => {
describe('Version Logic', () => {
it('should show "Latest Available" when current version equals latest', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={mockVersionInfo} onCancel={mockOnCancel} />,
)
@ -75,7 +75,7 @@ describe('AccountAbout', () => {
it('should show "Now Available" when current version is behind', () => {
const behindVersionInfo = { ...mockVersionInfo, latest_version: '0.7.0' }
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={behindVersionInfo} onCancel={mockOnCancel} />,
)
@ -88,7 +88,7 @@ describe('AccountAbout', () => {
it('should render correctly in Community Edition', () => {
mockIsCEEdition = true
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={mockVersionInfo} onCancel={mockOnCancel} />,
)
@ -99,7 +99,7 @@ describe('AccountAbout', () => {
mockIsCEEdition = true
const behindVersionInfo = { ...mockVersionInfo, latest_version: '0.7.0' }
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={behindVersionInfo} onCancel={mockOnCancel} />,
)
@ -109,7 +109,7 @@ describe('AccountAbout', () => {
describe('User Interactions', () => {
it('should call onCancel when close button is clicked', () => {
renderWithSystemFeatures(
renderWithConsoleQuery(
<AccountAbout langGeniusVersionInfo={mockVersionInfo} onCancel={mockOnCancel} />,
)

View File

@ -1,11 +1,10 @@
import type { GetSystemFeaturesResponse } from '@dify/contracts/api/console/system-features/types.gen'
import type { AppContextStateMockState } from '@/__tests__/utils/mock-app-context-state'
import type { ModalContextState } from '@/context/modal-context'
import type { ProviderContextState } from '@/context/provider-context'
import type { ConsoleStateFixture } from '@/test/console/state-fixture'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderToString } from 'react-dom/server'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { Plan } from '@/app/components/billing/type'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import AccountSection from '@/app/components/main-nav/components/account-section'
@ -13,7 +12,8 @@ import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
import { useRouter } from '@/next/navigation'
import { useLogout } from '@/service/use-common'
import { createAccountProfileQueryClient } from '@/test/account-profile-query'
import { createAccountProfileQueryClient } from '@/test/console/account-profile'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import AppSelector from '../index'
type DeepPartial<T> =
@ -51,10 +51,10 @@ vi.mock('@/app/components/base/theme-switcher', () => ({
const { mockSetTheme } = vi.hoisted(() => ({
mockSetTheme: vi.fn(),
}))
const mockAppContextState = vi.hoisted(() => ({
current: undefined as AppContextStateMockState | undefined,
const mockConsoleState = vi.hoisted(() => ({
current: undefined as ConsoleStateFixture | undefined,
}))
const mockUseAppContext = vi.hoisted(() => vi.fn())
const mockConsoleStateReader = vi.hoisted(() => vi.fn())
vi.mock('next-themes', () => ({
useTheme: () => ({
@ -63,31 +63,21 @@ vi.mock('next-themes', () => ({
}),
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/provider-context', () => ({
@ -159,9 +149,9 @@ const baseUserProfile = {
is_password_set: false,
}
const baseAppContextValue: AppContextStateMockState = {
const baseConsoleState: ConsoleStateFixture = {
userProfile: baseUserProfile,
mutateUserProfile: vi.fn(),
refreshUserProfile: vi.fn(),
currentWorkspace: {
id: '1',
name: 'Workspace',
@ -178,7 +168,7 @@ const baseAppContextValue: AppContextStateMockState = {
isCurrentWorkspaceOwner: true,
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceDatasetOperator: false,
mutateCurrentWorkspace: vi.fn(),
refreshCurrentWorkspace: vi.fn(),
langGeniusVersionInfo: {
current_env: 'testing',
current_version: '0.6.0',
@ -192,9 +182,9 @@ const baseAppContextValue: AppContextStateMockState = {
workspacePermissionKeys: [],
}
const setAppContextValue = (value: AppContextStateMockState) => {
mockAppContextState.current = value
mockUseAppContext.mockReturnValue(value)
const setConsoleState = (value: ConsoleStateFixture) => {
mockConsoleState.current = value
mockConsoleStateReader.mockReturnValue(value)
}
describe('AccountDropdown', () => {
@ -208,9 +198,9 @@ describe('AccountDropdown', () => {
) => {
const queryClient = createAccountProfileQueryClient({
...baseUserProfile,
...(mockAppContextState.current?.userProfile ?? {}),
...(mockConsoleState.current?.userProfile ?? {}),
})
return renderWithSystemFeatures(ui, {
return renderWithConsoleQuery(ui, {
queryClient,
systemFeatures: options.systemFeatures ?? { branding: { enabled: false } },
})
@ -222,7 +212,7 @@ describe('AccountDropdown', () => {
mockConfig.IS_CLOUD_EDITION = false
mockEnv.env.NEXT_PUBLIC_SITE_ABOUT = 'show'
setAppContextValue(baseAppContextValue)
setConsoleState(baseConsoleState)
vi.mocked(useProviderContext).mockReturnValue({
isEducationAccount: false,
plan: { type: Plan.sandbox },
@ -257,7 +247,7 @@ describe('AccountDropdown', () => {
avatar_url: 'current-avatar.png',
})
renderWithSystemFeatures(<AccountSection />, {
renderWithConsoleQuery(<AccountSection />, {
queryClient,
systemFeatures: { branding: { enabled: false } },
})
@ -353,12 +343,12 @@ describe('AccountDropdown', () => {
it('should show Compliance in Cloud Edition for workspace owner', () => {
// Arrange
mockConfig.IS_CLOUD_EDITION = true
setAppContextValue({
...baseAppContextValue,
userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
setConsoleState({
...baseConsoleState,
userProfile: { ...baseConsoleState.userProfile, name: 'User' },
isCurrentWorkspaceOwner: true,
langGeniusVersionInfo: {
...baseAppContextValue.langGeniusVersionInfo,
...baseConsoleState.langGeniusVersionInfo,
current_version: '0.6.0',
latest_version: '0.6.0',
},
@ -376,8 +366,8 @@ describe('AccountDropdown', () => {
it('should hide Compliance in Cloud Edition when user is not workspace owner', () => {
// Arrange
mockConfig.IS_CLOUD_EDITION = true
setAppContextValue({
...baseAppContextValue,
setConsoleState({
...baseConsoleState,
isCurrentWorkspaceOwner: false,
})
@ -476,11 +466,11 @@ describe('AccountDropdown', () => {
describe('Version Indicators', () => {
it('should show orange indicator when version is not latest', () => {
// Arrange
setAppContextValue({
...baseAppContextValue,
userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
setConsoleState({
...baseConsoleState,
userProfile: { ...baseConsoleState.userProfile, name: 'User' },
langGeniusVersionInfo: {
...baseAppContextValue.langGeniusVersionInfo,
...baseConsoleState.langGeniusVersionInfo,
current_version: '0.6.0',
latest_version: '0.7.0',
},
@ -498,11 +488,11 @@ describe('AccountDropdown', () => {
it('should show green indicator when version is latest', () => {
// Arrange
setAppContextValue({
...baseAppContextValue,
userProfile: { ...baseAppContextValue.userProfile, name: 'User' },
setConsoleState({
...baseConsoleState,
userProfile: { ...baseConsoleState.userProfile, name: 'User' },
langGeniusVersionInfo: {
...baseAppContextValue.langGeniusVersionInfo,
...baseConsoleState.langGeniusVersionInfo,
current_version: '0.7.0',
latest_version: '0.7.0',
},

View File

@ -1,10 +1,11 @@
import type { AccountSettingTab } from '../constants'
import type { AppContextStateMockState } from '@/__tests__/utils/mock-app-context-state'
import type { ConsoleStateFixture } from '@/test/console/state-fixture'
import { fireEvent, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useState } from 'react'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import { baseProviderContextValue, useProviderContext } from '@/context/provider-context'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { renderWithConsoleQuery } from '@/test/console/query-data'
import { ACCOUNT_SETTING_TAB } from '../constants'
import AccountSetting from '../index'
@ -12,7 +13,7 @@ const mockResetModelProviderListExpanded = vi.fn()
const mockConfig = vi.hoisted(() => ({
IS_CLOUD_EDITION: true,
}))
const mockAppContextState = vi.hoisted(() => ({
const mockConsoleState = vi.hoisted(() => ({
current: null as unknown,
}))
@ -34,31 +35,21 @@ vi.mock('@/context/provider-context', async (importOriginal) => {
}
})
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/account-state', async () => {
const { createAccountStateModuleMock } = await import('@/test/console/state-fixture')
return createAccountStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/workspace-state', async () => {
const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
return createWorkspaceStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => mockAppContextState.current ?? {})
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
vi.mock('@/context/version-state', async () => {
const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
return createVersionStateModuleMock(() => mockConsoleState.current ?? {})
})
vi.mock('@/next/navigation', () => ({
@ -88,21 +79,27 @@ vi.mock('next-themes', () => ({
})),
}))
vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({
useDefaultModel: vi.fn(() => ({ data: null, isLoading: false })),
useLanguage: vi.fn(() => 'en-US'),
useUpdateDefaultModel: vi.fn(() => ({ trigger: vi.fn() })),
useUpdateModelList: vi.fn(() => vi.fn()),
useInvalidateDefaultModel: vi.fn(() => vi.fn()),
useModelList: vi.fn(() => ({ data: [], isLoading: false })),
useSystemDefaultModelAndModelList: vi.fn(() => [null, vi.fn()]),
useMarketplaceAllPlugins: vi.fn(() => ({ plugins: [], isLoading: false })),
}))
vi.mock('@/app/components/header/account-setting/model-provider-page/atoms', () => ({
useResetModelProviderListExpanded: () => mockResetModelProviderListExpanded,
}))
vi.mock('@/app/components/header/account-setting/model-provider-page', () => ({
default: ({
onSearchTextChange,
searchText,
}: {
onSearchTextChange?: (value: string) => void
searchText: string
}) => (
<input
type="search"
aria-label="common.operation.search"
value={searchText}
onChange={(event) => onSearchTextChange?.(event.target.value)}
/>
),
}))
vi.mock('@/service/use-datasource', () => ({
useGetDataSourceListAuth: vi.fn(() => ({ data: { result: [] } })),
}))
@ -159,7 +156,7 @@ vi.mock('@/app/components/header/account-setting/access-rules-page', () => ({
default: () => <div data-testid="access-rules-page" />,
}))
const baseAppContextValue: AppContextStateMockState = {
const baseConsoleState: ConsoleStateFixture = {
userProfile: {
id: '1',
name: 'Test User',
@ -168,7 +165,7 @@ const baseAppContextValue: AppContextStateMockState = {
avatar_url: '',
is_password_set: false,
},
mutateUserProfile: vi.fn(),
refreshUserProfile: vi.fn(),
currentWorkspace: {
id: '1',
name: 'Workspace',
@ -185,7 +182,7 @@ const baseAppContextValue: AppContextStateMockState = {
isCurrentWorkspaceOwner: true,
isCurrentWorkspaceEditor: true,
isCurrentWorkspaceDatasetOperator: false,
mutateCurrentWorkspace: vi.fn(),
refreshCurrentWorkspace: vi.fn(),
langGeniusVersionInfo: {
current_env: 'testing',
current_version: '0.1.0',
@ -239,7 +236,7 @@ describe('AccountSetting', () => {
)
}
return renderWithSystemFeatures(<StatefulAccountSetting />, {
return renderWithConsoleQuery(<StatefulAccountSetting />, {
systemFeatures: {
webapp_auth: { enabled: true },
branding: { enabled: false },
@ -258,7 +255,7 @@ describe('AccountSetting', () => {
enableBilling: true,
enableReplaceWebAppLogo: true,
})
mockAppContextState.current = baseAppContextValue
mockConsoleState.current = baseConsoleState
vi.mocked(useBreakpoints).mockReturnValue(MediaType.pc)
})
@ -387,10 +384,10 @@ describe('AccountSetting', () => {
it('should not hide workspace menu items solely for dataset operators', () => {
// Arrange
const datasetOperatorContext = {
...baseAppContextValue,
...baseConsoleState,
isCurrentWorkspaceDatasetOperator: true,
}
mockAppContextState.current = datasetOperatorContext
mockConsoleState.current = datasetOperatorContext
// Act
renderAccountSetting()
@ -414,12 +411,12 @@ describe('AccountSetting', () => {
it('should keep moved integrations hidden when api extension permission is missing', () => {
// Arrange
const contextWithoutApiExtensionPermission = {
...baseAppContextValue,
workspacePermissionKeys: baseAppContextValue.workspacePermissionKeys!.filter(
...baseConsoleState,
workspacePermissionKeys: baseConsoleState.workspacePermissionKeys!.filter(
(key) => key !== 'api_extension.manage',
),
}
mockAppContextState.current = contextWithoutApiExtensionPermission
mockConsoleState.current = contextWithoutApiExtensionPermission
// Act
renderAccountSetting()
@ -433,12 +430,12 @@ describe('AccountSetting', () => {
it('should show custom tab when customization permission is missing', () => {
// Arrange
const contextWithoutCustomizationPermission = {
...baseAppContextValue,
workspacePermissionKeys: baseAppContextValue.workspacePermissionKeys!.filter(
...baseConsoleState,
workspacePermissionKeys: baseConsoleState.workspacePermissionKeys!.filter(
(key) => key !== 'customization.manage',
),
}
mockAppContextState.current = contextWithoutCustomizationPermission
mockConsoleState.current = contextWithoutCustomizationPermission
// Act
renderAccountSetting()
@ -454,12 +451,12 @@ describe('AccountSetting', () => {
it('should hide role and permission set entries when role management permission is missing', () => {
// Arrange
const contextWithoutRoleManagePermission = {
...baseAppContextValue,
workspacePermissionKeys: baseAppContextValue.workspacePermissionKeys!.filter(
...baseConsoleState,
workspacePermissionKeys: baseConsoleState.workspacePermissionKeys!.filter(
(key) => key !== 'workspace.role.manage',
),
}
mockAppContextState.current = contextWithoutRoleManagePermission
mockConsoleState.current = contextWithoutRoleManagePermission
// Act
renderAccountSetting()
@ -518,12 +515,12 @@ describe('AccountSetting', () => {
it('should hide billing entry when billing view permission is missing', () => {
// Arrange
const contextWithoutBillingViewPermission = {
...baseAppContextValue,
workspacePermissionKeys: baseAppContextValue.workspacePermissionKeys!.filter(
...baseConsoleState,
workspacePermissionKeys: baseConsoleState.workspacePermissionKeys!.filter(
(key) => key !== 'billing.view',
),
}
mockAppContextState.current = contextWithoutBillingViewPermission
mockConsoleState.current = contextWithoutBillingViewPermission
// Act
renderAccountSetting()
@ -550,19 +547,19 @@ describe('AccountSetting', () => {
it('should hide workflow log archives from custom RBAC roles that are not owner or admin', () => {
// Arrange
const contextWithRoleManagePermissionButNotManager = {
...baseAppContextValue,
...baseConsoleState,
currentWorkspace: {
...baseAppContextValue.currentWorkspace,
...baseConsoleState.currentWorkspace,
role: 'normal' as const,
},
isCurrentWorkspaceManager: false,
isCurrentWorkspaceOwner: false,
workspacePermissionKeys: [
...(baseAppContextValue.workspacePermissionKeys ?? []),
...(baseConsoleState.workspacePermissionKeys ?? []),
'workspace.role.manage',
],
}
mockAppContextState.current = contextWithRoleManagePermissionButNotManager
mockConsoleState.current = contextWithRoleManagePermissionButNotManager
// Act
renderAccountSetting()
@ -588,12 +585,12 @@ describe('AccountSetting', () => {
it('should not render billing page when active billing tab lacks billing view permission', () => {
// Arrange
const contextWithoutBillingViewPermission = {
...baseAppContextValue,
workspacePermissionKeys: baseAppContextValue.workspacePermissionKeys!.filter(
...baseConsoleState,
workspacePermissionKeys: baseConsoleState.workspacePermissionKeys!.filter(
(key) => key !== 'billing.view',
),
}
mockAppContextState.current = contextWithoutBillingViewPermission
mockConsoleState.current = contextWithoutBillingViewPermission
// Act
renderAccountSetting({ initialTab: ACCOUNT_SETTING_TAB.BILLING })
@ -688,18 +685,17 @@ describe('AccountSetting', () => {
expect(mockOnCancel).toHaveBeenCalled()
})
it('should update search value in provider tab', () => {
it('should keep provider search controlled at the account setting boundary', async () => {
// Arrange
const user = userEvent.setup()
renderAccountSetting({ initialTab: ACCOUNT_SETTING_TAB.PROVIDER })
// Act
const input = screen.getByRole('searchbox', { name: 'common.operation.search' })
fireEvent.change(input, { target: { value: 'test-search' } })
await user.type(input, 'test-search')
// Assert
// Assert
expect(input)!.toHaveValue('test-search')
expect(screen.getByPlaceholderText('common.modelProvider.searchModels'))!.toBeInTheDocument()
})
it('should handle scroll event in panel', () => {

View File

@ -1,50 +1,21 @@
import type { ReactNode } from 'react'
import type { AccessPolicyWithBindings } from '@/models/access-control'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { render } from '@/test/console/render'
import AccessRuleSection from '../access-rule-section'
const mocks = vi.hoisted(() => ({
workspacePermissionKeys: [] as string[],
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mocks.workspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mocks.workspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mocks.workspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mocks.workspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mocks.workspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
const rule: AccessPolicyWithBindings = {
policy: {

View File

@ -1,5 +1,6 @@
import type { ApiBasedExtensionResponse } from '@dify/contracts/api/console/api-based-extension/types.gen'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { render } from '@/test/console/render'
import { ApiBasedExtensionPage } from '../index'
const {
@ -18,42 +19,12 @@ const {
},
}))
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mockWorkspacePermissionKeys.current,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys.current,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys.current,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys.current,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys.current,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/service/client', () => ({
consoleQuery: {

View File

@ -1,5 +1,5 @@
import type { DataSourceAuth } from '../types'
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
import { FormTypeEnum } from '@/app/components/base/form/types'
import { usePluginAuthAction } from '@/app/components/plugins/plugin-auth'
import { CredentialTypeEnum } from '@/app/components/plugins/plugin-auth/types'
@ -13,6 +13,7 @@ import {
useInvalidDefaultDataSourceListAuth,
} from '@/service/use-datasource'
import { useInvalidDataSourceList } from '@/service/use-pipeline'
import { render } from '@/test/console/render'
import Card from '../card'
import { useDataSourceAuthUpdate } from '../hooks'
@ -22,42 +23,12 @@ let mockWorkspacePermissionKeys: string[] = [
'credential.manage',
]
vi.mock('@/context/account-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
vi.mock('@/context/permission-state', async () => {
const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
return createPermissionStateModuleMock(() => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/workspace-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/permission-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/version-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('@/context/system-features-state', async (importOriginal) => {
const { createAppContextStateAtomMock } = await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateAtomMock(importOriginal, () => ({
workspacePermissionKeys: mockWorkspacePermissionKeys,
}))
})
vi.mock('jotai', async (importOriginal) => {
const { createAppContextStateJotaiMock } =
await import('@/__tests__/utils/mock-app-context-state')
return createAppContextStateJotaiMock(importOriginal)
})
vi.mock('@/app/components/plugins/plugin-auth', () => ({
ApiKeyModal: vi.fn(

Some files were not shown because too many files have changed in this diff Show More