Skip to content

Commit 7ec8ce3

Browse files
authored
Fix erratic livequery tests. (#2095)
Change how we wait until an expected result is emitted from a live query. Current tests were more prone to timing issues and race conditions. Now we instead do the following for those tests: 1. Define the expected results 2. Subscribe to live query and wait until the expected results arrive, or a timeout of 500 ms happens. The thing is that liveQueries might emit a previous result at first, so by ignoring temporary outdated results we're not prone to timing issues. Co-authored-by: David Fahlander <[email protected]>
1 parent 8e55011 commit 7ec8ce3

File tree

1 file changed

+37
-71
lines changed

1 file changed

+37
-71
lines changed

test/tests-live-query.js

Lines changed: 37 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -44,43 +44,31 @@ class Signal {
4444
}
4545

4646
function liveQueryUnitTester(lq, {graceTime}={graceTime: 0}) {
47-
let currentVal;
48-
let currentError = null;
49-
let signal = ()=>{};
50-
let reject = ()=>{};
51-
let querying = 0;
52-
const subscription = liveQuery(async ()=>{
53-
++querying;
54-
try {
55-
currentVal = await lq();
56-
console.log("Emitted", currentVal);
57-
currentError = null;
58-
} catch (error) {
59-
currentError = error;
60-
}
61-
if (--querying === 0) setTimeout(()=>{
62-
if (querying === 0) {
63-
if (currentError)
64-
reject(currentError);
65-
else
66-
signal(currentVal);
67-
}
68-
}, graceTime);
69-
}).subscribe(x => x);
47+
const lq = liveQuery(lq)
7048
return {
71-
waitNextValue(timeout=500) {
72-
const promise = new Promise((resolve, rej) => {
73-
signal = resolve;
74-
reject = rej;
49+
waitTilDeepEqual(expected, description, timeout=500) {
50+
return new Promise((resolve, reject) => {
51+
let latestValue;
52+
const subscription = lq.subscribe(value => {
53+
latestValue = value;
54+
if (isDeepEqual(value, expected)) {
55+
deepEqual(value, expected, description);
56+
clearTimeout(timer);
57+
subscription.unsubscribe();
58+
resolve();
59+
}
60+
});
61+
let timer = setTimeout(() => {
62+
subscription.unsubscribe();
63+
try {
64+
deepEqual(latestValue, expected, description);
65+
resolve();
66+
} catch (e) {
67+
reject(e);
68+
}
69+
}, timeout);
7570
});
76-
return !timeout
77-
? promise
78-
: Promise.race([
79-
promise,
80-
new Promise((_, rej) => setTimeout(()=>rej(new Error("Timeout")), timeout))
81-
]);
82-
},
83-
subscription
71+
}
8472
}
8573
}
8674

@@ -158,22 +146,12 @@ module("live-query", {
158146
});*/
159147

160148
promisedTest("subscribe to range", async ()=> {
161-
let signal = new Signal();
162-
let subscription = liveQuery(()=>db.items.toArray()).subscribe(result => {
163-
signal.resolve(result);
164-
});
165-
let result = await signal.promise;
166-
deepEqual(result, [{id:1},{id:2},{id:3}], "First callback should give initally populated content");
167-
signal = new Signal();
149+
let tester = liveQueryUnitTester(()=>db.items.toArray());
150+
await tester.waitTilDeepEqual([{id: 1}, {id: 2}, {id: 3}], "First callback should give initally populated content");
168151
db.items.add({id:-1});
169-
result = await signal.promise;
170-
deepEqual(result, [{id:-1},{id:1},{id:2},{id:3}], "2nd callback should give updated content");
171-
172-
signal = new Signal();
152+
await tester.waitTilDeepEqual([{id:-1}, {id: 1}, {id: 2}, {id: 3}], "2nd callback should give updated content");
173153
db.items.delete(2);
174-
result = await signal.promise;
175-
deepEqual(result, [{id:-1},{id:1},{id:3}], "3rd callback should wake up when deletion was made");
176-
subscription.unsubscribe();
154+
await tester.waitTilDeepEqual([{id:-1}, {id: 1}, {id: 3}], "3rd callback should wake up when deletion was made");
177155
});
178156

179157
promisedTest("subscribe to keys", async ()=>{
@@ -821,33 +799,25 @@ promisedTest("Issue 2067: useLiveQuery does not update when multiple items are d
821799
deepEqual(items, [{id:3},{id:2},{id:1}], "Initial items are correct");
822800
const tester = liveQueryUnitTester(()=>db.items.reverse().toArray());
823801
db.items.where('id').above(0).delete();
824-
items = await tester.waitNextValue();
825-
deepEqual(items, [], "Items are deleted");
802+
await tester.waitTilDeepEqual([], "Items are deleted");
826803
db.items.bulkAdd([{id: -10},{id: 0},{id: 10}]);
827-
items = await tester.waitNextValue();
828-
deepEqual(items, [{id: 10},{id: 0},{id: -10}], "Reacts on bulkAdd");
829-
let promise = tester.waitNextValue();
804+
await tester.waitTilDeepEqual([{id: 10},{id: 0},{id: -10}], "Reacts on bulkAdd");
830805
db.items.where('id').above(0).delete();
831-
items = await promise;
832-
deepEqual(items, [{id: 0},{id: -10}], "Should have deleted items where id > 0");
833-
tester.subscription.unsubscribe();
806+
await tester.waitTilDeepEqual([{id: 0},{id: -10}], "Should have deleted items where id > 0");
834807
});
835808

836809
promisedTest("Issue 2058 - related but with bulkAdd and constraint error on duplicate primary keys.", async () => {
837810
const tester = liveQueryUnitTester(
838-
()=>db.items.toArray()
811+
()=>db.items.toArray(), { graceTime: 100 }
839812
);
840-
let items = await tester.waitNextValue();
841-
deepEqual(items, [{id:1},{id:2},{id:3}], "Initial items are correct");
842-
let promise = tester.waitNextValue();
813+
await tester.waitTilDeepEqual([{id:1},{id:2},{id:3}], "Initial items are correct");
843814
await db.items.bulkAdd([
844815
{id:3}, // This one won't be added (constraint violation)
845816
{id:88} // This one will be added
846817
]).catch(error => {
847818
equal(error.failuresByPos[0].name, "ConstraintError", "Expected constraint error for the first operation");
848819
});
849-
items = await promise;
850-
deepEqual(items, [{id:1},{id:2},{id:3},{id:88}], "The livequery emitted correct result after bulk operation");
820+
await tester.waitTilDeepEqual([{id:1},{id:2},{id:3},{id:88}], "The livequery emitted correct result after bulk operation");
851821
// Now making sure we go through a different code path (where the number of items > 50 in cache-middleware.ts)
852822
const itemsToAdd = new Array(51)
853823
.fill({id: 1}, 0, 40) // Positions 0..40 is constraint violations agains existing data + themselves
@@ -867,9 +837,7 @@ promisedTest("Issue 2058 - related but with bulkAdd and constraint error on dupl
867837
});
868838

869839
console.log("Before await promise", performance.now());
870-
items = await tester.waitNextValue();
871-
console.log("After await promise", performance.now());
872-
deepEqual(items, [
840+
await tester.waitTilDeepEqual([
873841
{id:1},
874842
{id:2},
875843
{id:3},
@@ -878,7 +846,7 @@ promisedTest("Issue 2058 - related but with bulkAdd and constraint error on dupl
878846
{id:100},
879847
{id:101}
880848
], "Correct state after trying to add these half baked entries");
881-
tester.subscription.unsubscribe();
849+
console.log("After await promise", performance.now());
882850
});
883851

884852
promisedTest("Issue 2058: Cache error after bulkPut failures", async () => {
@@ -891,8 +859,7 @@ promisedTest("Issue 2058: Cache error after bulkPut failures", async () => {
891859
{id:"1.2",a:1,b:2},
892860
{id:"2.1",a:2,b:1},
893861
]);
894-
let items = await tester.waitNextValue();
895-
deepEqual(items, [
862+
await tester.waitTilDeepEqual([
896863
{id:"1.1",a:1,b:1},
897864
{id:"1.2",a:1,b:2},
898865
{id:"2.1",a:2,b:1}
@@ -903,8 +870,7 @@ promisedTest("Issue 2058: Cache error after bulkPut failures", async () => {
903870
]).catch(error => {
904871
equal(error.failuresByPos[1].name, "ConstraintError", "Expected constraint error for the first operation");
905872
});
906-
items = await tester.waitNextValue();
907-
deepEqual(items, [
873+
await tester.waitTilDeepEqual([
908874
{id:"1.1",a:1,b:1},
909875
{id:"1.2",a:1,b:2},
910876
{id:"2.1",a:2,b:1},

0 commit comments

Comments
 (0)