Skip to content

test: Add comprehensive unit tests and CI workflow - #65

Merged
minorcell merged 1 commit into
mainfrom
xgopilot/claude/issue-64-1763533215
Nov 19, 2025
Merged

minorcell merged 1 commit into
mainfrom
xgopilot/claude/issue-64-1763533215

Conversation

@minorcell

Copy link
Copy Markdown
Member

Requested by @minorcell

Resolves #64

Summary

Added comprehensive unit test coverage for the Pick Quote extension and integrated automated testing into the CI pipeline.

Test Coverage

  • Utils Module (20 tests)

    • SHA-256 hash generation with edge cases
    • Item hash computation with deduplication logic
    • URL formatting and truncation
  • Database Module (26 tests)

    • Item CRUD operations (add, update, delete, export)
    • Search and filtering functionality
    • Category management
    • Deduplication logic verification
    • IndexedDB transaction handling
  • Export Module (13 tests)

    • ZIP file generation with markdown content
    • Image extraction from data URLs
    • Multiple item type handling
    • Edge cases (empty arrays, missing data)

Infrastructure

  • ✅ Jest testing framework with TypeScript support
  • ✅ fake-indexeddb for database mocking
  • ✅ Polyfills for Node.js environment (TextEncoder, crypto.subtle, structuredClone)
  • ✅ GitHub Actions workflow for automated CI testing
  • ✅ Test coverage reporting

Test Results

Test Suites: 3 passed, 3 total
Tests:       59 passed, 59 total
Snapshots:   0 total
Time:        5.02 s

Test plan

  • All 59 tests pass locally
  • CI workflow configured to run on push and PR
  • Tests cover critical functionality: hashing, database operations, export features
  • Edge cases and error handling tested

Generated with codeagent
Co-authored-by: minorcell 120795714+minorcell@users.noreply.github.com

- Set up Jest testing framework with TypeScript support
- Add fake-indexeddb for database testing
- Add test polyfills for TextEncoder, crypto.subtle, and structuredClone
- Create comprehensive test suites:
  - utils/index.test.ts: 20 tests for hashing and URL utilities
  - database/index.test.ts: 26 tests for IndexedDB operations
  - export/zipExport.test.ts: 13 tests for ZIP export functionality
- Add GitHub Actions workflow to run tests on CI
- All 59 tests passing with coverage

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: minorcell <120795714+minorcell@users.noreply.github.com>
@minorcell minorcell mentioned this pull request Nov 19, 2025

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +26 to +47
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install --frozen-lockfile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep pnpm lockfile in sync with new workflow step

The new CI job installs dependencies using pnpm install --frozen-lockfile (lines 26‑47), but this same commit also added new Jest dependencies and scripts to package.json without updating pnpm-lock.yaml. When pnpm runs with --frozen-lockfile and the lockfile is out of sync with package.json, it aborts with “Cannot install with frozen lockfile because pnpm-lock.yaml is not up to date,” so this workflow never reaches the test steps. Please update the pnpm lockfile (or drop the frozen flag) so the CI job introduced here can actually execute.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@codex fix this issue on this pr.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

  • Updated pnpm-lock.yaml to capture the new testing-related dependencies (@testing-library/*, @types/jest, fake-indexeddb, jest, jest-environment-jsdom, ts-jest, etc.), ensuring the CI workflow can run pnpm install --frozen-lockfile without aborting. pnpm-lock.yamlL41-L80

Testing

  • ⚠️ Not run (not requested)

View task →

Comment thread src/test/setup.ts

// Polyfill structuredClone for Node < 17
if (typeof global.structuredClone === 'undefined') {
global.structuredClone = (obj: any) => JSON.parse(JSON.stringify(obj))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Security Issue: Unsafe structuredClone polyfill

This polyfill has several critical issues:

  • Cannot handle circular references (will throw)
  • Loses functions, Symbols, and other non-JSON-serializable values
  • Doesn't match the real structuredClone behavior

This could mask production bugs that only appear in Node 17+. Consider using a proper polyfill library like core-js-pure or at minimum add validation:

if (typeof global.structuredClone === 'undefined') {
  global.structuredClone = (value: any) => {
    try {
      return JSON.parse(JSON.stringify(value))
    } catch (e) {
      throw new Error(`structuredClone polyfill failed: ${e.message}`)
    }
  }
}

run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Performance Issue: Redundant test execution

This workflow runs tests twice:

  1. Line 49: pnpm test
  2. Line 52: pnpm test:coverage

The second run repeats all tests with coverage instrumentation. Consider running tests only once:

- name: Run tests with coverage
  run: pnpm test:coverage
  if: matrix.node-version == '20.x'

- name: Run tests (no coverage)
  run: pnpm test
  if: matrix.node-version == '18.x'

This would reduce CI time by ~50% for the Node 20.x job.

} from './index'

// Helper to create a test item
const createTestItem = (overrides: Partial<Item> = {}): Item => ({

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Code Quality: Duplicate helper function

The createTestItem helper is duplicated in both database/index.test.ts and export/zipExport.test.ts with identical implementations. Consider extracting to a shared file:

// src/test/helpers.ts
export const createTestItem = (overrides: Partial<Item> = {}): Item => ({
  id: `item-${Date.now()}-${Math.random()}`,
  type: 'text',
  content: 'Test content',
  source: {
    title: 'Test Page',
    url: 'https://example.com/test',
    site: 'example.com'
  },
  createdAt: Date.now(),
  ...overrides
})

This improves maintainability if the Item type changes.

describe('searchItems', () => {
beforeEach(async () => {
// Set up test data
await addItem(createTestItem({

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Performance Issue: Inefficient test setup

This beforeEach hook runs for all 8 tests in the searchItems suite, performing 24 database operations total (8 tests × 3 items).

Consider using beforeAll instead since these tests only read data:

beforeAll(async () => {
  await addItem(createTestItem({ /* ... */ }))
  await addItem(createTestItem({ /* ... */ }))
  await addItem(createTestItem({ /* ... */ }))
})

