Skip to content

test: unify i18next mocks into centralized helpers#38

Open
tomerqodo wants to merge 6 commits intogreptile_combined_100_qodo_grep_sentry_1_base_test_unify_i18next_mocks_into_centralized_helpers_pr129from
greptile_combined_100_qodo_grep_sentry_1_head_test_unify_i18next_mocks_into_centralized_helpers_pr129
Open

test: unify i18next mocks into centralized helpers#38
tomerqodo wants to merge 6 commits intogreptile_combined_100_qodo_grep_sentry_1_base_test_unify_i18next_mocks_into_centralized_helpers_pr129from
greptile_combined_100_qodo_grep_sentry_1_head_test_unify_i18next_mocks_into_centralized_helpers_pr129

Conversation

@tomerqodo
Copy link

Benchmark PR from qodo-benchmark#129

hyoban and others added 6 commits December 30, 2025 16:26
Consolidate scattered i18next mock implementations across test files into
a single source of truth. This reduces duplication and ensures consistent
mock behavior.

- Create test/i18n-mock.ts with reusable factory functions
- Update vitest.setup.ts to use the centralized helpers
- Remove redundant mock definitions from 8 test files
- Update testing.md documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…eateReactI18nextMock` and detail global mock provisions.
@greptile-apps
Copy link

greptile-apps bot commented Jan 10, 2026

Greptile Overview

Greptile Summary

Overview

This PR centralizes i18next mocks into reusable helper functions in web/test/i18n-mock.ts and updates 17 test files to use the new centralized mocks instead of local implementations.

What Changed:

  • ✅ Created web/test/i18n-mock.ts with helper functions: createReactI18nextMock, createUseTranslationMock, createTransMock, createMixedTranslationMock, and createUseGetLanguageMock
  • ✅ Updated web/vitest.setup.ts to use the centralized mock for the global react-i18next mock
  • ✅ Updated 17 test files to remove local i18n mocks and rely on either the global mock or createReactI18nextMock for custom translations
  • ✅ Updated documentation (testing.md, mocking.md) and test template with usage examples

Architecture:
The centralized mock provides a flexible system where tests can either:

  1. Use the global mock (auto-loaded) for standard behavior
  2. Override with custom translations using createReactI18nextMock({ key: 'value' })

Critical Issues Found

🔴 Issue 1: Missing Global Mocks (Test Failures)

Impact: Tests will fail for components using useMixedTranslation and useGetLanguage

The documentation claims the global mock provides useMixedTranslation and useGetLanguage, but vitest.setup.ts only mocks react-i18next. Two test files removed their local mocks based on this incorrect documentation:

  • web/app/components/plugins/card/index.spec.tsx
  • web/app/components/plugins/plugin-mutation-model/index.spec.tsx

Both components use these hooks, so tests will crash when trying to import the actual implementations.

Required Fix: Add global mocks for @/app/components/plugins/marketplace/hooks and @/context/i18n in vitest.setup.ts

🟡 Issue 2: Missing returnObjects Support

Impact: Future tests will break if they use returnObjects option

The old global mock handled options?.returnObjects by returning a mock array. The new centralized mock deletes this property but doesn't handle it. While no tests in this PR use it, 5 existing tests in the codebase do (explore/create-app-modal, billing/pricing, etc.). If those tests are later updated to use the centralized mock, they'll break.

Recommended Fix: Add returnObjects handling to createTFunction in i18n-mock.ts

Positive Aspects

  • Excellent code organization: Centralized helpers eliminate duplication across test files
  • Good documentation: Clear examples showing how to use the helpers
  • Consistent API: All helper functions follow similar naming and usage patterns
  • Type safety: Uses TypeScript types throughout
  • Flexible design: Supports custom translations while providing sensible defaults

Recommendations

  1. Fix critical issues first: Add missing global mocks to prevent test failures
  2. Add returnObjects support: Ensure full compatibility with existing behavior
  3. Run tests: Verify all affected test files pass after fixes
  4. Update documentation: Align docs with actual implementation once mocks are added

Confidence Score: 1/5

  • This PR has critical issues that will cause test failures in production
  • Score of 1/5 reflects serious implementation gaps: (1) Missing global mocks for useMixedTranslation and useGetLanguage will cause runtime failures in at least 2 test files that removed their local mocks, and (2) Documentation incorrectly claims these mocks exist globally, creating a mismatch between docs and implementation. While the concept and code organization are excellent, the execution has critical bugs that must be fixed before merging.
  • Critical: web/vitest.setup.ts (add missing global mocks), web/app/components/plugins/card/index.spec.tsx (will fail without fixes), web/app/components/plugins/plugin-mutation-model/index.spec.tsx (will fail without fixes). Important: web/test/i18n-mock.ts (add returnObjects support)

Important Files Changed

File Analysis

Filename Score Overview
web/test/i18n-mock.ts 3/5 New centralized i18n mock helpers - missing returnObjects support and not fully integrated with global setup
web/vitest.setup.ts 2/5 Updated to use centralized mock but missing mocks for useMixedTranslation and useGetLanguage that documentation claims exist
web/testing/testing.md 3/5 Documentation updated with correct examples but incorrectly claims global mock provides useMixedTranslation and useGetLanguage
.claude/skills/frontend-testing/references/mocking.md 3/5 Documentation updated with correct examples but incorrectly claims global mock provides useMixedTranslation and useGetLanguage
web/app/components/plugins/card/index.spec.tsx 1/5 Removed local mocks for useMixedTranslation and useGetLanguage - tests will fail as these are not mocked globally
web/app/components/plugins/plugin-mutation-model/index.spec.tsx 1/5 Removed local mocks for useMixedTranslation and useGetLanguage - tests will fail as these are not mocked globally

Sequence Diagram

sequenceDiagram
    participant Test as Test File
    participant Vitest as vitest.setup.ts
    participant Mock as test/i18n-mock.ts
    participant Component as Component Under Test
    
    Note over Test,Component: Test Initialization
    Test->>Vitest: Load global setup
    Vitest->>Mock: Import createReactI18nextMock()
    Mock-->>Vitest: Return { useTranslation, Trans }
    Vitest->>Vitest: vi.mock('react-i18next')
    Note over Vitest: ❌ Missing: useMixedTranslation, useGetLanguage
    
    Note over Test,Component: Test with Custom Translations
    Test->>Mock: Import createReactI18nextMock({ key: 'Custom' })
    Test->>Test: vi.mock('react-i18next', () => ...)
    Test->>Component: render(<Component />)
    Component->>Mock: useTranslation()
    Mock-->>Component: { t: (key) => translations[key] || key }
    Component->>Mock: useMixedTranslation() ❌
    Note over Component,Mock: ERROR: Not mocked!
    Component->>Mock: useGetLanguage() ❌
    Note over Component,Mock: ERROR: Not mocked!
    
    Note over Test,Component: Expected Flow (After Fix)
    Vitest->>Mock: Import createMixedTranslationMock()
    Vitest->>Mock: Import createUseGetLanguageMock()
    Vitest->>Vitest: vi.mock('@/app/components/plugins/marketplace/hooks')
    Vitest->>Vitest: vi.mock('@/context/i18n')
    Test->>Component: render(<Component />)
    Component->>Mock: useMixedTranslation()
    Mock-->>Component: ✅ { t: mockFunction }
    Component->>Mock: useGetLanguage()
    Mock-->>Component: ✅ 'en-US'
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

6 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +10 to +35
export function createTFunction(translations: TranslationMap, defaultNs?: string) {
return (key: string, options?: Record<string, unknown>) => {
// Check if translations[key] is not undefined
if (translations[key] !== undefined)
return translations[key]

// Get namespace from options or use defaultNs
const ns = (options?.ns as string | undefined) ?? defaultNs
// Create fullKey by concatenating namespace and key with a dot
const fullKey = ns ? `${ns}.${key}` : key

// Check if translations[fullKey] is not undefined
if (translations[fullKey] !== undefined)
return translations[fullKey]

// Create a copy of options object
const params = { ...options }
// Delete the ns property from params
delete params.ns
// Delete the returnObjects property from params
delete params.returnObjects
// Create suffix by stringifying params if there are any keys
const suffix = Object.keys(params).length > 0 ? `:${JSON.stringify(params)}` : ''
// Return the fullKey concatenated with suffix
return `${fullKey}${suffix}`
}
Copy link

Choose a reason for hiding this comment

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

The createTFunction deletes the returnObjects property but doesn't handle it. The old global mock in vitest.setup.ts had this logic:

if (options?.returnObjects)
  return [`${key}-feature-1`, `${key}-feature-2`]

This functionality is now missing from the centralized mock. While no tests in this PR use returnObjects, other existing tests in the codebase do (e.g., explore/create-app-modal/index.spec.tsx, billing/pricing/index.spec.tsx). Those tests still have local mocks, but if they're updated later to use the centralized mock, they will break.

Suggested fix:

Suggested change
export function createTFunction(translations: TranslationMap, defaultNs?: string) {
return (key: string, options?: Record<string, unknown>) => {
// Check if translations[key] is not undefined
if (translations[key] !== undefined)
return translations[key]
// Get namespace from options or use defaultNs
const ns = (options?.ns as string | undefined) ?? defaultNs
// Create fullKey by concatenating namespace and key with a dot
const fullKey = ns ? `${ns}.${key}` : key
// Check if translations[fullKey] is not undefined
if (translations[fullKey] !== undefined)
return translations[fullKey]
// Create a copy of options object
const params = { ...options }
// Delete the ns property from params
delete params.ns
// Delete the returnObjects property from params
delete params.returnObjects
// Create suffix by stringifying params if there are any keys
const suffix = Object.keys(params).length > 0 ? `:${JSON.stringify(params)}` : ''
// Return the fullKey concatenated with suffix
return `${fullKey}${suffix}`
}
export function createTFunction(translations: TranslationMap, defaultNs?: string) {
return (key: string, options?: Record<string, unknown>) => {
// Handle returnObjects option
if (options?.returnObjects)
return [`${key}-feature-1`, `${key}-feature-2`]
// Check if translations[key] is not undefined
if (translations[key] !== undefined)
return translations[key]
// Get namespace from options or use defaultNs
const ns = (options?.ns as string | undefined) ?? defaultNs
// Create fullKey by concatenating namespace and key with a dot
const fullKey = ns ? `${ns}.${key}` : key
// Check if translations[fullKey] is not undefined
if (translations[fullKey] !== undefined)
return translations[fullKey]
// Create a copy of options object
const params = { ...options }
// Delete the ns property from params
delete params.ns
// Delete the returnObjects property from params
delete params.returnObjects
// Create suffix by stringifying params if there are any keys
const suffix = Object.keys(params).length > 0 ? `:${JSON.stringify(params)}` : ''
// Return the fullKey concatenated with suffix
return `${fullKey}${suffix}`
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/test/i18n-mock.ts
Line: 10:35

Comment:
The `createTFunction` deletes the `returnObjects` property but doesn't handle it. The old global mock in `vitest.setup.ts` had this logic:

```typescript
if (options?.returnObjects)
  return [`${key}-feature-1`, `${key}-feature-2`]
