refactor(web): migrate to Vitest and esm (#29974)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
Stephen Zhou
2025-12-22 16:35:22 +08:00
committed by GitHub
parent 42f7ecda12
commit eabdc5f0eb
268 changed files with 5455 additions and 6307 deletions

View File

@ -1,71 +0,0 @@
/**
* Mock for ky HTTP client
* This mock is used to avoid ESM issues in Jest tests
*/
type KyResponse = {
ok: boolean
status: number
statusText: string
headers: Headers
json: jest.Mock
text: jest.Mock
blob: jest.Mock
arrayBuffer: jest.Mock
clone: jest.Mock
}
type KyInstance = jest.Mock & {
get: jest.Mock
post: jest.Mock
put: jest.Mock
patch: jest.Mock
delete: jest.Mock
head: jest.Mock
create: jest.Mock
extend: jest.Mock
stop: symbol
}
const createResponse = (data: unknown = {}, status = 200): KyResponse => {
const response: KyResponse = {
ok: status >= 200 && status < 300,
status,
statusText: status === 200 ? 'OK' : 'Error',
headers: new Headers(),
json: jest.fn().mockResolvedValue(data),
text: jest.fn().mockResolvedValue(JSON.stringify(data)),
blob: jest.fn().mockResolvedValue(new Blob()),
arrayBuffer: jest.fn().mockResolvedValue(new ArrayBuffer(0)),
clone: jest.fn(),
}
// Ensure clone returns a new response-like object, not the same instance
response.clone.mockImplementation(() => createResponse(data, status))
return response
}
const createKyInstance = (): KyInstance => {
const instance = jest.fn().mockImplementation(() => Promise.resolve(createResponse())) as KyInstance
// HTTP methods
instance.get = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
instance.post = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
instance.put = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
instance.patch = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
instance.delete = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
instance.head = jest.fn().mockImplementation(() => Promise.resolve(createResponse()))
// Create new instance with custom options
instance.create = jest.fn().mockImplementation(() => createKyInstance())
instance.extend = jest.fn().mockImplementation(() => createKyInstance())
// Stop method for AbortController
instance.stop = Symbol('stop')
return instance
}
const ky = createKyInstance()
export default ky
export { ky }

View File

View File

@ -1,9 +1,41 @@
import { merge, noop } from 'lodash-es'
import { defaultPlan } from '@/app/components/billing/config'
import { baseProviderContextValue } from '@/context/provider-context'
import type { ProviderContextState } from '@/context/provider-context'
import type { Plan, UsagePlanInfo } from '@/app/components/billing/type'
// Avoid being mocked in tests
export const baseProviderContextValue: ProviderContextState = {
modelProviders: [],
refreshModelProviders: noop,
textGenerationModelList: [],
supportRetrievalMethods: [],
isAPIKeySet: true,
plan: defaultPlan,
isFetchedPlan: false,
enableBilling: false,
onPlanInfoChanged: noop,
enableReplaceWebAppLogo: false,
modelLoadBalancingEnabled: false,
datasetOperatorEnabled: false,
enableEducationPlan: false,
isEducationWorkspace: false,
isEducationAccount: false,
allowRefreshEducationVerify: false,
educationAccountExpireAt: null,
isLoadingEducationAccountInfo: false,
isFetchingEducationAccountInfo: false,
webappCopyrightEnabled: false,
licenseLimit: {
workspace_members: {
size: 0,
limit: 0,
},
},
refreshLicenseLimit: noop,
isAllowTransferWorkspace: false,
isAllowPublishAsCustomKnowledgePipelineTemplate: false,
}
export const createMockProviderContextValue = (overrides: Partial<ProviderContextState> = {}): ProviderContextState => {
const merged = merge({}, baseProviderContextValue, overrides)

View File

@ -1,40 +0,0 @@
/**
* Shared mock for react-i18next
*
* Jest automatically uses this mock when react-i18next is imported in tests.
* The default behavior returns the translation key as-is, which is suitable
* for most test scenarios.
*
* For tests that need custom translations, you can override with jest.mock():
*
* @example
* jest.mock('react-i18next', () => ({
* useTranslation: () => ({
* t: (key: string) => {
* if (key === 'some.key') return 'Custom translation'
* return key
* },
* }),
* }))
*/
export const useTranslation = () => ({
t: (key: string, options?: Record<string, unknown>) => {
if (options?.returnObjects)
return [`${key}-feature-1`, `${key}-feature-2`]
if (options)
return `${key}:${JSON.stringify(options)}`
return key
},
i18n: {
language: 'en',
changeLanguage: jest.fn(),
},
})
export const Trans = ({ children }: { children?: React.ReactNode }) => children
export const initReactI18next = {
type: '3rdParty',
init: jest.fn(),
}