Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Jun 12, 2025

开始给项目增加 vitest

目录结构

test/
├── main/                 # 主进程测试
│   ├── eventbus/        # EventBus 相关测试
│   ├── presenter/       # Presenter 层测试
│   └── utils/           # 工具函数测试
├── renderer/            # 渲染进程测试
│   ├── shell/           # Shell 应用测试
│   ├── stores/          # 状态管理测试
│   ├── components/      # 组件测试
│   └── composables/     # 组合式函数测试
├── shared/              # 共享模块测试
├── fixtures/            # 测试数据和模拟
└── utils/               # 测试工具函数

Summary by CodeRabbit

  • New Features

    • Added comprehensive testing scripts and dependencies, enabling unit and integration tests for both main and renderer processes.
    • Introduced detailed testing documentation to guide setup and best practices.
    • Added extensive test suites covering core functionalities, presenters, and application setup.
  • Bug Fixes

    • Corrected typos in method names to ensure consistent and accurate function calls.
  • Chores

    • Updated configuration files to exclude test directories from builds and linting.
    • Added and configured test setup and Vitest configuration files for reliable test environments.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 12, 2025

Walkthrough

The changes introduce a comprehensive testing infrastructure using Vitest, add related dependencies and scripts, and provide extensive documentation and setup files. The build configuration is updated to exclude the test directory from packaging. Several typos in method names are corrected for consistency. New tests are added for core modules, and configuration files for test environments are introduced.

Changes

Files/Groups Change Summary
.github/workflows/prcheck.yml Removed Windows platform from the CI build matrix.
.oxlintrc.json Changed ignore pattern from tests to test.
electron-builder.yml, electron-builder-macx64.yml Added exclusion of the test directory from packaged application files.
package.json Added Vitest, Vue Test Utils, jsdom, and related test scripts and devDependencies.
src/main/eventbus.ts, src/main/presenter/windowPresenter/index.ts, src/shared/presenter.d.ts Fixed typo: renamed method sendTodefaultTab to sendToDefaultTab across implementation and interface.
test/README.md Added detailed testing documentation and instructions.
test/main/eventbus/eventbus.test.ts Added comprehensive tests for EventBus event dispatching and error handling.
test/main/presenter/llmProviderPresenter.test.ts Added integration tests for LLMProviderPresenter covering provider management, streaming, and error handling.
test/renderer/shell/main.test.ts Added tests verifying Vue app setup, plugins, i18n, icon management, and component rendering in the shell main entry.
test/setup.ts, test/setup.renderer.ts Introduced setup files to mock Node.js, Electron, and renderer-specific modules for isolated testing.
vitest.config.ts, vitest.config.renderer.ts Added Vitest configuration files for main and renderer processes, specifying aliases, test environments, coverage, and setup files.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Vitest as Vitest CLI
    participant Setup as Test Setup Files
    participant App as Application Modules
    participant Mocks as Mocked Dependencies

    Dev->>Vitest: Run test script (e.g., npm test)
    Vitest->>Setup: Load setup.ts/setup.renderer.ts
    Setup->>Mocks: Mock Node.js/Electron/Vue modules
    Vitest->>App: Import modules under test
    App->>Mocks: Use mocked dependencies
    Vitest->>App: Execute test cases
    App-->>Vitest: Return test results
    Vitest-->>Dev: Output results and coverage
Loading

Poem

In a burrow deep, I nibbled code anew,
With Vitest seeds and jsdom dew.
Typos fixed, the tests now run,
Excluding "test" from every bun.
From EventBus hops to LLM lore,
This rabbit’s tests ensure much more!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@zerob13 zerob13 marked this pull request as ready for review June 12, 2025 14:40
@zerob13 zerob13 changed the title wip: add vitest test: add vitest Jun 12, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (13)
.oxlintrc.json (1)

