1- import { describe , it , expect , vi , beforeEach } from 'vitest' ;
1+ import { describe , it , expect , vi , beforeEach , onTestFinished } from 'vitest' ;
22import { ObjectQL } from './engine' ;
3+ import { ExpressionEngine } from '@objectstack/formula' ;
34import { SchemaRegistry } from './registry' ;
45import type { IDataDriver } from '@objectstack/spec/contracts' ;
56
@@ -1929,6 +1930,19 @@ describe('ObjectQL Engine', () => {
19291930 } ) ;
19301931
19311932 it ( 'pins `now` once per find so every row sees the same instant (#1979)' , async ( ) => {
1933+ // Asserted by CONSTRUCTION rather than by value (#5896). The regression
1934+ // this guards is a per-evaluation `new Date()`, and two such reads
1935+ // inside the same millisecond are equal in value while being distinct
1936+ // objects — so a value comparison only fails when the three
1937+ // evaluations happen to straddle a millisecond boundary. Measured
1938+ // against that exact regression, the value form passed through it in
1939+ // 3 of 10 full-file runs (and in 145 of 200 finds within one warm
1940+ // process): it reported by luck. Spying on the eval context pins the
1941+ // mechanism instead — ONE clock read, handed to every evaluation by
1942+ // identity — which fails whatever the millisecond happens to be.
1943+ const evaluate = vi . spyOn ( ExpressionEngine , 'evaluate' ) ;
1944+ onTestFinished ( ( ) => { evaluate . mockRestore ( ) ; } ) ;
1945+
19321946 vi . mocked ( SchemaRegistry . getObject ) . mockReturnValue ( {
19331947 name : 'ping' ,
19341948 fields : {
@@ -1946,8 +1960,17 @@ describe('ObjectQL Engine', () => {
19461960
19471961 const result = await engine . find ( 'ping' , { fields : [ 'id' , 'ts' ] } as any ) ;
19481962
1949- // Determinism: a single operation snapshots one `now`, shared across
1950- // every row — not a fresh wall-clock read per evaluation.
1963+ // 1 formula field × 3 rows: the evaluations the identity claim is over.
1964+ // Without this count the claim below could pass vacuously on an empty
1965+ // call list.
1966+ expect ( evaluate ) . toHaveBeenCalledTimes ( 3 ) ;
1967+ const nows = ( evaluate . mock . calls as unknown as Array < [ unknown , { now ?: Date } ] > )
1968+ . map ( ( [ , ctx ] ) => ctx . now ) ;
1969+ expect ( nows [ 0 ] ) . toBeInstanceOf ( Date ) ;
1970+ expect ( nows . every ( ( n ) => n === nows [ 0 ] ) ) . toBe ( true ) ;
1971+
1972+ // …and the consequence a caller can see. Kept as the caller-visible
1973+ // symptom, but it is no longer what makes this test report.
19511974 expect ( result [ 0 ] . ts ) . toEqual ( result [ 1 ] . ts ) ;
19521975 expect ( result [ 1 ] . ts ) . toEqual ( result [ 2 ] . ts ) ;
19531976 } ) ;
0 commit comments