Skip to content

Commit c8e9d84

Browse files
committed
tests: add more tests for debounced events
1 parent c9b72ba commit c8e9d84

File tree

1 file changed

+178
-6
lines changed

1 file changed

+178
-6
lines changed

test/service-module/service-module.test.ts

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import { stripSlashes } from '../../src/utils'
1717
import memory from 'feathers-memory'
1818
import { makeTodos } from '../fixtures/todos'
1919
import Vuex from 'vuex'
20+
import { performance } from 'perf_hooks'
21+
import enableServiceEvents from '../../src/service-module/service-module.events'
2022

2123
interface Options {
2224
idField: string
@@ -200,6 +202,14 @@ function makeSocketIoContext() {
200202
}
201203
}
202204

205+
class TodoDebounced extends BaseModel {
206+
public static modelName = 'TodoDebounced'
207+
public static test = true
208+
public constructor(data = {}, options?) {
209+
super(data, options)
210+
}
211+
}
212+
203213
const store = new Vuex.Store<RootState>({
204214
strict: true,
205215
plugins: [
@@ -209,22 +219,38 @@ function makeSocketIoContext() {
209219
servicePath: 'things'
210220
}),
211221
makeServicePlugin({
212-
Model: Thing,
222+
Model: ThingDebounced,
213223
service: feathersSocketioClient.service('things-debounced'),
214224
servicePath: 'things-debounced',
215225
debounceEventsTime: 20,
216226
namespace: 'things-debounced'
227+
}),
228+
makeServicePlugin({
229+
Model: TodoDebounced,
230+
service: feathersSocketioClient.service('todos-debounced'),
231+
servicePath: 'todos-debounced',
232+
debounceEventsTime: 20,
233+
namespace: 'todos-debounced'
217234
})
218235
]
219236
})
220237

238+
const debouncedQueue = enableServiceEvents({
239+
Model: TodoDebounced,
240+
service: feathersSocketioClient.service('todos-debounced'),
241+
store,
242+
options: store.state['todos-debounced']
243+
})
244+
221245
return {
222246
feathersSocketioClient,
223247
makeServicePlugin,
224248
BaseModel,
225249
Thing,
226250
ThingDebounced,
227-
store
251+
TodoDebounced,
252+
store,
253+
debouncedQueue
228254
}
229255
}
230256