15-15: Consider keeping the legacy tests ignore pattern as well
Previous configs ignored tests/*; the new single entry test is fine, but if any historical folder or developer still places specs under tests/ they will suddenly be lint-checked.
Add both patterns for a painless transition.

   "docs",
-  "test"
+  "test",
+  "tests"
electron-builder-macx64.yml (1)

8-9: Duplicate !test/* entries – drop one for cleanliness
The same exclusion appears twice (lines 8 and 19). Builder tolerates duplicates but it is noisy and increases merge-conflict surface.

-  - '!test/*'   # line 8
   ...
-  - '!test/*'   # line 19

Also applies to: 19-20

electron-builder.yml (1)

8-9: Same !test/* duplication as the mac config
Two identical exclusion lines (8 and 19) – safe but untidy. Remove the second.

Also applies to: 19-20

vitest.config.renderer.ts (1)

43-45: Timeouts: consider lowering for renderer unit tests
10 s per test/hook is generous and may hide hung tests. Typical unit tests complete in < 2 s. If E2E coverage is required, move those to Playwright/Cypress suites.

test/setup.ts (1)

63-71: Use vi.resetModules() to ensure module isolation between tests

vi.clearAllMocks() resets call counts, and vi.restoreAllMocks() restores spied-on methods, but neither unloads mocked modules. Stateful singletons (e.g. Electron mocks) will therefore persist across tests.

afterEach(() => {
   // Clean up after each test
   vi.restoreAllMocks()
+  vi.resetModules()
 })

This guarantees each test receives a fresh module instance.

test/README.md (1)

5-17: Specify a language for the directory-tree code block

Markdown-lint (MD040) flags fenced blocks without a language. Add text (or bash) to improve syntax highlighting and keep the linter quiet.

-```
+```text
 test/
 ├── main/
 ...

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

5-5: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

</details>

</details>

</blockquote></details>
<details>
<summary>vitest.config.ts (1)</summary><blockquote>

`7-9`: **Minor style nit – stray indentation**

Extra two-space indent before `'@shared'` is inconsistent with the rest of the file.  Not blocking, just keeping the config tidy.

```diff
-      '@': resolve('src/main/'),
-        '@shared': resolve('src/shared')
+      '@': resolve('src/main/'),
+      '@shared': resolve('src/shared')
test/setup.renderer.ts (2)

70-88: Global window.api stub looks good but consider freezing structure

Down-stream code may rely on Object.freeze(window.api) behaviour from preload. To mimic production more closely and avoid accidental mutation inside tests:

-Object.defineProperty(window, 'api', {
-  value: {
+Object.defineProperty(window, 'api', {
+  value: Object.freeze({
       devicePresenter: {
         getDeviceInfo: vi.fn(() => Promise.resolve({ /* … */ }))
       },
       windowPresenter: {
         minimize: vi.fn(),
         maximize: vi.fn(),
         close: vi.fn(),
         isMaximized: vi.fn(() => Promise.resolve(false))
       }
-  },
+  }),
   writable: true
 })

Optional, but reduces flakiness in larger suites.


103-106: Same isolation concern as main setup – reset mocked modules

Mirror the change suggested for test/setup.ts so renderer tests also start with clean modules.

afterEach(() => {
   vi.restoreAllMocks()
+  vi.resetModules()
 })
test/main/eventbus/eventbus.test.ts (2)

205-209: Prefer a deterministic promise-flush over setTimeout(0)

Using await new Promise(r => setTimeout(r, 0)) makes tests a tiny bit slower and can still race.
Consider a helper such as:

const flushPromises = () => new Promise(queueMicrotask);
await flushPromises();

or await vi.runAllTicks() if fake timers are active.

Also applies to: 221-223, 235-237


5-26: Add a global mock reset in afterEach

Mocks are re-created per beforeEach, but any stray vi.spyOn that forgets to mockRestore may leak across suites. Safer pattern:

afterEach(() => {
  vi.restoreAllMocks();
});
test/renderer/shell/main.test.ts (2)

8-17: Smoke test may be redundant & heavy

Importing full ESM bundles of vue, pinia, and vue-i18n only to assert that factory functions exist costs ~100 ms per run and adds no behavioural coverage.
Consider stubbing those imports or removing the test entirely.


62-73: Spy-only assertion adds little value

