hive-stream 2.0.5 → 3.0.0

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.
Files changed (89) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.env.example +2 -2
  3. package/.travis.yml +11 -11
  4. package/CHANGELOG.md +166 -0
  5. package/CLAUDE.md +75 -0
  6. package/LICENSE +21 -21
  7. package/README.md +338 -238
  8. package/dist/actions.d.ts +41 -10
  9. package/dist/actions.js +126 -23
  10. package/dist/actions.js.map +1 -1
  11. package/dist/adapters/base.adapter.d.ts +25 -25
  12. package/dist/adapters/base.adapter.js +63 -49
  13. package/dist/adapters/base.adapter.js.map +1 -1
  14. package/dist/adapters/mongodb.adapter.d.ts +50 -37
  15. package/dist/adapters/mongodb.adapter.js +363 -158
  16. package/dist/adapters/mongodb.adapter.js.map +1 -1
  17. package/dist/adapters/postgresql.adapter.d.ts +49 -0
  18. package/dist/adapters/postgresql.adapter.js +507 -0
  19. package/dist/adapters/postgresql.adapter.js.map +1 -0
  20. package/dist/adapters/sqlite.adapter.d.ts +40 -41
  21. package/dist/adapters/sqlite.adapter.js +470 -397
  22. package/dist/adapters/sqlite.adapter.js.map +1 -1
  23. package/dist/api.d.ts +6 -6
  24. package/dist/api.js +95 -55
  25. package/dist/api.js.map +1 -1
  26. package/dist/config.d.ts +16 -16
  27. package/dist/config.js +18 -18
  28. package/dist/config.js.map +1 -1
  29. package/dist/contracts/coinflip.contract.d.ts +27 -14
  30. package/dist/contracts/coinflip.contract.js +253 -94
  31. package/dist/contracts/coinflip.contract.js.map +1 -1
  32. package/dist/contracts/dice.contract.d.ts +37 -29
  33. package/dist/contracts/dice.contract.js +282 -155
  34. package/dist/contracts/dice.contract.js.map +1 -1
  35. package/dist/contracts/lotto.contract.d.ts +20 -20
  36. package/dist/contracts/lotto.contract.js +246 -246
  37. package/dist/contracts/nft.contract.d.ts +24 -0
  38. package/dist/contracts/nft.contract.js +533 -0
  39. package/dist/contracts/nft.contract.js.map +1 -0
  40. package/dist/contracts/token.contract.d.ts +18 -0
  41. package/dist/contracts/token.contract.js +263 -0
  42. package/dist/contracts/token.contract.js.map +1 -0
  43. package/dist/exchanges/bittrex.d.ts +6 -6
  44. package/dist/exchanges/bittrex.js +34 -34
  45. package/dist/exchanges/coingecko.d.ts +5 -0
  46. package/dist/exchanges/coingecko.js +40 -0
  47. package/dist/exchanges/coingecko.js.map +1 -0
  48. package/dist/exchanges/exchange.d.ts +9 -9
  49. package/dist/exchanges/exchange.js +26 -26
  50. package/dist/hive-rates.d.ts +9 -9
  51. package/dist/hive-rates.js +121 -75
  52. package/dist/hive-rates.js.map +1 -1
  53. package/dist/index.d.ts +12 -11
  54. package/dist/index.js +33 -32
  55. package/dist/index.js.map +1 -1
  56. package/dist/streamer.d.ts +140 -93
  57. package/dist/streamer.js +793 -545
  58. package/dist/streamer.js.map +1 -1
  59. package/dist/test.d.ts +1 -1
  60. package/dist/test.js +25 -25
  61. package/dist/test.js.map +1 -1
  62. package/dist/types/hive-stream.d.ts +35 -6
  63. package/dist/types/hive-stream.js +2 -2
  64. package/dist/utils.d.ts +27 -27
  65. package/dist/utils.js +271 -261
  66. package/dist/utils.js.map +1 -1
  67. package/ecosystem.config.js +17 -17
  68. package/jest.config.js +8 -8
  69. package/package.json +53 -48
  70. package/test-contract-block.md +18 -18
  71. package/tests/actions.spec.ts +252 -0
  72. package/tests/adapters/actions-persistence.spec.ts +144 -0
  73. package/tests/adapters/postgresql.adapter.spec.ts +127 -0
  74. package/tests/adapters/sqlite.adapter.spec.ts +180 -42
  75. package/tests/contracts/coinflip.contract.spec.ts +221 -131
  76. package/tests/contracts/dice.contract.spec.ts +202 -159
  77. package/tests/contracts/entrants.json +728 -728
  78. package/tests/contracts/lotto.contract.spec.ts +323 -323
  79. package/tests/contracts/nft.contract.spec.ts +948 -0
  80. package/tests/contracts/token.contract.spec.ts +334 -0
  81. package/tests/helpers/mock-adapter.ts +214 -0
  82. package/tests/setup.ts +29 -18
  83. package/tests/streamer-actions.spec.ts +263 -0
  84. package/tests/streamer.spec.ts +248 -151
  85. package/tests/utils.spec.ts +91 -94
  86. package/tsconfig.build.json +3 -22
  87. package/tslint.json +20 -20
  88. package/wallaby.js +26 -26
  89. package/.env +0 -3
