Skip to content

feat: add CI test workflow and timezone audit for chart utils#10

Merged
kilbot merged 12 commits intomainfrom
feature/timezone-audit-and-ci-tests
Jan 22, 2026
Merged

feat: add CI test workflow and timezone audit for chart utils#10
kilbot merged 12 commits intomainfrom
feature/timezone-audit-and-ci-tests

Conversation

@kilbot
Copy link
Copy Markdown
Contributor

@kilbot kilbot commented Jan 22, 2026

Summary

  • Add test.yml workflow to run Jest tests on PRs and pushes to main
  • Remove preview.yml (functionality replaced by test workflow)
  • Add timezone handling consistency tests for chart aggregation
  • Use isSameDay for single-day detection per CodeRabbit feedback

Changes

CI Workflow (test.yml)

  • Runs on all PRs and pushes to main
  • Executes pnpm jest --ci --passWithNoTests
  • Uses the existing setup-monorepo action for consistent environment

Chart Utils Timezone Audit

  • Added documentation explaining the UTC → local timezone flow
  • Added 3 new tests to catch timezone-related regressions:
    • should find orders when date range and orders use same conversion
    • should bucket multi-day orders by their date
    • should use isSameDay for single-day detection
  • Changed single-day detection from differenceInDays <= 1 to isSameDay() for clarity

Test Plan

  • All 40 chart utils tests pass
  • CI workflow runs successfully on this PR
  • No linter errors

Summary by CodeRabbit

  • Bug Fixes

    • Chart aggregation now uses calendar-day comparisons for consistent, timezone-aware results.
    • Safer POS metadata parsing to avoid errors when metadata is missing.
  • Tests

    • Added timezone-consistency tests and expanded line-item and ID-generation tests.
    • Many tests and mocks updated for stability; some legacy validation tests removed.
  • Chores

    • CI workflow renamed and now runs tests on pushes and pull requests; test command streamlined.
    • Removed an outdated testing dev-dependency.
  • Refactor

    • Removed custom validation plugins and stabilized test helpers with deterministic identifiers.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add test.yml workflow to run Jest tests on PRs and pushes to main
- Remove preview.yml (replaced by test workflow)
- Add timezone handling consistency tests for chart aggregation
- Use isSameDay for single-day detection per CodeRabbit feedback
- Document timezone conversion flow in test file comments
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

Updates CI workflow and test step; tightens calendar-day logic in chart aggregation and adds timezone-consistency tests; broad test refactors and mocks across POS and database packages; refactors populate internals; removes RxDB validation plugins (z-schema & AJV); adjusts Jest mappings and removes react-hooks test dependency.

Changes