addCollection is a plain vi.fn() and you verify it was called – this does not test your icon system. Either use the real @iconify/vue API or drop the case to keep the suite meaningful.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6b8d1c and 5d4e723.

📒 Files selected for processing (13)
  • .github/workflows/prcheck.yml (1 hunks)
  • .oxlintrc.json (1 hunks)
  • electron-builder-macx64.yml (1 hunks)
  • electron-builder.yml (1 hunks)
  • package.json (4 hunks)
  • test/README.md (1 hunks)
  • test/main/eventbus/eventbus.test.ts (1 hunks)
  • test/main/presenter/llmProviderPresenter.test.ts (1 hunks)
  • test/renderer/shell/main.test.ts (1 hunks)
  • test/setup.renderer.ts (1 hunks)
  • test/setup.ts (1 hunks)
  • vitest.config.renderer.ts (1 hunks)
  • vitest.config.ts (1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/prcheck.yml

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

🪛 markdownlint-cli2 (0.17.2)
test/README.md

5-5: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (4)
vitest.config.renderer.ts (2)

9-12: Verify @ alias points where you expect
'@': resolve('src/renderer/src') is unusual – many IDE/Vite presets map @ to the top-level src. Double-check imports like @/components/... still resolve after this change.


37-38: ⚠️ Potential issue

Glob pattern will not match any tests
'test/renderer/**/*.{test,spec}.{js,ts}' expands to *.{test,spec}.{js,ts}, which is invalid.
Use separate brace sections:

-    include: ['test/renderer/**/*.{test,spec}.{js,ts}'],
+    include: ['test/renderer/**/*.test.{js,ts}', 'test/renderer/**/*.spec.{js,ts}'],

Otherwise Vitest silently skips your renderer tests.

Likely an incorrect or invalid review comment.

test/README.md (1)

35-40: Doc/implementation drift – npm test not wired in package.json

The quick-start section recommends npm test, but that script is absent (see previous comment). Update either the docs or package.json to stay in sync.

Likely an incorrect or invalid review comment.

test/main/presenter/llmProviderPresenter.test.ts (1)

6-16: Ensure Vitest alias resolution matches '@/' paths

The mocks reference '@/eventbus', '@/presenter', …
If vitest.config.ts does not provide

resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }

the tests will fail at runtime.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 12, 2025

Caution

No docstrings were generated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

♻️ Duplicate comments (4)
.github/workflows/prcheck.yml (1)

35-35: Add trailing newline to satisfy YAML lint.

The file is missing a newline at EOF, causing YAML-lint to error.

-        run: npm run build
+        run: npm run build
+
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

test/setup.ts (1)

60-66: 🛠️ Refactor suggestion

path.join/resolve mock still hides platform-specific bugs

-    join: vi.fn((...args) => args.join('/')),
-    resolve: vi.fn((...args) => args.join('/'))
+    join: vi.spyOn(actual as any, 'join'),
+    resolve: vi.spyOn(actual as any, 'resolve')

Spying preserves real semantics while keeping call-count assertions intact.

test/main/presenter/llmProviderPresenter.test.ts (2)

132-150: Still performs real HTTP calls — please stub them

The test hits https://mockllm.anya2a.com/v1, making the suite slow and non-deterministic. Mock the request layer (vi.mock/msw/nock) and assert against the stubbed payload instead.


435-451: Possible infinite loop in concurrency section

The for await loop waits for events but a rejected stream may never yield, hanging until Vitest times out. Add a timeout guard (e.g. Promise.race with setTimeout) or abort signal.

🧹 Nitpick comments (11)
electron-builder.yml (1)

8-19: Remove duplicate exclusion and refine test directory pattern.

