Skip to content

chore(tests): fix SonarCloud test-assertion smells in integration tests#569

Closed
alichherawalla wants to merge 1 commit into
mainfrom
chore/sonar-tests-integration
Closed

chore(tests): fix SonarCloud test-assertion smells in integration tests#569
alichherawalla wants to merge 1 commit into
mainfrom
chore/sonar-tests-integration

Conversation

@alichherawalla

@alichherawalla alichherawalla commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Fixes SonarCloud code smells confined to test files under `tests/integration/`. Pure test-quality nits — no production code touched, no asserted value changed. Every test still asserts exactly the same thing.

What changed

S5906 (78 issues) — dedicated matchers over generic `.toBe()`
Applied Sonar's exact suggested replacement per line across 36 integration test files:

  • `expect(x.length).toBe(N)` -> `expect(x).toHaveLength(N)`
  • `expect(x).toBe(null)` -> `expect(x).toBeNull()`
  • `expect(x.length > 4).toBe(false)` -> `expect(x.length).toBeLessThanOrEqual(4)`
  • `expect(x.length > 4).toBe(true)` -> `expect(x.length).toBeGreaterThan(4)`

S5976 (1 issue) — parameterize duplicated tests
The 3 near-identical ``-tag stripping tests in `imageGenerationFlow.test.ts` collapsed into one `it.each` table. Each case keeps its descriptive name and coverage is identical.

Verification

  • All 36 changed test files pass (`npx jest` — 287 tests green).
  • `npx tsc --noEmit` clean.
  • Diff is +107/-127 (234 lines), all in test files.

Summary by CodeRabbit

  • Tests
    • Standardized integration-test assertions for collection sizes and null values using clearer Jest matchers.
    • Improved coverage for voice-mode image generation, resend behavior, download flows, prompt enhancement, queuing, routing, onboarding, and retrieval workflows.
    • Consolidated prompt-cleanup scenarios into parameterized coverage while preserving existing behavior checks.

S5906: replace generic assertions with dedicated matchers per Sonar's
exact suggestions (toHaveLength / toBeNull / toBeGreaterThan /
toBeLessThanOrEqual) across 36 integration test files. Every asserted
value is unchanged — tests assert exactly the same things.

S5976: parameterize the 3 near-identical <think>-tag stripping tests in
imageGenerationFlow.test.ts into a single it.each table (coverage identical).

Pure test-quality nits; no production code touched.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This test-only change standardizes array and null assertions across integration suites. It replaces direct .length and toBe(null) checks with Jest’s toHaveLength and toBeNull matchers, and consolidates prompt think-tag coverage into a parameterized test.

Changes

Integration assertion modernization