Cohort / File(s) Summary
CI / Workflow
.github/workflows/test.yml
Renamed workflow to test, added push trigger on main, removed EXPO_USE_FAST_RESOLVER env, renamed job to test, removed job permissions, and replaced build/preview steps with a single pnpm jest --ci --passWithNoTests step.
Chart aggregation & tests
packages/core/src/screens/main/reports/chart/utils.ts, packages/core/src/screens/main/reports/chart/utils.test.ts
Single-day check changed from diff-based to calendar-based (isSameDay(originalStart, originalEnd)); added timezone-consistency tests and a use-local-date mock to ensure consistent UTC→local conversions for date ranges and orders.
POS hooks & tests
packages/core/src/screens/main/pos/hooks/*
Large test refactors: switch to jsdom/Testing Library, add extensive mocks (uuid, logger, current order, localPatch, tax calculator, line-item parser), adjust expectations for nested data.line_items payloads and tax/pos_data behavior; parsePosData now early-returns null when metadata missing and logs parse errors with original string.
Jest config (core)
packages/core/jest.config.js
Added moduleNameMapper aliases: '^@wcpos/utils/(.*)$' -> '<rootDir>/../utils/src/$1' and '^@wcpos/database$' -> '<rootDir>/../database/src'.
DevDependency removals
packages/core/package.json, packages/hooks/package.json
Removed devDependency @testing-library/react-hooks.
Generate-ID tests
packages/database/src/plugins/generate-id.test.ts
Switched to mockCollection, added jsonSchema.properties metadata in mocks, updated initialization, and added test verifying generated UUID is set on data.uuid and appended into data.meta_data when schema includes meta_data.
Populate plugin & tests
packages/database/src/plugins/populate.ts, packages/database/src/plugins/populate.test.ts
Moved plugin registration to beforeAll, added explicit NestedCollection/NestedDoc typings in tests, reused collection across tests; refactored RxDocument.populateResource to use a typed self intermediate for property access.
Validation plugins removed
packages/database/src/plugins/validate.ts, packages/database/src/plugins/validate.ts.ajv
Removed both z-schema and AJV RxDB validation modules, their getValidator functions, custom keywords/format logic, and exported wrappedValidate* storage wrappers.
Test helpers (nested/products)
packages/database/src/tests/helpers/nested-collection.ts, packages/database/src/tests/helpers/products-collection.ts
Replaced faker/uuid/randomCouchString with randomToken; added generateUniqueDbName helper; removed multiInstance/eventReduce params from create; narrowed nestedDefaultSchema with as const; simplified DB options and return typing.
Other tests & fixtures
packages/core/src/lib/url/parse-link-header.test.ts, packages/core/src/screens/main/pos/hooks/calculate-order-totals.test.ts, packages/core/src/screens/main/pos/hooks/use-calculate-line-item-tax-and-totals.test.ts, packages/core/src/screens/main/pos/hooks/utils.test.ts, ...
Updated expectations and typings in various tests: parse-link-header returns null for empty inputs, tax ids/totals moved to numeric types, added/updated mocks and typing casts across multiple test files.
App/manifest bumps
apps/main/package.json, package.json, packages/core/package.json
Bumped expo and react-native-safe-area-context versions and a few devDependency version updates.
Submodule pointer
apps/electron
Submodule commit pointer updated (no code changes).

Sequence Diagram(s)

(Skipped — changes are primarily tests, refactors, and removals without a new multi-component runtime control flow that requires visualization.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • In-App Notifications #7 — Adds Novu in-app notifications (schemas/collections and UI) which may intersect with the database schema/tests and helpers modified in this PR.

Poem

🐰 I hopped through CI and tests anew,
Calendars checked and timezones too.
UUIDs tucked where metadata lays,
Validators gone, helpers now blaze.
Tiny paws, big code-day hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly summarizes the two main changes: adding a CI test workflow and improving timezone handling in chart utilities with focused tests.

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

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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 and usage tips.

- Add Record<string, any> type to data objects for dynamic property access
- Add missing jsonSchema.properties to mock collection schemas
- Add test for meta_data population behavior
- Fix populate.test.ts TypeScript type errors with proper type assertions
- Fix populate.ts TypeScript error in populateResource function
- Replace ESM-only imports (faker, uuid, randomCouchString) with rxdb's randomToken
- Simplify nested-collection helper to match working query tests pattern
- Update products-collection helper with same fixes
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/database/src/tests/helpers/nested-collection.ts`:
- Around line 33-34: The test helper in nested-collection.ts uses
randomToken(36) for the uuid field; change it to use the UUID v4 helper to match
other test helpers (like product-schemas.ts). Import the v4 function from the
'uuid' package (use the same import style used in product-schemas.ts, e.g. v4 as
uuidv4) and replace the default uuid value (uuid: string = randomToken(36)) with
uuid: string = uuidv4(); also remove the randomToken import if it becomes
unused.
🧹 Nitpick comments (5)
packages/database/src/plugins/populate.ts (1)

196-202: Consider adding a typed interface for the extended document.

The as any cast is functional but violates the coding guideline to avoid any. While RxDB plugin patterns often require dynamic property access, you could improve type safety with an interface.

♻️ Suggested type-safe approach
+// At the top of the file or in a types file
+interface PopulatedRxDocument extends RxDocument {
+	[key: `${string}Resource`]: ObservableResource<RxDocument[]>;
+	populate$: (key: string) => Observable<RxDocument[]>;
+}
+
 /** */
 proto.populateResource = function (this: RxDocument, key: string) {
-	const self = this as any;
+	const self = this as PopulatedRxDocument;
 	if (!self[key + 'Resource']) {
-		self[key + 'Resource'] = new ObservableResource(self.populate$(key));
+		(self as any)[key + 'Resource'] = new ObservableResource(self.populate$(key));
 	}
 	return self[key + 'Resource'];
 };

Note: The assignment still requires as any due to TypeScript's limitations with template literal index signatures during assignment, but reading is type-safe.

