Skip to content

test(web): standardize frontend tests on Vitest - #6569

Open
QuentinHsu wants to merge 4 commits into
mainfrom
test/frontend-vitest-migration
Open

test(web): standardize frontend tests on Vitest#6569
QuentinHsu wants to merge 4 commits into
mainfrom
test/frontend-vitest-migration

Conversation

@QuentinHsu

@QuentinHsu QuentinHsu commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

概述

  • 将前端测试运行器统一迁移至 Vitest。

改动说明

  • 新增 Vitest、jsdom 和 React Testing Library 配置及测试脚本。
  • 将现有 node:test 测试迁移至 Vitest。
  • 使用 React Testing Library 重写 JsonCodeEditor 组件测试,并移除 happy-dom 直接依赖。

测试说明

  • 更新测试环境初始化、TypeScript 配置与依赖锁文件。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

Summary by CodeRabbit

  • Tests
    • Migrated the web test suite to Vitest.
    • Expanded JSON editor coverage for accessibility, form behavior, user edits, and formatting.
    • Added a browser-like test environment with automated cleanup and common API support.
  • Chores
    • Added test and watch commands for local development.
    • Standardized test configuration and execution across the web application.
    • Updated continuous integration to use the project’s test command.

- configure Vitest, jsdom, and React Testing Library with shared test scripts.
- migrate existing node:test suites to the Vitest runner.
- rewrite JsonCodeEditor component tests with RTL and remove the direct happy-dom dependency.
# Conflicts:
#	web/src/features/profile/components/login-session-utils.test.ts
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The web test infrastructure now uses Vitest with jsdom and React Testing Library. The JSON editor tests use Testing Library interactions. Existing tests now use Vitest imports and lifecycle hooks.

Changes

Vitest test infrastructure

Layer / File(s) Summary
Vitest configuration and environment
web/package.json, web/vitest.config.ts, web/src/test-setup.ts, web/tsconfig.node.json, .github/workflows/ci.yml
Added Vitest scripts, dependencies, jsdom configuration, test setup, cleanup, browser API polyfills, TypeScript inclusion, and CI wiring.
JSON editor test migration
web/src/components/json-code-editor/__tests__/*
Replaced the custom DOM harness with Vitest and React Testing Library. Added coverage for accessibility, form behavior, refs, blur handling, controlled values, user edits, and JSON formatting.
Existing suite import migration
web/src/components/model-group-selector/*, web/src/components/ui/*, web/src/features/*, web/src/lib/*
Changed test lifecycle imports from node:test to vitest. Updated suite cleanup hooks from after to afterAll where required.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: calcium-ion

Poem

A rabbit checks each test with care,
Vitest runs through jsdom air.
The editor formats JSON bright,
Testing Library sees the user’s flight.
Green results hop everywhere.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the migration of frontend tests to Vitest.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 test/frontend-vitest-migration

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.

- invoke the configured Vitest script so browser test setup loads in CI.
- migrate remaining node:test suites to Vitest lifecycle APIs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@web/src/features/usage-logs/components/__tests__/cost-display.test.tsx`:
- Line 20: Remove the stale happy-dom Window imports and fixtures from
cost-display.test.tsx at lines 20-20 and 108-108, and from
tool-price-validation.test.tsx at lines 20-20 and 89-89; retain the existing
jsdom-based test behavior and cleanup.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3be0a2ad-0b5d-4b13-8b61-e1d1bb0a43bb

📥 Commits

Reviewing files that changed from the base of the PR and between 1eee799 and 6a137e0.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • web/src/features/auth/lib/__tests__/oauth-callback-mode.test.ts
  • web/src/features/channels/lib/__tests__/new-api-channel.test.ts
  • web/src/features/profile/components/__tests__/login-session-utils.test.ts
  • web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx
  • web/src/features/usage-logs/components/__tests__/cost-display.test.tsx
  • web/src/features/usage-logs/lib/__tests__/tool-surcharge.test.ts

*/
import assert from 'node:assert/strict'
import { after, describe, test } from 'node:test'
import { afterAll, describe, test } from 'vitest'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

for file in \
  web/src/features/usage-logs/components/__tests__/cost-display.test.tsx \
  web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx
do
  rg -n -C 3 '\bWindow\b|happy-dom|jsdom' "$file"
done

fd -i 'package.json|bun.lock|bun.lockb' web -x \
  rg -n '"happy-dom"|'\''happy-dom'\''' {}

Repository: QuantumNous/new-api

Length of output: 2378


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== package files =="
git ls-files 'web/**/package.json' | sed -n '1,120p'

echo
echo "== project/dependency declarations for happy-dom/jsdom/vitest =="
while IFS= read -r f; do
  echo "-- $f --"
  rg -n -C 2 '"(happy-dom|jsdom|vitest)\"|happy-dom|jsdom' "$f" || true
done < <(git ls-files 'web/**/package.json')

echo
echo "== vitest config files =="
git ls-files 'web' | rg '(^|/)(vitest\.config\.[cm][jt]sx?|vitest\.config\.[cm]?[jt]s|vite\.config\.[cm][jt]sx?)$' | while read -r f; do
  echo "-- $f --"
  sed -n '1,220p' "$f"
