test(sync): add canary test for entity type coverage

Add safeguards to prevent silent failures when new entity types are
added without proper registration:

- Add canary test that fails if EntityType union grows but test arrays
  aren't updated (verifies count matches expected 20 types)
- Create developer checklist at docs/ai/adding-new-entity-type-checklist.md
  documenting all required changes when adding new entity types
This commit is contained in:
Johannes Millan 2025-12-27 17:08:53 +01:00
parent 16d2ba1f25
commit 30fa62b9a4
2 changed files with 106 additions and 0 deletions

View file

@ -0,0 +1,82 @@
# Adding New Entity Types Checklist
This checklist ensures new entity types integrate properly with the operation log and sync system.
## When adding a new entity type:
### 1. Type Definition (`src/app/core/persistence/operation-log/operation.types.ts`)
- [ ] Add to `EntityType` union (line ~15)
### 2. Entity Registry (`src/app/core/persistence/operation-log/entity-registry.ts`)
- [ ] Add entry to `ENTITY_CONFIGS` with:
- `storagePattern`: 'adapter' | 'singleton' | 'map' | 'array' | 'virtual'
- `featureName`: NgRx feature key
- `payloadKey`: Key used in sync/import payloads
- Appropriate selectors for the storage pattern:
- **adapter**: `selectEntities`, `selectById`, `adapter`
- **singleton**: `selectState`
- **map**: `selectState`, `mapKey`
- **array**: `selectState`, `arrayKey`
- **virtual**: just `payloadKey`
### 3. Test Arrays (`src/app/core/persistence/operation-log/entity-registry.spec.ts`)
- [ ] Add to `REGULAR_ENTITY_TYPES` array (line ~17) OR `SPECIAL_OPERATION_TYPES` if special
- [ ] Add to appropriate category array:
- `ADAPTER_ENTITIES`
- `SINGLETON_ENTITIES`
- `MAP_ENTITIES`
- `ARRAY_ENTITIES`
- `VIRTUAL_ENTITIES`
- [ ] Update expected count in canary test (look for `expect(ALL_TESTED.length).toBe(...)`)
### 4. Meta-Reducers (if entity has relationships)
- [ ] Add cascade delete logic in appropriate meta-reducer under `src/app/root-store/meta/task-shared-meta-reducers/`
- [ ] Register meta-reducer in `META_REDUCERS` array in `src/app/root-store/meta/meta-reducer-registry.ts`
## When adding bulk actions:
Bulk actions operate on multiple entities atomically. Required setup:
- [ ] Set `isBulk: true` in action meta
- [ ] Use `entityIds` array (not single `entityId`)
- [ ] Ensure action has `isPersistent: true` and correct `entityType`
Example:
```typescript
updateTasks: (taskProps: { tasks: Update<Task>[] }) => ({
...taskProps,
meta: {
isPersistent: true,
entityType: 'TASK',
entityIds: taskProps.tasks.map((t) => t.id as string),
opType: OpType.Update,
isBulk: true, // Required for bulk operations
} satisfies PersistentActionMeta,
}),
```
## Verification
```bash
# Check the modified files
npm run checkFile src/app/core/persistence/operation-log/entity-registry.ts
npm run checkFile src/app/core/persistence/operation-log/operation.types.ts
# Run the entity registry tests
npm run test:file src/app/core/persistence/operation-log/entity-registry.spec.ts
```
## Why this matters
The operation log system depends on hardcoded registries to:
- Convert actions to operations and back
- Apply remote operations during sync
- Handle cascade deletes atomically
Missing or incomplete registrations cause **silent failures** - operations may not replay correctly on other devices.

View file

@ -410,5 +410,29 @@ describe('entity-registry', () => {
expect(REGULAR_ENTITY_TYPES).toContain(key as EntityType);
}
});
/**
* CANARY TEST: This test ensures test arrays stay in sync with EntityType union.
* If you add a new entity type to EntityType in operation.types.ts, you MUST also:
* 1. Add it to REGULAR_ENTITY_TYPES or SPECIAL_OPERATION_TYPES above
* 2. Add it to the appropriate category array (ADAPTER_ENTITIES, SINGLETON_ENTITIES, etc.)
* 3. Update the expected count below
*
* See docs/ai/adding-new-entity-type-checklist.md for full checklist.
*/
it('test arrays should cover all EntityType union members (canary)', () => {
const ALL_TESTED: EntityType[] = [
...REGULAR_ENTITY_TYPES,
...SPECIAL_OPERATION_TYPES,
];
// Update this count when adding new entity types to EntityType union
// Current: 17 regular + 3 special = 20 total
expect(ALL_TESTED.length).toBe(20);
// Verify no duplicates
const uniqueTypes = new Set(ALL_TESTED);
expect(uniqueTypes.size).toBe(ALL_TESTED.length);
});
});
});