Skip to content

ci: add GitHub Actions workflow for PR testing with coverage#5

Open
wilcorrea wants to merge 7 commits intomainfrom
claude/github-actions-testing-R8et4
Open

ci: add GitHub Actions workflow for PR testing with coverage#5
wilcorrea wants to merge 7 commits intomainfrom
claude/github-actions-testing-R8et4

Conversation

@wilcorrea
Copy link
Contributor

@wilcorrea wilcorrea commented Feb 14, 2026

Add CI pipeline that runs all tests with coverage reports on pull
requests targeting main. Configure @vitest/coverage-v8 for core
and react packages with v8 provider.

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ

Plan

Goal

Set up a GitHub Actions CI pipeline that validates pull requests before merge by running
all tests with coverage reporting.

What was done

  1. Created .github/workflows/ci.yml

    • Triggers on pull requests targeting main
    • Uses concurrency with cancel-in-progress: true to avoid wasting resources on outdated runs
    • Matches the existing infrastructure: Node.js 20, pnpm 9 (same as docs.yml)
    • Steps: checkout → pnpm setup → Node setup with cache → install → build packages → run tests with coverage
  2. Installed @vitest/coverage-v8 in @ybyra/core and @ybyra/react (the two packages with tests)

  3. Created vitest.config.ts in both packages with v8 coverage provider configuration

    • Excludes test files, barrel exports, locale files, and mock utilities from coverage metrics

Coverage status

Current coverage levels:

Package Lines Branches Functions
@ybyra/core 56% 98% 46%
@ybyra/react 26% 87% 83%

The main gaps are in files that require integration/rendering context:

  • schema.ts (0%) — complex factory with runtime wiring
  • use-data-form.ts (0%) — React hook needing component context
  • use-data-table.ts (0%) — React hook needing component context
  • Several field definition classes with untested builder methods

Next steps to reach 80% coverage

  1. Add unit tests for schema.ts (factory methods, configure(), create())
  2. Add unit tests for field builder methods (action.ts, group.ts, scope.ts)
  3. Add integration tests for use-data-form.ts and use-data-table.ts using @testing-library/react
  4. Once coverage reaches ~80%, enable thresholds in vitest.config.ts:
    thresholds: {
      lines: 80,
      branches: 80,
      functions: 80,
      statements: 80,
    }
    

Summary by CodeRabbit

  • Chores

    • Added CI to run install, build, and tests with coverage on pull requests
    • Updated .gitignore to exclude coverage output
  • Tests

    • Added per-package test configurations with V8 coverage and 80% thresholds
    • Introduced extensive unit and integration tests across core, UI, persistence, and demo packages
  • New Features

    • Expanded public API with additional field types and grouping utilities

Add CI pipeline that runs all tests with coverage reports on pull
requests targeting main. Configure @vitest/coverage-v8 for core
and react packages with v8 provider.

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ
@coderabbitai
Copy link

coderabbitai bot commented Feb 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a GitHub Actions CI workflow, Vitest coverage configs and coverage ignore rules, updates test/dev dependencies, and introduces many new unit tests across core, react, demo, persistence, svelte, and vue packages.

Changes

Cohort / File(s) Summary
CI Workflow
\.github/workflows/ci.yml
Adds a GitHub Actions workflow for PRs to main: concurrency group, job test on ubuntu-latest that checks out code, sets up pnpm v9 and Node 20 (with caching), installs deps, builds ./packages, and runs tests with coverage.
Ignore Rules
\.gitignore
Adds coverage/ and .coverage/ entries under a Coverage section.
Vitest Configs
packages/core/vitest.config.ts, packages/react/vitest.config.ts
New Vitest configs enabling V8 coverage, include src/**/*.ts, exclude test/index/types/mock/locales patterns, and enforce 80% thresholds for lines/branches/functions/statements.
Package Manifests
packages/core/package.json, packages/react/package.json, packages/demo/package.json
Adds @vitest/coverage-v8 to core; updates react devDependencies (vitest, @testing-library/react, jsdom, coverage plugin, react/react-dom versions); adds test script and vitest devDep in demo. Minor formatting changes.
Core tests
packages/core/src/fields.test.ts, packages/core/src/schema.test.ts, packages/core/src/scope.test.ts
Adds extensive unit tests covering field factories/definitions, schema composition/configure behavior, scope utilities, initial state building, and many type/behavior assertions.
React tests
packages/react/src/use-data-form.test.ts, packages/react/src/use-data-table.test.ts, packages/react/src/validation.test.ts
Adds comprehensive tests for hooks and validators: initialization, scoping, grouping, actions, fetching, pagination, selection, validation, translations, and bootstrap lifecycle.
Demo tests & handlers
packages/demo/src/.../events.test.ts, packages/demo/src/.../schema.test.ts, packages/demo/src/settings/handlers.test.ts, packages/demo/src/settings/hooks.test.ts
Adds tests for domain events, person schema, settings handlers and hooks covering navigation, CRUD flows, bootstrap/fetch behavior, and side effects.
Persistence tests
packages/persistence/src/web-driver.test.ts
Adds in-memory tests for web-driver persistence: init, create/read/update/destroy, search with pagination and sorting, and storage key behavior.
Svelte tests
packages/svelte/src/icons.test.ts, packages/svelte/src/proxy.test.ts, packages/svelte/src/registry.test.ts, packages/svelte/src/translate.test.ts, packages/svelte/src/validation.test.ts
Adds tests for icons resolution, state/schema proxy behavior, renderer registry isolation, translation helpers, and validation utilities.
Vue tests
packages/vue/src/icons.test.ts, packages/vue/src/proxy.test.ts, packages/vue/src/registry.test.ts, packages/vue/src/translate.test.ts, packages/vue/src/validation.test.ts
Adds analogous tests for icons, proxies, registry, translate helpers, and validation in the Vue package.