This reduces database operations by 87% (from 24 to 3).

await addItem(createTestItem({
id: 'image1',
type: 'image',
content: 'data:image/png;base64,xyz',

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Security Issue: Invalid base64 test data

The value 'xyz' is not valid base64. While this test doesn't exercise the export path, having invalid data could mask bugs. If this ever reaches dataUrlToBlob() in zipExport.ts, it would silently produce corrupted data.

Use a valid base64 image:

const validBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
content: `data:image/png;base64,${validBase64}`,

describe('database', () => {
beforeEach(() => {
// Clear IndexedDB before each test
indexedDB = new IDBFactory()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Performance Issue: Full database reinitialization

Resetting the entire IDBFactory for every test is expensive. With 26 database tests, this creates significant overhead.

Consider clearing only the data instead:

beforeEach(async () => {
  // Clear data without recreating the entire database
  const db = await openDb()
  const tx = db.transaction(['items', 'categories'], 'readwrite')
  tx.objectStore('items').clear()
  tx.objectStore('categories').clear()
  db.close()
})

This preserves the database schema and indexes, reducing setup time.

@minorcell

Copy link
Copy Markdown
Member Author

Code Review Summary

Excellent work on adding comprehensive test coverage! The test suite is well-organized with clear naming and good coverage of edge cases. The CI workflow follows best practices with matrix testing and caching.

Key Issues to Address:

  1. Security: Unsafe structuredClone polyfill in test setup could mask bugs
  2. Performance: CI runs tests twice (can save ~50% time on Node 20.x)
  3. Code Quality: Duplicate createTestItem helper across test files
  4. Performance: searchItems test suite repeats setup 8 times unnecessarily

Strengths:

  • Clear test organization with logical describe blocks
  • Comprehensive edge case coverage (duplicate prevention, filtering, etc.)
  • Proper mocking setup for IndexedDB and Chrome APIs
  • Good use of type safety throughout tests

All issues have inline comments with specific solutions. Great foundation for the project's testing infrastructure!

@minorcell

Copy link
Copy Markdown
Member Author

@codercellone 修复这个问题:

P1 Badge Keep pnpm lockfile in sync with new workflow step

The new CI job installs dependencies using pnpm install --frozen-lockfile (lines 26‑47), but this same commit also added new Jest dependencies and scripts to package.json without updating pnpm-lock.yaml. When pnpm runs with --frozen-lockfile and the lockfile is out of sync with package.json, it aborts with “Cannot install with frozen lockfile because pnpm-lock.yaml is not up to date,” so this workflow never reaches the test steps. Please update the pnpm lockfile (or drop the frozen flag) so the CI job introduced here can actually execute.

@minorcell
minorcell merged commit 914629b into main Nov 19, 2025
0 of 2 checks passed
@minorcell
minorcell deleted the xgopilot/claude/issue-64-1763533215 branch November 19, 2025 06:58
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