getta 0.4.7 → 1.0.1

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 (104) hide show
  1. package/README.md +161 -7
  2. package/dist/main/index.mjs +621 -0
  3. package/dist/main/index.mjs.map +1 -0
  4. package/dist/tsconfig.build.tsbuildinfo +1 -0
  5. package/{lib → dist}/types/constants.d.ts +2 -2
  6. package/dist/types/constants.d.ts.map +1 -0
  7. package/dist/types/helpers/buildEndpoint/index.d.ts +3 -0
  8. package/dist/types/helpers/buildEndpoint/index.d.ts.map +1 -0
  9. package/{lib/types/helpers/build-endpoint → dist/types/helpers/buildEndpoint}/types.d.ts +2 -2
  10. package/dist/types/helpers/buildEndpoint/types.d.ts.map +1 -0
  11. package/dist/types/helpers/defaultPathTemplateCallback/index.d.ts +2 -0
  12. package/dist/types/helpers/defaultPathTemplateCallback/index.d.ts.map +1 -0
  13. package/dist/types/helpers/delay/index.d.ts +2 -0
  14. package/{lib → dist}/types/helpers/delay/index.d.ts.map +1 -1
  15. package/dist/types/helpers/getResponseGroup/index.d.ts +2 -0
  16. package/dist/types/helpers/getResponseGroup/index.d.ts.map +1 -0
  17. package/dist/types/helpers/isCacheabilityValid/index.d.ts +3 -0
  18. package/dist/types/helpers/isCacheabilityValid/index.d.ts.map +1 -0
  19. package/dist/types/index.d.ts +5 -0
  20. package/dist/types/index.d.ts.map +1 -0
  21. package/{lib → dist}/types/main.d.ts +12 -12
  22. package/dist/types/main.d.ts.map +1 -0
  23. package/dist/types/types.d.ts +161 -0
  24. package/dist/types/types.d.ts.map +1 -0
  25. package/package.json +113 -145
  26. package/src/{__tests__ → __testUtils__}/data/136-7317.json +1 -1
  27. package/src/{__tests__ → __testUtils__}/data/180-1387.json +1 -1
  28. package/src/{__tests__ → __testUtils__}/data/183-3905.json +1 -1
  29. package/src/{__tests__ → __testUtils__}/data/202-3315.json +1 -1
  30. package/src/__testUtils__/data/index.ts +23 -0
  31. package/src/__testUtils__/helpers/index.ts +49 -0
  32. package/src/constants.ts +28 -28
  33. package/src/helpers/buildEndpoint/index.ts +34 -0
  34. package/src/helpers/{build-endpoint → buildEndpoint}/types.ts +2 -2
  35. package/src/helpers/defaultPathTemplateCallback/index.test.ts +11 -0
  36. package/src/helpers/defaultPathTemplateCallback/index.ts +17 -0
  37. package/src/helpers/delay/index.ts +2 -2
  38. package/src/helpers/getResponseGroup/index.ts +25 -0
  39. package/src/helpers/isCacheabilityValid/index.ts +6 -0
  40. package/src/index.ts +4 -4
  41. package/src/main.test.ts +283 -411
  42. package/src/main.ts +238 -241
  43. package/src/types.ts +114 -16
  44. package/tsconfig.build.json +14 -0
  45. package/tsconfig.json +9 -0
  46. package/CHANGELOG.md +0 -250
  47. package/jest.setup.js +0 -10
  48. package/lib/browser/index.js +0 -2
  49. package/lib/browser/index.js.map +0 -1
  50. package/lib/browser/production.analysis.txt +0 -91
  51. package/lib/main/constants.js +0 -97
  52. package/lib/main/helpers/build-endpoint/index.js +0 -38
  53. package/lib/main/helpers/build-endpoint/types.js +0 -1
  54. package/lib/main/helpers/default-path-template-callback/index.js +0 -16
  55. package/lib/main/helpers/delay/index.js +0 -12
  56. package/lib/main/helpers/get-response-group/index.js +0 -27
  57. package/lib/main/helpers/is-cacheability-valid/index.js +0 -13
  58. package/lib/main/index.js +0 -62
  59. package/lib/main/main.js +0 -580
  60. package/lib/main/types.js +0 -1
  61. package/lib/module/constants.mjs +0 -49
  62. package/lib/module/helpers/build-endpoint/index.mjs +0 -28
  63. package/lib/module/helpers/build-endpoint/types.mjs +0 -0
  64. package/lib/module/helpers/default-path-template-callback/index.mjs +0 -9
  65. package/lib/module/helpers/delay/index.mjs +0 -4
  66. package/lib/module/helpers/get-response-group/index.mjs +0 -19
  67. package/lib/module/helpers/is-cacheability-valid/index.mjs +0 -6
  68. package/lib/module/index.mjs +0 -4
  69. package/lib/module/main.mjs +0 -576
  70. package/lib/module/types.mjs +0 -0
  71. package/lib/types/__tests__/data/index.d.ts +0 -17
  72. package/lib/types/__tests__/data/index.d.ts.map +0 -1
  73. package/lib/types/__tests__/helpers/index.d.ts +0 -29
  74. package/lib/types/__tests__/helpers/index.d.ts.map +0 -1
  75. package/lib/types/__tests__/types.d.ts +0 -13
  76. package/lib/types/__tests__/types.d.ts.map +0 -1
  77. package/lib/types/constants.d.ts.map +0 -1
  78. package/lib/types/helpers/build-endpoint/index.d.ts +0 -3
  79. package/lib/types/helpers/build-endpoint/index.d.ts.map +0 -1
  80. package/lib/types/helpers/build-endpoint/types.d.ts.map +0 -1
  81. package/lib/types/helpers/default-path-template-callback/index.d.ts +0 -3
  82. package/lib/types/helpers/default-path-template-callback/index.d.ts.map +0 -1
  83. package/lib/types/helpers/default-path-template-callback/index.test.d.ts +0 -2
  84. package/lib/types/helpers/default-path-template-callback/index.test.d.ts.map +0 -1
  85. package/lib/types/helpers/delay/index.d.ts +0 -2
  86. package/lib/types/helpers/get-response-group/index.d.ts +0 -2
  87. package/lib/types/helpers/get-response-group/index.d.ts.map +0 -1
  88. package/lib/types/helpers/is-cacheability-valid/index.d.ts +0 -3
  89. package/lib/types/helpers/is-cacheability-valid/index.d.ts.map +0 -1
  90. package/lib/types/index.d.ts +0 -5
  91. package/lib/types/index.d.ts.map +0 -1
  92. package/lib/types/main.d.ts.map +0 -1
  93. package/lib/types/main.test.d.ts +0 -2
  94. package/lib/types/main.test.d.ts.map +0 -1
  95. package/lib/types/types.d.ts +0 -69
  96. package/lib/types/types.d.ts.map +0 -1
  97. package/src/__tests__/data/index.ts +0 -19
  98. package/src/__tests__/helpers/index.ts +0 -61
  99. package/src/__tests__/types.ts +0 -14
  100. package/src/helpers/build-endpoint/index.ts +0 -34
  101. package/src/helpers/default-path-template-callback/index.test.ts +0 -11
  102. package/src/helpers/default-path-template-callback/index.ts +0 -16
  103. package/src/helpers/get-response-group/index.ts +0 -22
  104. package/src/helpers/is-cacheability-valid/index.ts +0 -6