The !test/* exclusion appears twice (lines 8 and 19) and only excludes top-level files, not nested directories. Consolidate to a single glob that covers all test files:

-  - '!test/*'
+  - '!test/**'
electron-builder-macx64.yml (1)

8-19: Remove duplicate exclusion and refine test directory pattern.

The exclusion !test/* is duplicated (lines 8 and 19) and doesn't match nested files. Replace with a single recursive pattern:

-  - '!test/*'
+  - '!test/**'
.oxlintrc.json (1)

15-15: Ensure ignore pattern excludes nested test files.

The pattern "test" may not ignore subdirectories. Use a glob to match all files under test/:

-    "test"
+    "test/**"
test/setup.ts (1)

44-56: fs.promises.stat still un-stubbed – async callers will fail

Several production files call fs.promises.stat. Add it to the promises mock.

   promises: {
     access: vi.fn(),
     readFile: vi.fn(),
     writeFile: vi.fn(),
     mkdir: vi.fn(),
-    readdir: vi.fn()
+    readdir: vi.fn(),
+    stat: vi.fn()
   }
vitest.config.ts (1)

6-9: Alias indentation & trailing slash inconsistency

The @shared alias is indented one level deeper than @, and src/main/ includes a trailing slash while src/shared does not. Although harmless at runtime, this inconsistency sparks avoidable merge noise across commits.

-    alias: {
-      '@': resolve('src/main/'),
-        '@shared': resolve('src/shared')
-    }
+    alias: {
+      '@': resolve('src/main'),
+      '@shared': resolve('src/shared')
+    }
test/renderer/shell/main.test.ts (1)

58-73: addCollection assertion weak

The expectation only checks the first argument shape. To guarantee both icon sets are registered, assert on the actual payload or call order.

-expect(addCollection).toHaveBeenCalledTimes(2)
-expect(addCollection).toHaveBeenCalledWith(
-  expect.objectContaining({ icons: expect.any(Object) })
-)
+expect(addCollection).toHaveBeenNthCalledWith(1, lucideIcons)
+expect(addCollection).toHaveBeenNthCalledWith(2, vscodeIcons)
test/setup.renderer.ts (2)

15-24: Router mock is missing isReady & afterEach

Many Vue-Router consumers await router.isReady() or register afterEach hooks. Omitting them will crash tests that exercise navigation guards.

   createRouter: vi.fn(() => ({
+    isReady: vi.fn(() => Promise.resolve()),
+    afterEach: vi.fn(),
     push: vi.fn(),

61-68: Icon component should be a valid Vue component

Returning a plain object may trigger “runtime missing template compiler” warnings. Wrap the stub with defineComponent.

-import '@iconify/vue'
+import { defineComponent } from 'vue'
 ...
-  Icon: {
-    name: 'Icon',
-    template: '<span></span>'
-  }
+  Icon: defineComponent({
+    name: 'IconStub',
+    template: '<span></span>'
+  })
test/README.md (1)

5-17: Add language tag to fenced block (MD040)

Markdown-lint complains because the directory tree block lacks a language. Mark it as text to silence CI.

-```
+```text
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

5-5: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

test/main/eventbus/eventbus.test.ts (2)

206-212: Flushing async work with setTimeout is brittle

Instead of an empty setTimeout, rely on Vitest helpers to flush micro-tasks. This avoids test flakiness on slower runners.

-await new Promise(resolve => setTimeout(resolve, 0))
+await vi.runAllTicks()

334-349: Duplicate error-logging expectation pattern

The three error-handling tests share near-identical setup/teardown. Extract a helper or use describe.each to shrink the suite and reduce maintenance.

No diff provided – structural refactor suggested.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6b8d1c and 66c108b.

📒 Files selected for processing (16)
  • .github/workflows/prcheck.yml (1 hunks)
  • .oxlintrc.json (1 hunks)
  • electron-builder-macx64.yml (1 hunks)
  • electron-builder.yml (1 hunks)
  • package.json (4 hunks)
  • src/main/eventbus.ts (1 hunks)
  • src/main/presenter/windowPresenter/index.ts (1 hunks)
  • src/shared/presenter.d.ts (1 hunks)
  • test/README.md (1 hunks)
  • test/main/eventbus/eventbus.test.ts (1 hunks)
  • test/main/presenter/llmProviderPresenter.test.ts (1 hunks)
  • test/renderer/shell/main.test.ts (1 hunks)
  • test/setup.renderer.ts (1 hunks)
  • test/setup.ts (1 hunks)
  • vitest.config.renderer.ts (1 hunks)
  • vitest.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/main/presenter/llmProviderPresenter.test.ts (3)
src/main/presenter/llmProviderPresenter/index.ts (1)
  • LLMProviderPresenter (50-1051)
src/main/presenter/configPresenter/index.ts (1)
  • ConfigPresenter (73-954)
src/shared/presenter.d.ts (3)
  • LLM_PROVIDER (439-453)
  • ChatMessage (1048-1060)
  • LLMAgentEvent (1096-1099)
test/main/eventbus/eventbus.test.ts (2)
src/main/eventbus.ts (1)
  • EventBus (9-148)
src/shared/presenter.d.ts (2)
  • IWindowPresenter (143-168)
  • ITabPresenter (170-204)
🪛 YAMLlint (1.37.1)
.github/workflows/prcheck.yml

[error] 35-35: no new line character at the end of file

(new-line-at-end-of-file)

🪛 markdownlint-cli2 (0.17.2)
test/README.md

5-5: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🔇 Additional comments (4)
src/main/eventbus.ts (1)

51-51: Corrected method invocation for default tab.

The typo is fixed from sendTodefaultTab to sendToDefaultTab, aligning with the presenter API.

src/shared/presenter.d.ts (1)

165-167:

Details

✅ Verification successful

Ensure callers have been migrated to the new method name

sendToDefaultTab is now the canonical spelling. double-check all invocations (main + renderer) to avoid a silent runtime undefined is not a function.

Run

to confirm no lingering references.


🏁 Script executed:

#!/bin/bash
rg -n "sendTodefaultTab"

Length of output: 24


🏁 Script executed:

#!/bin/bash
# Check for any lingering references to the new canonical method name with correct casing
rg -n "sendToDefaultTab"

Length of output: 508


sendToDefaultTab migration complete
The method signature in src/shared/presenter.d.ts (line 166) and all call sites have been updated to the new canonical name; no occurrences of sendTodefaultTab remain.
• src/main/eventbus.ts:51
• src/main/presenter/windowPresenter/index.ts:916
• test/main/eventbus/eventbus.test.ts:17, 128

src/main/presenter/windowPresenter/index.ts (1)

916-991: Implementation reads well – no functional concerns spotted

Logic gracefully handles “no focused window / no tabs” cases, respects switchToTarget, and returns the correct boolean.

vitest.config.renderer.ts (1)

5-47: Renderer Vitest config looks good

jsdom environment, alias map and coverage filters are sensible.

Comment on lines +13 to +26
BrowserWindow: vi.fn(() => ({
loadURL: vi.fn(),
loadFile: vi.fn(),
on: vi.fn(),
webContents: {
send: vi.fn(),
on: vi.fn(),
isDestroyed: vi.fn(() => false)
},
isDestroyed: vi.fn(() => false),
close: vi.fn(),
show: vi.fn(),
hide: vi.fn()
})),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Missing static helpers & instance data on BrowserWindow mock

WindowPresenter relies on
BrowserWindow.getFocusedWindow()
BrowserWindow.fromWebContents()
window.id

These are absent and tests that exercise focus / IPC logic will explode.

-  BrowserWindow: vi.fn(() => ({
+  const createWindow = () => ({
+    id: Math.floor(Math.random() * 1000),
     ...
   }))
-  ,
+  const BrowserWindowMock: any = Object.assign(createWindow, {
+    fromWebContents: vi.fn(() => createWindow()),
+    getFocusedWindow: vi.fn(() => undefined) // customise in tests
+  })
+  BrowserWindow: BrowserWindowMock,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In test/setup.ts between lines 13 and 26, the BrowserWindow mock is missing
static methods getFocusedWindow and fromWebContents, as well as the instance
property id. Add these static methods to the BrowserWindow mock returning
appropriate mock instances, and include an id property on the mock window object
to ensure tests involving focus and IPC logic work correctly without errors.

Comment on lines 8 to 15
"scripts": {
"test": "vitest",
"test:main": "vitest --config vitest.config.ts test/main",
"test:renderer": "vitest --config vitest.config.renderer.ts test/renderer",
"test:coverage": "vitest --coverage",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui",
"format": "prettier --write .",
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Top-level test script runs only main tests

Running plain vitest picks up vitest.config.ts but ignores the renderer config, so npm test gives partial coverage.

-    "test": "vitest",
+    "test": "npm run test:main && npm run test:renderer",

This keeps CI/local workflows aligned with the documented intent.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"scripts": {
"test": "vitest",
"test:main": "vitest --config vitest.config.ts test/main",
"test:renderer": "vitest --config vitest.config.renderer.ts test/renderer",
"test:coverage": "vitest --coverage",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui",
"format": "prettier --write .",
"scripts": {
- "test": "vitest",
+ "test": "npm run test:main && npm run test:renderer",
"test:main": "vitest --config vitest.config.ts test/main",
"test:renderer": "vitest --config vitest.config.renderer.ts test/renderer",
"test:coverage": "vitest --coverage",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui",
"format": "prettier --write .",
🤖 Prompt for AI Agents
In package.json lines 8 to 15, the top-level "test" script runs only the main
tests using vitest with vitest.config.ts, ignoring the renderer tests and their
config. To fix this, modify the "test" script to run both main and renderer
tests by combining or chaining the commands so that both configurations are
used, ensuring full test coverage when running npm test.

Comment on lines +37 to +46
},
include: ['test/**/*.{test,spec}.{js,ts}'],
exclude: [
'node_modules/**',
'dist/**',
'out/**'
],
testTimeout: 10000,
hookTimeout: 10000,
setupFiles: ['./test/setup.ts']
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Glob pattern loses TSX / JSX and risks false-negatives

