Skip to content

Commit 2d1e938

Browse files
committed
polishing unit tests
1 parent 042262e commit 2d1e938

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

packages/data-connect/src/core/Cache.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type Value = string | number | boolean | null | undefined | object | Value[];
2424
/**
2525
* Defines the shape of query result data that represents a single entity.
2626
* It must have __typename and __id for normalization.
27+
*
28+
* TODO: this is just a StubDataObject isn't it...?
2729
*/
2830
export interface QueryResultData {
2931
[key: string]: Value;

packages/data-connect/test/unit/Cache.test.ts

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/* eslint-disable unused-imports/no-unused-imports-ts */
2-
/* eslint-disable @typescript-eslint/no-unused-vars */
31
/**
42
* @license
53
* Copyright 2024 Google LLC
@@ -21,22 +19,17 @@ import { deleteApp, FirebaseApp, initializeApp } from '@firebase/app';
2119
import { expect } from 'chai';
2220
import * as chai from 'chai';
2321
import chaiAsPromised from 'chai-as-promised';
24-
import * as sinon from 'sinon';
2522

2623
import {
2724
DataConnect,
2825
DataConnectOptions,
2926
DataSource,
30-
executeQuery,
3127
getDataConnect,
32-
mutationRef,
33-
queryRef,
3428
QueryResult,
3529
SerializedRef,
3630
SOURCE_SERVER
3731
} from '../../src';
3832
import { BackingDataObject, Cache, StubDataObject } from '../../src/core/Cache';
39-
import { Code, DataConnectError } from '../../src/core/error';
4033
chai.use(chaiAsPromised);
4134

4235
// Helper to create a mock QueryResult object for tests
@@ -97,6 +90,7 @@ interface Review extends StubDataObject {
9790
text: string;
9891
reviewer: Reviewer;
9992
}
93+
10094
interface Movie extends StubDataObject {
10195
__typename: 'Movie';
10296
__id: string;
@@ -121,7 +115,7 @@ const review1: Review = {
121115
reviewer: reviewer1
122116
};
123117

124-
const movie1: Movie = {
118+
const movieWithReviews: Movie = {
125119
__typename: 'Movie',
126120
__id: '1',
127121
id: '1',
@@ -130,7 +124,7 @@ const movie1: Movie = {
130124
reviews: [review1]
131125
};
132126

133-
const movie2: Movie = {
127+
const movieWithoutReviews: Movie = {
134128
__typename: 'Movie',
135129
__id: '2',
136130
id: '2',
@@ -181,12 +175,44 @@ describe('Normalized Cache Tests', () => {
181175
});
182176

183177
describe('updateCache', () => {
184-
it('should create new BDOs for a list of new entities', () => {
178+
it('should create a new BDO for a new returned entity', () => {
179+
// This test validates the `createBdo` path for multiple entities.
180+
const queryResult = createMockQueryResult(
181+
'getMovie',
182+
{ id: '2' },
183+
{ movie: movieWithoutReviews },
184+
options,
185+
dc
186+
);
187+
cache.updateCache(queryResult);
188+
189+
// 1. Check Result Tree Cache for the list of stubs
190+
const resultTreeKey = Cache.makeResultTreeCacheKey('getMovie', {
191+
id: '2'
192+
});
193+
const resultTree = cache.resultTreeCache.get(resultTreeKey)!;
194+
const stubDataObject = resultTree.movie as StubDataObject;
195+
expect(stubDataObject).to.not.be.a('StubDataObjectList');
196+
expect(stubDataObject).to.not.be.an('array');
197+
// expect(stubDataObject).to.be.a('StubDataObject');
198+
expect(stubDataObject.title).to.equal('The Matrix');
199+
200+
// 2. Check that four new BDOs were created in the BDO Cache
201+
expect(cache.bdoCache.size).to.equal(1); // movie1
202+
const bdo = cache.bdoCache.get(Cache.makeBdoCacheKey('Movie', '2'))!;
203+
expect(bdo).to.exist.and.be.an.instanceof(BackingDataObject);
204+
205+
// 3. White-box test: Check that each BDO has the correct stub as a listener.
206+
const listeners = bdo.listeners;
207+
expect(listeners.has(stubDataObject)).to.be.true;
208+
});
209+
210+
it('should create new BDOs for a list of new returned entities', () => {
185211
// This test validates the `createBdo` path for multiple entities.
186212
const queryResult = createMockQueryResult(
187213
'listMovies',
188214
{ limit: 2 },
189-
{ movies: [movie1, movie2] },
215+
{ movies: [movieWithReviews, movieWithoutReviews] },
190216
options,
191217
dc
192218
);
@@ -223,7 +249,7 @@ describe('Normalized Cache Tests', () => {
223249
'listMovies',
224250
{},
225251
{
226-
movies: [movie1]
252+
movies: [movieWithoutReviews]
227253
},
228254
options,
229255
dc
@@ -233,40 +259,40 @@ describe('Normalized Cache Tests', () => {
233259
// Get the original stub from the list to check it later
234260
const resultTreeKey = Cache.makeResultTreeCacheKey('listMovies', {});
235261
const originalStub = cache.resultTreeCache.get(resultTreeKey)!.movies[0];
236-
expect(originalStub.title).to.equal('Inception');
237-
expect(cache.bdoCache.size).to.equal(3); // movie1, review1, reviewer1
262+
expect(originalStub.title).to.equal('The Matrix');
263+
expect(cache.bdoCache.size).to.equal(1); // movie1
238264

239265
// Step 2: A new query result comes in with updated data for the same movie.
240266
// This should trigger the `updateBdo` logic path.
241-
const updatedMovie1 = {
242-
...movie1,
243-
title: "Inception (Director's Cut)"
267+
const updatedMovie2 = {
268+
...movieWithoutReviews,
269+
title: 'The Matrix Reloaded'
244270
};
245271
const singleQueryResult = createMockQueryResult(
246272
'getMovie',
247-
{ id: '1' },
248-
{ movie: updatedMovie1 },
273+
{ id: '2' },
274+
{ movie: updatedMovie2 },
249275
options,
250276
dc
251277
);
252278
cache.updateCache(singleQueryResult);
253279

254280
// Assertions
255281
// 1. No new BDO was created; the existing one was found and updated.
256-
expect(cache.bdoCache.size).to.equal(3);
282+
expect(cache.bdoCache.size).to.equal(1);
257283

258284
// 2. The new stub from the getMovie query has the new title.
259285
const newStub = cache.resultTreeCache.get(
260-
Cache.makeResultTreeCacheKey('getMovie', { id: '1' })
286+
Cache.makeResultTreeCacheKey('getMovie', { id: '2' })
261287
)!.movie as StubDataObject;
262-
expect(newStub.title).to.equal("Inception (Director's Cut)");
288+
expect(newStub.title).to.equal('The Matrix Reloaded');
263289

264290
// 3. CRITICAL: The original stub in the list was also updated via the listener mechanism.
265291
// This confirms that `updateFromServer` correctly notified all listeners.
266-
expect(originalStub.title).to.equal("Inception (Director's Cut)");
292+
expect(originalStub.title).to.equal('The Matrix Reloaded');
267293

268294
// 4. White-box test: The BDO now has two listeners (the original list stub and the new single-item stub).
269-
const bdo = cache.bdoCache.get(Cache.makeBdoCacheKey('Movie', '1'))!;
295+
const bdo = cache.bdoCache.get(Cache.makeBdoCacheKey('Movie', '2'))!;
270296
const listeners = bdo.listeners;
271297
expect(listeners.size).to.equal(2);
272298
expect(listeners.has(originalStub)).to.be.true;
@@ -296,7 +322,7 @@ describe('Normalized Cache Tests', () => {
296322
const queryResult = createMockQueryResult(
297323
'getMovieWithReviews',
298324
{ id: '1' },
299-
{ movie: movie1 },
325+
{ movie: movieWithReviews },
300326
options,
301327
dc
302328
);
@@ -325,15 +351,14 @@ describe('Normalized Cache Tests', () => {
325351
// 3. Check that stubs are distinct objects from BDOs
326352
const movieBdo = cache.bdoCache.get(Cache.makeBdoCacheKey('Movie', '1'))!;
327353
expect(movieStub).to.not.equal(movieBdo);
328-
expect({...movieStub}).to.equal({...movieBdo});
329354
});
330355

331356
it('should propagate changes from a nested entity to all parent listeners', () => {
332357
// 1. Cache a movie with its review
333358
const movieQueryResult = createMockQueryResult(
334359
'getMovie',
335360
{ id: '1' },
336-
{ movie: movie1 },
361+
{ movie: movieWithReviews },
337362
options,
338363
dc
339364
);
@@ -367,7 +392,7 @@ describe('Normalized Cache Tests', () => {
367392
// Movie with an aggregate field and a related object without a primary key
368393
const queryData = {
369394
movie: {
370-
...movie1,
395+
...movieWithReviews,
371396
__typename: 'Movie',
372397
__id: '1',
373398
// Non-normalizable aggregate field
@@ -412,7 +437,7 @@ describe('Normalized Cache Tests', () => {
412437
it('should handle null values in query results gracefully', () => {
413438
const queryData = {
414439
movie: {
415-
...movie1,
440+
...movieWithReviews,
416441
reviews: null // The list of reviews is null
417442
}
418443
};
@@ -431,9 +456,7 @@ describe('Normalized Cache Tests', () => {
431456
const movieStub = resultTree.movie as Movie;
432457
expect(movieStub.title).to.equal('Inception');
433458
expect(movieStub.reviews).to.be.null;
434-
// BDOs for movie, review, and reviewer from the original `movie1` object
435-
// should still be created, as the normalization happens recursively before nulling.
436-
expect(cache.bdoCache.size).to.equal(3);
459+
expect(cache.bdoCache.size).to.equal(1);
437460
});
438461
});
439462
});

0 commit comments

Comments
 (0)