Sequence Diagram(s)

sequenceDiagram
    participant GH as "GitHub Actions"
    participant Repo as "Repository"
    participant Runner as "Ubuntu Runner"
    participant Checkout as "actions/checkout"
    participant PNPM as "pnpm (v9, cache)"
    participant Node as "Node.js (v20, cache)"
    participant Build as "Build ./packages"
    participant Vitest as "Vitest (V8 coverage)"

    GH->>Repo: trigger on pull_request to main
    GH->>Runner: start job "test"
    Runner->>Checkout: checkout repository
    Runner->>PNPM: setup pnpm (restore/cache)
    Runner->>Node: setup Node.js (restore/cache)
    Runner->>PNPM: install dependencies
    Runner->>Build: build ./packages
    Runner->>Vitest: run tests with coverage
    Vitest-->>Runner: emit coverage report
    Runner-->>GH: report job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through code with tiny paws,

Workflows stitched and test-run laws,
Coverage carrots neatly stored,
Pipelines hum — the build's restored,
🥕 Cheers from a rabbit, CI adored.

🚥 Pre-merge checks | ✅ 3 | ❌ 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 (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a GitHub Actions workflow for CI testing with coverage reporting. The title directly relates to the primary modification across the changeset.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/github-actions-testing-R8et4

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

Add comprehensive tests for previously uncovered core modules:
- schema.test.ts: SchemaDefinition, configure(), extend/pick/omit
- scope.test.ts: buildInitialState(), isInScope()
- fields.test.ts: action variants/positioning/scopes, base field
  methods (hidden, disabled, group, scopes, column, etc.), and all
  field types (date, datetime, number, currency, file, toggle, checkbox)

Enable 80% coverage thresholds in vitest.config.ts for CI enforcement.
Core coverage: 56% → 99.56% lines.

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ
- Fill validation.ts gaps: minTime, maxTime, minItems, maxItems,
  required empty array
- Create use-data-form.test.ts: 47 tests covering state, scoping,
  groups, sections, setValue, validation, dirty/valid, actions,
  getFieldProps, fireEvent, bootstrap, translate, permitted
- Create use-data-table.test.ts: 41 tests covering columns,
  toggleColumn, fetch/reload, setSort, setFilter, setLimit, selection,
  formatValue, actions, getRowActions, permitted
- Add @testing-library/react and react-dom as dev dependencies
- Enable 80% coverage thresholds in vitest.config.ts
React coverage: 26% → 99.73% lines.

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ
Add comprehensive test suites for packages that previously had no tests:
- @ybyra/persistence: web-driver CRUD, pagination, and sorting tests
- @ybyra/demo: schema, events, handlers, hooks, and allPermissions tests
- @ybyra/svelte: validation, proxy, registry, translate, and icons tests
- @ybyra/vue: validation, proxy, registry, translate, and icons tests

230 new tests across 16 test files, all passing.

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ
Copy link

@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

🤖 Fix all issues with AI agents
In `@packages/demo/src/domain/person/events.test.ts`:
- Around line 57-67: The test for personEvents.active.change is missing
assertions that verify address fields are enabled; after calling
personEvents.active.change({ state, schema }) add assertions that
schema.street.disabled is false and schema.city.disabled is false so the test
verifies the handler enables those address fields when state.active is true
(keep existing birthDate.hidden assertion intact).

In `@packages/persistence/src/web-driver.test.ts`:
- Around line 1-22: Move the global mocks out of module scope into a proper
setup/teardown: save originals (const _origLocalStorage =
globalThis.localStorage, _origCrypto = globalThis.crypto) then in a beforeAll
define mocks via Object.defineProperty for 'localStorage' and 'crypto' with
configurable: true and writable: true and initialize the in-test storage; ensure
any per-test state is reset in beforeEach (e.g., clear the storage object);
finally restore the originals in afterAll by defining globalThis.localStorage =
_origLocalStorage and globalThis.crypto = _origCrypto (or re-define with
Object.defineProperty) so other suites are not affected.

In `@packages/svelte/src/icons.test.ts`:
- Around line 1-2: Add the missing coverage provider by adding the dependency
"@vitest/coverage-v8": "^3.0.0" to the svelte package's package.json
devDependencies; after adding it run install to update the lockfile so CI picks
up the new devDependency.

In `@packages/svelte/src/proxy.test.ts`:
- Around line 1-3: Add the missing `@vitest/coverage-v8` dependency (version
^3.0.0) to the svelte package's package.json under the devDependencies object so
the workspace-wide coverage run finds the reporter; update devDependencies to
include "@vitest/coverage-v8": "^3.0.0" and re-install/update the lockfile so
`pnpm -r test -- --coverage` succeeds in CI.

In `@packages/svelte/src/registry.test.ts`:
- Around line 1-3: Add the missing dev dependency "@vitest/coverage-v8" to the
svelte package's package.json devDependencies (use version "^3.0.0") so Vitest
coverage runs in `@ybyra/svelte`; update the devDependencies object to include
"@vitest/coverage-v8": "^3.0.0" and run install to ensure tests/CI pass.

In `@packages/svelte/src/translate.test.ts`:
- Around line 1-7: Add the missing devDependency "@vitest/coverage-v8" to the
svelte package's package.json devDependencies so vitest can collect coverage;
ensure the version matches the one used in the other packages (e.g., core/react)
to keep dependency versions consistent.

In `@packages/vue/src/translate.test.ts`:
- Around line 1-58: The Vue package is missing the `@vitest/coverage-v8`
devDependency which can break CI coverage reporting; add "@vitest/coverage-v8":
"<appropriate-version>" to the devDependencies of the packages/vue package.json
(matching the version used in the Svelte package), then run npm/yarn install and
re-run tests; verify resolveFieldLabel, resolveGroupLabel, and
resolveActionLabel tests still pass.
🧹 Nitpick comments (4)
packages/demo/src/support/allPermissions.test.ts (1)

29-51: Consider extracting a factory for action objects to reduce boilerplate.

The action configuration object is repeated verbatim across multiple tests. A small helper would improve readability and make it easier to adjust if the ActionProvide shape changes.

♻️ Suggested helper to reduce repetition
+function makeAction(overrides: Partial<{ open: boolean }> = {}) {
+  return {
+    variant: 'primary' as const,
+    positions: [],
+    align: 'end' as const,
+    hidden: false,
+    open: false,
+    scopes: null,
+    order: 0,
+    ...overrides,
+  }
+}
+
 describe('allPermissions', () => {
   // ...
   it('generates action permissions for non-open actions', () => {
     const schema = makeSchema({
       actions: {
-        create: { variant: 'primary', positions: [], align: 'end', hidden: false, open: false, scopes: null, order: 0 },
-        update: { variant: 'primary', positions: [], align: 'end', hidden: false, open: false, scopes: null, order: 0 },
+        create: makeAction(),
+        update: makeAction(),
       },
     })
     // ...
   })

   it('excludes open actions from permissions', () => {
     const schema = makeSchema({
       actions: {
-        add: { variant: 'primary', positions: [], align: 'end', hidden: false, open: true, scopes: null, order: 0 },
-        create: { variant: 'primary', positions: [], align: 'end', hidden: false, open: false, scopes: null, order: 0 },
+        add: makeAction({ open: true }),
+        create: makeAction(),
       },
     })
     // ...
   })
 })
packages/demo/src/settings/handlers.test.ts (1)

90-135: Consider awaiting async handlers in create and update tests.

The destroy tests correctly use async/await and mockResolvedValue, but create and update tests don't await the handler calls. If these handlers perform async operations internally (like the service calls), assertions may run before the handler completes, potentially leading to flaky tests or false positives.

For consistency with the destroy tests:

♻️ Suggested changes for create test
-    it('validates form and creates record on success', () => {
+    it('validates form and creates record on success', async () => {
       const service = makeService()
+      service.create.mockResolvedValue({ id: '1', name: 'Alice' })
       const handlers = createDefault(service)
       const component = makeComponent()
       const form: FormContract = { errors: {}, dirty: true, valid: true, validate: vi.fn().mockReturnValue(true), reset: vi.fn() }
-      handlers.create({ state: { name: 'Alice' }, component, form } as HandlerContext)
+      await handlers.create({ state: { name: 'Alice' }, component, form } as HandlerContext)
♻️ Suggested changes for update test
-    it('validates form and updates record on success', () => {
+    it('validates form and updates record on success', async () => {
       const service = makeService()
+      service.update.mockResolvedValue({ id: '1', name: 'Bob' })
       const handlers = createDefault(service)
       const component = makeComponent()
       const form: FormContract = { errors: {}, dirty: true, valid: true, validate: vi.fn().mockReturnValue(true), reset: vi.fn() }
-      handlers.update({ state: { id: '1', name: 'Bob' }, component, form } as HandlerContext)
+      await handlers.update({ state: { id: '1', name: 'Bob' }, component, form } as HandlerContext)
packages/demo/src/domain/person/events.test.ts (1)

20-81: Consider extracting repeated schema setup.

The same schema structure is defined in 5 tests within active.change. Extracting a helper function would reduce duplication and make future schema changes easier.

♻️ Optional: Extract schema setup helper
   describe('active.change', () => {
+    const createSchema = (overrides: Partial<Record<string, Record<string, unknown>>> = {}) => ({
+      name: { state: '', width: 100 },
+      birthDate: { hidden: false },
+      street: { disabled: false },
+      city: { disabled: false },
+      ...overrides,
+    })
+
     it('reverses name', () => {
       const state: Record<string, unknown> = { name: 'Alice', active: true }
-      const schema: Record<string, Record<string, unknown>> = {
-        name: { state: '', width: 100 },
-        birthDate: { hidden: false },
-        street: { disabled: false },
-        city: { disabled: false },
-      }
+      const schema = createSchema()
       personEvents.active.change({ state, schema })
       expect(state.name).toBe('ecilA')
     })
packages/persistence/src/web-driver.test.ts (1)

152-158: Pin the null‑sorting behavior explicitly.

The test only checks length; adding order assertions will lock in the intended null placement for ascending sorts.

✅ Suggested assertion
     const result = await driver.search(meta, { page: 1, limit: 10, sort: 'name', order: 'asc' })
     expect(result.data).toHaveLength(2)
+    expect(result.data[0].name).toBe('Alice')
+    expect(result.data[1].name).toBeNull()

Comment on lines +57 to +67
it('shows birthDate when active is true', () => {
const state: Record<string, unknown> = { name: 'Alice', active: true }
const schema: Record<string, Record<string, unknown>> = {
name: { state: '', width: 100 },
birthDate: { hidden: true },
street: { disabled: true },
city: { disabled: true },
}
personEvents.active.change({ state, schema })
expect(schema.birthDate.hidden).toBe(false)
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing assertion for address fields enabled state.

This test sets up street and city with disabled: true but only asserts on birthDate.hidden. To ensure the active.change handler correctly enables address fields when active is true, add assertions for street and city.

🧪 Proposed fix to add missing assertions
       personEvents.active.change({ state, schema })
       expect(schema.birthDate.hidden).toBe(false)
+      expect(schema.street.disabled).toBe(false)
+      expect(schema.city.disabled).toBe(false)
     })
🤖 Prompt for AI Agents
In `@packages/demo/src/domain/person/events.test.ts` around lines 57 - 67, The
test for personEvents.active.change is missing assertions that verify address
fields are enabled; after calling personEvents.active.change({ state, schema })
add assertions that schema.street.disabled is false and schema.city.disabled is
false so the test verifies the handler enables those address fields when
state.active is true (keep existing birthDate.hidden assertion intact).

Comment on lines +1 to +22
import { describe, it, expect, beforeEach } from 'vitest'
import { createWebDriver } from './web-driver'
import type { PersistenceMeta } from '@ybyra/core'

const storage: Record<string, string> = {}

Object.defineProperty(globalThis, 'localStorage', {
value: {
getItem: (key: string) => storage[key] ?? null,
setItem: (key: string, value: string) => { storage[key] = value },
removeItem: (key: string) => { delete storage[key] },
clear: () => { for (const key of Object.keys(storage)) delete storage[key] },
},
writable: true,
})

Object.defineProperty(globalThis, 'crypto', {
value: {
randomUUID: () => 'test-uuid-1234',
},
writable: true,
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and view its full content
cd /tmp && find . -name "web-driver.test.ts" -type f 2>/dev/null || echo "File not found, listing repository structure"

Repository: devitools/ybyra

Length of output: 41


🏁 Script executed:

# List the persistence package structure
ls -la packages/persistence/src/ 2>/dev/null | head -20 || echo "Directory check failed"

Repository: devitools/ybyra

Length of output: 424


🏁 Script executed:

# Search for the test file
git ls-files | grep -E "web-driver.test.ts|web-driver.ts" || echo "Files not found in git"

Repository: devitools/ybyra

Length of output: 141


🏁 Script executed:

# Read the full test file
cat -n packages/persistence/src/web-driver.test.ts

Repository: devitools/ybyra

Length of output: 6973


🏁 Script executed:

# Check for other test files in the persistence package
find packages/persistence -name "*.test.ts" -o -name "*.spec.ts" | sort

Repository: devitools/ybyra

Length of output: 102


🏁 Script executed:

# Check vitest config to understand test isolation
find . -name "vitest.config.*" -o -name "vite.config.*" | head -5

Repository: devitools/ybyra

Length of output: 242


🏁 Script executed:

# Check if persistence has a vitest config
ls -la packages/persistence/ | grep -E "vitest|vite"

Repository: devitools/ybyra

Length of output: 41


🏁 Script executed:

# Check the web-driver implementation to understand what it uses
head -30 packages/persistence/src/web-driver.ts

Repository: devitools/ybyra

Length of output: 1211


🏁 Script executed:

# Check if there's a root vitest config that might affect all tests
find . -maxdepth 2 -name "vitest.config.*" -o -name "vite.config.*" | xargs ls -l 2>/dev/null | head -10

Repository: devitools/ybyra

Length of output: 631


🏁 Script executed:

# Test Node.js behavior with globalThis.crypto
node <<'EOF'
const originalDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'crypto');
console.log('Original crypto descriptor:', originalDescriptor);

// Try to reconfigure (like the test does)
try {
  Object.defineProperty(globalThis, 'crypto', {
    value: { randomUUID: () => 'mock' },
    writable: true,
    configurable: true  // note: not in original
  });
  console.log('✓ Successfully reconfigured crypto with configurable:true');
  console.log('Current crypto.randomUUID:', globalThis.crypto.randomUUID());
  
  // Try to restore
  if (originalDescriptor) {
    Object.defineProperty(globalThis, 'crypto', originalDescriptor);
    console.log('✓ Successfully restored crypto');
  }
} catch (e) {
  console.log('✗ Error:', e.message);
}

// Now test without configurable:true (as in the code)
const testDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'crypto');
console.log('\nTrying to redefine without configurable:true...');
try {
  Object.defineProperty(globalThis, 'crypto', {
    value: { randomUUID: () => 'mock2' },
    writable: true
    // no configurable: true
  });
  console.log('✓ Redefined without configurable:true');
} catch (e) {
  console.log('✗ Error:', e.message);
}
EOF

Repository: devitools/ybyra

Length of output: 388


🏁 Script executed:

# Check what Node version and test environment context
cat packages/persistence/package.json 2>/dev/null || cat package.json | grep -A 5 -B 5 '"vitest"'

Repository: devitools/ybyra

Length of output: 815


🏁 Script executed:

# Look at the actual test running environment - check if there's a root config
cat vitest.config.ts 2>/dev/null || cat vite.config.ts 2>/dev/null || echo "No root config"

Repository: devitools/ybyra

Length of output: 73


Move mocks to beforeAll/afterAll for proper test isolation and restoration.

Mocking globals at module scope without restoration is poor practice. While globalThis.crypto is configurable in Node.js, the mock lacks configurable: true on the descriptor, making restoration more fragile. More importantly, the current setup doesn't restore the originals after tests, which can affect subsequent test suites if run in a shared process. Use beforeAll to set up mocks with proper descriptors and afterAll to restore originals.

🔧 Suggested hardening (isolation + restoration)
-import { describe, it, expect, beforeEach } from 'vitest'
+import { describe, it, expect, beforeEach, beforeAll, afterAll, vi } from 'vitest'
 import { createWebDriver } from './web-driver'
 import type { PersistenceMeta } from '@ybyra/core'

 const storage: Record<string, string> = {}
+const originalLocalStorage = Object.getOwnPropertyDescriptor(globalThis, 'localStorage')
+const originalCrypto = Object.getOwnPropertyDescriptor(globalThis, 'crypto')
+let randomUuidSpy: ReturnType<typeof vi.spyOn> | undefined

-Object.defineProperty(globalThis, 'localStorage', {
-  value: {
-    getItem: (key: string) => storage[key] ?? null,
-    setItem: (key: string, value: string) => { storage[key] = value },
-    removeItem: (key: string) => { delete storage[key] },
-    clear: () => { for (const key of Object.keys(storage)) delete storage[key] },
-  },
-  writable: true,
-})
-
-Object.defineProperty(globalThis, 'crypto', {
-  value: {
-    randomUUID: () => 'test-uuid-1234',
-  },
-  writable: true,
-})
+beforeAll(() => {
+  Object.defineProperty(globalThis, 'localStorage', {
+    value: {
+      getItem: (key: string) => storage[key] ?? null,
+      setItem: (key: string, value: string) => { storage[key] = value },
+      removeItem: (key: string) => { delete storage[key] },
+      clear: () => { for (const key of Object.keys(storage)) delete storage[key] },
+    },
+    writable: true,
+    configurable: true,
+  })
+
+  if (globalThis.crypto?.randomUUID) {
+    randomUuidSpy = vi.spyOn(globalThis.crypto, 'randomUUID').mockReturnValue('test-uuid-1234')
+  } else {
+    Object.defineProperty(globalThis, 'crypto', {
+      value: { randomUUID: () => 'test-uuid-1234' },
+      writable: true,
+      configurable: true,
+    })
+  }
+})
+
+afterAll(() => {
+  randomUuidSpy?.mockRestore()
+  if (originalLocalStorage) Object.defineProperty(globalThis, 'localStorage', originalLocalStorage)
+  else delete (globalThis as { localStorage?: unknown }).localStorage
+  if (originalCrypto) Object.defineProperty(globalThis, 'crypto', originalCrypto)
+  else delete (globalThis as { crypto?: unknown }).crypto
+})
🤖 Prompt for AI Agents
In `@packages/persistence/src/web-driver.test.ts` around lines 1 - 22, Move the
global mocks out of module scope into a proper setup/teardown: save originals
(const _origLocalStorage = globalThis.localStorage, _origCrypto =
globalThis.crypto) then in a beforeAll define mocks via Object.defineProperty
for 'localStorage' and 'crypto' with configurable: true and writable: true and
initialize the in-test storage; ensure any per-test state is reset in beforeEach
(e.g., clear the storage object); finally restore the originals in afterAll by
defining globalThis.localStorage = _origLocalStorage and globalThis.crypto =
_origCrypto (or re-define with Object.defineProperty) so other suites are not
affected.

Comment on lines +1 to +2
import { describe, it, expect, beforeEach } from 'vitest'
import { configureIcons, resolveActionIcon, resolveGroupIcon } from './icons'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Verify whether `@vitest/coverage-v8` is present in any package.json
rg -n "@vitest/coverage-v8" -g 'package.json'

# Locate the `@ybyra/svelte` package manifest
rg -n "\"name\"\\s*:\\s*\"@ybyra/svelte\"" -g 'package.json' -C 2

Repository: devitools/ybyra

Length of output: 688


🏁 Script executed:

# Read the full packages/svelte/package.json to confirm `@vitest/coverage-v8` is missing
cat packages/svelte/package.json

# Also check if there's a workspace root configuration
cat package.json | head -40

Repository: devitools/ybyra

Length of output: 2221


Add @vitest/coverage-v8 to @ybyra/svelte devDependencies.

The coverage provider is missing from packages/svelte/package.json. All other packages in the monorepo include it. Add "@vitest/coverage-v8": "^3.0.0" to the devDependencies of packages/svelte/package.json to resolve the CI coverage failure.

🧰 Tools
🪛 GitHub Actions: CI

[error] 1-1: pnpm recursive run failed: 'vitest run --passWithNoTests --coverage' exited with code 1 in @ybyra/svelte. Cause: Cannot find package '@vitest/coverage-v8'.


[error] 1-1: Cannot find package '@vitest/coverage-v8' required to collect coverage. Ensure @vitest/coverage-v8 is installed or correctly configured.

🤖 Prompt for AI Agents
In `@packages/svelte/src/icons.test.ts` around lines 1 - 2, Add the missing
coverage provider by adding the dependency "@vitest/coverage-v8": "^3.0.0" to
the svelte package's package.json devDependencies; after adding it run install
to update the lockfile so CI picks up the new devDependency.

Comment on lines +1 to +3
import { describe, it, expect } from 'vitest'
import { createStateProxy, createSchemaProxy } from './proxy'
import type { FieldConfig } from '@ybyra/core'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check where `@vitest/coverage-v8` is declared across all package.json files
echo "=== Searching for `@vitest/coverage-v8` in package.json files ==="
rg -n '"@vitest/coverage-v8"' -g 'package.json'

echo -e "\n=== List all package.json files ==="
fd 'package.json$'

Repository: devitools/ybyra

Length of output: 1068


🏁 Script executed:

#!/bin/bash
# Examine the structure of packages/svelte and its package.json
echo "=== Contents of packages/svelte/package.json ==="
cat packages/svelte/package.json

echo -e "\n=== Check root package.json for workspace config ==="
head -50 package.json

Repository: devitools/ybyra

Length of output: 2324


🏁 Script executed:

#!/bin/bash
# Check if CI is configured to run with coverage
echo "=== Check for vitest config files in packages/svelte ==="
fd 'vitest|vite' packages/svelte/ --type f

echo -e "\n=== Check CI workflow files for coverage flags ==="
find .github/workflows -name '*.yml' -o -name '*.yaml' | head -5 | xargs -I {} bash -c 'echo "File: {}" && grep -A2 -B2 "vitest\|coverage" {} 2>/dev/null || echo "No vitest/coverage config"'

Repository: devitools/ybyra

Length of output: 387


Add @vitest/coverage-v8 to packages/svelte devDependencies.

CI failure: the pnpm -r test -- --coverage command in .github/workflows/ci.yml runs tests with coverage across all packages, but @vitest/coverage-v8 is missing from packages/svelte/package.json. Add it to devDependencies (version ^3.0.0 to match other packages like packages/core).

🧰 Tools
🪛 GitHub Actions: CI

[error] 1-1: pnpm recursive run failed: 'vitest run --passWithNoTests --coverage' exited with code 1 in @ybyra/svelte. Cause: Cannot find package '@vitest/coverage-v8'.


[error] 1-1: Cannot find package '@vitest/coverage-v8' required to collect coverage. Ensure @vitest/coverage-v8 is installed or correctly configured.

🤖 Prompt for AI Agents
In `@packages/svelte/src/proxy.test.ts` around lines 1 - 3, Add the missing
`@vitest/coverage-v8` dependency (version ^3.0.0) to the svelte package's
package.json under the devDependencies object so the workspace-wide coverage run
finds the reporter; update devDependencies to include "@vitest/coverage-v8":
"^3.0.0" and re-install/update the lockfile so `pnpm -r test -- --coverage`
succeeds in CI.

Comment on lines +1 to +3
import { describe, it, expect } from 'vitest'
import { registerRenderers, getRenderer, createRegistry } from './registry'
import type { FieldRenderer } from './types'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's find all package.json files in packages directory
echo "=== All packages with package.json ==="
fd 'package.json' packages/

echo ""
echo "=== Checking for `@vitest/coverage-v8` in devDependencies ==="
for pkg_file in $(fd 'package.json' packages/); do
  dir=$(dirname "$pkg_file")
  pkg_name=$(jq -r '.name' "$pkg_file")
  has_coverage=$(jq '.devDependencies["@vitest/coverage-v8"]' "$pkg_file" 2>/dev/null)
  echo "$pkg_name: `@vitest/coverage-v8` = $has_coverage"
done

echo ""
echo "=== Full devDependencies for `@ybyra/svelte` ==="
cat packages/svelte/package.json | jq '.devDependencies' 2>/dev/null || echo "File not found"

echo ""
echo "=== Full devDependencies for `@ybyra/core` ==="
cat packages/core/package.json | jq '.devDependencies' 2>/dev/null || echo "File not found"

echo ""
echo "=== Full devDependencies for `@ybyra/react` ==="
cat packages/react/package.json | jq '.devDependencies' 2>/dev/null || echo "File not found"

Repository: devitools/ybyra

Length of output: 1549


CI is failing: missing @vitest/coverage-v8 dependency in @ybyra/svelte.

The pipeline error indicates that @vitest/coverage-v8 is not installed in this package. The PR description mentions coverage was added to @ybyra/core and @ybyra/react, but @ybyra/svelte was not included.

Add the dev dependency to packages/svelte/package.json:

"devDependencies": {
  "@vitest/coverage-v8": "^3.0.0"
}
🧰 Tools
🪛 GitHub Actions: CI

[error] 1-1: pnpm recursive run failed: 'vitest run --passWithNoTests --coverage' exited with code 1 in @ybyra/svelte. Cause: Cannot find package '@vitest/coverage-v8'.


[error] 1-1: Cannot find package '@vitest/coverage-v8' required to collect coverage. Ensure @vitest/coverage-v8 is installed or correctly configured.

🤖 Prompt for AI Agents
In `@packages/svelte/src/registry.test.ts` around lines 1 - 3, Add the missing dev
dependency "@vitest/coverage-v8" to the svelte package's package.json
devDependencies (use version "^3.0.0") so Vitest coverage runs in `@ybyra/svelte`;
update the devDependencies object to include "@vitest/coverage-v8": "^3.0.0" and
run install to ensure tests/CI pass.

Comment on lines +1 to +7
import { describe, it, expect } from 'vitest'
import { resolveFieldLabel, resolveGroupLabel, resolveActionLabel } from './translate'
import type { TranslateContract } from '@ybyra/core'

function createTranslate(translations: Record<string, string>): TranslateContract {
return (key: string) => translations[key] ?? key
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check which packages have `@vitest/coverage-v8` installed
echo "=== Packages with `@vitest/coverage-v8` ==="
rg '"@vitest/coverage-v8"' --glob 'packages/*/package.json' -l

echo ""
echo "=== Packages with vitest.config.ts ==="
fd vitest.config.ts packages/

echo ""
echo "=== Check svelte package.json devDependencies ==="
cat packages/svelte/package.json | grep -A 20 '"devDependencies"'

echo ""
echo "=== Check svelte/vitest.config.ts if it exists ==="
if [ -f packages/svelte/vitest.config.ts ]; then
  cat packages/svelte/vitest.config.ts
else
  echo "packages/svelte/vitest.config.ts does not exist"
fi

Repository: devitools/ybyra

Length of output: 647


🏁 Script executed:

#!/bin/bash
echo "=== Root vitest.config files ==="
fd vitest.config --glob 'vitest.config.*' | grep -v packages

echo ""
echo "=== Root package.json vitest/test config ==="
cat package.json | grep -A 30 '"vitest"' || cat package.json | grep -A 30 '"test"'

echo ""
echo "=== Check if workspaces are configured ==="
cat package.json | grep -A 10 '"workspaces"'

Repository: devitools/ybyra

Length of output: 1715


🏁 Script executed:

#!/bin/bash
echo "=== Svelte package.json scripts section ==="
cat packages/svelte/package.json | grep -A 5 '"scripts"'

echo ""
echo "=== Core vitest.config.ts ==="
cat packages/core/vitest.config.ts

echo ""
echo "=== React vitest.config.ts ==="
cat packages/react/vitest.config.ts

echo ""
echo "=== CI config files ==="
find . -path ./.git -prune -o -name '*.yml' -o -name '*.yaml' | grep -E '(github|gitlab|circleci|workflow)' | head -20

Repository: devitools/ybyra

Length of output: 1186


🏁 Script executed:

#!/bin/bash
echo "=== CI workflow content ==="
cat .github/workflows/ci.yml

Repository: devitools/ybyra

Length of output: 625


Missing @vitest/coverage-v8 dependency blocks CI for @ybyra/svelte.

The CI workflow runs pnpm -r test -- --coverage across all packages, which passes the coverage flag to vitest. The svelte package lacks @vitest/coverage-v8 in its devDependencies, causing the test step to fail when vitest attempts to collect coverage metrics.

Add @vitest/coverage-v8 to the devDependencies in packages/svelte/package.json, matching the configuration in packages/core and packages/react.

🧰 Tools
🪛 GitHub Actions: CI

[error] 1-1: pnpm recursive run failed: 'vitest run --passWithNoTests --coverage' exited with code 1 in @ybyra/svelte. Cause: Cannot find package '@vitest/coverage-v8'.


[error] 1-1: Cannot find package '@vitest/coverage-v8' required to collect coverage. Ensure @vitest/coverage-v8 is installed or correctly configured.

🤖 Prompt for AI Agents
In `@packages/svelte/src/translate.test.ts` around lines 1 - 7, Add the missing
devDependency "@vitest/coverage-v8" to the svelte package's package.json
devDependencies so vitest can collect coverage; ensure the version matches the
one used in the other packages (e.g., core/react) to keep dependency versions
consistent.

Comment on lines +1 to +58
import { describe, it, expect } from 'vitest'
import { resolveFieldLabel, resolveGroupLabel, resolveActionLabel } from './translate'
import type { TranslateContract } from '@ybyra/core'

function createTranslate(translations: Record<string, string>): TranslateContract {
return (key: string) => translations[key] ?? key
}

describe('resolveFieldLabel', () => {
it('returns state-specific translation when available', () => {
const t = createTranslate({ 'person.fields.name[editing]': 'Name (editing)' })
expect(resolveFieldLabel(t, 'person', 'name', 'editing')).toBe('Name (editing)')
})

it('falls back to base field key', () => {
const t = createTranslate({ 'person.fields.name': 'Full Name' })
expect(resolveFieldLabel(t, 'person', 'name', 'editing')).toBe('Full Name')
})

it('falls back to raw field name', () => {
const t = createTranslate({})
expect(resolveFieldLabel(t, 'person', 'name', 'editing')).toBe('name')
})

it('resolves base key when no state', () => {
const t = createTranslate({ 'person.fields.name': 'Full Name' })
expect(resolveFieldLabel(t, 'person', 'name', '')).toBe('Full Name')
})
})

describe('resolveGroupLabel', () => {
it('returns translation when key resolves', () => {
const t = createTranslate({ 'person.groups.personal': 'Personal Info' })
expect(resolveGroupLabel(t, 'person', 'personal')).toBe('Personal Info')
})

it('falls back to raw group name', () => {
const t = createTranslate({})
expect(resolveGroupLabel(t, 'person', 'personal')).toBe('personal')
})
})

describe('resolveActionLabel', () => {
it('returns domain-specific translation', () => {
const t = createTranslate({ 'person.actions.save': 'Save Person' })
expect(resolveActionLabel(t, 'person', 'save')).toBe('Save Person')
})

it('falls back to common action', () => {
const t = createTranslate({ 'common.actions.save': 'Save' })
expect(resolveActionLabel(t, 'person', 'save')).toBe('Save')
})

it('falls back to raw action name', () => {
const t = createTranslate({})
expect(resolveActionLabel(t, 'person', 'save')).toBe('save')
})
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check Vue package.json for coverage dependency
grep -A2 -B2 '@vitest/coverage-v8' packages/vue/package.json || echo "NOT FOUND in Vue package"

Repository: devitools/ybyra

Length of output: 83


🏁 Script executed:

# Also check the current devDependencies in Vue package
cat packages/vue/package.json | grep -A 20 '"devDependencies"'

Repository: devitools/ybyra

Length of output: 293


🏁 Script executed:

# Verify Svelte test file exists for comparison
cat packages/svelte/src/translate.test.ts | head -30

Repository: devitools/ybyra

Length of output: 1220


Add @vitest/coverage-v8 dependency to packages/vue/package.json.

The tests correctly mirror the Svelte implementation with proper translation key resolution fallback chains. However, the Vue package is missing the @vitest/coverage-v8 coverage dependency present in the Svelte package, which may cause CI failures when coverage reporting is configured.

🤖 Prompt for AI Agents
In `@packages/vue/src/translate.test.ts` around lines 1 - 58, The Vue package is
missing the `@vitest/coverage-v8` devDependency which can break CI coverage
reporting; add "@vitest/coverage-v8": "<appropriate-version>" to the
devDependencies of the packages/vue package.json (matching the version used in
the Svelte package), then run npm/yarn install and re-run tests; verify
resolveFieldLabel, resolveGroupLabel, and resolveActionLabel tests still pass.

Add comprehensive test suites for hooks and remaining gaps:
- @ybyra/svelte: use-data-form (47 tests), use-data-table (41 tests) -> 98.8% coverage
- @ybyra/vue: use-data-form (47 tests), use-data-table (41 tests) -> 98.7% coverage
- @ybyra/persistence: local-driver with expo-sqlite mocks (18 tests) -> 98.3% coverage
- @ybyra/demo: person handlers, hooks, personService (17 tests) -> 94.8% coverage

All 960 tests pass across 10 packages/playgrounds.

Coverage summary:
  core: 99.5% | react: 99.7% | svelte: 98.8%
  vue: 98.7%  | persistence: 98.3% | demo: 94.8%

https://claude.ai/code/session_01DcGDGNKmyUHf1DRxxeLGPZ
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