include: ['test/**/*.{test,spec}.{js,ts}'] does not match *.tsx/ *.jsx, and fast-glob expands this brace twice, which can occasionally mis-interpret nested braces. Prefer the explicit array recommended by Vitest docs.

-    include: ['test/**/*.{test,spec}.{js,ts}'],
+    include: [
+      'test/**/*.test.{js,ts,jsx,tsx}',
+      'test/**/*.spec.{js,ts,jsx,tsx}'
+    ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
},
include: ['test/**/*.{test,spec}.{js,ts}'],
exclude: [
'node_modules/**',
'dist/**',
'out/**'
],
testTimeout: 10000,
hookTimeout: 10000,
setupFiles: ['./test/setup.ts']
},
include: [
'test/**/*.test.{js,ts,jsx,tsx}',
'test/**/*.spec.{js,ts,jsx,tsx}'
],
exclude: [
'node_modules/**',
'dist/**',
'out/**'
],
testTimeout: 10000,
hookTimeout: 10000,
setupFiles: ['./test/setup.ts']
🤖 Prompt for AI Agents
In vitest.config.ts around lines 37 to 46, the include glob pattern does not
cover .tsx and .jsx files and uses brace expansion that can misinterpret nested
braces. Update the include array to explicitly list all test file extensions
separately, including .tsx and .jsx, for example by specifying patterns like
'test/**/*.test.ts', 'test/**/*.spec.ts', 'test/**/*.test.tsx',
'test/**/*.spec.tsx', 'test/**/*.test.jsx', and 'test/**/*.spec.jsx' to ensure
all relevant test files are included correctly.

