pmxtjs 0.1.0 → 0.1.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.
Files changed (60) hide show
  1. package/{src/BaseExchange.ts → dist/BaseExchange.d.ts} +4 -22
  2. package/dist/BaseExchange.js +30 -0
  3. package/dist/exchanges/Kalshi.d.ts +20 -0
  4. package/{src/exchanges/Kalshi.ts → dist/exchanges/Kalshi.js} +75 -114
  5. package/dist/exchanges/Polymarket.d.ts +38 -0
  6. package/{src/exchanges/Polymarket.ts → dist/exchanges/Polymarket.js} +105 -146
  7. package/{src/index.ts → dist/index.d.ts} +0 -1
  8. package/dist/index.js +20 -0
  9. package/{src/types.ts → dist/types.d.ts} +3 -17
  10. package/dist/types.js +5 -0
  11. package/package.json +9 -1
  12. package/readme.md +62 -0
  13. package/coverage/clover.xml +0 -334
  14. package/coverage/coverage-final.json +0 -4
  15. package/coverage/lcov-report/base.css +0 -224
  16. package/coverage/lcov-report/block-navigation.js +0 -87
  17. package/coverage/lcov-report/favicon.png +0 -0
  18. package/coverage/lcov-report/index.html +0 -131
  19. package/coverage/lcov-report/pmxt/BaseExchange.ts.html +0 -256
  20. package/coverage/lcov-report/pmxt/exchanges/Kalshi.ts.html +0 -1132
  21. package/coverage/lcov-report/pmxt/exchanges/Polymarket.ts.html +0 -1456
  22. package/coverage/lcov-report/pmxt/exchanges/index.html +0 -131
  23. package/coverage/lcov-report/pmxt/index.html +0 -116
  24. package/coverage/lcov-report/prettify.css +0 -1
  25. package/coverage/lcov-report/prettify.js +0 -2
  26. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  27. package/coverage/lcov-report/sorter.js +0 -210
  28. package/coverage/lcov-report/src/BaseExchange.ts.html +0 -256
  29. package/coverage/lcov-report/src/exchanges/Kalshi.ts.html +0 -1132
  30. package/coverage/lcov-report/src/exchanges/Polymarket.ts.html +0 -1456
  31. package/coverage/lcov-report/src/exchanges/index.html +0 -131
  32. package/coverage/lcov-report/src/index.html +0 -116
  33. package/coverage/lcov.info +0 -766
  34. package/examples/get_event_prices.ts +0 -37
  35. package/examples/historical_prices.ts +0 -117
  36. package/examples/orderbook.ts +0 -102
  37. package/examples/recent_trades.ts +0 -29
  38. package/examples/search_events.ts +0 -68
  39. package/examples/search_market.ts +0 -29
  40. package/jest.config.js +0 -11
  41. package/pmxt-0.1.0.tgz +0 -0
  42. package/test/exchanges/kalshi/ApiErrors.test.ts +0 -132
  43. package/test/exchanges/kalshi/EmptyResponse.test.ts +0 -44
  44. package/test/exchanges/kalshi/FetchAndNormalizeMarkets.test.ts +0 -56
  45. package/test/exchanges/kalshi/LiveApi.integration.test.ts +0 -40
  46. package/test/exchanges/kalshi/MarketHistory.test.ts +0 -185
  47. package/test/exchanges/kalshi/OrderBook.test.ts +0 -149
  48. package/test/exchanges/kalshi/SearchMarkets.test.ts +0 -174
  49. package/test/exchanges/kalshi/VolumeFallback.test.ts +0 -44
  50. package/test/exchanges/polymarket/DataValidation.test.ts +0 -271
  51. package/test/exchanges/polymarket/ErrorHandling.test.ts +0 -34
  52. package/test/exchanges/polymarket/FetchAndNormalizeMarkets.test.ts +0 -68
  53. package/test/exchanges/polymarket/GetMarketsBySlug.test.ts +0 -268
  54. package/test/exchanges/polymarket/LiveApi.integration.test.ts +0 -44
  55. package/test/exchanges/polymarket/MarketHistory.test.ts +0 -207
  56. package/test/exchanges/polymarket/OrderBook.test.ts +0 -167
  57. package/test/exchanges/polymarket/RequestParameters.test.ts +0 -39
  58. package/test/exchanges/polymarket/SearchMarkets.test.ts +0 -176
  59. package/test/exchanges/polymarket/TradeHistory.test.ts +0 -248
  60. package/tsconfig.json +0 -12
