diff --git a/channels/offline-channel-js/Tests/Unit/src/dbprovider.tests.ts b/channels/offline-channel-js/Tests/Unit/src/dbprovider.tests.ts index b805d84f3..5b970ebc9 100644 --- a/channels/offline-channel-js/Tests/Unit/src/dbprovider.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/dbprovider.tests.ts @@ -1,6 +1,6 @@ import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; import { IndexedDbProvider } from "../../../src/Providers/IndexDbProvider"; -import { createAsyncPromise, createAsyncRejectedPromise, doAwait } from "@nevware21/ts-async"; +import { createAsyncPromise, createAsyncRejectedPromise, createSyncPromise, doAwait, doAwaitResponse } from "@nevware21/ts-async"; import { arrForEach, strSubstr } from "@nevware21/ts-utils"; import { TestChannel } from "./TestHelper"; import { AppInsightsCore, IConfiguration, createDynamicConfig, generateW3CId, newGuid } from "@microsoft/applicationinsights-core-js"; @@ -65,44 +65,41 @@ export class OfflineDbProviderTests extends AITestClass { } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: init with auto clean set to true", - stepDelay: 100, - steps: [() => { + test: () => { + let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); let storageConfig = createDynamicConfig({autoClean: true}).cfg; let providerCxt = { itemCtx: itemCtx, storageConfig: storageConfig, - endpoint:DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH - } - this.ctx.isInit = provider.initialize(providerCxt); - this.ctx.provider = provider; - - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); + endpoint: endpoint + }; - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + Assert.ok(val, "init process is successful"); + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + Assert.ok(true, "should teardown provider"); + }, (reason) => { + Assert.ok(false, "error for teardown"); + }) + ); + } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: addEvent with no previous stored events", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); @@ -113,69 +110,47 @@ export class OfflineDbProviderTests extends AITestClass { endpoint: endpoint }; let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - Assert.deepEqual(item, evt, "should add expected item"); - Assert.ok(evt.id, "should add id to the item"); - this.preEvts.push(evt); - }, (reason) => { - this.ctx.addEventErr = reason; - Assert.ok(false, "error for add event"); - }); - - doAwait(provider.getNextBatch(), (item) => { - this.ctx.getEvt = item; - Assert.equal(item && item.length, 1, "should have one item"); - Assert.deepEqual((item as any)[0], evt, "should add expected item"); - }, (reason) => { - this.ctx.getEvtErr = reason; - Assert.ok(false, "error for get event") - }); - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.evt; - if (item) { - return true; - } - - return false; - }, "Wait for add Event response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getEvt; - if (item) { - return true; - } - - return false; - }, "Wait for get Event response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) + ).add(() => + doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + Assert.deepEqual(item, evt, "should add expected item"); + Assert.ok(evt.id, "should add id to the item"); + this.preEvts.push(evt); + }, (reason) => { + this.ctx.addEventErr = reason; + Assert.ok(false, "error for addEvt"); + }) + ).add(() => + doAwait(provider.getNextBatch(), (item) => { + this.ctx.getEvt = item; + Assert.equal(item && item.length, 1, "should have one item"); + Assert.deepEqual((item as any)[0], evt, "should add expected item"); + }, (reason) => { + this.ctx.getEvtErr = reason; + Assert.ok(false, "error for get event"); + }) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + Assert.ok(true, "should teardown provider"); + },(reason) => { + Assert.ok(false, "error for teardown"); + }) + ); + } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: addEvent with previous stored events", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); @@ -185,176 +160,114 @@ export class OfflineDbProviderTests extends AITestClass { storageConfig: storageConfig, endpoint: endpoint }; - // should have the event added by the previous test - let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "init error"); - }); - - doAwait(provider.getAllEvents(), (val) => { - this.ctx.preEvts = val; - Assert.equal(val && val.length, 1 , "should have the event from the previous test"); - Assert.equal((val as any)[0].id, this.preEvts[0].id, "should get back expected previous events"); - }, (reason)=> { - this.ctx.preEvtsErr = reason; - Assert.ok(false, "get previous events error"); - }); - - - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - Assert.equal(item, evt, "should have one event"); - }, (reason) => { - this.ctx.addEventErr = reason; - Assert.ok(false, "add event error"); - }); - doAwait(provider.getAllEvents(), (val) => { - this.ctx.allEvts = val; - Assert.equal(val && val.length, 2 , "should have the two events"); - Assert.deepEqual((val as any)[1], evt, "should get back expected added events"); - }, (reason)=> { - this.ctx.allEvtsErr = reason; - Assert.ok(false, "get all events error"); - }); - + let evt = TestHelper.mockEvent(endpoint, 3, false); let evt1 = TestHelper.mockEvent(endpoint, 1, false); let evt2 = TestHelper.mockEvent(endpoint, 2, false); - doAwait(provider.addEvent("", evt1, itemCtx), (item) => { - this.ctx.evt1 = item; - Assert.deepEqual(item, evt1, "should have expected event1"); - }, (reason) => { - this.ctx.addEvent1Err = reason; - Assert.ok(false, "add event1 error"); - }); - doAwait(provider.addEvent("", evt2, itemCtx), (item) => { - this.ctx.evt2 = item; - Assert.deepEqual(item, evt2, "should have expected event2"); - }, (reason) => { - this.ctx.addEvent2Err = reason; - Assert.ok(false, "add event2 error"); - }); - - doAwait(provider.getAllEvents(), (val) => { - this.ctx.allEvts1 = val; - Assert.equal(val && (val as any).length, 4, "should have four events"); - }, (reason)=> { - this.ctx.oneEvtsErr = reason; - Assert.ok(false, "get all events1 error"); - }); - doAwait(provider.getNextBatch(), (val) => { - this.ctx.nextBatch = val; - Assert.equal(val && (val as any).length, 1, "should return one event"); - Assert.deepEqual((val as any)[0], this.preEvts[0], "should have return the earliest event"); - }, (reason)=> { - this.ctx.nextBatchErr = reason; - Assert.ok(false, "get next batch error"); - }); + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) - doAwait(provider.getAllEvents(2), (val) => { - this.ctx.twoEvts = val; - Assert.equal(val && (val as any).length, 2, "should return two events"); - Assert.deepEqual((val as any)[0], this.preEvts[0], "should have return the earliest event1"); - }, (reason)=> { - this.ctx.twoEvtsErr = reason; - Assert.ok(false, "get two events error"); - }); - - doAwait(provider.clear(), (val) => { - this.ctx.clear = val; - Assert.equal(val && (val as any).length, 4, "should clear all events"); - this.preEvts = []; - }, (reason)=> { - this.ctx.clearErr = reason; - Assert.ok(false, "clear error"); - }); + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.preEvts = val; + Assert.equal(val && val.length, 1 , "should have the event from the previous test"); + Assert.ok((val as any)[0].id, "should have id"); + Assert.equal((val as any)[0].id, this.preEvts[0].id, "should get back expected previous events"); + }, (reason)=> { + this.ctx.preEvtsErr = reason; + Assert.ok(false, "get previous events error"); + }) - - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); + ).add(() => + doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + Assert.equal(item, evt, "should have one event"); + }, (reason)=> { + this.ctx.preEvtsErr = reason; + Assert.ok(false, "get previous events error"); + }) + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.allEvts = val; + Assert.equal(val && val.length, 2 , "should have the two events"); + Assert.deepEqual((val as any)[1], evt, "should get back expected added events"); + }, (reason) => { + this.ctx.addEventErr = reason; + Assert.ok(false, "add event error"); + }) + ).add(() => + doAwait(provider.addEvent("", evt1, itemCtx), (item) => { + this.ctx.evt1 = item; + Assert.deepEqual(item, evt1, "should have expected event1"); + }, (reason) => { + this.ctx.addEvent1Err = reason; + Assert.ok(false, "add event1 error"); + }) + ).add(() => + doAwait(provider.addEvent("", evt2, itemCtx), (item) => { + this.ctx.evt2 = item; + Assert.deepEqual(item, evt2, "should have expected event2"); + }, (reason) => { + this.ctx.addEvent2Err = reason; + Assert.ok(false, "add event2 error"); + }) + + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.allEvts1 = val; + Assert.equal(val && (val as any).length, 4, "should have four events"); + }, (reason)=> { + this.ctx.oneEvtsErr = reason; + Assert.ok(false, "get all events1 error"); + }) + + ).add(() => + doAwait(provider.getNextBatch(), (val) => { + this.ctx.nextBatch = val; + Assert.equal(val && (val as any).length, 1, "should return one event"); + Assert.deepEqual((val as any)[0], this.preEvts[0], "should have return the earliest event"); + }, (reason)=> { + this.ctx.nextBatchErr = reason; + Assert.ok(false, "get next batch error"); + }) + ).add(() => + doAwait(provider.getAllEvents(2), (val) => { + this.ctx.twoEvts = val; + Assert.equal(val && (val as any).length, 2, "should return two events"); + Assert.deepEqual((val as any)[0], this.preEvts[0], "should have return the earliest event1"); + }, (reason)=> { + this.ctx.twoEvtsErr = reason; + Assert.ok(false, "get two events error"); + }) + ).add(() => + doAwait(provider.clear(), (val) => { + this.ctx.clear = val; + Assert.equal(val && (val as any).length, 4, "should clear all events"); + }, (reason)=> { + this.ctx.twoEvtsErr = reason; + Assert.ok(false, "get two events error"); + }) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + }, (reason) => { + Assert.ok(false, "teardown error"); - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.preEvts; - if (item) { - return true; - } - - return false; - }, "Wait for get previous Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.evt; - if (item) { - return true; - } - - return false; - }, "Wait for add Event response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.allEvts; - if (item) { - return true; - } - - return false; - }, "Wait for get all Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item1 = this.ctx.evt1; - let item2 = this.ctx.evt2; - if (item1 && item2) { - return true; - } - - return false; - }, "Wait for add all Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts1; - if (items) { - return true; - } - - return false; - }, "Wait for get all Events1 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.nextBatch; - if (items && items.length == 1) { - return true; - } - - return false; - }, "Wait for get next Batch response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.twoEvts; - if (items && items.length == 2) { - return true; - } - - return false; - }, "Wait for get two Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.clear; - if (item) { - return true; - } - return false; - }, "Wait for clear response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + }) + ) + } }); - - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: getAllEvents should handle cursor errors", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); @@ -365,83 +278,66 @@ export class OfflineDbProviderTests extends AITestClass { endpoint: endpoint }; let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - }, (reason) => { - this.ctx.addEventErr = reason; - }); - let ctx = provider["_getDbgPlgTargets"](); - let db = ctx[3]; - this.sandbox.stub(db as any, "openDb").callsFake((name, ver, func, change?) => { - return createAsyncPromise((resolve, reject)=> { - try { - let openDbCtx = { - openCursor: (var1, var2, var3?) => { - return createAsyncRejectedPromise(new Error("open cursor mock error")); + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) + + ).add(() => + doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + }, (reason) => { + this.ctx.addEventErr = reason; + Assert.ok(false, "add evt error"); + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + }); + }) + + ).add(() => { + let ctx = provider["_getDbgPlgTargets"](); + let db = ctx[3]; + this.sandbox.stub(db as any, "openDb").callsFake((name, ver, func, change?) => { + return createAsyncPromise((resolve, reject)=> { + try { + let openDbCtx = { + openCursor: (var1, var2, var3?) => { + return createAsyncRejectedPromise(new Error("open cursor mock error")); + } } + // Database has been opened + doAwait(func(openDbCtx), resolve, reject); + } catch (e) { + reject(e); } - // Database has been opened - doAwait(func(openDbCtx), resolve, reject); - } catch (e) { - reject(e); - } - + }); + }); + return doAwait(provider.getNextBatch(), (val) => { + this.ctx.nextBatch = val; + Assert.ok(false, "should handle errors"); + }, (reason)=> { + this.ctx.nextBatchErr = reason; + Assert.equal(reason.message, "open cursor mock error"); }); - }); - - doAwait(provider.getNextBatch(), (val) => { - this.ctx.nextBatch = val; - }, (reason)=> { - this.ctx.nextBatchErr = reason; - }); - - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.evt; - if (item) { - return true; - } - - return false; - }, "Wait for add Event response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.nextBatchErr; - if (item) { - Assert.equal(item.message, "open cursor mock error"); - return true; - } - - return false; - }, "Wait for handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + }).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + },(reason) => { + Assert.ok(false, "teardown errors"); + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: removeEvents should delete expected events", - stepDelay: 100, - steps: [() => { + test: () => { this.core.addNotificationListener({ offlineBatchDrop: (cnt, reason)=> { this.batchDrop.push({cnt: cnt, reason: reason}); @@ -458,144 +354,116 @@ export class OfflineDbProviderTests extends AITestClass { notificationMgr: this.core.getNotifyMgr() }; let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - - doAwait(provider.removeEvents([evt]), (item) => { - this.ctx.removeEvts = item; - Assert.deepEqual(item && item.length, 0,"should not delete any events"); - }, (reason) => { - this.ctx.removeEvtsErr = reason; - Assert.ok(false, "error for remove events"); - }); - let evt1 = TestHelper.mockEvent(endpoint, 1, false); let evt2 = TestHelper.mockEvent(endpoint, 2, false); let evt4 = TestHelper.mockEvent(endpoint, 4, false); - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - Assert.deepEqual(item, evt, "should add exepcted evt"); + + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) + + ).add(() => + doAwait(provider.removeEvents([evt]), (item) => { + this.ctx.removeEvts = item; + Assert.deepEqual(item && item.length, 0,"should not delete any events"); + }, (reason) => { + this.ctx.removeEvtsErr = reason; + Assert.ok(false, "error for remove events"); + }) + + ).add(() => + doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + Assert.deepEqual(item, evt, "should add exepcted evt"); + }, (reason) => { + this.ctx.addEventErr = reason; + Assert.ok(false, "error for add events"); + }) + ).add(() => doAwait(provider.addEvent("", evt1, itemCtx), (item) => { this.ctx.evt1 = item; Assert.deepEqual(item, evt1, "should add exepcted evt1"); - doAwait(provider.addEvent("", evt2, itemCtx), (item) => { - this.ctx.evt2 = item; - Assert.deepEqual(item, evt2, "should add exepcted evt2"); - doAwait(provider.getAllEvents(), (val) => { - this.ctx.allEvts = val; - Assert.deepEqual(val && val.length, 3, "should have all expected 3 events"); - doAwait(provider.removeEvents([evt4]), (item) => { - this.ctx.removeEvts1 = item; - Assert.deepEqual(item && item.length, 0, "should not delete event1"); - doAwait(provider.removeEvents([evt, evt1]), (item) => { - this.ctx.removeEvts2 = item; - Assert.deepEqual(item && item.length, 2, "should delete all expected events"); - Assert.deepEqual((item as any)[0], evt, "should have deleted all event"); - Assert.deepEqual((item as any)[1], evt1, "should have deleted all event1"); - doAwait(provider.getAllEvents(), (val) => { - this.ctx.allEvts1 = val; - Assert.deepEqual(val && val.length, 1, "should have one event remaining"); - Assert.deepEqual((val as any)[0], evt2, "should have evt2"); - }, (reason)=> { - this.ctx.allEvts1Err = reason; - Assert.ok(false, "error for get all evts1"); - }); - }, (reason) => { - this.ctx.removeEvts2Err = reason; - Assert.ok(false, "error for remove events2"); - }); - }, (reason) => { - this.ctx.removeEvts1Err = reason; - Assert.ok(false, "error for remove events1"); - }); - }, (reason)=> { - this.ctx.allEvtsErr = reason; - Assert.ok(false, "error for get all events"); - - }); - }, (reason) => { - this.ctx.addEvent2Err = reason; - Assert.ok(false, "error for add event 2"); - }); }, (reason) => { this.ctx.addEvent1Err = reason; Assert.ok(false, "error for add event 1"); - }); - }, (reason) => { - this.ctx.addEventErr = reason; - Assert.ok(false, "error for add events"); - }); + }) + ).add(() => + doAwait(provider.addEvent("", evt2, itemCtx), (item) => { + this.ctx.evt2 = item; + Assert.deepEqual(item, evt2, "should add exepcted evt2"); + }, (reason) => { + this.ctx.addEvent2Err = reason; + Assert.ok(false, "error for add event 2"); + }) - - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.allEvts = val; + Assert.deepEqual(val && val.length, 3, "should have all expected 3 events"); + }, (reason)=> { + this.ctx.allEvtsErr = reason; + Assert.ok(false, "error for get all events"); + + }) - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.removeEvts; + ).add(() => + doAwait(provider.removeEvents([evt4]), (item) => { + this.ctx.removeEvts1 = item; + Assert.deepEqual(item && item.length, 0, "should not delete event1"); + }, (reason) => { + this.ctx.removeEvts1Err = reason; + Assert.ok(false, "error for remove events1"); + }) - if (items) { - return true; - } - - return false; - }, "Wait for remove evt response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts; + ).add(() => + doAwait(provider.removeEvents([evt, evt1]), (item) => { + this.ctx.removeEvts2 = item; + Assert.deepEqual(item && item.length, 2, "should delete all expected events"); + let item1 = (item as any)[0]; + let item2 = (item as any)[1]; + if (item1.id == evt1.id) { + Assert.deepEqual(item1, evt1, "should have deleted all event"); + Assert.deepEqual(item2, evt, "should have deleted all event1"); + } else { + Assert.deepEqual(item1, evt, "should have deleted all event"); + Assert.deepEqual(item2, evt1, "should have deleted all event1"); + } + }, (reason) => { + this.ctx.removeEvts2Err = reason; + Assert.ok(false, "error for remove events2"); + }) - if (items) { - return true; - } - - return false; - }, "Wait for get Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item1 = this.ctx.removeEvts1; - if (item1) { - return true; - } - - return false; - }, "Wait for remove Event1 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items2 = this.ctx.removeEvts2; + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.allEvts1 = val; + Assert.deepEqual(val && val.length, 1, "should have one event remaining"); + Assert.deepEqual((val as any)[0], evt2, "should have evt2"); + }, (reason)=> { + this.ctx.allEvts1Err = reason; + Assert.ok(false, "error for get all evts1"); + }) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + Assert.equal(this.batchDrop.length, 1, "notification should be called once"); // sent in clean process during initialization + Assert.equal(this.batchDrop[0].reason, 3, "notification should be called with expected reason time exceeded"); + },(reason) => { + Assert.ok(false, "teardown error"); - if (items2) { - return true; - } - - return false; - }, "Wait for remove event2 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts1; - - if (items ) { - return true; - } - - return false; - }, "Wait for get Events1 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - Assert.equal(this.batchDrop.length, 1, "notification should be called once"); // sent in clean process during initialization - Assert.equal(this.batchDrop[0].reason, 3, "notification should be called with expected reason time exceeded"); - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + }) + + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: clear should delete all events", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); @@ -605,99 +473,77 @@ export class OfflineDbProviderTests extends AITestClass { storageConfig: storageConfig, endpoint: endpoint }; - - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - - let evt = TestHelper.mockEvent(endpoint, 3, false); let evt1 = TestHelper.mockEvent(endpoint, 1, false); let evt2 = TestHelper.mockEvent(endpoint, 2, false); - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - Assert.deepEqual(item, evt, "should add evt"); - }, (reason) => { - this.ctx.addEventErr = reason; - Assert.ok(false, "error for add evt"); - }); - doAwait(provider.addEvent("", evt1, itemCtx), (item) => { - this.ctx.evt1 = item; - Assert.deepEqual(item, evt1, "should add evt1"); - }, (reason) => { - this.ctx.addEvent1Err = reason; - Assert.ok(false, "error for add evt1"); - }); - doAwait(provider.addEvent("", evt2, itemCtx), (item) => { - this.ctx.evt2 = item; - Assert.deepEqual(item, evt2, "should add evt2"); - }, (reason) => { - this.ctx.addEvent2Err = reason; - Assert.ok(false, "error for add evt2"); - }); - + + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) - doAwait(provider.clear(), (val)=> { - this.ctx.clearEvts = val; - Assert.ok(val && val.length >= 3, "should clear events"); // may have the events from previous test - }, (reason)=> { - this.ctx.clearEvtsErr = reason; - Assert.ok(false, "error for clear"); + ).add(() => + doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + Assert.deepEqual(item, evt, "should add evt"); + }, (reason) => { + this.ctx.addEventErr = reason; + Assert.ok(false, "error for add evt"); + }) + ).add(() => + doAwait(provider.addEvent("", evt1, itemCtx), (item) => { + this.ctx.evt1 = item; + Assert.deepEqual(item, evt1, "should add evt1"); + }, (reason) => { + this.ctx.addEvent1Err = reason; + Assert.ok(false, "error for add evt1"); + }) - }); + ).add(() => + doAwait(provider.addEvent("", evt2, itemCtx), (item) => { + this.ctx.evt2 = item; + Assert.deepEqual(item, evt2, "should add evt2"); + }, (reason) => { + this.ctx.addEvent2Err = reason; + Assert.ok(false, "error for add evt2"); + }) - doAwait(provider.getAllEvents(), (val) => { - this.ctx.allEvts1 = val; - Assert.equal(val && val.length, 0, "should not have any evnets" ); - }, (reason)=> { - this.ctx.allEvts1Err = reason; - Assert.ok(false, "get events error"); - }); + ).add(() => + doAwait(provider.clear(), (val)=> { + this.ctx.clearEvts = val; + Assert.ok(val && val.length >= 3, "should clear events"); // may have the events from previous test + }, (reason)=> { + this.ctx.clearEvtsErr = reason; + Assert.ok(false, "error for clear"); - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); + }) - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.evt; - let item1 = this.ctx.evt1; - let item2 = this.ctx.evt2; - if (item && item1 && item2) { - return true; - } - - return false; - }, "Wait for get Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts1; - - if (items && items.length == 0) { - return true; - } - - return false; - }, "Wait for get Events1 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + ).add(() => + doAwait(provider.getAllEvents(), (val) => { + this.ctx.allEvts1 = val; + Assert.equal(val && val.length, 0, "should not have any events" ); + }, (reason)=> { + this.ctx.allEvts1Err = reason; + Assert.ok(false, "get events error"); + }) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + },(reason) => { + Assert.ok(false, "teardown error"); + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "IndexedDbProvider: clean should delete all events that exist longer than max storage time", - stepDelay: 100, + pollDelay: 100, useFakeTimers: true, - steps: [() => { + test: () => { this.core.addNotificationListener({ offlineBatchDrop: (cnt, reason)=> { this.batchDrop.push({cnt: cnt, reason: reason}); @@ -713,7 +559,7 @@ export class OfflineDbProviderTests extends AITestClass { endpoint: endpoint, notificationMgr: this.core.getNotifyMgr() }; - + doAwait(provider.initialize(providerCxt), (val) => { this.ctx.isInit = val; }, (reason)=> { @@ -774,180 +620,60 @@ export class OfflineDbProviderTests extends AITestClass { Assert.ok(false, "get all events error") }); - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts; - let cnt = 0; - if (items && items.length == 3) { - arrForEach(items, (item) => { - cnt += item.criticalCnt; - }) - Assert.equal(cnt, 6, "should get expected three events"); - return true; - } - - return false; - }, "Wait for get Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.cleanEvts; - - if (item) { - return true; - } - - return false; - }, "Wait for clean Events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let items = this.ctx.allEvts1; - - if (items) { - return true; - } - - return false; - }, "Wait for get Events1 response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - Assert.equal(this.batchDrop.length, 1, "notification should be called once"); - Assert.equal(this.batchDrop[0].cnt, 2, "notification should be called with 2 count"); - Assert.equal(this.batchDrop[0].reason, 3, "notification should be called with expected reason clean time exceeded"); - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + return this._asyncQueue().concat(PollingAssert.asyncTaskPollingAssert(() => { + let isInit = this.ctx.isInit; + if (isInit) { + return true; + } + return false; + }, "Wait for Init response" + new Date().toISOString(), 30, 1000)).concat(PollingAssert.asyncTaskPollingAssert(() => { + let items = this.ctx.allEvts; + let cnt = 0; + if (items && items.length == 3) { + arrForEach(items, (item) => { + cnt += item.criticalCnt; + }) + Assert.equal(cnt, 6, "should get expected three events"); + return true; + } + + return false; + }, "Wait for get Events response" + new Date().toISOString(), 30, 1000)).concat(PollingAssert.asyncTaskPollingAssert(() => { + let item = this.ctx.cleanEvts; + + if (item) { + return true; + } + + return false; + }, "Wait for clean Events response" + new Date().toISOString(), 30, 1000)).concat(PollingAssert.asyncTaskPollingAssert(() => { + let items = this.ctx.allEvts1; + + if (items) { + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + }); + return true; + } + + return false; + }, "Wait for get Events1 response" + new Date().toISOString(), 30, 1000)).concat(PollingAssert.asyncTaskPollingAssert(() => { + let isclosed = this.ctx.isclosed; + if (isclosed) { + Assert.equal(this.batchDrop.length, 1, "notification should be called once"); + Assert.equal(this.batchDrop[0].cnt, 2, "notification should be called with 2 count"); + Assert.equal(this.batchDrop[0].reason, 3, "notification should be called with expected reason clean time exceeded"); + return true; + } + return false; + }, "Wait for close response" + new Date().toISOString(), 30, 1000)) + } }); - this.testCaseAsync({ - name: "IndexedDbProvider: Error handle should handle open errors", - stepDelay: 100, - steps: [() => { - let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; - let provider = new IndexedDbProvider(); - let itemCtx = this.core.getProcessTelContext(); - let storageConfig = createDynamicConfig({autoClean: true}).cfg; - let providerCxt = { - itemCtx: itemCtx, - storageConfig: storageConfig, - endpoint: endpoint - }; - let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - let ctx = provider["_getDbgPlgTargets"](); - let db = ctx[3]; - this.sandbox.stub(db as any, "openDb").callsFake((key) => { - return createAsyncRejectedPromise(new Error("open db mock error")) - }); - - - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - this.ctx.evt = item; - }, (reason) => { - this.ctx.addEventErr = reason; - }); - - doAwait(provider.removeEvents([evt]), (item) => { - this.ctx.removeEvt = item; - Assert.deepEqual(item, [], "should return []"); - }, (reason) => { - this.ctx.removeEvtErr = reason; - Assert.ok(false, "error for remove events"); - }); - doAwait(provider.getAllEvents(), (item) => { - this.ctx.getEvts = item; - }, (reason) => { - this.ctx.getEvtsErr = reason; - }); - - doAwait(provider.clean(), (item) => { - this.ctx.cleanEvts = item; - Assert.ok(!item, "should not clean"); - }, (reason) => { - this.ctx.cleanEvtsErr = reason; - Assert.ok(false, "error for clean"); - }); - - doAwait(provider.clear(), (item) => { - this.ctx.clearEvts = item; - Assert.deepEqual(item, [], "should not clear"); - }, (reason) => { - this.ctx.clearEvtsErr = reason; - Assert.ok(false, "error for clean"); - }); - - - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.addEventErr; - if (item) { - Assert.equal(item.message, "open db mock error"); - return true; - } - - return false; - }, "Wait for add Event handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.removeEvt; - if (item) { - return true; - } - - return false; - }, "Wait for remove Event handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getEvtsErr; - if (item) { - Assert.equal(item.message, "open db mock error"); - return true; - } - - return false; - }, "Wait for get all events handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.cleanEvts; - if (item !== null) { - return true; - } - - return false; - }, "Wait for get clean events handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.clearEvts; - if (item) { - return true; - } - - return false; - }, "Wait for get clear events handle error response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) - }); - - this.testCaseAsync({ - name: "IndexedDbProvider: Error handle should handle cursor errors", - stepDelay: 100, - steps: [() => { + this.testCase({ + name: "IndexedDbProvider: Error handle should handle open errors", + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let provider = new IndexedDbProvider(); let itemCtx = this.core.getProcessTelContext(); @@ -958,141 +684,98 @@ export class OfflineDbProviderTests extends AITestClass { endpoint: endpoint }; let evt = TestHelper.mockEvent(endpoint, 3, false); - doAwait(provider.initialize(providerCxt), (val) => { - this.ctx.isInit = val; - }, (reason)=> { - this.ctx.initErr = reason; - Assert.ok(false, "error for init"); - }); - - - let ctx = provider["_getDbgPlgTargets"](); - let db = ctx[3]; - this.sandbox.stub(db as any, "openDb").callsFake((name, ver, func, change?) => { - return createAsyncPromise((resolve, reject)=> { - try { - let openDbCtx = { - openCursor: (var1, var2, var3?) => { - return createAsyncRejectedPromise(new Error("open cursor mock error")); - }, - openStore: (var1, var2, var3) => { - return createAsyncRejectedPromise(new Error("open store mock error")); + return this._asyncQueue().add(() => + doAwait(provider.initialize(providerCxt), (val) => { + this.ctx.isInit = val; + let ctx = provider["_getDbgPlgTargets"](); + let db = ctx[3]; + this.sandbox.stub(db as any, "openDb").callsFake((name, ver, func, change?) => { + return createAsyncPromise((resolve, reject)=> { + try { + let openDbCtx = { + openCursor: (var1, var2, var3?) => { + return createAsyncRejectedPromise(new Error("open cursor mock error")); + }, + openStore: (var1, var2, var3) => { + return createAsyncRejectedPromise(new Error("open store mock error")); + } + } + // Database has been opened + doAwait(func(openDbCtx), resolve, reject); + } catch (e) { + reject(e); } - } - // Database has been opened - doAwait(func(openDbCtx), resolve, reject); - } catch (e) { - reject(e); - } - - }); - }); - - doAwait(provider.addEvent("", evt, itemCtx), (item) => { - Assert.ok(false, "should handle add event error"); - }, (reason) => { - this.ctx.addEvent = reason; - Assert.equal(reason.message, "open store mock error", "add event message"); - }); - doAwait(provider.getNextBatch(), (val) => { - Assert.ok(false, "should handle get next batch error") - }, (reason)=> { - this.ctx.nextBatch = reason; - Assert.equal(reason.message, "open cursor mock error", "get next batch message"); - }); + }); + }); + }, (reason)=> { + this.ctx.initErr = reason; + Assert.ok(false, "error for init"); + }) - doAwait(provider.getAllEvents(), (val) => { - Assert.ok(false, "should handle get all events error") - }, (reason)=> { - this.ctx.allEvts = reason; - Assert.equal(reason.message, "open cursor mock error", "get all events message"); - }); + ).add(() => { + + return doAwait(provider.addEvent("", evt, itemCtx), (item) => { + this.ctx.evt = item; + Assert.ok(false, "should handle add event error"); + }, (reason) => { + this.ctx.addEvent = reason; + Assert.equal(reason.message, "open store mock error", "add event message"); + }) + + + }).add(() => { + doAwait(provider.getNextBatch(), (val) => { + Assert.ok(false, "should handle get next batch error") + }, (reason)=> { + this.ctx.nextBatch = reason; + Assert.equal(reason.message, "open cursor mock error", "get next batch message"); + }) - doAwait(provider.removeEvents([evt]), (val) => { - this.ctx.removeEvts = val; - Assert.deepEqual([], val, "should handle remove events error") - }, (reason)=> { - this.ctx.removeEvtsErr = reason; - Assert.ok(false, "error for get next batch"); - }); + }).add(() => { + doAwait(provider.getAllEvents(), (val) => { + Assert.ok(false, "should handle get all events error") + }, (reason)=> { + this.ctx.allEvts = reason; + Assert.equal(reason.message, "open cursor mock error", "get all events message") + }) - doAwait(provider.clear(), (val) => { - this.ctx.clear = val; - Assert.deepEqual([], val, "should handle clear error") - }, (reason)=> { - this.ctx.clearErr = reason; - Assert.ok(false, "error for clear"); - }); + }).add(() => { + doAwait(provider.removeEvents([evt]), (val) => { + this.ctx.removeEvts = val; + Assert.deepEqual([], val, "should handle remove events error") + }, (reason)=> { + this.ctx.removeEvtsErr = reason; + Assert.ok(false, "error for get next batch"); + }) - doAwait(provider.clean(), (val) => { - this.ctx.clean = val; - Assert.ok(!val, "should handle clean error") - }, (reason)=> { - this.ctx.cleanErr = reason; - Assert.ok(false, "error for clean"); - }); + }).add(() => + doAwait(provider.clear(), (val) => { + this.ctx.clear = val; + Assert.deepEqual([], val, "should handle clear error") + }, (reason)=> { + this.ctx.clearErr = reason; + Assert.ok(false, "error for clear"); + }) - doAwait(provider.teardown(), () => { - this.ctx.isclosed = true; - }); + ).add(() => + doAwait(provider.clean(), (val) => { + this.ctx.clean = val; + Assert.ok(!val, "should handle clean error") + }, (reason)=> { + this.ctx.cleanErr = reason; + Assert.ok(false, "error for clean"); + }) - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for Init response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.addEvent; - if (item) { - return true; - } - - return false; - }, "Wait for add Event response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.nextBatch ; - if (item) { - return true; - } - - return false; - }, "Wait for next batch response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.allEvts; - if (item) { - return true; - } - - return false; - }, "Wait for all events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.removeEvts; - if (item) { - return true; - } - - return false; - }, "Wait for remove events response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.clear; - if (item) { - return true; - } - - return false; - }, "Wait for clear response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.clean; - if (item !== null) { - return true; - } - - return false; - }, "Wait for clean response" + new Date().toISOString(), 30, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 30, 1000) as any) + ).add(() => + doAwait(provider.teardown(), () => { + this.ctx.isclosed = true; + },(reason) => { + Assert.ok(false, "teardown error"); + }) + ) + } }); } diff --git a/channels/offline-channel-js/Tests/Unit/src/offlinebatchhandler.tests.ts b/channels/offline-channel-js/Tests/Unit/src/offlinebatchhandler.tests.ts index f28efe5fa..779c89abd 100644 --- a/channels/offline-channel-js/Tests/Unit/src/offlinebatchhandler.tests.ts +++ b/channels/offline-channel-js/Tests/Unit/src/offlinebatchhandler.tests.ts @@ -64,10 +64,9 @@ export class OfflineBatchHandlerTests extends AITestClass { } }); - this.testCaseAsync({ + this.testCase({ name: "Offline Batch Handler: init with IndexedDB storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.IndexedDb], autoClean: true, inStorageMaxTime: 1 } as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -79,40 +78,33 @@ export class OfflineBatchHandlerTests extends AITestClass { endpoint: endpoint } let batchHandler = new OfflineBatchHandler(); - doAwait(batchHandler.initialize(providerCxt),(res) => { - this.ctx.isInit = true; - let items = batchHandler["_getDbgPlgTargets"](); - let provider = items[0]; - let isInit = items[1]; - Assert.ok(provider, "provider is initialized"); - Assert.ok(isInit, "initialization is successful"); - }); - - doAwait(batchHandler.teardown(),(res) => { - this.ctx.isclosed = true; - }); + return this._asyncQueue().add(() => + doAwait(batchHandler.initialize(providerCxt),(res) => { + this.ctx.isInit = true; + let items = batchHandler["_getDbgPlgTargets"](); + let provider = items[0]; + let isInit = items[1]; + Assert.ok(provider, "provider is initialized"); + Assert.ok(isInit, "initialization is successful"); + + },(reason) => { + Assert.ok(false, "init errors"); + }) + ).add(() => + doAwait(batchHandler.teardown(),(res) => { + this.ctx.isclosed = true; + },(reason) => { + Assert.ok(false, "teardown errors"); + }) + ) - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - - return true; - } - return false; - }, "Wait for init response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) + } + }); - this.testCaseAsync({ + this.testCase({ name: "Store Batch: store batch with web storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true } as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -139,59 +131,50 @@ export class OfflineBatchHandlerTests extends AITestClass { result.push(res); } let evt = TestHelper.mockEvent(endpoint, 1, false); - doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { - this.ctx.storeBatch = true; - this.ctx.result = result; - }); - - doAwait(batchHandler.hasStoredBatch(),(res) => { - this.ctx.hasBatch = res; - }); - - - doAwait( batchHandler.teardown(), () => { - this.ctx.isclosed = true; - }); + + return this._asyncQueue().add(() => + doAwait(batchHandler.storeBatch(evt, cb) as any,(storeRes) => { + this.ctx.storeBatch = true; + this.ctx.result = result; + let res = result[0]; + let state = res.state == eBatchStoreStatus.Success; + Assert.ok(state, "state should be ok"); + let item = res.item; + Assert.ok(item.id, "item id should be set"); + Assert.equal(item.criticalCnt, 1, "expected item should be returned"); - }].concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch) { - let res = this.ctx.result[0]; - let state = res.state == eBatchStoreStatus.Success; - Assert.ok(state, "state should be ok"); - let item = res.item; - Assert.ok(item.id, "item id should be set"); - Assert.equal(item.criticalCnt, 1, "expected item should be returned"); - - let storageKey = "AIOffline_1_dc.services.visualstudio.com"; - let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; - let storageObject = JSON.parse(storageStr); - let storageEvts = storageObject.evts; - Assert.deepEqual(Object.keys(storageEvts).length, 1, "storgae should only have one event"); - Assert.ok(storageEvts[item.id], "storgae should contain expected item"); - - return true; - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch = this.ctx.hasBatch; - if (hasBatch) { - return true; - } - return false; - }, "Wait for has batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) + let storageKey = "AIOffline_1_dc.services.visualstudio.com"; + let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; + let storageObject = JSON.parse(storageStr); + let storageEvts = storageObject.evts; + Assert.deepEqual(Object.keys(storageEvts).length, 1, "storgae should only have one event"); + Assert.ok(storageEvts[item.id], "storgae should contain expected item"); + + + }, (reason) => { + Assert.ok(false, "init error"); + }) + + ).add(() => + doAwait(batchHandler.hasStoredBatch(),(res) => { + this.ctx.hasBatch = res; + }, (reason) => { + Assert.ok(false, "hasStoreBatch error") + }) + + ).add(() => + doAwait( batchHandler.teardown(), () => { + this.ctx.isclosed = true; + },(reason) => { + Assert.ok(false, "teardown errors") + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Store Batch: store batch with indexedDB storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.IndexedDb], autoClean: true, inStorageMaxTime:1} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -203,76 +186,54 @@ export class OfflineBatchHandlerTests extends AITestClass { endpoint: endpoint } let batchHandler = new OfflineBatchHandler(); - doAwait(batchHandler.initialize(providerCxt),(res) => { - this.ctx.isInit = true; - let items = batchHandler["_getDbgPlgTargets"](); - let provider = items[0]; - let isInit = items[1]; - Assert.ok(provider, "provider is initialized"); - Assert.ok(isInit, "initialization is successful"); - }); - - let result:any[] = []; let cb = (res) => { this.ctx.storeBatch = true; result.push(res); } let evt = TestHelper.mockEvent(endpoint, 1, false); - batchHandler.storeBatch(evt, cb); - doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { - this.ctx.storeBatch = true; - this.ctx.result = result; - }); - - - doAwait(batchHandler.hasStoredBatch(),(res) => { - this.ctx.hasBatch = res; - }); - - - doAwait( batchHandler.teardown(), () => { - this.ctx.isclosed = true; - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for init response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch) { - let res = this.ctx.result[0]; - let state = res.state == eBatchStoreStatus.Success; - Assert.ok(state, "state should be ok"); - let item = res.item; - Assert.ok(item.id, "item id should be set"); - Assert.equal(item.criticalCnt, 1, "expected item should be returned"); - - return true; - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch = this.ctx.hasBatch; - if (hasBatch) { - return true; - } - return false; - }, "Wait for has batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) + + return this._asyncQueue().add(() => + doAwait(batchHandler.initialize(providerCxt),(res) => { + this.ctx.isInit = true; + let items = batchHandler["_getDbgPlgTargets"](); + let provider = items[0]; + let isInit = items[1]; + Assert.ok(provider, "provider is initialized"); + Assert.ok(isInit, "initialization is successful"); + },(reason) => { + Assert.ok(false, "init errors") + }) + + ).add(() => + doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { + this.ctx.storeBatch = true; + this.ctx.result = result; + }, (reason) => { + Assert.ok(false, "storebatch error") + }) + + ).add(() => + doAwait(batchHandler.hasStoredBatch(),(res) => { + this.ctx.hasBatch = res; + }, (reason) => { + Assert.ok(false, "hasbatch error"); + }) + + ).add(() => + doAwait( batchHandler.teardown(), () => { + this.ctx.isclosed = true; + }, (reason) => { + Assert.ok(false, "teardown error") + }) + + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Clean Batch: clean batch with web storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, inStorageMaxTime:1} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -298,91 +259,79 @@ export class OfflineBatchHandlerTests extends AITestClass { let cb = (res) => { result.push(res); } - let evt = TestHelper.mockEvent(endpoint, 1, false); - doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { - this.ctx.storeBatch = 1; - this.ctx.result = result; - }); - - let evt1 = TestHelper.mockEvent(endpoint, 2, false); - doAwait(batchHandler.storeBatch(evt1, cb) as any,(res) => { - this.ctx.storeBatch = 2; - this.ctx.result = result; - }); - - let evt2 = TestHelper.mockEvent(endpoint, 3, false); - doAwait(batchHandler.storeBatch(evt2, cb) as any,(res) => { - this.ctx.storeBatch = 3; - this.ctx.result = result; - - }); - let storageKey = "AIOffline_1_dc.services.visualstudio.com"; - let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; - let storageObject = JSON.parse(storageStr); - let storageEvts = storageObject.evts; - Assert.deepEqual(Object.keys(storageEvts).length, 3, "storage should have three events"); - let cb1 = (res) => { this.ctx.hasBatch = res; } - doAwait(batchHandler.hasStoredBatch(cb1),(res) => { - - }); - let cb2 = (res) => { this.ctx.cleanBatch = true; this.ctx.cleanBatchRes = res; } - doAwait(batchHandler.cleanStorage(cb2) as any,(res) => { - - }); - - - doAwait( batchHandler.teardown(), () => { - this.ctx.isclosed = true; - }); + let evt = TestHelper.mockEvent(endpoint, 1, false); + let evt1 = TestHelper.mockEvent(endpoint, 2, false); + let evt2 = TestHelper.mockEvent(endpoint, 3, false); - }].concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch && storeBatch > 2) { - Assert.equal(storeBatch, 3, "should have three response"); - let res = this.ctx.result; - Assert.equal(res.length, 3, "response should have three items"); - return true - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch = this.ctx.hasBatch; - if (hasBatch) { - return true; - } - return false; - }, "Wait for has batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let cleanBatch = this.ctx.cleanBatch; - if (cleanBatch) { - let res = this.ctx.cleanBatchRes; - Assert.equal(res.batchCnt, 3, "should clean all three items"); - let storageKey = "AIOffline_1_dc.services.visualstudio.com"; - let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; - let storageObject = JSON.parse(storageStr); - let storageEvts = storageObject.evts; - Assert.deepEqual(Object.keys(storageEvts).length, 0, "storgae should not only have any event"); - return true; - } - return false; - }, "Wait for clean batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) + return this._asyncQueue().add(() => + doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { + this.ctx.storeBatch = 1; + this.ctx.result = result; + },(reason) => { + Assert.ok(false, "init errors"); + }) + + ).add(() => + doAwait(batchHandler.storeBatch(evt1, cb) as any,(res) => { + this.ctx.storeBatch = 2; + this.ctx.result = result; + },(reason) => { + Assert.ok(false, "store batch errors"); + }) + + ).add(() => + doAwait(batchHandler.storeBatch(evt2, cb) as any,(res) => { + this.ctx.storeBatch = 3; + this.ctx.result = result; + let storageKey = "AIOffline_1_dc.services.visualstudio.com"; + let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; + let storageObject = JSON.parse(storageStr); + let storageEvts = storageObject.evts; + Assert.deepEqual(Object.keys(storageEvts).length, 3, "storage should have three events"); + },(reason) => { + Assert.ok(false, "storebatch error") + }) + + ).add(() => + doAwait(batchHandler.hasStoredBatch(cb1),(res) => { + }, (reason) => { + Assert.ok(false, "hasstoredbatch error"); + }) + + ).add(() => + doAwait(batchHandler.cleanStorage(cb2) as any,(cleanRes) => { + let res = this.ctx.cleanBatchRes; + Assert.equal(res.batchCnt, 3, "should clean all three items"); + let storageKey = "AIOffline_1_dc.services.visualstudio.com"; + let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; + let storageObject = JSON.parse(storageStr); + let storageEvts = storageObject.evts; + Assert.deepEqual(Object.keys(storageEvts).length, 0, "storgae should not only have any event"); + },(reason) => { + Assert.ok(false, "clean storage errors") + }) + + ).add(() => + doAwait( batchHandler.teardown(), () => { + this.ctx.isclosed = true; + }, (reason) => { + Assert.ok(false, "teardown error") + }) + + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Clean Batch: clean batch with IndexedDB storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.IndexedDb], autoClean: true, inStorageMaxTime:1} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -396,116 +345,92 @@ export class OfflineBatchHandlerTests extends AITestClass { } let batchHandler = new OfflineBatchHandler(); let provider; - doAwait(batchHandler.initialize(providerCxt),(res) => { - this.ctx.isInit = true; - let items = batchHandler["_getDbgPlgTargets"](); - provider = items[0]; - let isInit = items[1]; - Assert.ok(provider, "provider is initialized"); - Assert.ok(isInit, "initialization is successful"); - }); - let result:any[] = []; let cb = (res) => { result.push(res); } - let evt = TestHelper.mockEvent(endpoint, 1, false); - doAwait(batchHandler.storeBatch(evt, cb),(res) => { - this.ctx.storeBatch = 1; - this.ctx.result = result; - }); - - let evt1 = TestHelper.mockEvent(endpoint, 2, false); - doAwait(batchHandler.storeBatch(evt1, cb),(res) => { - this.ctx.storeBatch = 2; - this.ctx.result = result; - }); - - let evt2 = TestHelper.mockEvent(endpoint, 3, false); - doAwait(batchHandler.storeBatch(evt2, cb),(res) => { - this.ctx.storeBatch = 3; - this.ctx.result = result; - - }); - let cb1 = (res) => { this.ctx.hasBatch = res; } - doAwait(batchHandler.hasStoredBatch(cb1),(res) => { - - }); - let cb2 = (res) => { this.ctx.cleanBatch = true; this.ctx.cleanBatchRes = res; } - doAwait(batchHandler.cleanStorage(cb2),(res) => { - - }); - let cb3 = (res) => { this.ctx.hasBatch1Called = true; this.ctx.hasBatch1 = res; } - doAwait(batchHandler.hasStoredBatch(cb3),(res) => { - - }); - - - doAwait( batchHandler.teardown(), () => { - this.ctx.isclosed = true; - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let isInit = this.ctx.isInit; - if (isInit) { - return true; - } - return false; - }, "Wait for int response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch && storeBatch > 2) { - Assert.equal(storeBatch, 3, "should have three response"); - let res = this.ctx.result; - Assert.equal(res.length, 3, "response should have three items"); - return true - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch = this.ctx.hasBatch; - if (hasBatch) { - return true; - } - return false; - }, "Wait for has batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let cleanBatch = this.ctx.cleanBatch; - if (cleanBatch) { - let res = this.ctx.cleanBatchRes; - Assert.equal(res.batchCnt, 3, "should clean all three items"); - return true; - } - return false; - }, "Wait for clean batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch1Called = this.ctx.hasBatch1Called; - if (hasBatch1Called) { - let hasBatch = this.ctx.hasBatch1; - Assert.equal(hasBatch, false, "should not contain any events") - return true; - } - return false; - }, "Wait for has batch1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) + let evt = TestHelper.mockEvent(endpoint, 1, false); + let evt1 = TestHelper.mockEvent(endpoint, 2, false); + let evt2 = TestHelper.mockEvent(endpoint, 3, false); + + return this._asyncQueue().add(() => + doAwait(batchHandler.initialize(providerCxt),(res) => { + this.ctx.isInit = true; + let items = batchHandler["_getDbgPlgTargets"](); + provider = items[0]; + let isInit = items[1]; + Assert.ok(provider, "provider is initialized"); + Assert.ok(isInit, "initialization is successful"); + }, (reason) => { + Assert.ok(false, "init errors") + }) + + ).add(() => + doAwait(batchHandler.storeBatch(evt, cb) as any,(res) => { + this.ctx.storeBatch = 1; + this.ctx.result = result; + }, (reason) => { + Assert.ok(false, "store batch errors") + }) + ).add(() => + doAwait(batchHandler.storeBatch(evt1, cb) as any,(res) => { + this.ctx.storeBatch = 2; + this.ctx.result = result; + }, (reason) => { + Assert.ok(false, "store batch error 1") + }) + ).add(() => + doAwait(batchHandler.storeBatch(evt2, cb) as any,(res) => { + this.ctx.storeBatch = 3; + this.ctx.result = result; + Assert.equal(result.length, 3, "response should have three items"); + }, (reason) => { + Assert.ok(false, "store batch error 2") + }) + ).add(() => + doAwait(batchHandler.hasStoredBatch(cb1),(res) => {},(reason) => { + Assert.ok(false, "has store batch error") + }) + ).add(() => + doAwait(batchHandler.cleanStorage(cb2) as any,(cleanRes) => { + let res = this.ctx.cleanBatchRes; + Assert.equal(res.batchCnt, 3, "should clean all three items"); + },(reason) => { + Assert.ok(false, "clean store batch error") + }) + ).add(() => + doAwait(batchHandler.hasStoredBatch(cb3),(res) => { + let hasBatch = this.ctx.hasBatch1; + Assert.equal(hasBatch, false, "should not contain any events") + },(reason) => { + Assert.ok(false, "has store store batch error") + + }) + ).add(() => + doAwait(batchHandler.teardown(), () => { + this.ctx.isclosed = true; + }, (reason) => { + Assert.ok(false, "teardown error") + + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: send Next Batch with web storge provider", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -530,23 +455,12 @@ export class OfflineBatchHandlerTests extends AITestClass { let evt = TestHelper.mockEvent(endpoint, 1, false); let evt1 = TestHelper.mockEvent(endpoint, 2, false); let evt2 = TestHelper.mockEvent(endpoint, 3, false); - doAwait(batchHandler.storeBatch(evt),(res) => { - this.ctx.storeBatch = 1; - }); - doAwait(batchHandler.storeBatch(evt1),(res) => { - this.ctx.storeBatch = 2; - }); - doAwait(batchHandler.storeBatch(evt2),(res) => { - this.ctx.storeBatch = 3; - }); - + let sender1Payload: any[] = [] let sender1 = (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => { sender1Payload.push(payload); oncomplete(400, {}); } - // 200 should be called first, in some case, re-try will be added back (sender2) and event2 will be returned again - // This is to guarantee the test gets events in order let sender2Payload: any[] = [] let sender2 = (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => { sender2Payload.push(payload); @@ -562,131 +476,81 @@ export class OfflineBatchHandlerTests extends AITestClass { let cb1 = (res) => { res1.push(res); } - doAwait(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { - this.ctx.sendBatch1 = true; - this.ctx.sendBatch1Res = res1; - this.ctx.sendBatch1Pd = sender1Payload; - }); - let res2: any[] = []; let cb2 = (res) => { res2.push(res); } - - doAwait(batchHandler.sendNextBatch(cb2, false, {sendPOST: sender2}) as any,(res) => { - this.ctx.sendBatch2 = true; - this.ctx.sendBatch2Res = res2; - this.ctx.sendBatch2Pd = sender2Payload; - }); - let res3: any[] = []; let cb3 = (res) => { res3.push(res); } - doAwait(batchHandler.sendNextBatch(cb3, false, {sendPOST: sender3}) as any,(res) => { - this.ctx.sendBatch3 = true; - this.ctx.sendBatch3Res = res3; - this.ctx.sendBatch3Pd = sender3Payload; - }); - - - let cb4 = (res) => { this.ctx.hasBatch1Called = true; this.ctx.hasBatch1 = res && res.length >= 1; } - doAwait(batchHandler.hasStoredBatch(cb4),(res) => { - - }); - - - doAwait( batchHandler.teardown(), () => { - this.ctx.isclosed = true; - }); + return this._asyncQueue().add(() => { + doAwait(batchHandler.storeBatch(evt), (res) => { + this.ctx.storeBatch = 1; + }, (reason) => { + Assert.ok(false, "storeBatch 1 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.storeBatch(evt1), (res) => { + this.ctx.storeBatch = 2; + }, (reason) => { + Assert.ok(false, "storeBatch 2 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.storeBatch(evt2), (res) => { + this.ctx.storeBatch = 3; + }, (reason) => { + Assert.ok(false, "storeBatch 3 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any, (res) => { + this.ctx.sendBatch1 = true; + this.ctx.sendBatch1Res = res1; + this.ctx.sendBatch1Pd = sender1Payload; + }, (reason) => { + Assert.ok(false, "sendNextBatch 1 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.sendNextBatch(cb2, false, {sendPOST: sender2}) as any, (res) => { + this.ctx.sendBatch2 = true; + this.ctx.sendBatch2Res = res2; + this.ctx.sendBatch2Pd = sender2Payload; + }, (reason) => { + Assert.ok(false, "sendNextBatch 2 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.sendNextBatch(cb3, false, {sendPOST: sender3}) as any, (res) => { + this.ctx.sendBatch3 = true; + this.ctx.sendBatch3Res = res3; + this.ctx.sendBatch3Pd = sender3Payload; + }, (reason) => { + Assert.ok(false, "sendNextBatch 3 error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.hasStoredBatch(cb4), (res) => { + }, (reason) => { + Assert.ok(false, "hasStoredBatch error: " + (reason && reason.message)); + }); + }).add(() => { + doAwait(batchHandler.teardown(), () => { + this.ctx.isclosed = true; + }, (reason) => { + Assert.ok(false, "teardown error: " + (reason && reason.message)); + }); + }) - }].concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch && storeBatch == 3) { - return true; - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch1; - let res = this.ctx.sendBatch1Res; - let payload = this.ctx.sendBatch1Pd - - if (sendBatch) { - Assert.equal(res.length, 1, "response 1 should be called once"); - let res1 = res[0]; - Assert.equal(res1.state, eBatchSendStatus.Drop, "response 1 state should be drop"); - Assert.ok(res1.data, "response 1 should have data"); - Assert.equal(res1.data.criticalCnt, 1 ,"response 1 should have expected data"); - - Assert.equal(payload.length, 1, "payload 1 should be called once"); - let payload1 = payload[0]; - Assert.equal(payload1.criticalCnt, 1 , "payload 1 should be contain expected item"); - return true; - } - return false; - }, "Wait for send batch 1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch2; - let res = this.ctx.sendBatch2Res; - let payload = this.ctx.sendBatch2Pd - - if (sendBatch) { - Assert.equal(res.length, 1, "response 2 should be called once"); - let res1 = res[0]; - Assert.equal(res1.state, eBatchSendStatus.Complete, "response 2 state should be retry"); - Assert.ok(res1.data, "response 2 should have data"); - Assert.equal(res1.data.criticalCnt, 2 ,"response 2 should have expected data"); - - Assert.equal(payload.length, 1, "payload 2 should be called once"); - let payload1 = payload[0]; - Assert.equal(payload1.criticalCnt, 2 , "payload 2 should be contain expected item"); - - return true; - } - return false; - }, "Wait for send batch 2 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch3; - let res = this.ctx.sendBatch3Res; - let payload = this.ctx.sendBatch3Pd + } - if (sendBatch) { - Assert.equal(res.length, 1, "response 3 should be called once"); - let res1 = res[0]; - Assert.equal(res1.state, eBatchSendStatus.Retry, "response 3 state should be complete"); - Assert.ok(res1.data, "response 3 should have data"); - Assert.equal(res1.data.criticalCnt, 3 ,"response 3 should have expected data"); - - Assert.equal(payload.length, 1, "payload 3 nshould be called once"); - let payload1 = payload[0]; - Assert.equal(payload1.criticalCnt, 3 , "payload 3 should be contain expected item"); - return true; - } - return false; - }, "Wait for send batch 3 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let hasBatch1Called = this.ctx.hasBatch1Called; - if (hasBatch1Called) { - let hasBatch = this.ctx.hasBatch1; - Assert.equal(hasBatch, false, "should not contain any events") - return true; - } - return false; - }, "Wait for has batch1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let isclosed = this.ctx.isclosed; - if (isclosed) { - return true; - } - return false; - }, "Wait for close response" + new Date().toISOString(), 15, 1000) as any) }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: send Next Batch with IndexedDB provider", - stepDelay: 100, - steps: [() => { + test: ()=> { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.IndexedDb], autoClean: false, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -712,74 +576,59 @@ export class OfflineBatchHandlerTests extends AITestClass { let evt = TestHelper.mockEvent(endpoint, 1, false); let evt1 = TestHelper.mockEvent(endpoint, 2, false); let evt2 = TestHelper.mockEvent(endpoint, 3, false); - doAwait(batchHandler.storeBatch(evt),(res) => { - this.ctx.storeBatch = 1; - }); - doAwait(batchHandler.storeBatch(evt1),(res) => { - this.ctx.storeBatch = 2; - }); - doAwait(batchHandler.storeBatch(evt2),(res) => { - this.ctx.storeBatch = 3; - }); - - let sender1Payload: any[] = [] - let sender1 = (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => { + + let sender1Payload: any[] = []; + let sender1 = (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => { sender1Payload.push(payload); oncomplete(400, {}); - } + }; let res1: any[] = []; - - let cb1 = (res) => { + let cb1 = (res) => { res1.push(res); - } - - - doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { - this.ctx.sendBatch1 = true; - this.ctx.sendBatch1Res = res1; - this.ctx.sendBatch1Pd = sender1Payload; - Assert.equal(res.value.state, eBatchSendStatus.Drop, "should have drop status"); - doAwaitResponse(provider.getAllEvents(), (res)=> { - this.ctx.getAll = true; - let val = res.value; - Assert.equal(val && val.length, 2, "should have 2 events"); - let sentcriticalCnt = res1[0].data.criticalCnt; - arrForEach(val, (item) => { - Assert.ok(sentcriticalCnt !== item.criticalCnt, "should not contain deleted item"); - }); - }); - - }); - - }].concat(PollingAssert.createPollingAssert(() => { - let storeBatch = this.ctx.storeBatch; - if (storeBatch && storeBatch == 3) { - return true; - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch1; - - if (sendBatch) { - - return true; - } - return false; - }, "Wait for send send batch response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getAll; - - if (item) { + }; + + return this._asyncQueue().add(() => + doAwait(batchHandler.storeBatch(evt), (res) => { + this.ctx.storeBatch = 1; + }, (reason) => { + Assert.ok(false, "storeBatch 1 error: " + (reason && reason.message)); + }) + ).add(() => + doAwait(batchHandler.storeBatch(evt1), (res) => { + this.ctx.storeBatch = 2; + }, (reason) => { + Assert.ok(false, "storeBatch 2 error: " + (reason && reason.message)); + }) + ).add(() => + doAwait(batchHandler.storeBatch(evt2), (res) => { + this.ctx.storeBatch = 3; + }, (reason) => { + Assert.ok(false, "storeBatch 3 error: " + (reason && reason.message)); + }) + ).add(() => - return true; - } - return false; - }, "Wait for get all response" + new Date().toISOString(), 15, 1000) as any) + doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any, (res) => { + this.ctx.sendBatch1 = true; + this.ctx.sendBatch1Res = res1; + this.ctx.sendBatch1Pd = sender1Payload; + Assert.equal(res.value.state, eBatchSendStatus.Drop, "should have drop status"); + doAwaitResponse(provider.getAllEvents(), (res)=> { + this.ctx.getAll = true; + let val = res.value; + Assert.equal(val && val.length, 2, "should have 2 events"); + let sentcriticalCnt = res1[0].data.criticalCnt; + arrForEach(val, (item) => { + Assert.ok(sentcriticalCnt !== item.criticalCnt, "should not contain deleted item"); + }); + }); + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: send Next Batch with IndexedDB provider test1 with retry code", - stepDelay: 100, - steps: [() => { + test: () => { let batchHandler = this.batchHandler; this.ctx.isInit = true; this.ctx.handler = batchHandler; @@ -802,12 +651,14 @@ export class OfflineBatchHandlerTests extends AITestClass { res1.push(res); } - doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { - this.ctx.sendBatch1 = true; - this.ctx.sendBatch1Res = res1; - this.ctx.sendBatch1Pd = sender1Payload; - Assert.equal(res.value.state, eBatchSendStatus.Retry, "should have retry status"); - + return this._asyncQueue().add(() => + doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { + this.ctx.sendBatch1 = true; + this.ctx.sendBatch1Res = res1; + this.ctx.sendBatch1Pd = sender1Payload; + Assert.equal(res.value.state, eBatchSendStatus.Retry, "should have retry status"); + }) + ).add(()=> doAwaitResponse(provider.getAllEvents(), (res)=> { this.ctx.getAll = true; let val = res.value; @@ -821,32 +672,14 @@ export class OfflineBatchHandlerTests extends AITestClass { let storageObject = JSON.parse(storageStr); let storageEvts = storageObject.evts; Assert.deepEqual(Object.keys(storageEvts).length, 1, "storgae should only have one event"); - }); - - }); - - - }].concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch1; - - if (sendBatch) { - return true; - } - return false; - }, "Wait for send batch 1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getAll; - - if (item) { - return true; - } - return false; - }, "Wait for get all response" + new Date().toISOString(), 15, 1000) as any) + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: send Next Batch with IndexedDB provider test1 with 200", - stepDelay: 100, - steps: [() => { + test: () => { let batchHandler = this.batchHandler; this.ctx.isInit = true; this.ctx.handler = batchHandler; @@ -863,18 +696,19 @@ export class OfflineBatchHandlerTests extends AITestClass { oncomplete(200, {}); } - let res1: any[] = []; let cb1 = (res) => { res1.push(res); } - doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { - this.ctx.sendBatch1 = true; - this.ctx.sendBatch1Res = res1; - this.ctx.sendBatch1Pd = sender1Payload; - Assert.equal(res.value.state, eBatchSendStatus.Complete, "should have complete status"); - + return this._asyncQueue().add(() => + doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { + this.ctx.sendBatch1 = true; + this.ctx.sendBatch1Res = res1; + this.ctx.sendBatch1Pd = sender1Payload; + Assert.equal(res.value.state, eBatchSendStatus.Complete, "should have complete status"); + }) + ).add(() => doAwaitResponse(provider.getAllEvents(), (res)=> { this.ctx.getAll = true; let val = res.value; @@ -882,32 +716,14 @@ export class OfflineBatchHandlerTests extends AITestClass { let storageKey = "AIOffline_1_dc.services.visualstudio.com"; let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; Assert.deepEqual(storageStr, null, "storgae should not have one event"); - }); - - }); - - - }].concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch1; - - if (sendBatch) { - return true; - } - return false; - }, "Wait for send batch 1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getAll; - - if (item) { - return true; - } - return false; - }, "Wait for get all response" + new Date().toISOString(), 15, 1000) as any) + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: send Next Batch with IndexedDB provider test1 with unload events", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageKey = "AIOffline_1_dc.services.visualstudio.com"; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; @@ -947,14 +763,17 @@ export class OfflineBatchHandlerTests extends AITestClass { let cb1 = (res) => { res1.push(res); } - - doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { - this.ctx.sendBatch1 = true; - this.ctx.sendBatch1Res = res1; - this.ctx.sendBatch1Pd = sender1Payload; - Assert.equal(res.value.state, eBatchSendStatus.Complete, "should have complete status"); - Assert.equal(res.value.data.id, evt.id, "should have expected event"); - + + + return this._asyncQueue().add(() => + doAwaitResponse(batchHandler.sendNextBatch(cb1, false, {sendPOST: sender1}) as any,(res) => { + this.ctx.sendBatch1 = true; + this.ctx.sendBatch1Res = res1; + this.ctx.sendBatch1Pd = sender1Payload; + Assert.equal(res.value.state, eBatchSendStatus.Complete, "should have complete status"); + Assert.equal(res.value.data.id, evt.id, "should have expected event"); + }) + ).add(() => doAwaitResponse(provider.getAllEvents(), (res)=> { this.ctx.getAll = true; let val = res.value; @@ -962,32 +781,14 @@ export class OfflineBatchHandlerTests extends AITestClass { let storageStr = AITestClass.orgLocalStorage.getItem(storageKey) as any; let evts = JSON.parse(storageStr).evts; Assert.deepEqual(evts, {}, "storage should not have one event"); - }); - - }); - - - }].concat(PollingAssert.createPollingAssert(() => { - let sendBatch = this.ctx.sendBatch1; - - if (sendBatch) { - return true; - } - return false; - }, "Wait for send batch 1 response" + new Date().toISOString(), 15, 1000) as any).concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getAll; - - if (item) { - return true; - } - return false; - }, "Wait for get all response" + new Date().toISOString(), 15, 1000) as any) + }) + ) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: Error handle store batch", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -1015,36 +816,35 @@ export class OfflineBatchHandlerTests extends AITestClass { }); let evt = TestHelper.mockEvent(endpoint, 1, false); + doAwaitResponse(batchHandler.storeBatch(evt, cb1),(res) => { this.ctx.storeBatch = true; if (res.rejected) { Assert.ok(false, "error should be catched"); return; } - + let item = res.value; Assert.equal(item?.state, eBatchStoreStatus.Failure, "should have expected state"); Assert.equal(item?.item.message, "add event mock error" , "should have expected message"); Assert.equal(res1.length, 1, "should call callback"); Assert.equal(res1[0].state, item?.state, "should call callback with expected response"); - - }); - - - }].concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.storeBatch; + }) - if (item) { - return true; - } - return false; - }, "Wait for store batch response" + new Date().toISOString(), 15, 1000) as any) + return this._asyncQueue().concat(PollingAssert.asyncTaskPollingAssert(() => { + let item = this.ctx.storeBatch; + + if (item) { + return true; + } + return false; + }, "Wait for store batch response" + new Date().toISOString(), 15, 1000)) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: Error handle clean batch", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -1083,26 +883,24 @@ export class OfflineBatchHandlerTests extends AITestClass { Assert.equal(item?.batchCnt, 0, "should have expected state"); Assert.equal(res1.length, 1, "should call callback"); Assert.equal(res1[0].batchCnt, item?.batchCnt, "should call callback with expected response"); + batchHandler.teardown(); }); - batchHandler.teardown(); - - - }].concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.clearBatch; - - if (item) { - return true; - } - return false; - }, "Wait for clear batch response" + new Date().toISOString(), 15, 1000) as any) + return this._asyncQueue().concat(PollingAssert.asyncTaskPollingAssert(() => { + let item = this.ctx.clearBatch; + + if (item) { + return true; + } + return false; + }, "Wait for clear batch response" + new Date().toISOString(), 15, 1000)) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: Error handle add batch with remove error", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -1151,25 +949,22 @@ export class OfflineBatchHandlerTests extends AITestClass { Assert.equal(item?.data.message, "remove mock error" , "should have expected message"); Assert.equal(res1.length, 1, "should call callback"); Assert.equal(res1[0].state, item?.state, "should call callback with expected response"); + batchHandler.teardown(); }); - batchHandler.teardown(); - - - }].concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.addBatch; - - if (item) { - return true; - } - return false; - }, "Wait for add batch response" + new Date().toISOString(), 15, 1000) as any) + return this._asyncQueue().concat(PollingAssert.asyncTaskPollingAssert(() => { + let item = this.ctx.addBatch; + if (item) { + return true; + } + return false; + }, "Wait for add batch response" + new Date().toISOString(), 15, 1000)) + } }); - this.testCaseAsync({ + this.testCase({ name: "Send Next Batch: Error handle add batch", - stepDelay: 100, - steps: [() => { + test: () => { let endpoint = DEFAULT_BREEZE_ENDPOINT + DEFAULT_BREEZE_PATH; let storageObj = {providers:[eStorageProviders.LocalStorage], autoClean: true, senderCfg:{retryCodes: [500]}, maxRetry: 2} as IOfflineChannelConfiguration; let storageConfig = createDynamicConfig(storageObj).cfg; @@ -1213,21 +1008,20 @@ export class OfflineBatchHandlerTests extends AITestClass { Assert.equal(item?.data.message, "get mock error" , "should have expected message"); Assert.equal(res1.length, 1, "should call callback again"); Assert.equal(res1[0].state, item?.state, "should call callback with expected response"); + batchHandler.teardown(); }); - batchHandler.teardown(); - - - }].concat(PollingAssert.createPollingAssert(() => { - let item = this.ctx.getBatch; - - if (item) { - return true; - } - return false; - }, "Wait for get batch response" + new Date().toISOString(), 15, 1000) as any) + + return this._asyncQueue().concat(PollingAssert.asyncTaskPollingAssert(() => { + let item = this.ctx.getBatch; + + if (item) { + return true; + } + return false; + }, "Wait for get batch response" + new Date().toISOString(), 15, 1000)) + } }); - } } diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index e58f83e89..0313947d5 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -1716,9 +1716,9 @@ "integrity": "sha512-II+C1wgzUia0g+tGAH+PBb4XiTm8/C/i6sN23r21NNskBYOYrv+qnW0tFQ/IxZzKVwrK4CTglf8YO3poJUclQA==" }, "node_modules/@types/react": { - "version": "16.14.64", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.64.tgz", - "integrity": "sha512-CcJ89hvLdpjYzV9QHYAbD2IVggc8RYEd7Km40HzJPuN3TiKv9sfSNYXj8zohrIGJPiKMClMIXJE+XJX1qZXpnw==", + "version": "16.14.65", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.65.tgz", + "integrity": "sha512-Guc3kE+W8LrQB9I3bF3blvNH15dXFIVIHIJTqrF8cp5XI/3IJcHGo4C3sJNPb8Zx49aofXKnAGIKyonE4f7XWg==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "^0.16", @@ -1763,16 +1763,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", - "integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.0.tgz", + "integrity": "sha512-CACyQuqSHt7ma3Ns601xykeBK/rDeZa3w6IS6UtMQbixO5DWy+8TilKkviGDH6jtWCo8FGRKEK5cLLkPvEammQ==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/type-utils": "8.32.1", - "@typescript-eslint/utils": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/type-utils": "8.33.0", + "@typescript-eslint/utils": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -1786,21 +1786,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "@typescript-eslint/parser": "^8.33.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz", - "integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.0.tgz", + "integrity": "sha512-JaehZvf6m0yqYp34+RVnihBAChkqeH+tqqhS0GuX1qgPpwLvmTPheKEs6OeCK6hVJgXZHJ2vbjnC9j119auStQ==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/typescript-estree": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4" }, "engines": { @@ -1815,14 +1815,32 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.0.tgz", + "integrity": "sha512-d1hz0u9l6N+u/gcrk6s6gYdl7/+pp8yHheRTqP6X5hVDKALEaTn8WfGiit7G511yueBEL3OpOEpD+3/MBdoN+A==", + "peer": true, + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.33.0", + "@typescript-eslint/types": "^8.33.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz", - "integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.0.tgz", + "integrity": "sha512-LMi/oqrzpqxyO72ltP+dBSP6V0xiUb4saY7WLtxSfiNEBI8m321LLVFU9/QDJxjDQG9/tjSqKz/E3380TEqSTw==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1" + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1832,14 +1850,30 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.0.tgz", + "integrity": "sha512-sTkETlbqhEoiFmGr1gsdq5HyVbSOF0145SYDJ/EQmXHtKViCaGvnyLqWFFHtEXoS0J1yU8Wyou2UGmgW88fEug==", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz", - "integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.0.tgz", + "integrity": "sha512-lScnHNCBqL1QayuSrWeqAL5GmqNdVUQAAMTaCwdYEdWfIrSrOGzyLGRCHXcCixa5NK6i5l0AfSO2oBSjCjf4XQ==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.32.1", - "@typescript-eslint/utils": "8.32.1", + "@typescript-eslint/typescript-estree": "8.33.0", + "@typescript-eslint/utils": "8.33.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -1856,9 +1890,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz", - "integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.0.tgz", + "integrity": "sha512-DKuXOKpM5IDT1FA2g9x9x1Ug81YuKrzf4mYX8FAVSNu5Wo/LELHWQyM1pQaDkI42bX15PWl0vNPt1uGiIFUOpg==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1869,13 +1903,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz", - "integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.0.tgz", + "integrity": "sha512-vegY4FQoB6jL97Tu/lWRsAiUUp8qJTqzAmENH2k59SJhw0Th1oszb9Idq/FyyONLuNqT1OADJPXfyUNOR8SzAQ==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/visitor-keys": "8.32.1", + "@typescript-eslint/project-service": "8.33.0", + "@typescript-eslint/tsconfig-utils": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/visitor-keys": "8.33.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1931,15 +1967,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz", - "integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.0.tgz", + "integrity": "sha512-lPFuQaLA9aSNa7D5u2EpRiqdAUhzShwGg/nhpBlc4GR6kcTABttCuyjFs8BcEZ8VWrjCBof/bePhP3Q3fS+Yrw==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.32.1", - "@typescript-eslint/types": "8.32.1", - "@typescript-eslint/typescript-estree": "8.32.1" + "@typescript-eslint/scope-manager": "8.33.0", + "@typescript-eslint/types": "8.33.0", + "@typescript-eslint/typescript-estree": "8.33.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1954,12 +1990,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.32.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz", - "integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==", + "version": "8.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.0.tgz", + "integrity": "sha512-7RW7CMYoskiz5OOGAWjJFxgb7c5UNjTG292gYhWeOAcFmYCtVCSqjqSBj5zMhxbXo2JOW95YYrUWJfU0zrpaGQ==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.32.1", + "@typescript-eslint/types": "8.33.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2858,9 +2894,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.157", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.157.tgz", - "integrity": "sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==" + "version": "1.5.159", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.159.tgz", + "integrity": "sha512-CEvHptWAMV5p6GJ0Lq8aheyvVbfzVrv5mmidu1D3pidoVNkB3tTBsTMVtPJ+rzRK5oV229mCLz9Zj/hNvU8GBA==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -6819,9 +6855,9 @@ } }, "node_modules/zod": { - "version": "3.25.23", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.23.tgz", - "integrity": "sha512-Od2bdMosahjSrSgJtakrwjMDb1zM1A3VIHCPGveZt/3/wlrTWBya2lmEh2OYe4OIu8mPTmmr0gnLHIWQXdtWBg==", + "version": "3.25.32", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.32.tgz", + "integrity": "sha512-OSm2xTIRfW8CV5/QKgngwmQW/8aPfGdaQFlrGoErlgg/Epm7cjb6K6VEyExfe65a3VybUOnu381edLb0dfJl0g==", "funding": { "url": "https://github.com/sponsors/colinhacks" }