Comment on lines +19 to +36
it('应该正确创建Vue应用实例', () => {
// 模拟Vue应用创建流程
const mockApp = {
use: vi.fn().mockReturnThis(),
mount: vi.fn()
}

const createApp = vi.fn(() => mockApp)
const createPinia = vi.fn(() => ({}))
const createI18n = vi.fn(() => ({
global: { t: vi.fn(), locale: 'zh-CN' }
}))

// 验证函数被调用
expect(createApp).toBeDefined()
expect(createPinia).toBeDefined()
expect(createI18n).toBeDefined()
})
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Tests assert stubs, not production code

createApp, createPinia, and createI18n are locally-defined mocks; the test never touches the real entry file, so a typo in src/renderer/main.ts would pass unnoticed. Import the actual module and spy on the real factories instead.

-const createApp = vi.fn(() => mockApp)
-const createPinia = vi.fn(() => ({}))
-const createI18n = vi.fn(() => ({ … }))
+vi.mock('vue', async (orig) => {
+  const mod = await orig()
+  return { ...mod, createApp: vi.fn(() => mockApp) }
+})
+// idem for pinia / vue-i18n
+await import('@/renderer/main') // or relative path

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In test/renderer/shell/main.test.ts around lines 19 to 36, the test currently
only asserts on locally defined mock functions instead of the real production
code, which means it won't catch issues in the actual implementation. To fix
this, import the real module from src/renderer/main.ts and use spies on the real
createApp, createPinia, and createI18n functions to verify their behavior. This
ensures the test interacts with the actual code and detects any typos or errors
in the production factories.

Comment on lines +11 to +18
eventBus = new EventBus()

// Mock WindowPresenter
mockWindowPresenter = {
sendToWindow: vi.fn(),
sendToAllWindows: vi.fn(),
sendToDefaultTab: vi.fn()
} as Partial<IWindowPresenter> as IWindowPresenter
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Heavy casting hides type drift

as Partial<IWindowPresenter> as IWindowPresenter discards type-safety and will not alert when the interface evolves. Prefer an explicit helper that fills required fields with no-ops to keep TS protection.

const mockWindowPresenter: IWindowPresenter = {
  createShellWindow: vi.fn(),
  mainWindow: undefined,
  previewFile: vi.fn(),
  minimize: vi.fn(),
  maximize: vi.fn(),
  close: vi.fn(),
  hide: vi.fn(),
  show: vi.fn(),
  isMaximized: vi.fn(),
  isMainWindowFocused: vi.fn(),
  sendToAllWindows: vi.fn(),
  sendToWindow: vi.fn(),
  sendToDefaultTab: vi.fn(),
  closeWindow: vi.fn(),
}
🤖 Prompt for AI Agents
In test/main/eventbus/eventbus.test.ts around lines 11 to 18, the
mockWindowPresenter uses heavy casting with 'as Partial<IWindowPresenter> as
IWindowPresenter' which bypasses type safety. Replace this with an explicit mock
object that implements all required IWindowPresenter methods and properties
using no-op functions or appropriate defaults to maintain TypeScript type
checking and catch interface changes.

Comment on lines +98 to +104
afterEach(() => {
// Stop all active streams after each test
const activeStreams = (llmProviderPresenter as any).activeStreams as Map<string, any>
for (const [eventId] of activeStreams) {
llmProviderPresenter.stopStream(eventId)
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mark afterEach async and await stream shutdown

stopStream is async; without await the test runner may finish while streams are still tearing down, causing flaky leakage into later tests.

-afterEach(() => {
+afterEach(async () => {-      llmProviderPresenter.stopStream(eventId)
+      await llmProviderPresenter.stopStream(eventId)
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
afterEach(() => {
// Stop all active streams after each test
const activeStreams = (llmProviderPresenter as any).activeStreams as Map<string, any>
for (const [eventId] of activeStreams) {
llmProviderPresenter.stopStream(eventId)
}
})
afterEach(async () => {
// Stop all active streams after each test
const activeStreams = (llmProviderPresenter as any).activeStreams as Map<string, any>
for (const [eventId] of activeStreams) {
await llmProviderPresenter.stopStream(eventId)
}
})
🤖 Prompt for AI Agents
In test/main/presenter/llmProviderPresenter.test.ts around lines 98 to 104, the
afterEach hook calls the async stopStream method without awaiting it, which can
cause tests to finish before streams are fully stopped. Mark the afterEach
callback as async and await each call to stopStream to ensure all streams are
properly shut down before proceeding to the next test.

@zerob13 zerob13 merged commit 0bbb40f into dev Jun 12, 2025
2 checks passed
@zerob13 zerob13 deleted the refactor/add-test branch September 21, 2025 14:48
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.

2 participants