@@ -1,271 +0,0 @@
1
- import axios from 'axios';
2
- import { PolymarketExchange } from '../../../src/exchanges/Polymarket';
3
-
4
- /**
5
- * Polymarket Data Validation Test
6
- *
7
- * What: Tests handling of malformed, missing, or edge-case data from the API.
8
- * Why: Real-world APIs can return unexpected data structures that must be handled gracefully.
9
- * How: Mocks various edge cases and verifies robust parsing and fallback logic.
10
- */
11
-
12
- jest.mock('axios');
13
- const mockedAxios = axios as jest.Mocked<typeof axios>;
14
-
15
- describe('PolymarketExchange - Data Validation', () => {
16
- let exchange: PolymarketExchange;
17
-
18
- beforeEach(() => {
19
- exchange = new PolymarketExchange();
20
- jest.clearAllMocks();
21
- });
22
-
23
- it('should handle stringified JSON in outcomes field', async () => {
24
- mockedAxios.get.mockResolvedValue({
25
- data: [{
26
- id: 'event-1',
27
- slug: 'test',
28
- title: 'Test Event',
29
- markets: [{
30
- id: 'market-1',
31
- question: 'Test?',
32
- outcomes: '["Yes", "No"]', // Stringified
33
- outcomePrices: '["0.52", "0.48"]',
34
- clobTokenIds: '["token1", "token2"]',
35
- endDate: '2025-12-31T00:00:00Z',
36
- volume24hr: '100000'
37
- }]
38
- }]
39
- });
40
-
41
- const markets = await exchange.fetchMarkets();
42
-
43
- expect(markets[0].outcomes.length).toBe(2);
44
- expect(markets[0].outcomes[0].label).toBe('Yes');
45
- });
46
-
47
- it('should handle array outcomes field', async () => {
48
- mockedAxios.get.mockResolvedValue({
49
- data: [{
50
- id: 'event-1',
51
- slug: 'test',
52
- title: 'Test Event',
53
- markets: [{
54
- id: 'market-1',
55
- question: 'Test?',
56
- outcomes: ['Yes', 'No'], // Already parsed
57
- outcomePrices: ['0.52', '0.48'],
58
- clobTokenIds: ['token1', 'token2'],
59
- endDate: '2025-12-31T00:00:00Z',
60
- volume24hr: '100000'
61
- }]
62
- }]
63
- });
64
-
65
- const markets = await exchange.fetchMarkets();
66
-
67
- expect(markets[0].outcomes.length).toBe(2);
68
- });
69
-
70
- it('should handle malformed JSON in outcomes gracefully', async () => {
71
- mockedAxios.get.mockResolvedValue({
72
- data: [{
73
- id: 'event-1',
74
- slug: 'test',
75
- title: 'Test Event',
76
- markets: [{
77
- id: 'market-1',
78
- question: 'Test?',
79
- outcomes: '{invalid json}',
80
- outcomePrices: '["0.52", "0.48"]',
81
- clobTokenIds: '["token1", "token2"]',
82
- endDate: '2025-12-31T00:00:00Z',
83
- volume24hr: '100000'
84
- }]
85
- }]
86
- });
87
-
88
- const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
89
- const markets = await exchange.fetchMarkets();
90
-
91
- expect(consoleSpy).toHaveBeenCalled();
92
- expect(markets[0].outcomes.length).toBe(0);
93
- consoleSpy.mockRestore();
94
- });
95
-
96
- it('should handle missing volume fields with fallback', async () => {
97
- mockedAxios.get.mockResolvedValue({
98
- data: [{
99
- id: 'event-1',
100
- slug: 'test',
101
- title: 'Test Event',
102
- markets: [{
103
- id: 'market-1',
104
- question: 'Test?',
105
- outcomes: '["Yes", "No"]',
106
- outcomePrices: '["0.52", "0.48"]',
107
- clobTokenIds: '["token1", "token2"]',
108
- endDate: '2025-12-31T00:00:00Z'
109
- // Missing volume24hr and volume
110
- }]
111
- }]
112
- });
113
-
114
- const markets = await exchange.fetchMarkets();
115
-
116
- expect(markets[0].volume24h).toBe(0);
117
- expect(markets[0].volume).toBe(0);
118
- });
119
-
120
- it('should handle alternative volume field names', async () => {
121
- mockedAxios.get.mockResolvedValue({
122
- data: [{
123
- id: 'event-1',
124
- slug: 'test',
125
- title: 'Test Event',
126
- markets: [{
127
- id: 'market-1',
128
- question: 'Test?',
129
- outcomes: '["Yes", "No"]',
130
- outcomePrices: '["0.52", "0.48"]',
131
- clobTokenIds: '["token1", "token2"]',
132
- endDate: '2025-12-31T00:00:00Z',
133
- volume_24h: '50000' // Alternative field name
134
- }]
135
- }]
136
- });
137
-
138
- const markets = await exchange.fetchMarkets();
139
-
140
- expect(markets[0].volume24h).toBe(50000);
141
- });
142
-
143
- it('should handle missing liquidity with nested fallback', async () => {
144
- mockedAxios.get.mockResolvedValue({
145
- data: [{
146
- id: 'event-1',
147
- slug: 'test',
148
- title: 'Test Event',
149
- markets: [{
150
- id: 'market-1',
151
- question: 'Test?',
152
- outcomes: '["Yes", "No"]',
153
- outcomePrices: '["0.52", "0.48"]',
154
- clobTokenIds: '["token1", "token2"]',
155
- endDate: '2025-12-31T00:00:00Z',
156
- volume24hr: '100000',
157
- rewards: { liquidity: 25000 } // Nested liquidity
158
- }]
159
- }]
160
- });
161
-
162
- const markets = await exchange.fetchMarkets();
163
-
164
- expect(markets[0].liquidity).toBe(25000);
165
- });
166
-
167
- it('should handle candidate name extraction for Yes/No markets', async () => {
168
- mockedAxios.get.mockResolvedValue({
169
- data: [{
170
- id: 'event-1',
171
- slug: 'test',
172
- title: 'Presidential Election',
173
- markets: [{
174
- id: 'market-1',
175
- question: 'Will Trump win?',
176
- groupItemTitle: 'Trump',
177
- outcomes: '["Yes", "No"]',
178
- outcomePrices: '["0.52", "0.48"]',
179
- clobTokenIds: '["token1", "token2"]',
180
- endDate: '2025-12-31T00:00:00Z',
181
- volume24hr: '100000'
182
- }]
183
- }]
184
- });
185
-
186
- const markets = await exchange.fetchMarkets();
187
-
188
- expect(markets[0].outcomes[0].label).toBe('Trump');
189
- expect(markets[0].outcomes[1].label).toBe('Not Trump');
190
- });
191
-
192
- it('should handle multi-outcome markets', async () => {
193
- mockedAxios.get.mockResolvedValue({
194
- data: [{
195
- id: 'event-1',
196
- slug: 'test',
197
- title: 'Winner Prediction',
198
- markets: [{
199
- id: 'market-1',
200
- question: 'Who will win?',
201
- outcomes: '["Trump", "Biden", "RFK Jr", "Other"]',
202
- outcomePrices: '["0.40", "0.35", "0.15", "0.10"]',
203
- clobTokenIds: '["token1", "token2", "token3", "token4"]',
204
- endDate: '2025-12-31T00:00:00Z',
205
- volume24hr: '100000'
206
- }]
207
- }]
208
- });
209
-
210
- const markets = await exchange.fetchMarkets();
211
-
212
- expect(markets[0].outcomes.length).toBe(4);
213
- expect(markets[0].outcomes[0].label).toBe('Trump');
214
- expect(markets[0].outcomes[3].label).toBe('Other');
215
- });
216
-
217
- it('should handle missing endDate with fallback', async () => {
218
- mockedAxios.get.mockResolvedValue({
219
- data: [{
220
- id: 'event-1',
221
- slug: 'test',
222
- title: 'Test Event',
223
- markets: [{
224
- id: 'market-1',
225
- question: 'Test?',
226
- outcomes: '["Yes", "No"]',
227
- outcomePrices: '["0.52", "0.48"]',
228
- clobTokenIds: '["token1", "token2"]',
229
- volume24hr: '100000'
230
- // Missing endDate
231
- }]
232
- }]
233
- });
234
-
235
- const markets = await exchange.fetchMarkets();
236
-
237
- expect(markets[0].resolutionDate).toBeInstanceOf(Date);
238
- });
239
-
240
- it('should skip events without markets', async () => {
241
- mockedAxios.get.mockResolvedValue({
242
- data: [
243
- {
244
- id: 'event-1',
245
- slug: 'test',
246
- title: 'Test Event'
247
- // Missing markets field
248
- },
249
- {
250
- id: 'event-2',
251
- slug: 'test2',
252
- title: 'Test Event 2',
253
- markets: [{
254
- id: 'market-1',
255
- question: 'Test?',
256
- outcomes: '["Yes", "No"]',
257
- outcomePrices: '["0.52", "0.48"]',
258
- clobTokenIds: '["token1", "token2"]',
259
- endDate: '2025-12-31T00:00:00Z',
260
- volume24hr: '100000'
261
- }]
262
- }
263
- ]
264
- });
265
-
266
- const markets = await exchange.fetchMarkets();
267
-
268
- expect(markets.length).toBe(1);
269
- expect(markets[0].id).toBe('market-1');
270
- });
271
- });
@@ -1,34 +0,0 @@
1
- import axios from 'axios';
2
- import { PolymarketExchange } from '../../../src/exchanges/Polymarket';
3
-
4
- /**
5
- * Polymarket Error Handling Test
6
- *
7
- * What: Tests how the Polymarket exchange handle API errors and network failures.
8
- * Why: To ensure application stability when external services are unavailable.
9
- * How: Mocks a rejected axios promise and verifies that the exchange returns an empty
10
- * array instead of throwing, and logs the error.
11
- */
12
-
13
- jest.mock('axios');
14
- const mockedAxios = axios as jest.Mocked<typeof axios>;
15
-
16
- describe('PolymarketExchange - Error Handling', () => {
17
- let exchange: PolymarketExchange;
18
-
19
- beforeEach(() => {
20
- exchange = new PolymarketExchange();
21
- jest.clearAllMocks();
22
- });
23
-
24
- it('should handle API errors by returning an empty list', async () => {
25
- mockedAxios.get.mockRejectedValue(new Error('Network Error'));
26
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
27
-
28
- const markets = await exchange.fetchMarkets();
29
-
30
- expect(markets).toEqual([]);
31
- expect(consoleSpy).toHaveBeenCalled();
32
- consoleSpy.mockRestore();
33
- });
34
- });
@@ -1,68 +0,0 @@
1
- import axios from 'axios';
2
- import { PolymarketExchange } from '../../../src/exchanges/Polymarket';
3
-
4
- /**
5
- * Polymarket Markets Normalization Test
6
- *
7
- * What: Tests the normalization of Polymarket's Gamma API response.
8
- * Why: Polymarket's API often returns outcomes and prices as stringified JSON.
9
- * We need to ensure these are correctly parsed regardless of whether
10
- * the API returns them as strings or actual arrays.
11
- * How: Mocks various response formats from the Gamma API and validates the UnifiedMarket output.
12
- */
13
-
14
- jest.mock('axios');
15
- const mockedAxios = axios as jest.Mocked<typeof axios>;
16
-
17
- describe('PolymarketExchange - Fetch and Normalize Markets', () => {
18
- let exchange: PolymarketExchange;
19
-
20
- beforeEach(() => {
21
- exchange = new PolymarketExchange();
22
- jest.clearAllMocks();
23
- });
24
-
25
- const mockGammaResponse = [
26
- {
27
- id: "eventId1",
28
- title: "Presidential Election 2024",
29
- markets: [
30
- {
31
- id: "marketId1",
32
- question: "Winner",
33
- volume_24h: 1000000,
34
- outcomePrices: "[\"0.60\", \"0.40\"]", // Stringified JSON
35
- outcomes: "[\"Candidate A\", \"Candidate B\"]", // Stringified JSON
36
- rewards: { liquidity: 50000 }
37
- },
38
- {
39
- id: "marketId2",
40
- question: "Runner Up",
41
- outcomes: ["A", "B"], // Actual array
42
- outcomePrices: ["0.1", "0.9"], // Actual array
43
- volume24hr: "500" // Alternative field name
44
- }
45
- ]
46
- }
47
- ];
48
-
49
- it('should correctly parse stringified and non-stringified outcomes/prices', async () => {
50
- mockedAxios.get.mockResolvedValue({ data: mockGammaResponse });
51
-
52
- const markets = await exchange.fetchMarkets();
53
-
54
- expect(markets).toHaveLength(2);
55
-
56
- // Check Market 1 (Stringified)
57
- const m1 = markets[0];
58
- expect(m1.id).toBe("marketId1");
59
- expect(m1.outcomes[0].label).toBe("Candidate A");
60
- expect(m1.outcomes[0].price).toBe(0.60);
61
-
62
- // Check Market 2 (Array)
63
- const m2 = markets[1];
64
- expect(m2.id).toBe("marketId2");
65
- expect(m2.outcomes[0].label).toBe("A");
66
- expect(m2.volume24h).toBe(500);
67
- });
68
- });
@@ -1,268 +0,0 @@
1
- import axios from 'axios';
2
- import { PolymarketExchange } from '../../../src/exchanges/Polymarket';
3
-
4
- /**
5
- * Polymarket getMarketsBySlug() Test
6
- *
7
- * What: Tests fetching specific markets by their event slug (from URL).
8
- * Why: This is a CRITICAL user-facing feature for deep-linking to specific events.
9
- * How: Mocks Gamma API responses for slug-based queries and verifies data extraction.
10
- */
11
-
12
- jest.mock('axios');
13
- const mockedAxios = axios as jest.Mocked<typeof axios>;
14
-
15
- describe('PolymarketExchange - getMarketsBySlug', () => {
16
- let exchange: PolymarketExchange;
17
-
18
- beforeEach(() => {
19
- exchange = new PolymarketExchange();
20
- jest.clearAllMocks();
21
- });
22
-
23
- it('should fetch markets by slug successfully', async () => {
24
- mockedAxios.get.mockResolvedValue({
25
- data: [{
26
- id: 'event-1',
27
- slug: 'fed-rate-decision',
28
- title: 'Federal Reserve Rate Decision',
29
- description: 'Will the Fed cut rates?',
30
- markets: [{
31
- id: 'market-1',
32
- question: 'Rate cut in March?',
33
- description: 'Federal Reserve rate decision',
34
- outcomes: '["Yes", "No"]',
35
- outcomePrices: '["0.52", "0.48"]',
36
- clobTokenIds: '["token1", "token2"]',
37
- endDate: '2025-03-31T00:00:00Z',
38
- volume24hr: '100000',
39
- volume: '500000',
40
- liquidity: '50000'
41
- }]
42
- }]
43
- });
44
-
45
- const markets = await exchange.getMarketsBySlug('fed-rate-decision');
46
-
47
- expect(markets.length).toBe(1);
48
- expect(markets[0].id).toBe('market-1');
49
- expect(markets[0].title).toBe('Federal Reserve Rate Decision');
50
- expect(markets[0].outcomes.length).toBe(2);
51
- });
52
-
53
- it('should handle empty events array', async () => {
54
- mockedAxios.get.mockResolvedValue({
55
- data: []
56
- });
57
-
58
- const markets = await exchange.getMarketsBySlug('nonexistent-slug');
59
-
60
- expect(markets).toEqual([]);
61
- });
62
-
63
- it('should handle null events', async () => {
64
- mockedAxios.get.mockResolvedValue({
65
- data: null
66
- });
67
-
68
- const markets = await exchange.getMarketsBySlug('invalid-slug');
69
-
70
- expect(markets).toEqual([]);
71
- });
72
-
73
- it('should skip events without markets', async () => {
74
- mockedAxios.get.mockResolvedValue({
75
- data: [{
76
- id: 'event-1',
77
- slug: 'test-event',
78
- title: 'Test Event'
79
- // Missing markets field
80
- }]
81
- });
82
-
83
- const markets = await exchange.getMarketsBySlug('test-event');
84
-
85
- expect(markets).toEqual([]);
86
- });
87
-
88
- it('should handle candidate name extraction', async () => {
89
- mockedAxios.get.mockResolvedValue({
90
- data: [{
91
- id: 'event-1',
92
- slug: 'election-2024',
93
- title: 'Presidential Election',
94
- markets: [{
95
- id: 'market-1',
96
- question: 'Will Trump win?',
97
- groupItemTitle: 'Trump',
98
- outcomes: '["Yes", "No"]',
99
- outcomePrices: '["0.48", "0.52"]',
100
- clobTokenIds: '["token1", "token2"]',
101
- endDate: '2024-11-05T00:00:00Z',
102
- volume24hr: '1000000'
103
- }]
104
- }]
105
- });
106
-
107
- const markets = await exchange.getMarketsBySlug('election-2024');
108
-
109
- expect(markets[0].outcomes[0].label).toBe('Trump');
110
- expect(markets[0].outcomes[1].label).toBe('Not Trump');
111
- });
112
-
113
- it('should fallback to question for candidate name', async () => {
114
- mockedAxios.get.mockResolvedValue({
115
- data: [{
116
- id: 'event-1',
117
- slug: 'test',
118
- title: 'Test',
119
- markets: [{
120
- id: 'market-1',
121
- question: 'Biden',
122
- outcomes: '["Yes", "No"]',
123
- outcomePrices: '["0.50", "0.50"]',
124
- clobTokenIds: '["token1", "token2"]',
125
- endDate: '2025-12-31T00:00:00Z',
126
- volume24hr: '10000'
127
- }]
128
- }]
129
- });
130
-
131
- const markets = await exchange.getMarketsBySlug('test');
132
-
133
- expect(markets[0].outcomes[0].label).toBe('Biden');
134
- });
135
-
136
- it('should handle JSON parsing errors gracefully', async () => {
137
- mockedAxios.get.mockResolvedValue({
138
- data: [{
139
- id: 'event-1',
140
- slug: 'test',
141
- title: 'Test Event',
142
- markets: [{
143
- id: 'market-1',
144
- question: 'Test?',
145
- outcomes: '{invalid json}',
146
- outcomePrices: '["0.50", "0.50"]',
147
- clobTokenIds: '["token1", "token2"]',
148
- endDate: '2025-12-31T00:00:00Z',
149
- volume24hr: '10000'
150
- }]
151
- }]
152
- });
153
-
154
- const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => { });
155
- const markets = await exchange.getMarketsBySlug('test');
156
-
157
- expect(consoleSpy).toHaveBeenCalled();
158
- expect(markets[0].outcomes.length).toBe(0);
159
- consoleSpy.mockRestore();
160
- });
161
-
162
- it('should handle price change data', async () => {
163
- mockedAxios.get.mockResolvedValue({
164
- data: [{
165
- id: 'event-1',
166
- slug: 'test',
167
- title: 'Test',
168
- markets: [{
169
- id: 'market-1',
170
- question: 'Test?',
171
- outcomes: '["Yes", "No"]',
172
- outcomePrices: '["0.52", "0.48"]',
173
- clobTokenIds: '["token1", "token2"]',
174
- endDate: '2025-12-31T00:00:00Z',
175
- volume24hr: '10000',
176
- oneDayPriceChange: 0.05
177
- }]
178
- }]
179
- });
180
-
181
- const markets = await exchange.getMarketsBySlug('test');
182
-
183
- expect(markets[0].outcomes[0].priceChange24h).toBe(0.05);
184
- });
185
-
186
- it('should handle missing endDate with fallback', async () => {
187
- mockedAxios.get.mockResolvedValue({
188
- data: [{
189
- id: 'event-1',
190
- slug: 'test',
191
- title: 'Test',
192
- markets: [{
193
- id: 'market-1',
194
- question: 'Test?',
195
- outcomes: '["Yes", "No"]',
196
- outcomePrices: '["0.50", "0.50"]',
197
- clobTokenIds: '["token1", "token2"]',
198
- volume24hr: '10000'
199
- // Missing endDate
200
- }]
201
- }]
202
- });
203
-
204
- const markets = await exchange.getMarketsBySlug('test');
205
-
206
- expect(markets[0].resolutionDate).toBeInstanceOf(Date);
207
- });
208
-
209
- it('should handle API errors gracefully', async () => {
210
- mockedAxios.get.mockRejectedValue(new Error('API Error'));
211
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
212
-
213
- const markets = await exchange.getMarketsBySlug('test');
214
-
215
- expect(markets).toEqual([]);
216
- expect(consoleSpy).toHaveBeenCalled();
217
- consoleSpy.mockRestore();
218
- });
219
-
220
- it('should include image data', async () => {
221
- mockedAxios.get.mockResolvedValue({
222
- data: [{
223
- id: 'event-1',
224
- slug: 'test',
225
- title: 'Test',
226
- image: 'https://example.com/image.jpg',
227
- markets: [{
228
- id: 'market-1',
229
- question: 'Test?',
230
- outcomes: '["Yes", "No"]',
231
- outcomePrices: '["0.50", "0.50"]',
232
- clobTokenIds: '["token1", "token2"]',
233
- endDate: '2025-12-31T00:00:00Z',
234
- volume24hr: '10000'
235
- }]
236
- }]
237
- });
238
-
239
- const markets = await exchange.getMarketsBySlug('test');
240
-
241
- expect(markets[0].image).toBe('https://example.com/image.jpg');
242
- });
243
-
244
- it('should handle volume field variations', async () => {
245
- mockedAxios.get.mockResolvedValue({
246
- data: [{
247
- id: 'event-1',
248
- slug: 'test',
249
- title: 'Test',
250
- markets: [{
251
- id: 'market-1',
252
- question: 'Test?',
253
- outcomes: '["Yes", "No"]',
254
- outcomePrices: '["0.50", "0.50"]',
255
- clobTokenIds: '["token1", "token2"]',
256
- endDate: '2025-12-31T00:00:00Z',
257
- volume_24h: '25000', // Alternative field name
258
- volume: '100000'
259
- }]
260
- }]
261
- });
262
-
263
- const markets = await exchange.getMarketsBySlug('test');
264
-
265
- expect(markets[0].volume24h).toBe(25000);
266
- expect(markets[0].volume).toBe(100000);
267
- });
268
- });
@@ -1,44 +0,0 @@
1
- import { PolymarketExchange } from '../../../src/exchanges/Polymarket';
2
-
3
- /**
4
- * Polymarket Integration Test (Live API)
5
- *
6
- * What: Verifies real-world connectivity and data structure from Polymarket's Gamma API.
7
- * Why: Polymarket data is complex and frequently changes; live tests catch schema drift.
8
- * How: Makes actual HTTP requests to Polymarket and validates the properties
9
- * of the returned UnifiedMarket objects.
10
- */
11
-
12
- describe('PolymarketExchange - Live API Integration', () => {
13
- const exchange = new PolymarketExchange();
14
- jest.setTimeout(15000);
15
-
16
- it('should fetch real active markets with correct schema', async () => {
17
- const markets = await exchange.fetchMarkets({ limit: 5 });
18
-
19
- expect(markets.length).toBeGreaterThan(0);
20
-
21
- const m = markets[0];
22
- expect(m.id).toBeDefined();
23
- expect(m.title.length).toBeGreaterThan(0);
24
- expect(m.outcomes.length).toBeGreaterThanOrEqual(2);
25
- expect(m.url).toContain('polymarket.com');
26
- expect(m.resolutionDate).toBeInstanceOf(Date);
27
- });
28
-
29
- it('should support pagination on live API', async () => {
30
- const page1 = await exchange.fetchMarkets({ limit: 1, offset: 0 });
31
- const page2 = await exchange.fetchMarkets({ limit: 1, offset: 1 });
32
-
33
- if (page1.length > 0 && page2.length > 0) {
34
- expect(page1[0].id).not.toBe(page2[0].id);
35
- }
36
- });
37
-
38
- it('should return top markets with non-zero volume', async () => {
39
- const markets = await exchange.fetchMarkets({ limit: 3, sort: 'volume' });
40
- if (markets.length > 0) {
41
- expect(markets[0].volume24h).toBeGreaterThan(0);
42
- }
43
- });
44
- });