done

Repository: QuantumNous/new-api

Length of output: 296


🏁 Script executed:

#!/usr/bin/env bash
set -uo pipefail

echo "== package files under tracked repo =="
git ls-files | rg '(^|/)web/src/features/.*/package\.json$|(^|/)web/package\.json$|(^|/)package\.json$' || true

echo
echo "== happy-dom / jsdom declarations in package manifests =="
while IFS= read -r f; do
  echo "-- $f --"
  rg -n -C 2 '"(happy-dom|jsdom|vitest)\"|happy-dom|jsdom' "$f" || true
done < <(git ls-files | rg '(^|/)web/src/features/.*/package\.json$|(^|/)web/package\.json$|(^|/)package\.json$')

echo
echo "== vitest config files =="
git ls-files | rg '(^|/)(vitest\.config\.[cm][jt]sx?|vitest\.config\.[cm]?[jt]s|vite\.config\.[cm][jt]sx?)$' | while read -r f; do
  echo "-- $f --"
  sed -n '1,220p' "$f"
done

Repository: QuantumNous/new-api

Length of output: 1615


🏁 Script executed:

#!/usr/bin/env bash
set -uo pipefail

echo "== web/package.json =="
cat web/package.json

echo
echo "== focused declarations =="
python3 - <<'PY'
import json
from pathlib import Path
p = Path('web/package.json')
data = json.loads(p.read_text())
for section in ('dependencies','devDependencies','peerDependencies','optionalDependencies'):
    print(f'[{section}]')
    deps = data.get(section,{})
    for name in ('happy-dom','jsdom','vitest','`@types/jsdom`'):
        if name in deps:
            print(f'{name}: {deps[name]}')
PY

echo
echo "== imports/usages in test files =="
python3 - <<'PY'
from pathlib import Path
for p in [
    Path('web/src/features/usage-logs/components/__tests__/cost-display.test.tsx'),
    Path('web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx'),
]:
    print(f'-- {p} --')
    text = p.read_text()
    for idx,line in enumerate(text.splitlines(),1):
        if 'Window' in line or 'happy-dom' in line or 'jsdom' in line or 'afterAll' in line:
            print(f'{idx}: {line}')
PY

Repository: QuantumNous/new-api

Length of output: 4780


🌐 Web query:

Vitest 4 jsdom environment global Window property domGlobals configuration

💡 Result:

In Vitest, there is no configuration setting explicitly named "domGlobals" [1][2]. Vitest manages global browser-like APIs through its environment system (e.g., jsdom or happy-dom) [3][4]. When using the jsdom environment, Vitest automatically injects browser globals into the Node.js global object [5][6]. Vitest uses a facade pattern to ensure that window, self, global, and globalThis consistently share the same state [6][7]. If you need to configure or customize the jsdom environment, you should use the environmentOptions configuration in your vitest.config file [3][1]: // vitest.config.ts import { defineConfig } from 'vitest/config' export default defineConfig({ test: { environment: 'jsdom', environmentOptions: { jsdom: { // Options passed directly to the JSDOM constructor url: 'http://localhost:3000', userAgent: 'MyApp/1.0', }, }, }, }) Key points regarding global configuration in Vitest: 1. Environment Selection: Set environment: 'jsdom' in your test configuration to enable the browser-like environment [3][4]. 2. Globals API: If you want Vitest's test APIs (like describe, it, expect) to be globally available, set globals: true in your test configuration [8]. 3. TypeScript Support: To help TypeScript recognize the jsdom-specific globals, add vitest/jsdom to the types array in your tsconfig.json [4]: { "compilerOptions": { "types": ["vitest/jsdom"] } } Vitest manages the Window object internally by populating the global namespace with the JSDOM window's properties [6]. Modifications to standard window properties are generally handled by Vitest's internal utility functions to maintain synchronization across the various global aliases (window, self, etc.) [6][7].

Citations:


Remove the stale happy-dom imports and fixtures

Vitest test runs use jsdom, but both tests still import and create Window from happy-dom. Since happy-dom is no longer declared in web/package.json, delete web/src/features/usage-logs/components/__tests__/cost-display.test.tsx#L22-L25 and web/src/features/usage-logs/components/__tests__/cost-display.test.tsx#L108-L109; update the same fixture/cleanup in web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx#L22-L25 and web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx#L89-L90.

📍 Affects 2 files
  • web/src/features/usage-logs/components/__tests__/cost-display.test.tsx#L20-L20 (this comment)
  • web/src/features/usage-logs/components/__tests__/cost-display.test.tsx#L108-L108
  • web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx#L20-L20
  • web/src/features/system-settings/models/__tests__/tool-price-validation.test.tsx#L89-L89
🤖 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 `@web/src/features/usage-logs/components/__tests__/cost-display.test.tsx` at
line 20, Remove the stale happy-dom Window imports and fixtures from
cost-display.test.tsx at lines 20-20 and 108-108, and from
tool-price-validation.test.tsx at lines 20-20 and 89-89; retain the existing
jsdom-based test behavior and cleanup.

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