ci: add GitHub Actions workflow for PR testing with coverage#5
ci: add GitHub Actions workflow for PR testing with coverage#5
Conversation
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
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
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
There was a problem hiding this comment.
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
ActionProvideshape 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 increateandupdatetests.The
destroytests correctly useasync/awaitandmockResolvedValue, butcreateandupdatetests 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
destroytests:♻️ 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()
| 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) | ||
| }) |
There was a problem hiding this comment.
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).
| 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, | ||
| }) |
There was a problem hiding this comment.
🧩 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.tsRepository: 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" | sortRepository: devitools/ybyra
Length of output: 102
🏁 Script executed:
# Check vitest config to understand test isolation
find . -name "vitest.config.*" -o -name "vite.config.*" | head -5Repository: 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.tsRepository: 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 -10Repository: 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);
}
EOFRepository: 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.
| import { describe, it, expect, beforeEach } from 'vitest' | ||
| import { configureIcons, resolveActionIcon, resolveGroupIcon } from './icons' |
There was a problem hiding this comment.
🧩 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 2Repository: 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 -40Repository: 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.
| import { describe, it, expect } from 'vitest' | ||
| import { createStateProxy, createSchemaProxy } from './proxy' | ||
| import type { FieldConfig } from '@ybyra/core' |
There was a problem hiding this comment.
🧩 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.jsonRepository: 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.
| import { describe, it, expect } from 'vitest' | ||
| import { registerRenderers, getRenderer, createRegistry } from './registry' | ||
| import type { FieldRenderer } from './types' |
There was a problem hiding this comment.
🧩 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.
| 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 | ||
| } |
There was a problem hiding this comment.
🧩 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"
fiRepository: 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 -20Repository: devitools/ybyra
Length of output: 1186
🏁 Script executed:
#!/bin/bash
echo "=== CI workflow content ==="
cat .github/workflows/ci.ymlRepository: 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.
| 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') | ||
| }) | ||
| }) |
There was a problem hiding this comment.
🧩 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 -30Repository: 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
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
Created
.github/workflows/ci.ymlmainconcurrencywithcancel-in-progress: trueto avoid wasting resources on outdated runsdocs.yml)Installed
@vitest/coverage-v8in@ybyra/coreand@ybyra/react(the two packages with tests)Created
vitest.config.tsin both packages with v8 coverage provider configurationCoverage status
Current coverage levels:
@ybyra/core@ybyra/reactThe main gaps are in files that require integration/rendering context:
schema.ts(0%) — complex factory with runtime wiringuse-data-form.ts(0%) — React hook needing component contextuse-data-table.ts(0%) — React hook needing component contextNext steps to reach 80% coverage
schema.ts(factory methods,configure(),create())action.ts,group.ts,scope.ts)use-data-form.tsanduse-data-table.tsusing@testing-library/reactvitest.config.ts:Summary by CodeRabbit
Chores
Tests
New Features