```

This functionality is now missing from the centralized mock. While no tests in this PR use `returnObjects`, other existing tests in the codebase do (e.g., `explore/create-app-modal/index.spec.tsx`, `billing/pricing/index.spec.tsx`). Those tests still have local mocks, but if they're updated later to use the centralized mock, they will break.

**Suggested fix:**
```suggestion
export function createTFunction(translations: TranslationMap, defaultNs?: string) {
  return (key: string, options?: Record<string, unknown>) => {
    // Handle returnObjects option
    if (options?.returnObjects)
      return [`${key}-feature-1`, `${key}-feature-2`]
    
    // Check if translations[key] is not undefined
    if (translations[key] !== undefined)
      return translations[key]

    // Get namespace from options or use defaultNs
    const ns = (options?.ns as string | undefined) ?? defaultNs
    // Create fullKey by concatenating namespace and key with a dot
    const fullKey = ns ? `${ns}.${key}` : key

    // Check if translations[fullKey] is not undefined
    if (translations[fullKey] !== undefined)
      return translations[fullKey]

    // Create a copy of options object
    const params = { ...options }
    // Delete the ns property from params
    delete params.ns
    // Delete the returnObjects property from params
    delete params.returnObjects
    // Create suffix by stringifying params if there are any keys
    const suffix = Object.keys(params).length > 0 ? `:${JSON.stringify(params)}` : ''
    // Return the fullKey concatenated with suffix
    return `${fullKey}${suffix}`
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 88 to 96
// mock react-i18next
vi.mock('react-i18next', async () => {
const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
const { createReactI18nextMock } = await import('./test/i18n-mock')
return {
...actual,
useTranslation: (defaultNs?: string) => ({
t: (key: string, options?: Record<string, unknown>) => {
if (options?.returnObjects)
return [`${key}-feature-1`, `${key}-feature-2`]
const ns = options?.ns ?? defaultNs
if (options || ns) {
const { ns: _ns, ...rest } = options ?? {}
const prefix = ns ? `${ns}.` : ''
const suffix = Object.keys(rest).length > 0 ? `:${JSON.stringify(rest)}` : ''
return `${prefix}${key}${suffix}`
}
return key
},
i18n: {
language: 'en',
changeLanguage: vi.fn(),
},
}),
...createReactI18nextMock(),
}
})
Copy link

Choose a reason for hiding this comment

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

Critical issue: The global mock only provides useTranslation and Trans from createReactI18nextMock(), but the documentation in testing.md and mocking.md claims it also provides:

  • useMixedTranslation (from @/app/components/plugins/marketplace/hooks)
  • useGetLanguage (from @/context/i18n)

These are NOT mocked here, which causes test failures for components that use them (e.g., plugins/card/index.spec.tsx and plugins/plugin-mutation-model/index.spec.tsx removed their local mocks for these hooks in this PR).

Required fix: Add the missing global mocks after the react-i18next mock:

Suggested change
// mock react-i18next
vi.mock('react-i18next', async () => {
const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
const { createReactI18nextMock } = await import('./test/i18n-mock')
return {
...actual,
useTranslation: (defaultNs?: string) => ({
t: (key: string, options?: Record<string, unknown>) => {
if (options?.returnObjects)
return [`${key}-feature-1`, `${key}-feature-2`]
const ns = options?.ns ?? defaultNs
if (options || ns) {
const { ns: _ns, ...rest } = options ?? {}
const prefix = ns ? `${ns}.` : ''
const suffix = Object.keys(rest).length > 0 ? `:${JSON.stringify(rest)}` : ''
return `${prefix}${key}${suffix}`
}
return key
},
i18n: {
language: 'en',
changeLanguage: vi.fn(),
},
}),
...createReactI18nextMock(),
}
})
// mock react-i18next
vi.mock('react-i18next', async () => {
const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
const { createReactI18nextMock } = await import('./test/i18n-mock')
return {
...actual,
...createReactI18nextMock(),
}
})
// mock useMixedTranslation hook
vi.mock('@/app/components/plugins/marketplace/hooks', async () => {
const actual = await vi.importActual<typeof import('@/app/components/plugins/marketplace/hooks')>('@/app/components/plugins/marketplace/hooks')
const { createMixedTranslationMock } = await import('./test/i18n-mock')
return {
...actual,
...createMixedTranslationMock(),
}
})
// mock useGetLanguage hook
vi.mock('@/context/i18n', async () => {
const actual = await vi.importActual<typeof import('@/context/i18n')>('@/context/i18n')
const { createUseGetLanguageMock } = await import('./test/i18n-mock')
return {
...actual,
...createUseGetLanguageMock(),
}
})
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/vitest.setup.ts
Line: 88:96

Comment:
**Critical issue:** The global mock only provides `useTranslation` and `Trans` from `createReactI18nextMock()`, but the documentation in `testing.md` and `mocking.md` claims it also provides:
- `useMixedTranslation` (from `@/app/components/plugins/marketplace/hooks`)
- `useGetLanguage` (from `@/context/i18n`)

These are NOT mocked here, which causes test failures for components that use them (e.g., `plugins/card/index.spec.tsx` and `plugins/plugin-mutation-model/index.spec.tsx` removed their local mocks for these hooks in this PR).

**Required fix:** Add the missing global mocks after the `react-i18next` mock:

```suggestion
// mock react-i18next
vi.mock('react-i18next', async () => {
  const actual = await vi.importActual<typeof import('react-i18next')>('react-i18next')
  const { createReactI18nextMock } = await import('./test/i18n-mock')
  return {
    ...actual,
    ...createReactI18nextMock(),
  }
})

// mock useMixedTranslation hook
vi.mock('@/app/components/plugins/marketplace/hooks', async () => {
  const actual = await vi.importActual<typeof import('@/app/components/plugins/marketplace/hooks')>('@/app/components/plugins/marketplace/hooks')
  const { createMixedTranslationMock } = await import('./test/i18n-mock')
  return {
    ...actual,
    ...createMixedTranslationMock(),
  }
})

// mock useGetLanguage hook
vi.mock('@/context/i18n', async () => {
  const actual = await vi.importActual<typeof import('@/context/i18n')>('@/context/i18n')
  const { createUseGetLanguageMock } = await import('./test/i18n-mock')
  return {
    ...actual,
    ...createUseGetLanguageMock(),
  }
})
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 9 to 11
// Mock External Dependencies Only
// ================================

Copy link

Choose a reason for hiding this comment

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

Test will fail: Same issue as plugins/card/index.spec.tsx - the PluginMutationModal component uses useMixedTranslation and useGetLanguage, but the local mocks were removed and these hooks are not mocked in the global setup.

Fix: Either restore the local mocks OR add them to the global setup in vitest.setup.ts (see comment on that file).

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/app/components/plugins/plugin-mutation-model/index.spec.tsx
Line: 9:11

Comment:
**Test will fail:** Same issue as `plugins/card/index.spec.tsx` - the PluginMutationModal component uses `useMixedTranslation` and `useGetLanguage`, but the local mocks were removed and these hooks are not mocked in the global setup.

**Fix:** Either restore the local mocks OR add them to the global setup in `vitest.setup.ts` (see comment on that file).

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 330 to +338
1. **i18n**: Uses global mock in `web/vitest.setup.ts` (auto-loaded by Vitest setup)

The global mock returns translation keys as-is. For custom translations, override:
The global mock provides:

- `useTranslation` - returns translation keys with namespace prefix
- `Trans` component - renders i18nKey and components
- `useMixedTranslation` (from `@/app/components/plugins/marketplace/hooks`)
- `useGetLanguage` (from `@/context/i18n`) - returns `'en-US'`

Copy link

Choose a reason for hiding this comment

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

Documentation inaccuracy: This section claims the global mock provides useMixedTranslation and useGetLanguage, but these are NOT actually mocked in web/vitest.setup.ts. The global setup only mocks react-i18next (which provides useTranslation and Trans).

This misleading documentation caused test files like plugins/card/index.spec.tsx and plugins/plugin-mutation-model/index.spec.tsx to remove their local mocks for these hooks, which will cause test failures.

Fix: Either update the documentation to reflect what's actually mocked, OR add the missing mocks to vitest.setup.ts.

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/testing/testing.md
Line: 330:338

Comment:
**Documentation inaccuracy:** This section claims the global mock provides `useMixedTranslation` and `useGetLanguage`, but these are NOT actually mocked in `web/vitest.setup.ts`. The global setup only mocks `react-i18next` (which provides `useTranslation` and `Trans`).

This misleading documentation caused test files like `plugins/card/index.spec.tsx` and `plugins/plugin-mutation-model/index.spec.tsx` to remove their local mocks for these hooks, which will cause test failures.

**Fix:** Either update the documentation to reflect what's actually mocked, OR add the missing mocks to `vitest.setup.ts`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 52 to +62
### 1. i18n (Auto-loaded via Global Mock)

A global mock is defined in `web/vitest.setup.ts` and is auto-loaded by Vitest setup.
**No explicit mock needed** for most tests - it returns translation keys as-is.

For tests requiring custom translations, override the mock:
The global mock provides:

- `useTranslation` - returns translation keys with namespace prefix
- `Trans` component - renders i18nKey and components
- `useMixedTranslation` (from `@/app/components/plugins/marketplace/hooks`)
- `useGetLanguage` (from `@/context/i18n`) - returns `'en-US'`

Copy link

Choose a reason for hiding this comment

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

Documentation inaccuracy: Same issue as testing.md - this documentation claims the global mock provides useMixedTranslation and useGetLanguage, but these are NOT actually mocked in web/vitest.setup.ts.

Fix: Either update the documentation to reflect what's actually mocked, OR add the missing mocks to vitest.setup.ts.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/skills/frontend-testing/references/mocking.md
Line: 52:62

Comment:
**Documentation inaccuracy:** Same issue as `testing.md` - this documentation claims the global mock provides `useMixedTranslation` and `useGetLanguage`, but these are NOT actually mocked in `web/vitest.setup.ts`.

**Fix:** Either update the documentation to reflect what's actually mocked, OR add the missing mocks to `vitest.setup.ts`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 21 to 23
// Mock External Dependencies Only
// ================================

Copy link

Choose a reason for hiding this comment

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

Test will fail: The Card component uses useMixedTranslation and useGetLanguage (imported in the actual component), but this test file removed the local mocks for these hooks. The global mock in vitest.setup.ts does NOT provide mocks for these hooks, so tests will fail when trying to render the Card component.

Fix: Either restore the local mocks that were removed in this PR OR add global mocks for these hooks in vitest.setup.ts (see comment on that file).

Prompt To Fix With AI
This is a comment left during a code review.
Path: web/app/components/plugins/card/index.spec.tsx
Line: 21:23

Comment:
**Test will fail:** The Card component uses `useMixedTranslation` and `useGetLanguage` (imported in the actual component), but this test file removed the local mocks for these hooks. The global mock in `vitest.setup.ts` does NOT provide mocks for these hooks, so tests will fail when trying to render the Card component.

**Fix:** Either restore the local mocks that were removed in this PR OR add global mocks for these hooks in `vitest.setup.ts` (see comment on that file).

How can I resolve this? If you propose a fix, please make it concise.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants