|
| 1 | +import {waitFor} from '@testing-library/dom'; |
| 2 | + |
1 | 3 | import {HourlyDataCache, ONE_HOUR_S, getHourlyBuckets} from '../HourlyDataCache';
|
2 | 4 |
|
3 | 5 | const mockedCache = {
|
4 |
| - has: jest.fn(), |
5 |
| - get: jest.fn(), |
6 |
| - set: jest.fn(), |
| 6 | + has: jest.fn<any, any, any>(() => false), |
| 7 | + get: jest.fn<any, any, any>(), |
| 8 | + set: jest.fn<any, any, any>(), |
7 | 9 | };
|
8 | 10 | let mockShouldThrowError = false;
|
9 | 11 | jest.mock('idb-lru-cache', () => {
|
@@ -31,10 +33,10 @@ describe('HourlyDataCache', () => {
|
31 | 33 | expect(cache.getHourData(0)).toEqual([1, 2, 3]);
|
32 | 34 | });
|
33 | 35 |
|
34 |
| - it('throws if you attempt to add data spanning multiple hours to partial cache', () => { |
35 |
| - expect(() => { |
36 |
| - cache.addData(0, 2 * ONE_HOUR_S, [1, 2, 3, 4, 5, 6]); |
37 |
| - }).toThrow('Expected all data to fit within an hour'); |
| 36 | + it('throws if you attempt to add data spanning multiple hours to partial cache', async () => { |
| 37 | + await expect(() => { |
| 38 | + return cache.addData(0, 2 * ONE_HOUR_S, [1, 2, 3, 4, 5, 6]); |
| 39 | + }).rejects.toThrow('Expected all data to fit within an hour'); |
38 | 40 | });
|
39 | 41 | });
|
40 | 42 |
|
@@ -142,67 +144,84 @@ describe('HourlyDataCache Subscriptions', () => {
|
142 | 144 | beforeEach(() => {
|
143 | 145 | mockShouldThrowError = throwingError;
|
144 | 146 | cache = new HourlyDataCache<number>({version: VERSION, id: 'test'});
|
| 147 | + mockedCache.has.mockResolvedValue(false); |
145 | 148 | });
|
146 |
| - it('should notify subscriber immediately with existing data', () => { |
| 149 | + |
| 150 | + it('should notify subscriber immediately with existing data', async () => { |
| 151 | + mockedCache.has.mockResolvedValue(false); |
147 | 152 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
148 | 153 |
|
149 | 154 | const callback = jest.fn();
|
150 | 155 | cache.subscribe(1, callback);
|
151 | 156 |
|
152 |
| - expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 157 | + await waitFor(() => { |
| 158 | + expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 159 | + }); |
153 | 160 | });
|
154 | 161 |
|
155 |
| - it('should notify subscriber with new data added to the subscribed hour', () => { |
| 162 | + it('should notify subscriber with new data added to the subscribed hour', async () => { |
156 | 163 | const callback = jest.fn();
|
157 | 164 | cache.subscribe(0, callback);
|
158 | 165 |
|
159 | 166 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
160 | 167 |
|
161 |
| - expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 168 | + await waitFor(() => { |
| 169 | + expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 170 | + }); |
162 | 171 | });
|
163 | 172 |
|
164 |
| - it('should notify subscriber with new data added to subsequent hours', () => { |
| 173 | + it('should notify subscriber with new data added to subsequent hours', async () => { |
165 | 174 | const callback = jest.fn();
|
166 | 175 | cache.subscribe(0, callback);
|
167 | 176 |
|
168 | 177 | cache.addData(ONE_HOUR_S, 2 * ONE_HOUR_S, [4, 5, 6]);
|
169 | 178 |
|
170 |
| - expect(callback).toHaveBeenCalledWith([4, 5, 6]); |
| 179 | + await waitFor(() => { |
| 180 | + expect(callback).toHaveBeenCalledWith([4, 5, 6]); |
| 181 | + }); |
171 | 182 | });
|
172 | 183 |
|
173 |
| - it('should aggregate data from multiple hours for the subscriber', () => { |
| 184 | + it('should aggregate data from multiple hours for the subscriber', async () => { |
174 | 185 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
175 | 186 |
|
176 | 187 | const callback = jest.fn();
|
177 | 188 | cache.subscribe(0, callback);
|
178 | 189 |
|
179 |
| - expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 190 | + await waitFor(() => { |
| 191 | + expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 192 | + }); |
180 | 193 |
|
181 | 194 | cache.addData(ONE_HOUR_S, 2 * ONE_HOUR_S, [4, 5, 6]);
|
182 | 195 |
|
183 |
| - expect(callback).toHaveBeenCalledWith([1, 2, 3, 4, 5, 6]); |
| 196 | + await waitFor(() => { |
| 197 | + expect(callback).toHaveBeenCalledWith([1, 2, 3, 4, 5, 6]); |
| 198 | + }); |
184 | 199 | });
|
185 | 200 |
|
186 |
| - it('should not notify subscribers of data added before their subscription hour', () => { |
| 201 | + it('should not notify subscribers of data added before their subscription hour', async () => { |
187 | 202 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
188 | 203 |
|
189 | 204 | const callback = jest.fn();
|
190 | 205 | cache.subscribe(ONE_HOUR_S, callback);
|
191 | 206 |
|
192 | 207 | cache.addData(2 * ONE_HOUR_S, 3 * ONE_HOUR_S, [4, 5, 6]);
|
193 | 208 |
|
194 |
| - expect(callback).toHaveBeenCalledWith([4, 5, 6]); |
| 209 | + await waitFor(() => { |
| 210 | + expect(callback).toHaveBeenCalledWith([4, 5, 6]); |
| 211 | + }); |
195 | 212 | });
|
196 | 213 |
|
197 |
| - it('should stop notifying unsubscribed callbacks', () => { |
| 214 | + it('should stop notifying unsubscribed callbacks', async () => { |
198 | 215 | const callback = jest.fn();
|
199 | 216 | const unsubscribe = cache.subscribe(0, callback);
|
200 | 217 | unsubscribe();
|
201 | 218 |
|
202 | 219 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
203 | 220 | cache.addData(ONE_HOUR_S, 2 * ONE_HOUR_S, [4, 5, 6]);
|
204 | 221 |
|
205 |
| - expect(callback).not.toHaveBeenCalled(); |
| 222 | + await waitFor(() => { |
| 223 | + expect(callback).not.toHaveBeenCalled(); |
| 224 | + }); |
206 | 225 | });
|
207 | 226 | },
|
208 | 227 | );
|
@@ -240,6 +259,8 @@ describe('HourlyDataCache with IndexedDB', () => {
|
240 | 259 |
|
241 | 260 | cache.addData(0, ONE_HOUR_S, [1, 2, 3]);
|
242 | 261 |
|
| 262 | + await Promise.resolve(); |
| 263 | + |
243 | 264 | const mockCallArgs = mockedCache.set.mock.calls[0];
|
244 | 265 | const map = mockCallArgs[1];
|
245 | 266 | expect(map.cache).toEqual(
|
@@ -277,4 +298,43 @@ describe('HourlyDataCache with IndexedDB', () => {
|
277 | 298 | expect(cache.getHourData(sixDaysAgo)).toEqual([1, 2, 3]);
|
278 | 299 | expect(cache.getHourData(eightDaysAgo)).toEqual([]);
|
279 | 300 | });
|
| 301 | + |
| 302 | + it('should notify subscribers of existing data if the subscription is added before the indexeddb cache data is loaded', async () => { |
| 303 | + let res: any; |
| 304 | + mockedCache.has.mockResolvedValue(true); |
| 305 | + |
| 306 | + const sec = Date.now() / 1000; |
| 307 | + const nowHour = Math.floor(sec / ONE_HOUR_S); |
| 308 | + |
| 309 | + mockedCache.get.mockImplementation(async () => { |
| 310 | + await new Promise((resolve) => { |
| 311 | + res = () => { |
| 312 | + resolve(true); |
| 313 | + }; |
| 314 | + }); |
| 315 | + return { |
| 316 | + value: { |
| 317 | + version: VERSION, |
| 318 | + cache: new Map([ |
| 319 | + [nowHour, [{start: nowHour, end: nowHour + ONE_HOUR_S, data: [1, 2, 3]}]], |
| 320 | + ]), |
| 321 | + }, |
| 322 | + }; |
| 323 | + }); |
| 324 | + |
| 325 | + const cache = new HourlyDataCache<number>({id: 'test', version: VERSION}); |
| 326 | + |
| 327 | + cache.addData(0, ONE_HOUR_S, [4]); |
| 328 | + |
| 329 | + const callback = jest.fn(); |
| 330 | + cache.subscribe(0, callback); |
| 331 | + |
| 332 | + await Promise.resolve(); |
| 333 | + |
| 334 | + res(true); |
| 335 | + |
| 336 | + await waitFor(() => { |
| 337 | + expect(callback).toHaveBeenCalledWith([1, 2, 3]); |
| 338 | + }); |
| 339 | + }); |
280 | 340 | });
|
0 commit comments