@@ -700,6 +726,7 @@ describe('Service Module', function () {
700726
isRemovePending: false,
701727
keepCopiesInStore: false,
702728
debounceEventsTime: null,
729+
debounceEventsMaxWait: 1000,
703730
keyedById: {},
704731
nameStyle: 'short',
705732
namespace: 'service-todos',
@@ -1022,6 +1049,8 @@ describe('Service Module', function () {
10221049
BaseModel,
10231050
Thing,
10241051
ThingDebounced,
1052+
TodoDebounced,
1053+
debouncedQueue,
10251054
store
10261055
} = makeSocketIoContext()
10271056

@@ -1044,6 +1073,8 @@ describe('Service Module', function () {
10441073
})
10451074

10461075
it('created debounced', function (done) {
1076+
const { debounceEventsTime } = store.state['things-debounced']
1077+
10471078
// eslint-disable-next-line @typescript-eslint/no-unused-vars
10481079
const listener = item => {
10491080
assert(
@@ -1059,7 +1090,7 @@ describe('Service Module', function () {
10591090
.service('things-debounced')
10601091
.off('created', listener)
10611092
done()
1062-
}, 30)
1093+
}, debounceEventsTime * 2)
10631094
}
10641095
// eslint-disable-next-line @typescript-eslint/no-unused-vars
10651096
feathersSocketioClient.service('things-debounced').on('created', listener)
@@ -1083,6 +1114,9 @@ describe('Service Module', function () {
10831114
})
10841115

10851116
it('patched debounced', function (done) {
1117+
const { debounceEventsTime } = store.state['things-debounced']
1118+
1119+
store.commit('things-debounced/clearAll')
10861120
store.commit('things-debounced/addItem', { id: 1, test: false })
10871121

10881122
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1096,7 +1130,7 @@ describe('Service Module', function () {
10961130
store.state['things-debounced'].keyedById[1].test,
10971131
'the item received from the socket event was updated in the store'
10981132
)
1099-
}, 30)
1133+
}, debounceEventsTime * 2)
11001134
feathersSocketioClient
11011135
.service('things-debounced')
11021136
.off('patched', listener)
@@ -1126,6 +1160,9 @@ describe('Service Module', function () {
11261160
})
11271161

11281162
it('updated debounced', function (done) {
1163+
const { debounceEventsTime } = store.state['things-debounced']
1164+
1165+
store.commit('things-debounced/clearAll')
11291166
store.commit('things-debounced/addItem', { id: 1, test: false })
11301167

11311168
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1140,7 +1177,7 @@ describe('Service Module', function () {
11401177
'the item received from the socket event was updated in the store'
11411178
)
11421179
done()
1143-
}, 30)
1180+
}, debounceEventsTime * 2)
11441181
feathersSocketioClient
11451182
.service('things-debounced')
11461183
.off('updated', listener)
@@ -1170,6 +1207,9 @@ describe('Service Module', function () {
11701207
})
11711208

11721209
it('removed debounced', function (done) {
1210+
const { debounceEventsTime } = store.state['things-debounced']
1211+
1212+
store.commit('things-debounced/clearAll')
11731213
store.commit('things-debounced/addItem', { id: 1, test: false })
11741214

11751215
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1185,7 +1225,7 @@ describe('Service Module', function () {
11851225
'the item received from the socket event was removed from the store'
11861226
)
11871227
done()
1188-
}, 30)
1228+
}, debounceEventsTime * 2)
11891229

11901230
feathersSocketioClient
11911231
.service('things-debounced')
@@ -1196,5 +1236,137 @@ describe('Service Module', function () {
11961236

11971237
feathersSocketioClient.service('things-debounced').remove(1)
11981238
})
1239+
1240+
it('debounce works with plenty items', function (done) {
1241+
store.commit('things-debounced/clearAll')
1242+
1243+
const { debounceEventsTime } = store.state['things-debounced']
1244+
1245+
const itemsCount = 100
1246+
let i = 0
1247+
1248+
assert(
1249+
Object.keys(store.state['things-debounced'].keyedById).length === 0,
1250+
'no items at start'
1251+
)
1252+
1253+
const setTimeoutCreate = () => {
1254+
setTimeout(() => {
1255+
feathersSocketioClient
1256+
.service('things-debounced')
1257+
.create({ test: true, i })
1258+
i++
1259+
assert(
1260+
Object.keys(store.state['things-debounced'].keyedById).length === 0,
1261+
`no items at i: ${i}`
1262+
)
1263+
if (i < itemsCount) {
1264+
setTimeoutCreate()
1265+
} else {
1266+
setTimeout(() => {
1267+
assert(
1268+
Object.keys(
1269+
store.state['things-debounced'].keyedById.length ===
1270+
itemsCount
1271+
),
1272+
'all items are in store'
1273+
)
1274+
done()
1275+
}, debounceEventsTime * 2)
1276+
}
1277+
}, debounceEventsTime / 4)
1278+
}
1279+
setTimeoutCreate()
1280+
})
1281+
1282+
it('debounced events get invoked during continuous events', function (done) {
1283+
store.commit('things-debounced/clearAll')
1284+
1285+
const { debounceEventsTime, debounceEventsMaxWait } = store.state[
1286+
'things-debounced'
1287+
]
1288+
1289+
assert(
1290+
Object.keys(store.state['things-debounced'].keyedById).length === 0,
1291+
'no items at start'
1292+
)
1293+
assert(debounceEventsMaxWait > 0, 'maxWait is set')
1294+
1295+
const startedAt = performance.now()
1296+
let i = 0
1297+
1298+
const setTimeoutCreate = () => {
1299+
setTimeout(() => {
1300+
feathersSocketioClient
1301+
.service('things-debounced')
1302+
.create({ test: true, i })
1303+
i++
1304+
const timePassed = Math.floor(
1305+
performance.now() - startedAt - debounceEventsTime
1306+
)
1307+
if (timePassed <= debounceEventsMaxWait) {
1308+
if (performance.now() - startedAt <= debounceEventsMaxWait) {
1309+
assert(
1310+
Object.keys(store.state['things-debounced'].keyedById)
1311+
.length === 0,
1312+
`no items at i: ${i}, milliseconds passed: ${timePassed}`
1313+
)
1314+
}
1315+
setTimeoutCreate()
1316+
} else {
1317+
assert(
1318+
Object.keys(store.state['things-debounced'].keyedById).length ===
1319+
i - 1,
1320+
`items are inserted after maxWait`
1321+
)
1322+
done()
1323+
}
1324+
}, debounceEventsTime / 4)
1325+
}
1326+
setTimeoutCreate()
1327+
})
1328+
1329+
it('debounded remove after addOrUpdate also removes addOrUpdate queue and vise versa', function () {
1330+
const { idField } = store.state['todos-debounced']
1331+
1332+
assert(
1333+
Object.keys(debouncedQueue.addOrUpdateById).length === 0,
1334+
"'addOrUpdateById' initially empty"
1335+
)
1336+
1337+
assert(
1338+
Object.keys(debouncedQueue.removeItemById).length === 0,
1339+
"'removeItemById' initially empty"
1340+
)
1341+
1342+
debouncedQueue.enqueueAddOrUpdate({ [idField]: 1, test: true })
1343+
1344+
assert(
1345+
debouncedQueue.addOrUpdateById[1],
1346+
"queued item for 'addOrUpdate' correctly"
1347+
)
1348+
1349+
debouncedQueue.enqueueRemoval({ [idField]: 1, test: false })
1350+
1351+
assert(
1352+
!debouncedQueue.addOrUpdateById[1],
1353+
"queued item for 'addOrUpdate' removed immediately"
1354+
)
1355+
assert(
1356+
debouncedQueue.removeItemById[1],
1357+
'queued item for removal correctly'
1358+
)
1359+
1360+
debouncedQueue.enqueueAddOrUpdate({ [idField]: 1, test: true })
1361+
1362+
assert(
1363+
debouncedQueue.addOrUpdateById[1],
1364+
"queued item for 'addOrUpdate' correctly again"
1365+
)
1366+
assert(
1367+
!debouncedQueue.removeItemById[1],
1368+
"queued item for 'remove' removed immediately"
1369+
)
1370+
})
11991371
})
12001372
})

0 commit comments

Comments
 (0)