@pancakeswap/token-lists 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,543 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest'
2
+ import { createStore, Store } from 'redux'
3
+
4
+ import { fetchTokenList, acceptListUpdate, addList, removeList, enableList, updateListVersion } from './actions'
5
+ import { ListsState, createTokenListReducer, NEW_LIST_STATE } from './reducer'
6
+
7
+ const DEFAULT_ACTIVE_LIST_URLS = []
8
+ const DEFAULT_LIST_OF_LISTS = ['https://tokens.pancakeswap.finance/pancakeswap-extended.json']
9
+ const STUB_TOKEN_LIST = {
10
+ name: '',
11
+ timestamp: '',
12
+ version: { major: 1, minor: 1, patch: 1 },
13
+ tokens: [],
14
+ }
15
+
16
+ const UNSUPPORTED_LIST_URLS = []
17
+
18
+ const reducer = createTokenListReducer(
19
+ {
20
+ lastInitializedDefaultListOfLists: DEFAULT_LIST_OF_LISTS,
21
+ byUrl: {
22
+ ...DEFAULT_LIST_OF_LISTS.concat(...UNSUPPORTED_LIST_URLS).reduce((memo, listUrl) => {
23
+ memo[listUrl] = NEW_LIST_STATE
24
+ return memo
25
+ }, {}),
26
+ },
27
+ activeListUrls: DEFAULT_ACTIVE_LIST_URLS,
28
+ },
29
+ DEFAULT_LIST_OF_LISTS,
30
+ DEFAULT_ACTIVE_LIST_URLS,
31
+ )
32
+
33
+ const PATCHED_STUB_LIST = {
34
+ ...STUB_TOKEN_LIST,
35
+ version: { ...STUB_TOKEN_LIST.version, patch: STUB_TOKEN_LIST.version.patch + 1 },
36
+ }
37
+ const MINOR_UPDATED_STUB_LIST = {
38
+ ...STUB_TOKEN_LIST,
39
+ version: { ...STUB_TOKEN_LIST.version, minor: STUB_TOKEN_LIST.version.minor + 1 },
40
+ }
41
+ const MAJOR_UPDATED_STUB_LIST = {
42
+ ...STUB_TOKEN_LIST,
43
+ version: { ...STUB_TOKEN_LIST.version, major: STUB_TOKEN_LIST.version.major + 1 },
44
+ }
45
+
46
+ describe('list reducer', () => {
47
+ let store: Store<ListsState>
48
+
49
+ beforeEach(() => {
50
+ store = createStore(reducer, {
51
+ byUrl: {},
52
+ activeListUrls: undefined,
53
+ })
54
+ })
55
+
56
+ describe('fetchTokenList', () => {
57
+ describe('pending', () => {
58
+ it('sets pending', () => {
59
+ store.dispatch(fetchTokenList.pending({ requestId: 'request-id', url: 'fake-url' }))
60
+ expect(store.getState()).toEqual({
61
+ byUrl: {
62
+ 'fake-url': {
63
+ error: null,
64
+ loadingRequestId: 'request-id',
65
+ current: null,
66
+ pendingUpdate: null,
67
+ },
68
+ },
69
+ selectedListUrl: undefined,
70
+ })
71
+ })
72
+
73
+ it('does not clear current list', () => {
74
+ store = createStore(reducer, {
75
+ byUrl: {
76
+ 'fake-url': {
77
+ error: null,
78
+ current: STUB_TOKEN_LIST,
79
+ pendingUpdate: null,
80
+ loadingRequestId: null,
81
+ },
82
+ },
83
+ activeListUrls: undefined,
84
+ })
85
+
86
+ store.dispatch(fetchTokenList.pending({ requestId: 'request-id', url: 'fake-url' }))
87
+ expect(store.getState()).toEqual({
88
+ byUrl: {
89
+ 'fake-url': {
90
+ error: null,
91
+ current: STUB_TOKEN_LIST,
92
+ loadingRequestId: 'request-id',
93
+ pendingUpdate: null,
94
+ },
95
+ },
96
+ activeListUrls: undefined,
97
+ })
98
+ })
99
+ })
100
+
101
+ describe('fulfilled', () => {
102
+ it('saves the list', () => {
103
+ store.dispatch(
104
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
105
+ )
106
+ expect(store.getState()).toEqual({
107
+ byUrl: {
108
+ 'fake-url': {
109
+ error: null,
110
+ current: STUB_TOKEN_LIST,
111
+ loadingRequestId: null,
112
+ pendingUpdate: null,
113
+ },
114
+ },
115
+ activeListUrls: undefined,
116
+ })
117
+ })
118
+
119
+ it('does not save the list in pending if current is same', () => {
120
+ store.dispatch(
121
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
122
+ )
123
+ store.dispatch(
124
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
125
+ )
126
+ expect(store.getState()).toEqual({
127
+ byUrl: {
128
+ 'fake-url': {
129
+ error: null,
130
+ current: STUB_TOKEN_LIST,
131
+ loadingRequestId: null,
132
+ pendingUpdate: null,
133
+ },
134
+ },
135
+ activeListUrls: undefined,
136
+ })
137
+ })
138
+
139
+ it('does not save to current if list is newer patch version', () => {
140
+ store.dispatch(
141
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
142
+ )
143
+
144
+ store.dispatch(
145
+ fetchTokenList.fulfilled({ tokenList: PATCHED_STUB_LIST, requestId: 'request-id', url: 'fake-url' }),
146
+ )
147
+ expect(store.getState()).toEqual({
148
+ byUrl: {
149
+ 'fake-url': {
150
+ error: null,
151
+ current: STUB_TOKEN_LIST,
152
+ loadingRequestId: null,
153
+ pendingUpdate: PATCHED_STUB_LIST,
154
+ },
155
+ },
156
+ activeListUrls: undefined,
157
+ })
158
+ })
159
+ it('does not save to current if list is newer minor version', () => {
160
+ store.dispatch(
161
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
162
+ )
163
+
164
+ store.dispatch(
165
+ fetchTokenList.fulfilled({ tokenList: MINOR_UPDATED_STUB_LIST, requestId: 'request-id', url: 'fake-url' }),
166
+ )
167
+ expect(store.getState()).toEqual({
168
+ byUrl: {
169
+ 'fake-url': {
170
+ error: null,
171
+ current: STUB_TOKEN_LIST,
172
+ loadingRequestId: null,
173
+ pendingUpdate: MINOR_UPDATED_STUB_LIST,
174
+ },
175
+ },
176
+ activeListUrls: undefined,
177
+ })
178
+ })
179
+ it('does not save to pending if list is newer major version', () => {
180
+ store.dispatch(
181
+ fetchTokenList.fulfilled({ tokenList: STUB_TOKEN_LIST, requestId: 'request-id', url: 'fake-url' }),
182
+ )
183
+
184
+ store.dispatch(
185
+ fetchTokenList.fulfilled({ tokenList: MAJOR_UPDATED_STUB_LIST, requestId: 'request-id', url: 'fake-url' }),
186
+ )
187
+ expect(store.getState()).toEqual({
188
+ byUrl: {
189
+ 'fake-url': {
190
+ error: null,
191
+ current: STUB_TOKEN_LIST,
192
+ loadingRequestId: null,
193
+ pendingUpdate: MAJOR_UPDATED_STUB_LIST,
194
+ },
195
+ },
196
+ activeListUrls: undefined,
197
+ })
198
+ })
199
+ })
200
+
201
+ describe('rejected', () => {
202
+ it('no-op if not loading', () => {
203
+ store.dispatch(fetchTokenList.rejected({ requestId: 'request-id', errorMessage: 'abcd', url: 'fake-url' }))
204
+ expect(store.getState()).toEqual({
205
+ byUrl: {},
206
+ activeListUrls: undefined,
207
+ })
208
+ })
209
+
210
+ it('sets the error if loading', () => {
211
+ store = createStore(reducer, {
212
+ byUrl: {
213
+ 'fake-url': {
214
+ error: null,
215
+ current: null,
216
+ loadingRequestId: 'request-id',
217
+ pendingUpdate: null,
218
+ },
219
+ },
220
+ activeListUrls: undefined,
221
+ })
222
+ store.dispatch(fetchTokenList.rejected({ requestId: 'request-id', errorMessage: 'abcd', url: 'fake-url' }))
223
+ expect(store.getState()).toEqual({
224
+ byUrl: {
225
+ 'fake-url': {
226
+ error: 'abcd',
227
+ current: null,
228
+ loadingRequestId: null,
229
+ pendingUpdate: null,
230
+ },
231
+ },
232
+ activeListUrls: undefined,
233
+ })
234
+ })
235
+ })
236
+ })
237
+
238
+ describe('addList', () => {
239
+ it('adds the list key to byUrl', () => {
240
+ store.dispatch(addList('list-id'))
241
+ expect(store.getState()).toEqual({
242
+ byUrl: {
243
+ 'list-id': {
244
+ error: null,
245
+ current: null,
246
+ loadingRequestId: null,
247
+ pendingUpdate: null,
248
+ },
249
+ },
250
+ activeListUrls: undefined,
251
+ })
252
+ })
253
+ it('no op for existing list', () => {
254
+ store = createStore(reducer, {
255
+ byUrl: {
256
+ 'fake-url': {
257
+ error: null,
258
+ current: STUB_TOKEN_LIST,
259
+ loadingRequestId: null,
260
+ pendingUpdate: null,
261
+ },
262
+ },
263
+ activeListUrls: undefined,
264
+ })
265
+ store.dispatch(addList('fake-url'))
266
+ expect(store.getState()).toEqual({
267
+ byUrl: {
268
+ 'fake-url': {
269
+ error: null,
270
+ current: STUB_TOKEN_LIST,
271
+ loadingRequestId: null,
272
+ pendingUpdate: null,
273
+ },
274
+ },
275
+ activeListUrls: undefined,
276
+ })
277
+ })
278
+ })
279
+
280
+ describe('acceptListUpdate', () => {
281
+ it('swaps pending update into current', () => {
282
+ store = createStore(reducer, {
283
+ byUrl: {
284
+ 'fake-url': {
285
+ error: null,
286
+ current: STUB_TOKEN_LIST,
287
+ loadingRequestId: null,
288
+ pendingUpdate: PATCHED_STUB_LIST,
289
+ },
290
+ },
291
+ activeListUrls: undefined,
292
+ })
293
+ store.dispatch(acceptListUpdate('fake-url'))
294
+ expect(store.getState()).toEqual({
295
+ byUrl: {
296
+ 'fake-url': {
297
+ error: null,
298
+ current: PATCHED_STUB_LIST,
299
+ loadingRequestId: null,
300
+ pendingUpdate: null,
301
+ },
302
+ },
303
+ activeListUrls: undefined,
304
+ })
305
+ })
306
+ })
307
+
308
+ describe('removeList', () => {
309
+ it('deletes the list key', () => {
310
+ store = createStore(reducer, {
311
+ byUrl: {
312
+ 'fake-url': {
313
+ error: null,
314
+ current: STUB_TOKEN_LIST,
315
+ loadingRequestId: null,
316
+ pendingUpdate: PATCHED_STUB_LIST,
317
+ },
318
+ },
319
+ activeListUrls: undefined,
320
+ })
321
+ store.dispatch(removeList('fake-url'))
322
+ expect(store.getState()).toEqual({
323
+ byUrl: {},
324
+ activeListUrls: undefined,
325
+ })
326
+ })
327
+ it('Removes from active lists if active list is removed', () => {
328
+ store = createStore(reducer, {
329
+ byUrl: {
330
+ 'fake-url': {
331
+ error: null,
332
+ current: STUB_TOKEN_LIST,
333
+ loadingRequestId: null,
334
+ pendingUpdate: PATCHED_STUB_LIST,
335
+ },
336
+ },
337
+ activeListUrls: ['fake-url'],
338
+ })
339
+ store.dispatch(removeList('fake-url'))
340
+ expect(store.getState()).toEqual({
341
+ byUrl: {},
342
+ activeListUrls: [],
343
+ })
344
+ })
345
+ })
346
+
347
+ describe('enableList', () => {
348
+ it('enables a list url', () => {
349
+ store = createStore(reducer, {
350
+ byUrl: {
351
+ 'fake-url': {
352
+ error: null,
353
+ current: STUB_TOKEN_LIST,
354
+ loadingRequestId: null,
355
+ pendingUpdate: PATCHED_STUB_LIST,
356
+ },
357
+ },
358
+ activeListUrls: undefined,
359
+ })
360
+ store.dispatch(enableList('fake-url'))
361
+ expect(store.getState()).toEqual({
362
+ byUrl: {
363
+ 'fake-url': {
364
+ error: null,
365
+ current: STUB_TOKEN_LIST,
366
+ loadingRequestId: null,
367
+ pendingUpdate: PATCHED_STUB_LIST,
368
+ },
369
+ },
370
+ activeListUrls: ['fake-url'],
371
+ })
372
+ })
373
+ it('adds to url keys if not present already on enable', () => {
374
+ store = createStore(reducer, {
375
+ byUrl: {
376
+ 'fake-url': {
377
+ error: null,
378
+ current: STUB_TOKEN_LIST,
379
+ loadingRequestId: null,
380
+ pendingUpdate: PATCHED_STUB_LIST,
381
+ },
382
+ },
383
+ activeListUrls: undefined,
384
+ })
385
+ store.dispatch(enableList('fake-url-invalid'))
386
+ expect(store.getState()).toEqual({
387
+ byUrl: {
388
+ 'fake-url': {
389
+ error: null,
390
+ current: STUB_TOKEN_LIST,
391
+ loadingRequestId: null,
392
+ pendingUpdate: PATCHED_STUB_LIST,
393
+ },
394
+ 'fake-url-invalid': {
395
+ error: null,
396
+ current: null,
397
+ loadingRequestId: null,
398
+ pendingUpdate: null,
399
+ },
400
+ },
401
+ activeListUrls: ['fake-url-invalid'],
402
+ })
403
+ })
404
+ it('enable works if list already added', () => {
405
+ store = createStore(reducer, {
406
+ byUrl: {
407
+ 'fake-url': {
408
+ error: null,
409
+ current: null,
410
+ loadingRequestId: null,
411
+ pendingUpdate: null,
412
+ },
413
+ },
414
+ activeListUrls: undefined,
415
+ })
416
+ store.dispatch(enableList('fake-url'))
417
+ expect(store.getState()).toEqual({
418
+ byUrl: {
419
+ 'fake-url': {
420
+ error: null,
421
+ current: null,
422
+ loadingRequestId: null,
423
+ pendingUpdate: null,
424
+ },
425
+ },
426
+ activeListUrls: ['fake-url'],
427
+ })
428
+ })
429
+ })
430
+
431
+ describe('updateVersion', () => {
432
+ describe('never initialized', () => {
433
+ beforeEach(() => {
434
+ store = createStore(reducer, {
435
+ byUrl: {
436
+ 'https://unpkg.com/@uniswap/default-token-list@latest/uniswap-default.tokenlist.json': {
437
+ error: null,
438
+ current: STUB_TOKEN_LIST,
439
+ loadingRequestId: null,
440
+ pendingUpdate: null,
441
+ },
442
+ 'https://unpkg.com/@uniswap/default-token-list@latest': {
443
+ error: null,
444
+ current: STUB_TOKEN_LIST,
445
+ loadingRequestId: null,
446
+ pendingUpdate: null,
447
+ },
448
+ },
449
+ activeListUrls: undefined,
450
+ })
451
+ store.dispatch(updateListVersion())
452
+ })
453
+
454
+ it('clears the current lists', () => {
455
+ expect(
456
+ store.getState().byUrl['https://unpkg.com/@uniswap/default-token-list@latest/uniswap-default.tokenlist.json'],
457
+ ).toBeUndefined()
458
+ expect(store.getState().byUrl['https://unpkg.com/@uniswap/default-token-list@latest']).toBeUndefined()
459
+ })
460
+
461
+ it('puts in all the new lists', () => {
462
+ expect(Object.keys(store.getState().byUrl)).toEqual(DEFAULT_LIST_OF_LISTS)
463
+ })
464
+ it('all lists are empty', () => {
465
+ const s = store.getState()
466
+ Object.keys(s.byUrl).forEach((url) => {
467
+ expect(s.byUrl[url]).toEqual({
468
+ error: null,
469
+ current: null,
470
+ loadingRequestId: null,
471
+ pendingUpdate: null,
472
+ })
473
+ })
474
+ })
475
+ it('sets initialized lists', () => {
476
+ expect(store.getState().lastInitializedDefaultListOfLists).toEqual(DEFAULT_LIST_OF_LISTS)
477
+ })
478
+ it('sets selected list', () => {
479
+ expect(store.getState().activeListUrls).toEqual(DEFAULT_ACTIVE_LIST_URLS)
480
+ })
481
+ })
482
+ describe('initialized with a different set of lists', () => {
483
+ beforeEach(() => {
484
+ store = createStore(reducer, {
485
+ byUrl: {
486
+ 'https://unpkg.com/@uniswap/default-token-list@latest/uniswap-default.tokenlist.json': {
487
+ error: null,
488
+ current: STUB_TOKEN_LIST,
489
+ loadingRequestId: null,
490
+ pendingUpdate: null,
491
+ },
492
+ 'https://unpkg.com/@uniswap/default-token-list@latest': {
493
+ error: null,
494
+ current: STUB_TOKEN_LIST,
495
+ loadingRequestId: null,
496
+ pendingUpdate: null,
497
+ },
498
+ },
499
+ activeListUrls: undefined,
500
+ lastInitializedDefaultListOfLists: ['https://unpkg.com/@uniswap/default-token-list@latest'],
501
+ })
502
+ store.dispatch(updateListVersion())
503
+ })
504
+
505
+ it('does not remove lists not in last initialized list of lists', () => {
506
+ expect(
507
+ store.getState().byUrl['https://unpkg.com/@uniswap/default-token-list@latest/uniswap-default.tokenlist.json'],
508
+ ).toEqual({
509
+ error: null,
510
+ current: STUB_TOKEN_LIST,
511
+ loadingRequestId: null,
512
+ pendingUpdate: null,
513
+ })
514
+ })
515
+ it('removes lists in the last initialized list of lists', () => {
516
+ expect(store.getState().byUrl['https://unpkg.com/@uniswap/default-token-list@latest']).toBeUndefined()
517
+ })
518
+
519
+ it('each of those initialized lists is empty', () => {
520
+ const { byUrl } = store.getState()
521
+ // note we don't expect the uniswap default list to be prepopulated
522
+ // this is ok.
523
+ Object.keys(byUrl).forEach((url) => {
524
+ if (url !== 'https://unpkg.com/@uniswap/default-token-list@latest/uniswap-default.tokenlist.json') {
525
+ expect(byUrl[url]).toEqual({
526
+ error: null,
527
+ current: null,
528
+ loadingRequestId: null,
529
+ pendingUpdate: null,
530
+ })
531
+ }
532
+ })
533
+ })
534
+
535
+ it('sets initialized lists', () => {
536
+ expect(store.getState().lastInitializedDefaultListOfLists).toEqual(DEFAULT_LIST_OF_LISTS)
537
+ })
538
+ it('sets default list to selected list', () => {
539
+ expect(store.getState().activeListUrls).toEqual(DEFAULT_ACTIVE_LIST_URLS)
540
+ })
541
+ })
542
+ })
543
+ })