33
44import * as v from "valibot" ;
55import { describe , expect , test } from "vitest" ;
6- import { defineReducer , defineSchema , Entity } from "../src" ;
6+ import { defineReducer , defineSchema , Entity , mutation } from "../src" ;
77import { valibot } from "../src/valibot" ; // Use 'ventyd/valibot' in production
88import { Order } from "./entities/Order" ;
99import { User } from "./entities/User" ;
@@ -57,7 +57,7 @@ describe("Entity Unit Tests", () => {
5757 state : v . object ( { value : v . string ( ) } ) ,
5858 } ) ,
5959 initialEventName : "test:created" ,
60- generateId : ( ) => `test -${ idCounter ++ } ` ,
60+ generateId : ( type ) => `${ type } -${ idCounter ++ } ` ,
6161 } ) ;
6262
6363 const reducer = defineReducer ( schema , ( _ , event ) => {
@@ -67,7 +67,7 @@ describe("Entity Unit Tests", () => {
6767 return { value : "" } ;
6868 } ) ;
6969
70- const TestEntity = Entity ( schema , reducer ) ;
70+ class TestEntity extends Entity ( schema , reducer ) { }
7171
7272 const entity1 = TestEntity . create ( {
7373 body : { value : "first" } ,
@@ -78,11 +78,109 @@ describe("Entity Unit Tests", () => {
7878
7979 // generateId is called 3 times per entity:
8080 // 1) entityId, 2) validation eventId (discarded), 3) actual eventId
81- expect ( entity1 . entityId ) . toBe ( "test -1000" ) ;
82- expect ( entity1 [ " $$queuedEvents" ] [ 0 ] ?. eventId ) . toBe ( "test -1002" ) ;
81+ expect ( entity1 . entityId ) . toBe ( "entityId -1000" ) ;
82+ expect ( entity1 [ " $$queuedEvents" ] [ 0 ] ?. eventId ) . toBe ( "eventId -1002" ) ;
8383
84- expect ( entity2 . entityId ) . toBe ( "test-1003" ) ;
85- expect ( entity2 [ " $$queuedEvents" ] [ 0 ] ?. eventId ) . toBe ( "test-1005" ) ;
84+ expect ( entity2 . entityId ) . toBe ( "entityId-1003" ) ;
85+ expect ( entity2 [ " $$queuedEvents" ] [ 0 ] ?. eventId ) . toBe ( "eventId-1005" ) ;
86+ } ) ;
87+
88+ test ( "should generate different IDs for entityId and eventId types" , ( ) => {
89+ const generatedIds : Array < { type : string ; id : string } > = [ ] ;
90+
91+ const schema = defineSchema ( "test" , {
92+ schema : valibot ( {
93+ event : {
94+ created : v . object ( { value : v . string ( ) } ) ,
95+ } ,
96+ state : v . object ( { value : v . string ( ) } ) ,
97+ } ) ,
98+ initialEventName : "test:created" ,
99+ generateId : ( type ) => {
100+ const id = `${ type } -${ Date . now ( ) } -${ Math . random ( ) } ` ;
101+ generatedIds . push ( { type, id } ) ;
102+ return id ;
103+ } ,
104+ } ) ;
105+
106+ const reducer = defineReducer ( schema , ( _ , event ) => {
107+ if ( event . eventName === "test:created" ) {
108+ return { value : event . body . value } ;
109+ }
110+ return { value : "" } ;
111+ } ) ;
112+
113+ class TestEntity extends Entity ( schema , reducer ) { }
114+
115+ const entity = TestEntity . create ( {
116+ body : { value : "test" } ,
117+ } ) ;
118+
119+ // Filter out the validation eventId (discarded)
120+ const entityIdCalls = generatedIds . filter ( ( g ) => g . type === "entityId" ) ;
121+ const eventIdCalls = generatedIds . filter ( ( g ) => g . type === "eventId" ) ;
122+
123+ // Should have at least 1 entityId call
124+ expect ( entityIdCalls . length ) . toBeGreaterThanOrEqual ( 1 ) ;
125+ // Should have at least 2 eventId calls (1 for validation, 1 for actual event)
126+ expect ( eventIdCalls . length ) . toBeGreaterThanOrEqual ( 2 ) ;
127+
128+ // Verify entityId starts with "entityId-"
129+ expect ( entity . entityId ) . toMatch ( / ^ e n t i t y I d - / ) ;
130+ // Verify eventId starts with "eventId-"
131+ expect ( entity [ " $$queuedEvents" ] [ 0 ] ?. eventId ) . toMatch ( / ^ e v e n t I d - / ) ;
132+ } ) ;
133+
134+ test ( "should pass correct type argument to generateId" , ( ) => {
135+ const typeCallLog : Array < "entityId" | "eventId" > = [ ] ;
136+
137+ const schema = defineSchema ( "test" , {
138+ schema : valibot ( {
139+ event : {
140+ created : v . object ( { value : v . string ( ) } ) ,
141+ updated : v . object ( { value : v . string ( ) } ) ,
142+ } ,
143+ state : v . object ( { value : v . string ( ) } ) ,
144+ } ) ,
145+ initialEventName : "test:created" ,
146+ generateId : ( type ) => {
147+ typeCallLog . push ( type ) ;
148+ return crypto . randomUUID ( ) ;
149+ } ,
150+ } ) ;
151+
152+ const reducer = defineReducer ( schema , ( prevState , event ) => {
153+ if ( event . eventName === "test:created" ) {
154+ return { value : event . body . value } ;
155+ }
156+ if ( event . eventName === "test:updated" ) {
157+ return { value : event . body . value } ;
158+ }
159+ return prevState ;
160+ } ) ;
161+
162+ class TestEntity extends Entity ( schema , reducer ) {
163+ updateValue = mutation ( this , ( dispatch , value : string ) => {
164+ dispatch ( "test:updated" , { value } ) ;
165+ } ) ;
166+ }
167+
168+ const entity = TestEntity . create ( {
169+ body : { value : "initial" } ,
170+ } ) ;
171+
172+ // Update using mutation method
173+ entity . updateValue ( "updated" ) ;
174+
175+ // Verify that entityId was called once for entity creation
176+ const entityIdCalls = typeCallLog . filter ( ( t ) => t === "entityId" ) ;
177+ expect ( entityIdCalls . length ) . toBe ( 1 ) ;
178+
179+ // Verify that eventId was called for events
180+ // Should be 3 calls: validation for created, actual created, actual updated
181+ // (validation only happens for initial event, not for regular dispatch)
182+ const eventIdCalls = typeCallLog . filter ( ( t ) => t === "eventId" ) ;
183+ expect ( eventIdCalls . length ) . toBe ( 3 ) ;
86184 } ) ;
87185 } ) ;
88186
0 commit comments