package/src/main.test.ts CHANGED
@@ -1,362 +1,277 @@
1
- import { StringObject } from "@repodog/types";
2
- import fetchMock, { MockRequest } from "fetch-mock";
3
- import md5 from "md5";
4
- import { performance } from "perf_hooks";
5
- import { PRD_136_7317 } from "./__tests__/data";
1
+ import { jest } from '@jest/globals';
2
+ import { mockFetch } from 'fetch-mocked';
3
+ import { performance } from 'node:perf_hooks';
4
+ import { Md5 } from 'ts-md5';
5
+ import { PRD_136_7317 } from './__testUtils__/data/index.ts';
6
6
  import {
7
7
  basePath,
8
+ buildTestEndpoint,
8
9
  defaultEtag,
10
+ defaultHeaders,
9
11
  defaultPath,
10
12
  defaultPathTemplateData,
11
13
  defaultPayload,
12
14
  getCache,
15
+ graphqlPath,
13
16
  idPathTemplateData,
14
- mockRequest,
15
17
  pathTemplateDataWithoutID,
16
- tearDownTest,
17
- } from "./__tests__/helpers";
18
- import {
19
- COOKIE_HEADER,
20
- DELETE_METHOD,
21
- GET_METHOD,
22
- IF_NONE_MATCH_HEADER,
23
- LOCATION_HEADER,
24
- MAX_REDIRECTS_EXCEEDED_ERROR,
25
- MAX_RETRIES_EXCEEDED_ERROR,
26
- POST_METHOD,
27
- PUT_METHOD,
28
- RESOURCE_NOT_FOUND_ERROR,
29
- } from "./constants";
30
- import delay from "./helpers/delay";
31
- import { Getta, createRestClient } from "./main";
32
- import { ResponseDataWithErrors, ShortcutProperties } from "./types";
33
-
34
- describe("Getta", () => {
35
- describe("constructor", () => {
36
- it("SHOULD return an instance of the Getta class", () => {
18
+ } from './__testUtils__/helpers/index.ts';
19
+ import * as consts from './constants.ts';
20
+ import { delay } from './helpers/delay/index.ts';
21
+ import { Getta, createRestClient } from './main.ts';
22
+ import { type FetchResponse, type ResponseDataWithErrors, type ShortcutProperties } from './types.ts';
23
+
24
+ const mockedFetch = mockFetch(jest.fn);
25
+
26
+ describe('Getta', () => {
27
+ afterEach(() => {
28
+ mockedFetch.mockReset();
29
+ });
30
+
31
+ describe('constructor', () => {
32
+ it('should return an instance of the Getta class', () => {
37
33
  const restClient = createRestClient({ basePath, cache: getCache(), performance });
38
34
  expect(restClient).toBeInstanceOf(Getta);
39
35
  });
40
36
  });
41
37
 
42
- describe("get method", () => {
43
- let restClient: Getta & ShortcutProperties<"getProduct">;
38
+ describe('get method', () => {
39
+ let restClient: Getta & ShortcutProperties<'getProduct'>;
44
40
  let response: ResponseDataWithErrors | ResponseDataWithErrors[];
45
41
 
46
- beforeAll(() => {
47
- restClient = createRestClient<"getProduct">(
42
+ beforeEach(() => {
43
+ restClient = createRestClient<'getProduct'>(
48
44
  { basePath, cache: getCache(), performance },
49
45
  {
50
46
  getProduct: [
51
47
  defaultPath,
52
48
  {
53
- method: GET_METHOD,
49
+ method: consts.GET_METHOD,
54
50
  pathTemplateData: pathTemplateDataWithoutID,
55
51
  },
56
52
  ],
57
- },
53
+ }
58
54
  );
59
55
  });
60
56
 
61
- describe("WHEN a resource is requested", () => {
62
- beforeAll(async () => {
63
- mockRequest(
64
- defaultPath,
65
- PRD_136_7317.body,
66
- { pathTemplateData: defaultPathTemplateData },
67
- ({ endpoint, ...rest }) => {
68
- fetchMock.get(endpoint, rest);
69
- },
70
- );
57
+ afterEach(async () => {
58
+ await restClient.cache?.clear();
59
+ });
71
60
 
72
- response = await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
73
- });
61
+ describe('when a resource is requested', () => {
62
+ beforeEach(async () => {
63
+ mockedFetch.mockGetOnce(buildTestEndpoint(defaultPath), {
64
+ body: PRD_136_7317.body,
65
+ headers: defaultHeaders,
66
+ });
74
67
 
75
- afterAll(async () => {
76
- await tearDownTest({ fetchMock, restClient });
68
+ response = await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
77
69
  });
78
70
 
79
- it("SHOULD have made one request", () => {
80
- expect(fetchMock.calls().length).toBe(1);
71
+ it('should have made one request', () => {
72
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
81
73
  });
82
74
 
83
- it("SHOULD return the correct response", () => {
75
+ it('should return the correct response', () => {
84
76
  expect(response).toEqual(
85
77
  expect.objectContaining({
86
78
  data: PRD_136_7317.body,
87
- }),
79
+ })
88
80
  );
89
81
  });
90
82
  });
91
83
 
92
- describe("WHEN a resource is requested with a shortcut", () => {
93
- beforeAll(async () => {
94
- mockRequest(
95
- defaultPath,
96
- PRD_136_7317.body,
97
- { pathTemplateData: defaultPathTemplateData },
98
- ({ endpoint, ...rest }) => {
99
- fetchMock.get(endpoint, rest);
100
- },
101
- );
84
+ describe('when a resource is requested with a shortcut', () => {
85
+ beforeEach(async () => {
86
+ mockedFetch.mockGetOnce(buildTestEndpoint(defaultPath), {
87
+ body: PRD_136_7317.body,
88
+ headers: defaultHeaders,
89
+ });
102
90
 
103
91
  response = await restClient.getProduct({ pathTemplateData: idPathTemplateData });
104
92
  });
105
93
 
106
- afterAll(async () => {
107
- await tearDownTest({ fetchMock, restClient });
108
- });
109
-
110
- it("SHOULD have made one request", () => {
111
- expect(fetchMock.calls().length).toBe(1);
94
+ it('should have made one request', () => {
95
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
112
96
  });
113
97
 
114
- it("SHOULD return the correct response", () => {
98
+ it('should return the correct response', () => {
115
99
  expect(response).toEqual(
116
100
  expect.objectContaining({
117
101
  data: PRD_136_7317.body,
118
- }),
102
+ })
119
103
  );
120
104
  });
121
105
  });
122
106
 
123
- describe("WHEN a resource is in the cache", () => {
124
- describe("WHEN the cache entry is valid", () => {
125
- beforeAll(async () => {
126
- mockRequest(
127
- defaultPath,
128
- PRD_136_7317.body,
129
- { pathTemplateData: defaultPathTemplateData },
130
- ({ endpoint, ...rest }) => {
131
- fetchMock.get(endpoint, rest);
132
- },
133
- );
107
+ describe('when a resource is in the cache', () => {
108
+ describe('when the cache entry is valid', () => {
109
+ beforeEach(async () => {
110
+ mockedFetch.mockGetOnce(buildTestEndpoint(defaultPath), {
111
+ body: PRD_136_7317.body,
112
+ headers: defaultHeaders,
113
+ });
134
114
 
135
115
  await restClient.getProduct({ pathTemplateData: idPathTemplateData });
136
- fetchMock.restore();
116
+ mockedFetch.mockClear();
137
117
  response = await restClient.getProduct({ pathTemplateData: idPathTemplateData });
138
118
  });
139
119
 
140
- afterAll(async () => {
141
- await tearDownTest({ fetchMock, restClient });
142
- });
143
-
144
- it("SHOULD not have made a request", () => {
145
- expect(fetchMock.calls().length).toBe(0);
120
+ it('should not have made a request', () => {
121
+ expect(mockedFetch).not.toHaveBeenCalled();
146
122
  });
147
123
 
148
- it("SHOULD return the correct response", () => {
124
+ it('should return the correct response', () => {
149
125
  expect(response).toEqual(
150
126
  expect.objectContaining({
151
127
  data: PRD_136_7317.body,
152
- }),
128
+ })
153
129
  );
154
130
  });
155
131
  });
156
132
 
157
- describe("WHEN the cache entry is invalid", () => {
158
- function matcher(_url: string, { headers }: MockRequest) {
159
- return !!headers && (headers as StringObject)[IF_NONE_MATCH_HEADER] === defaultEtag;
160
- }
161
-
162
- async function invalidCacheEntryTestSetup() {
163
- mockRequest(
164
- defaultPath,
165
- PRD_136_7317.body,
166
- { headers: { "cache-control": "public, max-age=1" }, pathTemplateData: defaultPathTemplateData },
167
- ({ endpoint, ...rest }) => {
168
- fetchMock.get(endpoint, rest);
169
- },
170
- );
133
+ describe('when the cache entry is invalid', () => {
134
+ beforeEach(async () => {
135
+ mockedFetch.mockGetOnce(buildTestEndpoint(defaultPath), {
136
+ body: PRD_136_7317.body,
137
+ headers: { ...defaultHeaders, 'cache-control': 'public, max-age=1' },
138
+ });
171
139
 
172
140
  await restClient.getProduct({ pathTemplateData: idPathTemplateData });
173
141
  await delay(1000);
142
+ mockedFetch.mockClear();
143
+ });
174
144
 
175
- fetchMock.restore();
176
- }
177
-
178
- describe("WHEN the response returns not modified status code", () => {
179
- beforeAll(async () => {
180
- await invalidCacheEntryTestSetup();
181
-
182
- mockRequest(
183
- defaultPath,
184
- PRD_136_7317.body,
185
- { pathTemplateData: defaultPathTemplateData },
186
- ({ headers }) => {
187
- fetchMock.mock(matcher, { headers, status: 304 });
188
- },
145
+ describe('when the response returns not modified status code', () => {
146
+ beforeEach(async () => {
147
+ mockedFetch.mockGetOnce(
148
+ { headers: { [consts.IF_NONE_MATCH_HEADER]: defaultEtag }, url: buildTestEndpoint(defaultPath) },
149
+ { headers: defaultHeaders, status: 304 }
189
150
  );
190
151
 
191
152
  response = await restClient.getProduct({ pathTemplateData: idPathTemplateData });
192
153
  });
193
154
 
194
- afterAll(async () => {
195
- await tearDownTest({ fetchMock, restClient });
155
+ it('should have made one request', () => {
156
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
196
157
  });
197
158
 
198
- it("SHOULD have made one request", () => {
199
- expect(fetchMock.calls().length).toBe(1);
200
- });
201
-
202
- it("SHOULD return the correct response", () => {
159
+ it('should return the correct response', () => {
203
160
  expect(response).toEqual(
204
161
  expect.objectContaining({
205
162
  data: PRD_136_7317.body,
206
- }),
163
+ })
207
164
  );
208
165
  });
209
166
  });
210
167
 
211
- describe("WHEN the response returns the resource", () => {
212
- beforeAll(async () => {
213
- await invalidCacheEntryTestSetup();
214
-
215
- mockRequest(
216
- defaultPath,
217
- PRD_136_7317.body,
218
- { pathTemplateData: defaultPathTemplateData },
219
- ({ body, headers }) => {
220
- fetchMock.mock(matcher, { body, headers, status: 200 });
221
- },
168
+ describe('when the response returns the resource', () => {
169
+ beforeEach(async () => {
170
+ mockedFetch.mockGetOnce(
171
+ { headers: { [consts.IF_NONE_MATCH_HEADER]: defaultEtag }, url: buildTestEndpoint(defaultPath) },
172
+ { body: PRD_136_7317.body, headers: defaultHeaders }
222
173
  );
223
174
 
224
175
  response = await restClient.getProduct({ pathTemplateData: idPathTemplateData });
225
176
  });
226
177
 
227
- afterAll(async () => {
228
- await tearDownTest({ fetchMock, restClient });
229
- });
230
-
231
- it("SHOULD have made one request", () => {
232
- expect(fetchMock.calls().length).toBe(1);
178
+ it('should have made one request', () => {
179
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
233
180
  });
234
181
 
235
- it("SHOULD return the correct response", () => {
182
+ it('should return the correct response', () => {
236
183
  expect(response).toEqual(
237
184
  expect.objectContaining({
238
185
  data: PRD_136_7317.body,
239
- }),
186
+ })
240
187
  );
241
188
  });
242
189
  });
243
190
 
244
- describe("WHEN the response returns a 404", () => {
245
- beforeAll(async () => {
246
- await invalidCacheEntryTestSetup();
247
-
248
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ body, headers }) => {
249
- fetchMock.mock(matcher, { body, headers, status: 404 });
250
- });
191
+ describe('when the response returns a 404', () => {
192
+ beforeEach(async () => {
193
+ mockedFetch.mockGetOnce(
194
+ { headers: { [consts.IF_NONE_MATCH_HEADER]: defaultEtag }, url: buildTestEndpoint(defaultPath) },
195
+ { status: 404 }
196
+ );
251
197
 
252
198
  response = await restClient.getProduct({ pathTemplateData: idPathTemplateData });
253
199
  });
254
200
 
255
- afterAll(async () => {
256
- await tearDownTest({ fetchMock, restClient });
257
- });
258
-
259
- it("SHOULD have made one request", () => {
260
- expect(fetchMock.calls().length).toBe(1);
201
+ it('should have made one request', () => {
202
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
261
203
  });
262
204
 
263
- it("SHOULD return the correct response", () => {
205
+ it('should return the correct response', () => {
264
206
  expect(response).toEqual(
265
207
  expect.objectContaining({
266
- data: {},
267
- errors: [new Error(RESOURCE_NOT_FOUND_ERROR)],
268
- }),
208
+ errors: [new Error(consts.RESOURCE_NOT_FOUND_ERROR)],
209
+ })
269
210
  );
270
211
  });
271
212
  });
272
213
  });
273
214
  });
274
215
 
275
- describe("WHEN a request is redirected more than five times", () => {
276
- const REDIRECT_COOKIE_FLAG = "status=redirect";
277
-
278
- function matcher(_url: string, { headers }: MockRequest) {
279
- return !!headers && (headers as StringObject)[COOKIE_HEADER] === REDIRECT_COOKIE_FLAG;
280
- }
281
-
282
- beforeAll(async () => {
283
- mockRequest(
284
- defaultPath,
285
- {},
286
- { headers: { [LOCATION_HEADER]: basePath }, pathTemplateData: defaultPathTemplateData },
287
- ({ body, headers }) => {
288
- fetchMock.mock(matcher, { body, headers, status: 301 });
289
- },
216
+ describe('when a request is redirected more than five times', () => {
217
+ const REDIRECT_COOKIE_FLAG = 'status=redirect';
218
+
219
+ beforeEach(async () => {
220
+ mockedFetch.mockGet(
221
+ { headers: { [consts.COOKIE_HEADER]: REDIRECT_COOKIE_FLAG }, url: '*' },
222
+ { headers: { ...defaultHeaders, [consts.LOCATION_HEADER]: basePath }, status: 301 }
290
223
  );
291
224
 
292
225
  response = await restClient.getProduct({
293
- headers: { [COOKIE_HEADER]: REDIRECT_COOKIE_FLAG },
226
+ headers: { [consts.COOKIE_HEADER]: REDIRECT_COOKIE_FLAG },
294
227
  pathTemplateData: idPathTemplateData,
295
228
  });
296
229
  });
297
230
 
298
- afterAll(async () => {
299
- await tearDownTest({ fetchMock, restClient });
300
- });
301
-
302
- it("SHOULD have made five requests", () => {
303
- expect(fetchMock.calls().length).toBe(5);
231
+ it('should have made five requests', () => {
232
+ expect(mockedFetch).toHaveBeenCalledTimes(5);
304
233
  });
305
234
 
306
- it("SHOULD return the correct response", () => {
235
+ it('should return the correct response', () => {
307
236
  expect(response).toEqual(
308
237
  expect.objectContaining({
309
- errors: [new Error(`${MAX_REDIRECTS_EXCEEDED_ERROR} 5.`)],
310
- }),
238
+ errors: [new Error(`${consts.MAX_REDIRECTS_EXCEEDED_ERROR} 5.`)],
239
+ })
311
240
  );
312
241
  });
313
242
  });
314
243
 
315
- describe("WHEN a request is retried more than three times", () => {
316
- const RETRY_COOKIE_FLAG = "status=retry";
244
+ describe('when a request is retried more than three times', () => {
245
+ const RETRY_COOKIE_FLAG = 'status=retry';
317
246
 
318
- function matcher(_url: string, { headers }: MockRequest) {
319
- return !!headers && (headers as StringObject)[COOKIE_HEADER] === RETRY_COOKIE_FLAG;
320
- }
321
-
322
- beforeAll(async () => {
323
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ body, headers }) => {
324
- fetchMock.mock(matcher, { body, headers, status: 500 });
325
- });
247
+ beforeEach(async () => {
248
+ mockedFetch.mockGet(
249
+ { headers: { [consts.COOKIE_HEADER]: RETRY_COOKIE_FLAG }, url: buildTestEndpoint(defaultPath) },
250
+ { body: PRD_136_7317.body, status: 500 }
251
+ );
326
252
 
327
253
  response = await restClient.getProduct({
328
- headers: { [COOKIE_HEADER]: RETRY_COOKIE_FLAG },
254
+ headers: { [consts.COOKIE_HEADER]: RETRY_COOKIE_FLAG },
329
255
  pathTemplateData: idPathTemplateData,
330
256
  });
331
257
  });
332
258
 
333
- afterAll(async () => {
334
- await tearDownTest({ fetchMock, restClient });
335
- });
336
-
337
- it("SHOULD have made three requests", () => {
338
- expect(fetchMock.calls().length).toBe(3);
259
+ it('should have made three requests', () => {
260
+ expect(mockedFetch).toHaveBeenCalledTimes(3);
339
261
  });
340
262
 
341
- it("SHOULD return the correct response", () => {
263
+ it('should return the correct response', () => {
342
264
  expect(response).toEqual(
343
265
  expect.objectContaining({
344
- errors: [new Error(`${MAX_RETRIES_EXCEEDED_ERROR} 3.`)],
345
- }),
266
+ errors: [new Error(`${consts.MAX_RETRIES_EXCEEDED_ERROR} 3.`)],
267
+ })
346
268
  );
347
269
  });
348
270
  });
349
271
 
350
- describe("WHEN the same resource is requested in quick succession", () => {
351
- beforeAll(async () => {
352
- mockRequest(
353
- defaultPath,
354
- PRD_136_7317.body,
355
- { pathTemplateData: defaultPathTemplateData },
356
- ({ endpoint, ...rest }) => {
357
- fetchMock.get(endpoint, rest);
358
- },
359
- );
272
+ describe('when the same resource is requested in quick succession', () => {
273
+ beforeEach(async () => {
274
+ mockedFetch.mockGet(buildTestEndpoint(defaultPath), { body: PRD_136_7317.body, headers: defaultHeaders });
360
275
 
361
276
  response = await Promise.all([
362
277
  restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData }),
@@ -364,336 +279,293 @@ describe("Getta", () => {
364
279
  ]);
365
280
  });
366
281
 
367
- afterAll(async () => {
368
- await tearDownTest({ fetchMock, restClient });
369
- });
370
-
371
- it("SHOULD have made one request", () => {
372
- expect(fetchMock.calls().length).toBe(1);
282
+ it('should have made one request', () => {
283
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
373
284
  });
374
285
 
375
- it("SHOULD return the correct response", () => {
376
- expect((response as ResponseDataWithErrors[])[0]).toEqual(
286
+ it('should return the correct response', () => {
287
+ expect(response as ResponseDataWithErrors[]).toEqual([
377
288
  expect.objectContaining({
378
289
  data: PRD_136_7317.body,
379
290
  }),
380
- );
381
-
382
- expect((response as ResponseDataWithErrors[])[1]).toEqual(
383
291
  expect.objectContaining({
384
292
  data: PRD_136_7317.body,
385
293
  }),
386
- );
294
+ ]);
387
295
  });
388
296
  });
389
297
 
390
- describe("WHEN a request times out", () => {
391
- // TODO
298
+ describe('when a request times out', () => {
299
+ beforeEach(async () => {
300
+ mockedFetch.mockGet(buildTestEndpoint(defaultPath), { body: PRD_136_7317.body }, { delay: 200 });
301
+ // @ts-expect-error property is private
302
+ restClient._fetchTimeout = 100;
303
+
304
+ response = await restClient.getProduct({
305
+ pathTemplateData: idPathTemplateData,
306
+ });
307
+ });
308
+
309
+ it('should have made one request', () => {
310
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
311
+ });
312
+
313
+ it('should return the correct response', () => {
314
+ expect(response).toEqual(
315
+ expect.objectContaining({
316
+ errors: [new Error(`${consts.FETCH_TIMEOUT_ERROR} 100ms.`)],
317
+ })
318
+ );
319
+ });
392
320
  });
393
321
  });
394
322
 
395
- describe("post method", () => {
396
- let restClient: Getta & ShortcutProperties<"postProduct">;
397
- let response: ResponseDataWithErrors | ResponseDataWithErrors[];
323
+ describe('post method', () => {
324
+ let restClient: Getta & ShortcutProperties<'postProduct'>;
325
+ let response: FetchResponse;
398
326
 
399
- beforeAll(() => {
400
- restClient = createRestClient<"postProduct">(
327
+ beforeEach(() => {
328
+ restClient = createRestClient<'postProduct'>(
401
329
  { basePath, cache: getCache(), performance },
402
330
  {
403
331
  postProduct: [
404
- defaultPath,
332
+ graphqlPath,
405
333
  {
406
- method: POST_METHOD,
407
- pathTemplateData: pathTemplateDataWithoutID,
334
+ method: consts.POST_METHOD,
408
335
  },
409
336
  ],
410
- },
337
+ }
411
338
  );
412
339
  });
413
340
 
414
- describe("WHEN a resource is requested", () => {
415
- beforeAll(async () => {
416
- mockRequest(
417
- defaultPath,
418
- PRD_136_7317.body,
419
- { pathTemplateData: defaultPathTemplateData },
420
- ({ endpoint, ...rest }) => {
421
- fetchMock.post(endpoint, rest);
422
- },
341
+ afterEach(async () => {
342
+ await restClient.cache?.clear();
343
+ });
344
+
345
+ describe('when a resource is requested', () => {
346
+ beforeEach(async () => {
347
+ mockedFetch.mockPostOnce(
348
+ { body: { mock: true }, url: buildTestEndpoint(graphqlPath) },
349
+ { body: PRD_136_7317.body, headers: defaultHeaders }
423
350
  );
424
351
 
425
- response = await restClient.post(defaultPath, {
426
- body: defaultPayload,
427
- pathTemplateData: defaultPathTemplateData,
352
+ response = await restClient.post(graphqlPath, {
353
+ body: JSON.stringify({ ...defaultPayload, mock: true }),
428
354
  });
429
355
  });
430
356
 
431
- afterAll(async () => {
432
- await tearDownTest({ fetchMock, restClient });
357
+ it('should have made one request', () => {
358
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
433
359
  });
434
360
 
435
- it("SHOULD have made one request", () => {
436
- expect(fetchMock.calls().length).toBe(1);
437
- });
438
-
439
- it("SHOULD return the correct response", () => {
361
+ it('should return the correct response', () => {
440
362
  expect(response).toEqual(
441
363
  expect.objectContaining({
442
364
  data: PRD_136_7317.body,
443
- }),
365
+ })
444
366
  );
445
367
  });
446
368
  });
447
369
 
448
- describe("WHEN a resource is requested with a shortcut", () => {
449
- beforeAll(async () => {
450
- mockRequest(
451
- defaultPath,
452
- PRD_136_7317.body,
453
- { pathTemplateData: defaultPathTemplateData },
454
- ({ endpoint, ...rest }) => {
455
- fetchMock.post(endpoint, rest);
456
- },
370
+ describe('when a resource is requested with a shortcut', () => {
371
+ beforeEach(async () => {
372
+ mockedFetch.mockPostOnce(
373
+ { body: { mock: true }, url: buildTestEndpoint(graphqlPath) },
374
+ { body: PRD_136_7317.body, headers: defaultHeaders }
457
375
  );
458
376
 
459
- response = await restClient.postProduct({ body: defaultPayload, pathTemplateData: idPathTemplateData });
460
- });
461
-
462
- afterAll(async () => {
463
- await tearDownTest({ fetchMock, restClient });
377
+ response = await restClient.postProduct({ body: JSON.stringify({ ...defaultPayload, mock: true }) });
464
378
  });
465
379
 
466
- it("SHOULD have made one request", () => {
467
- expect(fetchMock.calls().length).toBe(1);
380
+ it('should have made one request', () => {
381
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
468
382
  });
469
383
 
470
- it("SHOULD return the correct response", () => {
384
+ it('should return the correct response', () => {
471
385
  expect(response).toEqual(
472
386
  expect.objectContaining({
473
387
  data: PRD_136_7317.body,
474
- }),
388
+ })
475
389
  );
476
390
  });
477
391
  });
478
392
  });
479
393
 
480
- describe("delete method", () => {
481
- let restClient: Getta & ShortcutProperties<"deleteProduct">;
482
- let response: ResponseDataWithErrors | ResponseDataWithErrors[];
483
- let requestHash: string;
394
+ describe('delete method', () => {
395
+ let restClient: Getta & ShortcutProperties<'deleteProduct'>;
396
+ let response: FetchResponse;
484
397
 
485
- beforeAll(() => {
486
- restClient = createRestClient<"deleteProduct">(
398
+ beforeEach(() => {
399
+ restClient = createRestClient<'deleteProduct'>(
487
400
  { basePath, cache: getCache(), performance },
488
401
  {
489
402
  deleteProduct: [
490
403
  defaultPath,
491
404
  {
492
- method: DELETE_METHOD,
405
+ method: consts.DELETE_METHOD,
493
406
  pathTemplateData: pathTemplateDataWithoutID,
494
407
  },
495
408
  ],
496
- },
409
+ }
497
410
  );
498
411
  });
499
412
 
500
- describe("WHEN a resource is requested to be deleted", () => {
501
- beforeAll(async () => {
502
- mockRequest(
503
- defaultPath,
504
- PRD_136_7317.body,
505
- { pathTemplateData: defaultPathTemplateData },
506
- ({ endpoint, ...rest }) => {
507
- requestHash = md5(endpoint);
508
- fetchMock.get(endpoint, rest);
509
- },
510
- );
413
+ afterEach(async () => {
414
+ await restClient.cache?.clear();
415
+ });
511
416
 
512
- response = await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
513
- fetchMock.restore();
417
+ describe('when a resource is requested to be deleted', () => {
418
+ beforeEach(async () => {
419
+ const url = buildTestEndpoint(defaultPath);
514
420
 
515
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ endpoint, ...rest }) => {
516
- fetchMock.delete(endpoint, rest);
421
+ mockedFetch.mockGetOnce(url, {
422
+ body: PRD_136_7317.body,
423
+ headers: defaultHeaders,
517
424
  });
518
425
 
426
+ mockedFetch.mockDeleteOnce(url);
427
+ await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
428
+ mockedFetch.mockClear();
519
429
  response = await restClient.delete(defaultPath, { pathTemplateData: defaultPathTemplateData });
520
430
  });
521
431
 
522
- afterAll(async () => {
523
- await tearDownTest({ fetchMock, restClient });
524
- });
525
-
526
- it("SHOULD have made one request", () => {
527
- expect(fetchMock.calls().length).toBe(1);
432
+ it('should have made one request', () => {
433
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
528
434
  });
529
435
 
530
- it("SHOULD return the correct response", () => {
531
- expect(response).toEqual(
532
- expect.objectContaining({
533
- data: {},
534
- }),
535
- );
436
+ it('should return the correct response', () => {
437
+ expect(response.status).toBe(200);
536
438
  });
537
439
 
538
- it("SHOULD delete any matching cache entry", async () => {
539
- expect(await restClient?.cache?.has(requestHash)).toBe(false);
440
+ it('should delete any matching cache entry', async () => {
441
+ await expect(restClient.cache?.has(Md5.hashStr(buildTestEndpoint(defaultPath)))).resolves.toBe(false);
540
442
  });
541
443
  });
542
444
 
543
- describe("WHEN a resource is requested to be deleted with a shortcut", () => {
544
- beforeAll(async () => {
545
- mockRequest(
546
- defaultPath,
547
- PRD_136_7317.body,
548
- { pathTemplateData: defaultPathTemplateData },
549
- ({ endpoint, ...rest }) => {
550
- requestHash = md5(endpoint);
551
- fetchMock.get(endpoint, rest);
552
- },
553
- );
554
-
555
- response = await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
556
- fetchMock.restore();
445
+ describe('when a resource is requested to be deleted with a shortcut', () => {
446
+ beforeEach(async () => {
447
+ const url = buildTestEndpoint(defaultPath);
557
448
 
558
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ endpoint, ...rest }) => {
559
- fetchMock.delete(endpoint, rest);
449
+ mockedFetch.mockGetOnce(url, {
450
+ body: PRD_136_7317.body,
451
+ headers: defaultHeaders,
560
452
  });
561
453
 
454
+ mockedFetch.mockDeleteOnce(url);
455
+ await restClient.get(defaultPath, { pathTemplateData: defaultPathTemplateData });
456
+ mockedFetch.mockClear();
562
457
  response = await restClient.deleteProduct({ pathTemplateData: idPathTemplateData });
563
458
  });
564
459
 
565
- afterAll(async () => {
566
- await tearDownTest({ fetchMock, restClient });
460
+ it('should have made one request', () => {
461
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
567
462
  });
568
463
 
569
- it("SHOULD have made one request", () => {
570
- expect(fetchMock.calls().length).toBe(1);
464
+ it('should return the correct response', () => {
465
+ expect(response.status).toBe(200);
571
466
  });
572
467
 
573
- it("SHOULD return the correct response", () => {
574
- expect(response).toEqual(
575
- expect.objectContaining({
576
- data: {},
577
- }),
578
- );
579
- });
580
-
581
- it("SHOULD delete any matching cache entry", async () => {
582
- expect(await restClient?.cache?.has(requestHash)).toBe(false);
468
+ it('should delete any matching cache entry', async () => {
469
+ await expect(restClient.cache?.has(Md5.hashStr(buildTestEndpoint(defaultPath)))).resolves.toBe(false);
583
470
  });
584
471
  });
585
472
  });
586
473
 
587
- describe("put method", () => {
588
- let restClient: Getta & ShortcutProperties<"putProduct">;
589
- let response: ResponseDataWithErrors | ResponseDataWithErrors[];
474
+ describe('put method', () => {
475
+ let restClient: Getta & ShortcutProperties<'putProduct'>;
476
+ let response: FetchResponse;
590
477
 
591
- beforeAll(() => {
592
- restClient = createRestClient<"putProduct">(
478
+ beforeEach(() => {
479
+ restClient = createRestClient<'putProduct'>(
593
480
  { basePath, cache: getCache(), performance },
594
481
  {
595
482
  putProduct: [
596
483
  defaultPath,
597
484
  {
598
- method: PUT_METHOD,
485
+ method: consts.PUT_METHOD,
599
486
  pathTemplateData: pathTemplateDataWithoutID,
600
487
  },
601
488
  ],
602
- },
489
+ }
603
490
  );
604
491
  });
605
492
 
606
- describe("WHEN a resource is send", () => {
607
- beforeAll(async () => {
608
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ endpoint, ...rest }) => {
609
- fetchMock.put(endpoint, rest);
610
- });
493
+ afterEach(async () => {
494
+ await restClient.cache?.clear();
495
+ });
496
+
497
+ describe('when a resource is send', () => {
498
+ beforeEach(async () => {
499
+ mockedFetch.mockPutOnce({ body: { mock: true }, url: buildTestEndpoint(defaultPath) }, { status: 201 });
611
500
 
612
501
  response = await restClient.put(defaultPath, {
613
- body: defaultPayload,
502
+ body: JSON.stringify({ ...defaultPayload, mock: true }),
614
503
  pathTemplateData: defaultPathTemplateData,
615
504
  });
616
505
  });
617
506
 
618
- afterAll(async () => {
619
- await tearDownTest({ fetchMock, restClient });
620
- });
621
-
622
- it("SHOULD have made one request", () => {
623
- expect(fetchMock.calls().length).toBe(1);
507
+ it('should have made one request', () => {
508
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
624
509
  });
625
510
 
626
- it("SHOULD return the correct response", () => {
627
- expect(response).toEqual(
628
- expect.objectContaining({
629
- data: {},
630
- }),
631
- );
511
+ it('should return the correct response', () => {
512
+ expect(response.status).toBe(201);
632
513
  });
633
514
  });
634
515
 
635
- describe("WHEN a resource is sent with a shortcut", () => {
636
- beforeAll(async () => {
637
- mockRequest(defaultPath, {}, { pathTemplateData: defaultPathTemplateData }, ({ endpoint, ...rest }) => {
638
- fetchMock.put(endpoint, rest);
639
- });
640
-
641
- response = await restClient.putProduct({ body: defaultPayload, pathTemplateData: idPathTemplateData });
642
- });
516
+ describe('when a resource is sent with a shortcut', () => {
517
+ beforeEach(async () => {
518
+ mockedFetch.mockPutOnce({ body: { mock: true }, url: buildTestEndpoint(defaultPath) }, { status: 201 });
643
519
 
644
- afterAll(async () => {
645
- await tearDownTest({ fetchMock, restClient });
520
+ response = await restClient.putProduct({
521
+ body: JSON.stringify({ ...defaultPayload, mock: true }),
522
+ pathTemplateData: idPathTemplateData,
523
+ });
646
524
  });
647
525
 
648
- it("SHOULD have made one request", () => {
649
- expect(fetchMock.calls().length).toBe(1);
526
+ it('should have made one request', () => {
527
+ expect(mockedFetch).toHaveBeenCalledTimes(1);
650
528
  });
651
529
 
652
- it("SHOULD return the correct response", () => {
653
- expect(response).toEqual(
654
- expect.objectContaining({
655
- data: {},
656
- }),
657
- );
530
+ it('should return the correct response', () => {
531
+ expect(response.status).toBe(201);
658
532
  });
659
533
  });
660
534
  });
661
535
 
662
- describe("rate limiting", () => {
536
+ describe('rate limiting', () => {
663
537
  let restClient: Getta;
664
538
 
665
- beforeAll(() => {
666
- restClient = createRestClient({ basePath, performance });
539
+ beforeEach(() => {
540
+ restClient = createRestClient({ basePath, performance, rateLimit: true });
667
541
  });
668
542
 
669
- describe("WHEN the number of requests per second exceeds rateLimitPerSecond", () => {
670
- beforeAll(async () => {
671
- const requestKeys = [...Array(55).keys()];
672
-
673
- requestKeys.forEach(key => {
674
- mockRequest(`product/${key}`, {}, {}, ({ endpoint, ...rest }) => {
675
- fetchMock.get(endpoint, rest);
676
- });
677
- });
543
+ afterEach(async () => {
544
+ await restClient.cache?.clear();
545
+ // @ts-expect-error property is private
546
+ clearTimeout(restClient._rateLimitTimer);
547
+ });
678
548
 
679
- // @ts-ignore
680
- restClient._addRequestToRateLimitedQueue = jest
681
- .fn()
682
- .mockResolvedValue({ data: {}, headers: new Headers(), status: 200 });
549
+ describe('when the number of requests per second exceeds rateLimitPerSecond', () => {
550
+ beforeEach(async () => {
551
+ const requestKeys = [...Array.from({ length: 55 }).keys()];
683
552
 
684
- await Promise.all(requestKeys.map(key => restClient.get(`product/${key}`)));
685
- });
553
+ for (const key of requestKeys) {
554
+ mockedFetch.mockGetOnce(buildTestEndpoint(`product/${key}`));
555
+ }
686
556
 
687
- afterAll(async () => {
688
- await tearDownTest({ fetchMock, restClient });
557
+ // @ts-expect-error property is private
558
+ restClient._addRequestToRateLimitedQueue = jest.fn().mockResolvedValue({ status: 200 });
559
+ await Promise.all(requestKeys.map(key => restClient.get(`product/${key}`, { headers: defaultHeaders })));
689
560
  });
690
561
 
691
- it("SHOULD call fetch one less than the rate limit", () => {
692
- expect(fetchMock.calls().length).toBe(49);
562
+ it('should call fetch one less than the rate limit', () => {
563
+ expect(mockedFetch).toHaveBeenCalledTimes(49);
693
564
  });
694
565
 
695
- it("SHOULD add the excess requests to rateLimitedRequestQueue", async () => {
696
- // @ts-ignore
566
+ it('should add the excess requests to rateLimitedRequestQueue', () => {
567
+ // @ts-expect-error property is private
568
+ // eslint-disable-next-line @typescript-eslint/unbound-method
697
569
  expect(restClient._addRequestToRateLimitedQueue).toHaveBeenCalledTimes(6);
698
570
  });
699
571
  });