Layer / File(s) Summary
Audio and download assertions
__tests__/integration/audio/*, __tests__/integration/downloads/*, __tests__/integration/chat/voiceNoteChatModeEmptyTurn.redflow.test.ts
Array-count checks now use toHaveLength for image generation, rendered content, voice-note dispatches, and download state.
Generation flow and resend coverage
__tests__/integration/generation/*
Generation, queue, resend, streaming-state, and prompt-context assertions use Jest matchers; think-tag cases are consolidated into an it.each(...) matrix.
Happy-path image, speech, and tool assertions
__tests__/integration/happy/*, __tests__/integration/image/*
Image-generation, speech-dispatch, and tool-result count assertions use toHaveLength.
State, onboarding, and RAG assertions
__tests__/integration/models/*, __tests__/integration/onboarding/*, __tests__/integration/rag/*, __tests__/integration/stores/*
Null checks use toBeNull, and collection counts use toHaveLength without changing tested flows.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • off-grid-ai/OGAM#558: Introduced or touched related resend-image turn fallback tests updated here.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the changes: SonarCloud-focused test assertion cleanup in integration tests.
Description check ✅ Passed The description is detailed and covers summary, changes, and verification, but it omits several template sections like Type of Change and Checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/sonar-tests-integration

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@__tests__/integration/generation/imageGenerationFlow.test.ts`:
- Around line 1183-1218: Delete the parameterized mockist test block around the
thinking-model prompt cases, including its mocked generateResponse setup and
toHaveBeenCalled assertion. Do not replace or repair it; follow the project
guideline that tests under __tests__ should use rendered integration behavior
and user-visible assertions instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1b31c052-aa34-49d3-857d-cf844bd0a9fc

📥 Commits

Reviewing files that changed from the base of the PR and between 856bca1 and 5e5dd1f.

📒 Files selected for processing (36)
  • __tests__/integration/audio/voiceModeImageJourney.rendered.happy.test.tsx
  • __tests__/integration/audio/voiceModeResendEnhancedImage.rendered.redflow.test.tsx
  • __tests__/integration/audio/voiceModeResendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/chat/voiceNoteChatModeEmptyTurn.redflow.test.ts
  • __tests__/integration/downloads/downloadedCountBadge.rendered.happy.test.tsx
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.redflow.test.ts
  • __tests__/integration/downloads/iosImageStagingPurgedRedownloads.rendered.redflow.test.tsx
  • __tests__/integration/downloads/iosInterruptedNoFailedEntry.redflow.test.ts
  • __tests__/integration/downloads/iosTextRetryReissues.rendered.redflow.test.tsx
  • __tests__/integration/downloads/queuedDownloadsSurviveKill.redflow.test.ts
  • __tests__/integration/downloads/textRetryReissuesOnIosLostDownloadId.rendered.redflow.test.tsx
  • __tests__/integration/generation/enhancementNoThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/enhancementStreamingProgress.rendered.redflow.test.tsx
  • __tests__/integration/generation/generationFlow.test.ts
  • __tests__/integration/generation/imageGenerationFlow.test.ts
  • __tests__/integration/generation/queuedForceImagePreservesMode.rendered.redflow.test.tsx
  • __tests__/integration/generation/queuedSendFeedback.test.ts
  • __tests__/integration/generation/reloadRaceKeepsThinking.rendered.redflow.test.tsx
  • __tests__/integration/generation/remoteParallelTools.rendered.happy.test.tsx
  • __tests__/integration/generation/resendImageRoutes.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageRoutesLlama.rendered.redflow.test.tsx
  • __tests__/integration/generation/resendImageTurnFallsBackToText.rendered.redflow.test.tsx
  • __tests__/integration/happy/imageBackends.happy.test.tsx
  • __tests__/integration/happy/imageIntentRouting.happy.test.tsx
  • __tests__/integration/happy/imageLightbox.happy.test.tsx
  • __tests__/integration/happy/imageModeToggle.happy.test.tsx
  • __tests__/integration/happy/imageOomCard.happy.test.tsx
  • __tests__/integration/happy/smartBudgeting.happy.test.tsx
  • __tests__/integration/happy/speakMessage.happy.test.tsx
  • __tests__/integration/happy/tools.happy.test.tsx
  • __tests__/integration/image/imageTunablesReadFreshFromStore.redflow.test.ts
  • __tests__/integration/models/activeModelService.test.ts
  • __tests__/integration/onboarding/spotlightFlowIntegration.test.ts
  • __tests__/integration/rag/embeddingFlow.test.ts
  • __tests__/integration/rag/ragFlow.test.ts
  • __tests__/integration/stores/chatStoreIntegration.test.ts

Comment on lines +1183 to +1218
it.each([
{
name: 'should strip <think> tags from thinking model responses',
// Simulate a thinking model that wraps reasoning in <think> tags
inputPrompt: 'sunset over mountains',
enhancedResponse:
'<think>Let me enhance this prompt by adding artistic details...</think>A majestic sunset over mountains, golden hour lighting, oil painting style',
// The prompt passed to image generation should NOT contain <think> tags
expectedPrompt: 'A majestic sunset over mountains, golden hour lighting, oil painting style',
},
{
name: 'should handle thinking model response that is only a think block',
// Simulate a model that only outputs thinking with no actual response
inputPrompt: 'a cat',
enhancedResponse: '<think>I need to think about how to enhance this prompt...</think>',
// When stripping produces empty string, should fall back to original prompt
expectedPrompt: 'a cat',
},
{
name: 'should handle response without think tags normally',
// Non-thinking model returns plain enhanced prompt
inputPrompt: 'simple prompt',
enhancedResponse: 'A beautiful enhanced prompt with details',
expectedPrompt: 'A beautiful enhanced prompt with details',
},
])('$name', async ({ inputPrompt, enhancedResponse, expectedPrompt }) => {
setupThinkingModelEnhancement();
// Simulate a thinking model that wraps reasoning in <think> tags
mockLlmService.generateResponse.mockResolvedValue(
'<think>Let me enhance this prompt by adding artistic details...</think>A majestic sunset over mountains, golden hour lighting, oil painting style'
);

await imageGenerationService.generateImage({
prompt: 'sunset over mountains',
});

// The prompt passed to image generation should NOT contain <think> tags
expect(mockLocalDreamService.generateImage).toHaveBeenCalledWith(
expect.objectContaining({
prompt: 'A majestic sunset over mountains, golden hour lighting, oil painting style',
}),
expect.any(Function),
expect.any(Function),
);
});

it('should handle thinking model response that is only a think block', async () => {
setupThinkingModelEnhancement();
// Simulate a model that only outputs thinking with no actual response
mockLlmService.generateResponse.mockResolvedValue(
'<think>I need to think about how to enhance this prompt...</think>'
);

await imageGenerationService.generateImage({
prompt: 'a cat',
});

// When stripping produces empty string, should fall back to original prompt
expect(mockLocalDreamService.generateImage).toHaveBeenCalledWith(
expect.objectContaining({
prompt: 'a cat',
}),
expect.any(Function),
expect.any(Function),
);
});

it('should handle response without think tags normally', async () => {
setupThinkingModelEnhancement();
// Non-thinking model returns plain enhanced prompt
mockLlmService.generateResponse.mockResolvedValue(
'A beautiful enhanced prompt with details'
);
mockLlmService.generateResponse.mockResolvedValue(enhancedResponse);

await imageGenerationService.generateImage({
prompt: 'simple prompt',
prompt: inputPrompt,
});

expect(mockLocalDreamService.generateImage).toHaveBeenCalledWith(
expect.objectContaining({
prompt: 'A beautiful enhanced prompt with details',
prompt: expectedPrompt,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Delete this mockist test rather than repairing it.

As per coding guidelines for __tests__/**/*.{ts,tsx}, you should delete mockist tests that mock application code or assert toHaveBeenCalled rather than repairing or parameterizing them. Tests should instead be rendered integration tests that mount the screen and assert what the user sees.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@__tests__/integration/generation/imageGenerationFlow.test.ts` around lines
1183 - 1218, Delete the parameterized mockist test block around the
thinking-model prompt cases, including its mocked generateResponse setup and
toHaveBeenCalled assertion. Do not replace or repair it; follow the project
guideline that tests under __tests__ should use rendered integration behavior
and user-visible assertions instead.

Source: Coding guidelines

@alichherawalla

Copy link
Copy Markdown
Collaborator Author

Included in release PR #571 via merge commit 5c00126; closing this superseded source PR.

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.

1 participant