@@ -0,0 +1,334 @@
1
+ import { TokenContract } from '../../src/contracts/token.contract';
2
+ import { MockAdapter } from '../helpers/mock-adapter';
3
+
4
+ describe('TokenContract', () => {
5
+ let tokenContract: TokenContract;
6
+ let mockAdapter: MockAdapter;
7
+ let mockStreamer: any;
8
+
9
+ beforeEach(() => {
10
+ mockAdapter = new MockAdapter();
11
+ mockStreamer = {
12
+ getAdapter: () => mockAdapter
13
+ };
14
+
15
+ tokenContract = new TokenContract();
16
+ tokenContract._instance = mockStreamer;
17
+ tokenContract.updateBlockInfo(12345, 'block123', 'prevblock123', 'txn123');
18
+ });
19
+
20
+ describe('createToken', () => {
21
+ it('should create a new token successfully', async () => {
22
+ mockAdapter.reset();
23
+ tokenContract.create();
24
+ mockAdapter.setQueryResult([]); // No existing token with same symbol
25
+
26
+ const payload = {
27
+ symbol: 'TEST',
28
+ name: 'Test Token',
29
+ precision: 3,
30
+ maxSupply: '1000000'
31
+ };
32
+
33
+ await (tokenContract as any).createToken(payload, { sender: 'alice' });
34
+
35
+ const insertQuery = mockAdapter.queries.find(q => q.includes('INSERT INTO tokens'));
36
+ expect(insertQuery).toBeDefined();
37
+ expect(mockAdapter.events.length).toBe(1);
38
+ expect(mockAdapter.events[0].action).toBe('createToken');
39
+ });
40
+
41
+ it('should reject invalid token symbol', async () => {
42
+ const payload = {
43
+ symbol: 'invalid-symbol',
44
+ name: 'Test Token',
45
+ maxSupply: '1000000'
46
+ };
47
+
48
+ await expect((tokenContract as any).createToken(payload, { sender: 'alice' }))
49
+ .rejects.toThrow('Symbol must be 1-10 uppercase alphanumeric characters');
50
+ });
51
+
52
+ it('should reject invalid max supply', async () => {
53
+ const payload = {
54
+ symbol: 'TEST',
55
+ name: 'Test Token',
56
+ maxSupply: '0'
57
+ };
58
+
59
+ await expect((tokenContract as any).createToken(payload, { sender: 'alice' }))
60
+ .rejects.toThrow('Maximum supply must be between 1 and 9007199254740991');
61
+ });
62
+
63
+ it('should reject max supply too large', async () => {
64
+ const payload = {
65
+ symbol: 'TEST',
66
+ name: 'Test Token',
67
+ maxSupply: '9007199254740992'
68
+ };
69
+
70
+ await expect((tokenContract as any).createToken(payload, { sender: 'alice' }))
71
+ .rejects.toThrow('Maximum supply must be between 1 and 9007199254740991');
72
+ });
73
+
74
+ it('should reject invalid precision', async () => {
75
+ const payload = {
76
+ symbol: 'TEST',
77
+ name: 'Test Token',
78
+ precision: 9,
79
+ maxSupply: '1000000'
80
+ };
81
+
82
+ await expect((tokenContract as any).createToken(payload, { sender: 'alice' }))
83
+ .rejects.toThrow('Precision must be between 0 and 8');
84
+ });
85
+
86
+ it('should create token with URL', async () => {
87
+ mockAdapter.reset();
88
+ tokenContract.create();
89
+ mockAdapter.setQueryResult([]); // No existing token with same symbol
90
+
91
+ const payload = {
92
+ symbol: 'TEST',
93
+ name: 'Test Token',
94
+ url: 'https://example.com/token',
95
+ precision: 3,
96
+ maxSupply: '1000000'
97
+ };
98
+
99
+ await (tokenContract as any).createToken(payload, { sender: 'alice' });
100
+
101
+ const insertQuery = mockAdapter.queries.find(q => q.includes('INSERT INTO tokens'));
102
+ expect(insertQuery).toBeDefined();
103
+ expect(mockAdapter.events.length).toBe(1);
104
+ expect(mockAdapter.events[0].action).toBe('createToken');
105
+ });
106
+
107
+ it('should reject URL too long', async () => {
108
+ const longUrl = 'https://example.com/' + 'a'.repeat(250);
109
+ const payload = {
110
+ symbol: 'TEST',
111
+ name: 'Test Token',
112
+ url: longUrl,
113
+ maxSupply: '1000000'
114
+ };
115
+
116
+ await expect((tokenContract as any).createToken(payload, { sender: 'alice' }))
117
+ .rejects.toThrow('URL must be 256 characters or less');
118
+ });
119
+ });
120
+
121
+ describe('issueTokens', () => {
122
+ it('should issue tokens successfully', async () => {
123
+ mockAdapter.reset();
124
+ mockAdapter.setTestContext({ noExistingBalance: true });
125
+ tokenContract.create();
126
+
127
+ mockAdapter.setQueryResult([{
128
+ symbol: 'TEST',
129
+ name: 'Test Token',
130
+ creator: 'alice',
131
+ precision: 3,
132
+ current_supply: '0',
133
+ max_supply: '1000000'
134
+ }]);
135
+
136
+ const payload = {
137
+ symbol: 'TEST',
138
+ to: 'bob',
139
+ amount: '100',
140
+ memo: 'Initial distribution'
141
+ };
142
+
143
+ await (tokenContract as any).issueTokens(payload, { sender: 'alice' });
144
+
145
+ const updateQuery = mockAdapter.queries.find(q => q.includes('UPDATE tokens SET current_supply'));
146
+ const insertQuery = mockAdapter.queries.find(q => q.includes('INSERT INTO token_balances'));
147
+ expect(updateQuery).toBeDefined();
148
+ expect(insertQuery).toBeDefined();
149
+ expect(mockAdapter.events.length).toBe(1);
150
+ expect(mockAdapter.events[0].action).toBe('issueTokens');
151
+ });
152
+
153
+ it('should reject issuance by non-creator', async () => {
154
+ mockAdapter.reset();
155
+ tokenContract.create();
156
+
157
+ mockAdapter.setQueryResult([{
158
+ symbol: 'TEST',
159
+ name: 'Test Token',
160
+ creator: 'alice',
161
+ precision: 3,
162
+ current_supply: '0',
163
+ max_supply: '1000000'
164
+ }]);
165
+
166
+ const payload = {
167
+ symbol: 'TEST',
168
+ to: 'bob',
169
+ amount: '100'
170
+ };
171
+
172
+ await expect((tokenContract as any).issueTokens(payload, { sender: 'charlie' }))
173
+ .rejects.toThrow('Only the token creator can issue new tokens');
174
+ });
175
+
176
+ it('should reject issuance exceeding max supply', async () => {
177
+ mockAdapter.reset();
178
+ mockAdapter.setTestContext({ maxSupplyExceeded: true });
179
+ tokenContract.create();
180
+
181
+ mockAdapter.setQueryResult([{
182
+ symbol: 'TEST',
183
+ name: 'Test Token',
184
+ creator: 'alice',
185
+ precision: 3,
186
+ current_supply: '999999',
187
+ max_supply: '1000000'
188
+ }]);
189
+
190
+ const payload = {
191
+ symbol: 'TEST',
192
+ to: 'bob',
193
+ amount: '100'
194
+ };
195
+
196
+ await expect((tokenContract as any).issueTokens(payload, { sender: 'alice' }))
197
+ .rejects.toThrow('Cannot issue tokens: would exceed maximum supply');
198
+ });
199
+ });
200
+
201
+ describe('transferTokens', () => {
202
+ it('should transfer tokens successfully', async () => {
203
+ mockAdapter.reset();
204
+ tokenContract.create();
205
+
206
+ const payload = {
207
+ symbol: 'TEST',
208
+ to: 'bob',
209
+ amount: '100',
210
+ memo: 'Payment'
211
+ };
212
+
213
+ await (tokenContract as any).transferTokens(payload, { sender: 'alice' });
214
+
215
+ const updateQuery = mockAdapter.queries.find(q => q.includes('UPDATE token_balances SET balance'));
216
+ const insertQuery = mockAdapter.queries.find(q => q.includes('INSERT INTO token_transfers'));
217
+ expect(updateQuery).toBeDefined();
218
+ expect(insertQuery).toBeDefined();
219
+ expect(mockAdapter.events.length).toBe(1);
220
+ expect(mockAdapter.events[0].action).toBe('transferTokens');
221
+ });
222
+
223
+ it('should reject transfer with insufficient balance', async () => {
224
+ mockAdapter.reset();
225
+ mockAdapter.setTestContext({ insufficientBalance: true });
226
+ tokenContract.create();
227
+
228
+ const payload = {
229
+ symbol: 'TEST',
230
+ to: 'bob',
231
+ amount: '100'
232
+ };
233
+
234
+ await expect((tokenContract as any).transferTokens(payload, { sender: 'alice' }))
235
+ .rejects.toThrow('Insufficient balance');
236
+ });
237
+
238
+ it('should reject transfer of non-existent token', async () => {
239
+ mockAdapter.reset();
240
+ mockAdapter.setTestContext({ nonExistentToken: 'NONEXISTENT' });
241
+ tokenContract.create();
242
+
243
+ const payload = {
244
+ symbol: 'NONEXISTENT',
245
+ to: 'bob',
246
+ amount: '100'
247
+ };
248
+
249
+ await expect((tokenContract as any).transferTokens(payload, { sender: 'alice' }))
250
+ .rejects.toThrow('Token NONEXISTENT does not exist');
251
+ });
252
+ });
253
+
254
+ describe('getBalance', () => {
255
+ it('should return balance for existing account', async () => {
256
+ mockAdapter.reset();
257
+ tokenContract.create();
258
+
259
+ mockAdapter.setQueryResult([{ balance: '500' }]);
260
+
261
+ const payload = {
262
+ account: 'alice',
263
+ symbol: 'TEST'
264
+ };
265
+
266
+ await (tokenContract as any).getBalance(payload, { sender: 'bob' });
267
+
268
+ const selectQuery = mockAdapter.queries.find(q => q.includes('SELECT balance FROM token_balances'));
269
+ expect(selectQuery).toBeDefined();
270
+ expect(mockAdapter.events.length).toBe(1);
271
+ expect(mockAdapter.events[0].action).toBe('getBalance');
272
+ });
273
+
274
+ it('should return zero balance for non-existent account', async () => {
275
+ mockAdapter.reset();
276
+ mockAdapter.setTestContext({ zeroBalance: true });
277
+ tokenContract.create();
278
+
279
+ const payload = {
280
+ account: 'alice',
281
+ symbol: 'TEST'
282
+ };
283
+
284
+ await (tokenContract as any).getBalance(payload, { sender: 'bob' });
285
+
286
+ expect(mockAdapter.events[0].data.data.balance).toBe('0');
287
+ });
288
+ });
289
+
290
+ describe('getTokenInfo', () => {
291
+ it('should return token information', async () => {
292
+ mockAdapter.reset();
293
+ tokenContract.create();
294
+
295
+ const tokenData = {
296
+ symbol: 'TEST',
297
+ name: 'Test Token',
298
+ url: 'https://example.com/token',
299
+ precision: 3,
300
+ max_supply: '1000000',
301
+ current_supply: '500000',
302
+ creator: 'alice',
303
+ created_at: new Date()
304
+ };
305
+
306
+ mockAdapter.setQueryResult([tokenData]);
307
+
308
+ const payload = {
309
+ symbol: 'TEST'
310
+ };
311
+
312
+ await (tokenContract as any).getTokenInfo(payload, { sender: 'bob' });
313
+
314
+ const selectQuery = mockAdapter.queries.find(q => q.includes('SELECT * FROM tokens'));
315
+ expect(selectQuery).toBeDefined();
316
+ expect(mockAdapter.events.length).toBe(1);
317
+ expect(mockAdapter.events[0].action).toBe('getTokenInfo');
318
+ expect(mockAdapter.events[0].data.data.token_info).toEqual(tokenData);
319
+ });
320
+
321
+ it('should reject request for non-existent token', async () => {
322
+ mockAdapter.reset();
323
+ mockAdapter.setTestContext({ nonExistentToken: 'NONEXISTENT' });
324
+ tokenContract.create();
325
+
326
+ const payload = {
327
+ symbol: 'NONEXISTENT'
328
+ };
329
+
330
+ await expect((tokenContract as any).getTokenInfo(payload, { sender: 'bob' }))
331
+ .rejects.toThrow('Token NONEXISTENT does not exist');
332
+ });
333
+ });
334
+ });
@@ -0,0 +1,214 @@
1
+ import { AdapterBase } from '../../src/adapters/base.adapter';
2
+
3
+ export class MockAdapter extends AdapterBase {
4
+ public queries: string[] = [];
5
+ public events: any[] = [];
6
+ private queryResults: any[][] = [];
7
+ private currentQueryIndex = 0;
8
+ private testContext: any = {};
9
+ public async create(): Promise<boolean> {
10
+ return true;
11
+ }
12
+
13
+ public async destroy(): Promise<boolean> {
14
+ return true;
15
+ }
16
+
17
+ public async loadActions() {
18
+ return [];
19
+ }
20
+
21
+ public async loadState() {
22
+ return { lastBlockNumber: 0, actions: [] };
23
+ }
24
+
25
+ public async saveState(data: any): Promise<boolean> {
26
+ return true;
27
+ }
28
+
29
+ public async processBlock(block: any): Promise<any> {
30
+ return true;
31
+ }
32
+
33
+ public async processOperation(op: any, blockNumber: number, blockId: string, prevBlockId: string, trxId: string, blockTime: Date): Promise<any> {
34
+ return true;
35
+ }
36
+
37
+ public async processTransfer(operation: any, payload: any, metadata: any): Promise<boolean> {
38
+ return true;
39
+ }
40
+
41
+ public async processCustomJson(operation: any, payload: any, metadata: any): Promise<boolean> {
42
+ return true;
43
+ }
44
+
45
+ public async find(table: string, queryObject: Record<string, any>): Promise<any> {
46
+ return [];
47
+ }
48
+
49
+ public async findOne(table: string, queryObject: Record<string, any>): Promise<any> {
50
+ return null;
51
+ }
52
+
53
+ public async insert(table: string, data: any): Promise<any> {
54
+ return true;
55
+ }
56
+
57
+ public async replace(table: string, queryObject: Record<string, any>, data: any): Promise<any> {
58
+ return data;
59
+ }
60
+
61
+ public async addEvent(date: string | Date, contract: string, action: string, payload: any, data: any): Promise<boolean> {
62
+ this.events.push({ date, contract, action, payload, data });
63
+ return true;
64
+ }
65
+
66
+ public async query(sql: string, params?: any[]): Promise<any[]> {
67
+ this.queries.push(sql);
68
+
69
+ // Handle specific queries with predetermined responses
70
+ if (sql.includes('CREATE TABLE')) {
71
+ return [];
72
+ }
73
+
74
+ if (sql.includes('SELECT precision FROM tokens WHERE symbol = ?')) {
75
+ const symbol = params?.[0];
76
+ if (this.testContext.nonExistentToken === symbol) {
77
+ return [];
78
+ }
79
+ return [{ precision: 3 }];
80
+ }
81
+
82
+ if (sql.includes('SELECT balance FROM token_balances WHERE account = ? AND symbol = ?')) {
83
+ const account = params?.[0];
84
+ const symbol = params?.[1];
85
+
86
+ // Handle test scenarios
87
+ if (this.testContext.insufficientBalance && account === 'alice') {
88
+ return [{ balance: '50' }];
89
+ }
90
+ if (this.testContext.zeroBalance && account === 'alice') {
91
+ return [];
92
+ }
93
+ if (this.testContext.noExistingBalance) {
94
+ return [];
95
+ }
96
+
97
+ // Default balances
98
+ if (account === 'alice') {
99
+ return [{ balance: '1000' }];
100
+ } else if (account === 'bob') {
101
+ return [{ balance: '50' }];
102
+ }
103
+ return [];
104
+ }
105
+
106
+ if (sql.includes('SELECT * FROM tokens WHERE symbol = ?')) {
107
+ const symbol = params?.[0];
108
+ if (this.testContext.nonExistentToken === symbol) {
109
+ return [];
110
+ }
111
+
112
+ // Handle max supply exceeded test
113
+ if (this.testContext.maxSupplyExceeded) {
114
+ return [{
115
+ symbol: 'TEST',
116
+ name: 'Test Token',
117
+ creator: 'alice',
118
+ precision: 3,
119
+ max_supply: '1000000',
120
+ current_supply: '999999'
121
+ }];
122
+ }
123
+
124
+ // Return token info for existing tokens
125
+ return [{
126
+ symbol: 'TEST',
127
+ name: 'Test Token',
128
+ url: 'https://example.com/token',
129
+ precision: 3,
130
+ max_supply: '1000000',
131
+ current_supply: '500000',
132
+ creator: 'alice',
133
+ created_at: new Date()
134
+ }];
135
+ }
136
+
137
+ if (sql.includes('SELECT symbol FROM tokens WHERE symbol = ?')) {
138
+ const symbol = params?.[0];
139
+ if (this.testContext.existingToken === symbol) {
140
+ return [{ symbol }];
141
+ }
142
+ return [];
143
+ }
144
+
145
+ // Use sequential results for other queries
146
+ if (this.queryResults.length > this.currentQueryIndex) {
147
+ return this.queryResults[this.currentQueryIndex++];
148
+ }
149
+ return [];
150
+ }
151
+
152
+ public setQueryResult(result: any[], index?: number): void {
153
+ if (index !== undefined) {
154
+ this.queryResults[index] = result;
155
+ } else {
156
+ this.queryResults.push(result);
157
+ }
158
+ }
159
+
160
+ public setQueryResults(results: any[][]): void {
161
+ this.queryResults = results;
162
+ this.currentQueryIndex = 0;
163
+ }
164
+
165
+ public reset(): void {
166
+ this.queries = [];
167
+ this.events = [];
168
+ this.queryResults = [];
169
+ this.currentQueryIndex = 0;
170
+ this.testContext = {};
171
+ }
172
+
173
+ public setTestContext(context: any): void {
174
+ this.testContext = context;
175
+ }
176
+
177
+ public async getTransfers() {
178
+ return [];
179
+ }
180
+
181
+ public async getEvents() {
182
+ return [];
183
+ }
184
+
185
+ public async getJson() {
186
+ return [];
187
+ }
188
+
189
+ public async getTransfersByContract(contract: string) {
190
+ return [];
191
+ }
192
+
193
+ public async getTransfersByAccount(account: string) {
194
+ return [];
195
+ }
196
+
197
+ public async getTransfersByBlockid(blockId: any) {
198
+ return [];
199
+ }
200
+
201
+ public async getJsonByContract(contract: string) {
202
+ return [];
203
+ }
204
+
205
+ public async getJsonByAccount(account: string) {
206
+ return [];
207
+ }
208
+
209
+ public async getJsonByBlockid(blockId: any) {
210
+ return [];
211
+ }
212
+ }
213
+
214
+ export const createMockAdapter = () => new MockAdapter();
package/tests/setup.ts CHANGED
@@ -1,19 +1,30 @@
1
- import { GlobalWithFetchMock } from 'jest-fetch-mock';
2
-
3
- // (global as any).console = {
4
- // log: jest.fn(), // console.log are ignored in tests
5
-
6
- // // Keep native behaviour for other methods, use those to print out things in your own tests, not `console.log`
7
- // error: console.error,
8
- // warn: console.warn,
9
- // info: console.info,
10
- // debug: console.debug,
11
- // };
12
-
13
- const customGlobal: GlobalWithFetchMock = global as unknown as GlobalWithFetchMock;
14
- customGlobal.fetch = require('jest-fetch-mock');
15
- customGlobal.fetchMock = customGlobal.fetch;
16
-
17
- process.on('unhandledRejection', (error) => {
18
- throw error; // Or whatever you like...
1
+ import { GlobalWithFetchMock } from 'jest-fetch-mock';
2
+
3
+ // (global as any).console = {
4
+ // log: jest.fn(), // console.log are ignored in tests
5
+
6
+ // // Keep native behaviour for other methods, use those to print out things in your own tests, not `console.log`
7
+ // error: console.error,
8
+ // warn: console.warn,
9
+ // info: console.info,
10
+ // debug: console.debug,
11
+ // };
12
+
13
+ const fetchMock = require('jest-fetch-mock');
14
+ const customGlobal: GlobalWithFetchMock = global as unknown as GlobalWithFetchMock;
15
+
16
+ // Safely assign fetch mock
17
+ if (!customGlobal.fetch) {
18
+ customGlobal.fetch = fetchMock;
19
+ } else {
20
+ Object.defineProperty(customGlobal, 'fetch', {
21
+ value: fetchMock,
22
+ writable: true,
23
+ configurable: true
24
+ });
25
+ }
26
+ customGlobal.fetchMock = customGlobal.fetch;
27
+
28
+ process.on('unhandledRejection', (error) => {
29
+ throw error; // Or whatever you like...
19
30
  });