packages/database/src/tests/helpers/nested-collection.ts (2)

42-47: Inconsistent database naming strategy with products-collection.ts.

This file uses Date.now() for unique names while products-collection.ts uses randomToken(10). For consistency and to avoid potential collisions in parallel test runs on the same millisecond, consider using the same approach.

♻️ Align with products-collection.ts approach
-/**
- * Generate a unique database name
- */
-function generateUniqueDbName(baseName: string): string {
-	return `${baseName}_${Date.now()}`;
-}
-
 export async function create(
 	size: number = 20,
 	collectionName: string = 'nested',
 	storage: RxStorage<any, object, object> = getRxStorageMemory()
 ): Promise<RxCollection<any, object, object>> {
 	const db = await createRxDatabase({
-		name: generateUniqueDbName('nesteddb'),
+		name: randomToken(10),
 		storage,
 		allowSlowCount: true,
 	});

Also applies to: 55-55


53-53: Return type uses any, losing type safety.

The return type RxCollection<any, object, object> is less strict than products-collection.ts which uses RxCollection<typeof productDefaultSchema, object, object>. Per coding guidelines, avoid any types.

♻️ Use schema type for better type safety
 export async function create(
 	size: number = 20,
 	collectionName: string = 'nested',
 	storage: RxStorage<any, any> = getRxStorageMemory()
-): Promise<RxCollection<any, object, object>> {
+): Promise<RxCollection<typeof nestedDefaultSchema, object, object>> {
packages/database/src/plugins/populate.test.ts (2)

7-18: Type definitions use any and are incomplete.

The NestedDoc interface is missing properties from the schema (uuid, name) and uses any in multiple places, which violates coding guidelines. A more complete interface would reduce the need for as unknown as casts throughout the tests.

♻️ Improve type definitions
 // Type for collection with plugin methods
 type NestedCollection = Awaited<ReturnType<typeof create>> & {
-	upsertRefs: (data: any) => Promise<void>;
-	removeRefs: (data: any) => Promise<void>;
+	upsertRefs: (data: NestedData) => Promise<void>;
+	removeRefs: (data: NestedData) => Promise<void>;
 };

+// Base nested data shape
+interface NestedData {
+	uuid: string;
+	name: string;
+	child?: (NestedData | string)[];
+}
+
 // Type for document with plugin methods
-interface NestedDoc {
-	child: string[];
-	populate: (key: string) => Promise<NestedDoc[]>;
-	toPopulatedJSON: () => Promise<any>;
-}
+interface NestedDoc extends NestedData {
+	child: string[];
+	populate: (key: string) => Promise<NestedDoc[]>;
+	toPopulatedJSON: () => Promise<NestedData>;
+}

40-40: Multiple as unknown as casts indicate type definition gaps.

The repeated use of as unknown as NestedDoc is a code smell suggesting the types don't align well with RxDB's actual return types. Consider extending RxDB's document type properly or creating a utility type.

♻️ Create a typed query helper
// Helper to reduce casting boilerplate
async function findNestedDoc(
	collection: NestedCollection,
	id?: string
): Promise<NestedDoc | null> {
	const query = id ? collection.findOne(id) : collection.findOne();
	return query.exec() as Promise<NestedDoc | null>;
}

Also applies to: 51-51, 66-66, 81-81

Comment on lines +33 to +34
uuid: string = randomToken(36),
name: string = `nested-${randomToken(6)}`
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1. Read the file to understand context
echo "=== File content around lines 33-34 ==="
head -40 packages/database/src/tests/helpers/nested-collection.ts | tail -20

echo -e "\n=== Find randomToken function ==="
rg -n "function randomToken|const randomToken|export.*randomToken" -A 3 --type ts

echo -e "\n=== Find uuid schema definition ==="
rg -n "uuid.*maxLength|uuid.*max_length" --type ts -A 2 -B 2 | head -50

echo -e "\n=== Search for UUID validation patterns ==="
rg -n "uuid.*validate|validateUUID|isUUID|UUID.*regex|uuid.*pattern" --type ts | head -30

Repository: wcpos/monorepo

Length of output: 507


🏁 Script executed:

#!/bin/bash
# Read entire file to see imports and schema
echo "=== Full file content ==="
cat -n packages/database/src/tests/helpers/nested-collection.ts

echo -e "\n=== Find randomToken import ==="
rg -n "import.*randomToken|from.*randomToken" --type ts

echo -e "\n=== Find randomToken definition anywhere ==="
rg -n "function randomToken|const randomToken = " --type ts -A 5

Repository: wcpos/monorepo

Length of output: 2422


🏁 Script executed:

#!/bin/bash
# Check if there's any UUID format validation in the codebase
echo "=== Search for UUID format/pattern validation ==="
rg -n "uuid.*regex|uuid.*format|Pattern.*uuid|validate.*uuid" --type ts | head -20

echo -e "\n=== Check if schema validation enforces format ==="
rg -n "format.*uuid|pattern.*uuid" --type ts | head -20

echo -e "\n=== Look for actual UUID generation (standard format with hyphens) ==="
rg -n "uuid|UUID" --type ts -g '!*.test.ts' | grep -i "v4\|v1\|generate" | head -20

echo -e "\n=== Check RxDB schema validation in actual collections ==="
rg -n "primaryKey.*uuid|type.*string.*uuid" --type ts -A 3 | head -40

Repository: wcpos/monorepo

Length of output: 4769


🏁 Script executed:

#!/bin/bash
# Check how product-schemas handles UUID generation for comparison
echo "=== product-schemas.ts UUID handling ==="
cat -n packages/database/src/tests/helpers/product-schemas.ts | head -50

echo -e "\n=== Check order-schema.ts UUID handling ==="
cat -n packages/database/src/tests/helpers/order-schema.ts | head -50

Repository: wcpos/monorepo

Length of output: 1616


🏁 Script executed:

#!/bin/bash
# Check if order-schema has a generate function
echo "=== Check order-schema.ts for generate function ==="
cat -n packages/database/src/tests/helpers/order-schema.ts | tail -20

Repository: wcpos/monorepo

Length of output: 525


Use uuidv4() instead of randomToken(36) for consistency with other test helpers.

Similar test helpers in the same directory (product-schemas.ts) use uuidv4() from the 'uuid' library for UUID generation. Update nested-collection.ts to follow the same pattern for consistency:

- import { randomToken } from 'rxdb/plugins/utils';
+ import { v4 as uuidv4 } from 'uuid';
export const generateNested = (
-	uuid: string = randomToken(36),
+	uuid: string = uuidv4(),
	name: string = `nested-${randomToken(6)}`
) => {
🤖 Prompt for AI Agents
In `@packages/database/src/tests/helpers/nested-collection.ts` around lines 33 -
34, The test helper in nested-collection.ts uses randomToken(36) for the uuid
field; change it to use the UUID v4 helper to match other test helpers (like
product-schemas.ts). Import the v4 function from the 'uuid' package (use the
same import style used in product-schemas.ts, e.g. v4 as uuidv4) and replace the
default uuid value (uuid: string = randomToken(36)) with uuid: string =
uuidv4(); also remove the randomToken import if it becomes unused.

- Fix mock paths to match actual module locations
- Add uuid, @wcpos/utils/logger mocks for ESM module compatibility
- Add moduleNameMapper for @wcpos/utils and @wcpos/database
- Fix TypeScript scoping error in parsePosData (posData not in catch scope)
- Simplify price update test assertions to check metadata updates
- Add logger mock to avoid __DEV__ not defined error
- Add type assertion for mock customer object
- Update shipping test expectation to include postcode field
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@packages/core/jest.config.js`:
- Around line 27-28: The Jest moduleNameMapper entry for '^@wcpos/database$'
only matches the exact package name and misses subpath imports; add a subpath
pattern similar to '^@wcpos/utils/(.*)$' to map '^@wcpos/database/(.*)$' to the
database src folder (use the same '<rootDir>/../database/src/$1' style) so
imports like '@wcpos/database/src' resolve correctly while keeping the existing
exact '^@wcpos/database$' mapping.

In `@packages/core/src/screens/main/pos/hooks/use-update-line-item.test.ts`:
- Around line 97-108: The test mock for useLineItemData is looking for the wrong
metadata key (_pos_data) which doesn't match production; update the
getLineItemData mock inside useLineItemData (the jest.mock block) to search for
'_woocommerce_pos_data' instead of '_pos_data' so the test mirrors real code
behavior and returns parsed JSON from that meta entry; keep the rest of the mock
behavior (default return object and function name getLineItemData) unchanged.
- Around line 49-55: The test mock in use-update-line-item.test.ts uses the
metadata key '_pos_data' but the assertion and production utils expect
'_woocommerce_pos_data'; update the mock metadata key from '_pos_data' to
'_woocommerce_pos_data' (and any other occurrences in that test file) so the
mocked meta_data array matches the assertion and the keys used by utils.ts.
🧹 Nitpick comments (1)
packages/core/src/screens/main/pos/hooks/use-update-line-item.test.ts (1)

76-95: Consider documenting the mock tax calculation.

The mock uses a hardcoded 10% tax rate. A brief comment explaining this is intentional for predictable test assertions would help future maintainers.

Optional: Add clarifying comment
 // Mock useCalculateLineItemTaxAndTotals
 jest.mock('./use-calculate-line-item-tax-and-totals', () => ({
 	useCalculateLineItemTaxAndTotals: () => ({
+		// Mock uses fixed 10% tax rate for predictable test assertions
 		calculateLineItemTaxesAndTotals: jest.fn().mockImplementation((lineItem) => {
 			const quantity = lineItem.quantity ?? 1;
 			const price = lineItem.price ?? 10;

Comment on lines +27 to +28
'^@wcpos/utils/(.*)$': '<rootDir>/../utils/src/$1',
'^@wcpos/database$': '<rootDir>/../database/src',
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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether subpath imports exist for `@wcpos/database`
rg -n "@wcpos/database/" --type=ts --type=tsx --type=js --type=jsx

Repository: wcpos/monorepo

Length of output: 85


🏁 Script executed:

#!/bin/bash
# Verify whether subpath imports exist for `@wcpos/database`
rg -n "@wcpos/database/" --type=ts --type=js

Repository: wcpos/monorepo

Length of output: 863


🏁 Script executed:

#!/bin/bash
# Search for all `@wcpos/database` imports to see the full pattern
rg -n "@wcpos/database" --type=ts --type=js | head -30

# Also check if there are other subpath patterns
rg -n "@wcpos/database/[^s]" --type=ts --type=js

Repository: wcpos/monorepo

Length of output: 3535


🏁 Script executed:

#!/bin/bash
# Read the jest.config.js file to verify current state
cat -n packages/core/jest.config.js | head -50

Repository: wcpos/monorepo

Length of output: 1109


Add a subpath mapper for @wcpos/database to resolve subpath imports.

The mapper for @wcpos/database is exact-only and will fail to resolve subpath imports like @wcpos/database/src (found in packages/query). Add a subpath pattern to match the @wcpos/utils mapper style:

Required mapper extension
 moduleNameMapper: {
   '^expo-localization$': '<rootDir>/jest/__mocks__/expo-localization.js',
   '^@wcpos/utils/(.*)$': '<rootDir>/../utils/src/$1',
   '^@wcpos/database$': '<rootDir>/../database/src',
+  '^@wcpos/database/(.*)$': '<rootDir>/../database/src/$1',
 },
🤖 Prompt for AI Agents
In `@packages/core/jest.config.js` around lines 27 - 28, The Jest moduleNameMapper
entry for '^@wcpos/database$' only matches the exact package name and misses
subpath imports; add a subpath pattern similar to '^@wcpos/utils/(.*)$' to map
'^@wcpos/database/(.*)$' to the database src folder (use the same
'<rootDir>/../database/src/$1' style) so imports like '@wcpos/database/src'
resolve correctly while keeping the existing exact '^@wcpos/database$' mapping.

- Add type assertions for mock data
- Change tax IDs from strings to numbers
- Update expected values to match implementation output format
  (no trailing zeros, and correct cart_tax/total calculations)
- Replace import from '@testing-library/react-hooks' with '@testing-library/react'
- Add @jest-environment jsdom directive for DOM-dependent tests
- Pass explicit undefined/null arguments instead of no args
- Expect null return value for empty inputs (matches implementation)
Address CodeRabbit feedback to use production metadata key name
@kilbot kilbot merged commit d9ee332 into main Jan 22, 2026
2 of 3 checks passed
@kilbot kilbot deleted the feature/timezone-audit-and-ci-tests branch January 22, 2026 14:29
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