ftmocks-utils 1.1.6 → 1.1.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +371 -231
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -1,135 +1,166 @@
1
1
  // import fs from 'fs';
2
- const fs = require('fs')
2
+ const fs = require("fs");
3
3
  // import path from 'path';
4
- const path = require('path')
4
+ const path = require("path");
5
5
 
6
- const nameToFolder = name => {
7
- return name.replaceAll(' ', '_');
6
+ const nameToFolder = (name) => {
7
+ return name.replaceAll(" ", "_");
8
8
  };
9
9
 
10
- const getMockDir = config => {
11
- if(!path.isAbsolute(config.MOCK_DIR)) {
12
- return path.resolve( process.cwd(), config.MOCK_DIR);
10
+ const getMockDir = (config) => {
11
+ if (!path.isAbsolute(config.MOCK_DIR)) {
12
+ return path.resolve(process.cwd(), config.MOCK_DIR);
13
13
  }
14
14
  return config.MOCK_DIR;
15
- }
15
+ };
16
16
 
17
- const getFallbackDir = config => {
18
- if(config.FALLBACK_DIR && !path.isAbsolute(config.FALLBACK_DIR)) {
19
- return path.resolve( process.cwd(), config.FALLBACK_DIR);
17
+ const getFallbackDir = (config) => {
18
+ if (config.FALLBACK_DIR && !path.isAbsolute(config.FALLBACK_DIR)) {
19
+ return path.resolve(process.cwd(), config.FALLBACK_DIR);
20
20
  }
21
21
  return config.FALLBACK_DIR;
22
- }
22
+ };
23
23
 
24
- const capitalizeHeader = header => {
24
+ const capitalizeHeader = (header) => {
25
25
  return header
26
- .split('-')
27
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
28
- .join('-');
29
- }
26
+ .split("-")
27
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
28
+ .join("-");
29
+ };
30
30
 
31
- const capitalizeHeaders = headers => {
31
+ const capitalizeHeaders = (headers) => {
32
32
  return Object.fromEntries(
33
- Object.entries(headers).map(([key, value]) => [capitalizeHeader(key), value])
33
+ Object.entries(headers).map(([key, value]) => [
34
+ capitalizeHeader(key),
35
+ value,
36
+ ])
34
37
  );
35
38
  };
36
39
 
37
- const getHeaders = headers => {
40
+ const getHeaders = (headers) => {
38
41
  let res = null;
39
42
  try {
40
- res = new Map([...Object.entries(headers), ...Object.entries(capitalizeHeaders(headers))]);
41
- } catch(e) {
42
- console.debug('error at getHeaders', e);
43
- res = new Map([['Content-Type', 'application/json'], ['content-type', 'application/json']]);
43
+ res = new Map([
44
+ ...Object.entries(headers),
45
+ ...Object.entries(capitalizeHeaders(headers)),
46
+ ]);
47
+ } catch (e) {
48
+ console.debug("error at getHeaders", e);
49
+ res = new Map([
50
+ ["Content-Type", "application/json"],
51
+ ["content-type", "application/json"],
52
+ ]);
44
53
  }
45
54
  return Object.fromEntries(res);
46
- }
55
+ };
47
56
 
48
57
  const areJsonEqual = (jsonObj1, jsonObj2) => {
49
58
  // Check if both are objects and not null
50
- if (typeof jsonObj1 === 'object' && jsonObj1 !== null &&
51
- typeof jsonObj2 === 'object' && jsonObj2 !== null) {
52
-
59
+ if (
60
+ typeof jsonObj1 === "object" &&
61
+ jsonObj1 !== null &&
62
+ typeof jsonObj2 === "object" &&
63
+ jsonObj2 !== null
64
+ ) {
53
65
  // Get the keys of both objects
54
66
  const keys1 = Object.keys(jsonObj1);
55
67
  const keys2 = Object.keys(jsonObj2);
56
-
68
+
57
69
  // Check if the number of keys is different
58
70
  if (keys1.length !== keys2.length) {
59
71
  return false;
60
72
  }
61
-
73
+
62
74
  // Recursively check each key-value pair
63
75
  for (let key of keys1) {
64
76
  if (!keys2.includes(key) || !areJsonEqual(jsonObj1[key], jsonObj2[key])) {
65
77
  return false;
66
78
  }
67
79
  }
68
-
80
+
69
81
  return true;
70
82
  } else {
71
83
  // For non-object types, use strict equality comparison
72
84
  return jsonObj1 === jsonObj2;
73
85
  }
74
- }
86
+ };
75
87
 
76
88
  const getDefaultMockDataFromConfig = (testConfig) => {
77
- const defaultPath = path.join(getMockDir(testConfig), 'default.json');
78
-
79
- try {
80
- const defaultData = fs.readFileSync(defaultPath, 'utf8');
81
- let parsedData = JSON.parse(defaultData);
82
-
83
- // Read and attach mock data for each entry in parsedData
84
- parsedData.forEach(entry => {
85
- const mockFilePath = path.join(getMockDir(testConfig), 'defaultMocks', `mock_${entry.id}.json`);;
86
- try {
87
- const mockData = fs.readFileSync(mockFilePath, 'utf8');
88
- entry.fileContent = JSON.parse(mockData);
89
- } catch (error) {
90
- console.error(`Error reading mock data for ${entry.path}:`, error);
91
- return entry; // Return the original entry if there's an error
92
- }
93
- });
94
- return parsedData;
95
- } catch (error) {
96
- console.error(`Error reading or parsing default.json:`, error);
97
- return [];
98
- }
99
- }
89
+ const defaultPath = path.join(getMockDir(testConfig), "default.json");
90
+
91
+ try {
92
+ const defaultData = fs.readFileSync(defaultPath, "utf8");
93
+ let parsedData = JSON.parse(defaultData);
94
+
95
+ // Read and attach mock data for each entry in parsedData
96
+ parsedData.forEach((entry) => {
97
+ const mockFilePath = path.join(
98
+ getMockDir(testConfig),
99
+ "defaultMocks",
100
+ `mock_${entry.id}.json`
101
+ );
102
+ try {
103
+ const mockData = fs.readFileSync(mockFilePath, "utf8");
104
+ entry.fileContent = JSON.parse(mockData);
105
+ } catch (error) {
106
+ console.error(`Error reading mock data for ${entry.path}:`, error);
107
+ return entry; // Return the original entry if there's an error
108
+ }
109
+ });
110
+ return parsedData;
111
+ } catch (error) {
112
+ console.error(`Error reading or parsing default.json:`, error);
113
+ return [];
114
+ }
115
+ };
100
116
 
101
117
  // src/index.js
102
118
  const loadMockDataFromConfig = (testConfig, _testName) => {
103
119
  try {
104
120
  let testName = _testName;
105
- if(!testName) {
121
+ if (!testName) {
106
122
  // Read the test ID from mockServer.config.json
107
- const configPath = path.join(getMockDir(testConfig), 'mockServer.config.json');
108
- const configData = fs.readFileSync(configPath, 'utf8');
123
+ const configPath = path.join(
124
+ getMockDir(testConfig),
125
+ "mockServer.config.json"
126
+ );
127
+ const configData = fs.readFileSync(configPath, "utf8");
109
128
  const config = JSON.parse(configData);
110
129
  testName = config.testName;
111
130
  }
112
131
  // Read the tests from testConfig
113
- const mocksPath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, '_mock_list.json');
114
- const mocksData = fs.readFileSync(mocksPath, 'utf8');
132
+ const mocksPath = path.join(
133
+ getMockDir(testConfig),
134
+ `test_${nameToFolder(testName)}`,
135
+ "_mock_list.json"
136
+ );
137
+ const mocksData = fs.readFileSync(mocksPath, "utf8");
115
138
  const mocks = JSON.parse(mocksData);
116
139
 
117
- mocks.forEach(mock => {
118
- const fileContent = JSON.parse(fs.readFileSync(path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${mock.id}.json`), 'utf8'));
140
+ mocks.forEach((mock) => {
141
+ const fileContent = JSON.parse(
142
+ fs.readFileSync(
143
+ path.join(
144
+ getMockDir(testConfig),
145
+ `test_${nameToFolder(testName)}`,
146
+ `mock_${mock.id}.json`
147
+ ),
148
+ "utf8"
149
+ )
150
+ );
119
151
  mock.fileContent = fileContent;
120
152
  });
121
153
 
122
-
123
154
  return mocks;
124
155
  } catch (error) {
125
- console.debug('Error loading test data:', error.message);
156
+ console.debug("Error loading test data:", error.message);
126
157
  return [];
127
158
  }
128
159
  };
129
160
 
130
- const clearNulls = postData => {
131
- Object.keys(postData || {}).forEach(key => {
132
- if(postData[key] === null) {
161
+ const clearNulls = (postData) => {
162
+ Object.keys(postData || {}).forEach((key) => {
163
+ if (postData[key] === null) {
133
164
  delete postData[key];
134
165
  }
135
166
  });
@@ -139,120 +170,188 @@ const isSameRequest = (req1, req2) => {
139
170
  clearNulls(req1.postData);
140
171
  clearNulls(req2.postData);
141
172
  let matched = true;
142
- if(req1.url !== req2.url) {
173
+ if (req1.url !== req2.url) {
143
174
  matched = false;
144
- } else if(req1.method?.toLowerCase() !== req2.method?.toLowerCase()) {
175
+ } else if (req1.method?.toLowerCase() !== req2.method?.toLowerCase()) {
145
176
  matched = false;
146
- } else if((!req1.postData && req2.postData) || (req1.postData && !req2.postData)) {
147
- matched = areJsonEqual(req1.postData || {} , req2.postData || {});
148
- } else if(req1.postData && req2.postData && !areJsonEqual(req1.postData , req2.postData)) {
177
+ } else if (
178
+ (!req1.postData && req2.postData) ||
179
+ (req1.postData && !req2.postData)
180
+ ) {
181
+ matched = areJsonEqual(req1.postData || {}, req2.postData || {});
182
+ } else if (
183
+ req1.postData &&
184
+ req2.postData &&
185
+ !areJsonEqual(req1.postData, req2.postData)
186
+ ) {
149
187
  matched = false;
150
188
  }
151
189
  return matched;
152
- }
190
+ };
153
191
 
154
- const processURL = (url, ignoreParams=[]) => {
155
- // Remove the hostname from the URL
156
- const urlWithoutHost = url.replace(/^(https?:\/\/)?[^\/]+/, '');
157
- const processedURL = new URL(`http://domain.com${urlWithoutHost}`);
158
- const params = new URLSearchParams(processedURL.search);
159
- if(ignoreParams?.length > 0) {
160
- ignoreParams.forEach(ip => {
161
- params.delete(ip);
162
- });
163
- }
164
- params.sort();
165
- return decodeURIComponent(`${processedURL.pathname}?${params}`);
166
- }
167
-
192
+ const processURL = (url, ignoreParams = []) => {
193
+ // Remove the hostname from the URL
194
+ const urlWithoutHost = url.replace(/^(https?:\/\/)?[^\/]+/, "");
195
+ const processedURL = new URL(`http://domain.com${urlWithoutHost}`);
196
+ const params = new URLSearchParams(processedURL.search);
197
+ if (ignoreParams?.length > 0) {
198
+ ignoreParams.forEach((ip) => {
199
+ params.delete(ip);
200
+ });
201
+ }
202
+ params.sort();
203
+ return decodeURIComponent(`${processedURL.pathname}?${params}`);
204
+ };
168
205
 
169
206
  function compareMockToRequest(mock, req) {
170
- const mockURL = processURL(mock.fileContent.url, mock.fileContent.ignoreParams);
171
- const reqURL = processURL(req.originalUrl, mock.fileContent.ignoreParams);
172
- const postData = mock.fileContent.request?.postData?.text ? JSON.parse(mock.fileContent.request?.postData?.text) : mock.fileContent.request?.postData;
173
- return isSameRequest({url: mockURL, method: mock.fileContent.method, postData}, {
207
+ const mockURL = processURL(
208
+ mock.fileContent.url,
209
+ mock.fileContent.ignoreParams
210
+ );
211
+ const reqURL = processURL(req.originalUrl, mock.fileContent.ignoreParams);
212
+ const postData = mock.fileContent.request?.postData?.text
213
+ ? JSON.parse(mock.fileContent.request?.postData?.text)
214
+ : mock.fileContent.request?.postData;
215
+ return isSameRequest(
216
+ { url: mockURL, method: mock.fileContent.method, postData },
217
+ {
174
218
  method: req.method,
175
219
  postData: req.body,
176
220
  url: reqURL,
177
- });
221
+ }
222
+ );
178
223
  }
179
224
 
180
225
  function compareMockToFetchRequest(mock, fetchReq) {
181
- try{
182
- const mockURL = processURL(mock.fileContent.url, mock.fileContent.ignoreParams);
226
+ try {
227
+ const mockURL = processURL(
228
+ mock.fileContent.url,
229
+ mock.fileContent.ignoreParams
230
+ );
183
231
  const reqURL = processURL(fetchReq.url, mock.fileContent.ignoreParams);
184
- const postData = mock.fileContent.request?.postData?.text ? JSON.parse(mock.fileContent.request?.postData?.text) : mock.fileContent.request?.postData;
185
- return isSameRequest({url: mockURL, method: mock.fileContent.method, postData}, {
186
- method: fetchReq.options.method || 'GET',
187
- postData: fetchReq.options.body?.length ? JSON.parse(fetchReq.options.body) : fetchReq.options.body,
188
- url: reqURL,
189
- });
190
- } catch(e) {
191
- console.debug('error at compareMockToFetchRequest', mock, fetchReq);
232
+ const postData = mock.fileContent.request?.postData?.text
233
+ ? JSON.parse(mock.fileContent.request?.postData?.text)
234
+ : mock.fileContent.request?.postData;
235
+ return isSameRequest(
236
+ { url: mockURL, method: mock.fileContent.method, postData },
237
+ {
238
+ method: fetchReq.options.method || "GET",
239
+ postData: fetchReq.options.body?.length
240
+ ? JSON.parse(fetchReq.options.body)
241
+ : fetchReq.options.body,
242
+ url: reqURL,
243
+ }
244
+ );
245
+ } catch (e) {
246
+ console.debug("error at compareMockToFetchRequest", mock, fetchReq);
192
247
  console.debug(e);
193
248
  }
194
249
  return false;
195
250
  }
196
251
 
197
- function getMatchingMockData({testMockData, defaultMockData, url, options, testConfig, testName}) {
252
+ function getMatchingMockData({
253
+ testMockData,
254
+ defaultMockData,
255
+ url,
256
+ options,
257
+ testConfig,
258
+ testName,
259
+ }) {
198
260
  let served = false;
199
- let matchedMocks = testMockData?.filter(mock => {
200
- if (mock.fileContent.waitForPrevious && !served) {
201
- return false;
202
- }
203
- served = mock.fileContent.served;
204
- return compareMockToFetchRequest(mock, { url, options });
205
- }) || [];
206
- let foundMock = matchedMocks.find(mock => !mock.fileContent.served) ? matchedMocks.find(mock => !mock.fileContent.served) : matchedMocks[matchedMocks.length - 1];
261
+ let matchedMocks =
262
+ testMockData?.filter((mock) => {
263
+ if (mock.fileContent.waitForPrevious && !served) {
264
+ return false;
265
+ }
266
+ served = mock.fileContent.served;
267
+ return compareMockToFetchRequest(mock, { url, options });
268
+ }) || [];
269
+ let foundMock = matchedMocks.find((mock) => !mock.fileContent.served)
270
+ ? matchedMocks.find((mock) => !mock.fileContent.served)
271
+ : matchedMocks[matchedMocks.length - 1];
207
272
  // updating stats to mock file
208
- if(foundMock) {
209
- const mockFilePath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${foundMock.id}.json`);
273
+ if (foundMock) {
274
+ const mockFilePath = path.join(
275
+ getMockDir(testConfig),
276
+ `test_${nameToFolder(testName)}`,
277
+ `mock_${foundMock.id}.json`
278
+ );
210
279
  foundMock.fileContent.served = true;
211
- fs.writeFileSync(mockFilePath, JSON.stringify(foundMock.fileContent, null, 2));
280
+ fs.writeFileSync(
281
+ mockFilePath,
282
+ JSON.stringify(foundMock.fileContent, null, 2)
283
+ );
212
284
  }
213
-
214
- if(!foundMock) {
215
- foundMock = defaultMockData.find(tm => compareMockToFetchRequest(tm, {
216
- url,
217
- options
218
- }));
285
+
286
+ if (!foundMock) {
287
+ foundMock = defaultMockData.find((tm) =>
288
+ compareMockToFetchRequest(tm, {
289
+ url,
290
+ options,
291
+ })
292
+ );
219
293
  }
220
294
  return foundMock ? foundMock.fileContent : null;
221
295
  }
222
296
 
223
- async function resetAllMockStats({testMockData, testConfig, testName}) {
224
- for(let i=0; i<testMockData.length; i++) {
297
+ async function resetAllMockStats({ testMockData, testConfig, testName }) {
298
+ for (let i = 0; i < testMockData.length; i++) {
225
299
  const tmd = testMockData[i];
226
- const mockFilePath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${tmd.id}.json`);
300
+ const mockFilePath = path.join(
301
+ getMockDir(testConfig),
302
+ `test_${nameToFolder(testName)}`,
303
+ `mock_${tmd.id}.json`
304
+ );
227
305
  tmd.fileContent.served = false;
228
- await fs.writeFileSync(mockFilePath, JSON.stringify(tmd.fileContent, null, 2));
306
+ await fs.writeFileSync(
307
+ mockFilePath,
308
+ JSON.stringify(tmd.fileContent, null, 2)
309
+ );
229
310
  }
230
311
  }
231
312
 
232
- async function initiatePlaywrightRoutes (page, ftmocksConifg, testName, mockPath = '**/*', excludeMockPath = null) {
233
- const testMockData = testName ? loadMockDataFromConfig(ftmocksConifg, testName) : [];
234
- resetAllMockStats({testMockData, testConfig: ftmocksConifg, testName});
313
+ async function initiatePlaywrightRoutes(
314
+ page,
315
+ ftmocksConifg,
316
+ testName,
317
+ mockPath = "**/*",
318
+ excludeMockPath = null
319
+ ) {
320
+ const testMockData = testName
321
+ ? loadMockDataFromConfig(ftmocksConifg, testName)
322
+ : [];
323
+ resetAllMockStats({ testMockData, testConfig: ftmocksConifg, testName });
235
324
  const defaultMockData = getDefaultMockDataFromConfig(ftmocksConifg);
236
- console.debug('calling initiatePlaywrightRoutes fetch');
325
+ console.debug("calling initiatePlaywrightRoutes fetch");
237
326
  await page.route(mockPath, async (route, request) => {
238
327
  const url = request.url();
239
328
  const options = {
240
- options: {
241
- url,
242
- method: request.method(),
243
- body: request.postData(),
244
- }
245
- }
329
+ url,
330
+ method: request.method(),
331
+ body: request.postData(),
332
+ };
246
333
  if (excludeMockPath && new RegExp(excludeMockPath).test(url)) {
247
334
  await route.fallback();
248
335
  return;
249
336
  }
250
- console.debug('got fetch request', request.method(), request.url(), request.postData());
251
- let mockData = getMatchingMockData({testMockData, defaultMockData, url, options, testConfig: ftmocksConifg, testName});
337
+ console.debug(
338
+ "got fetch request",
339
+ request.method(),
340
+ request.url(),
341
+ request.postData()
342
+ );
343
+ let mockData = getMatchingMockData({
344
+ testMockData,
345
+ defaultMockData,
346
+ url,
347
+ options,
348
+ testConfig: ftmocksConifg,
349
+ testName,
350
+ });
252
351
  if (mockData) {
253
- console.debug('mocked', url, options);
352
+ console.debug("mocked", url, options);
254
353
  const { content, headers, status } = mockData.response;
255
-
354
+
256
355
  const json = {
257
356
  status,
258
357
  headers: getHeaders(headers),
@@ -261,31 +360,37 @@ async function initiatePlaywrightRoutes (page, ftmocksConifg, testName, mockPath
261
360
 
262
361
  await route.fulfill(json);
263
362
  } else {
264
- console.debug('missing mock data', url, options);
363
+ console.debug("missing mock data", url, options);
265
364
  const fallbackDir = getFallbackDir(ftmocksConifg);
266
- if(!fallbackDir) {
365
+ if (!fallbackDir) {
267
366
  await route.fallback();
268
367
  return;
269
368
  }
270
369
  const urlObj = new URL(route.request().url());
271
- const filePath = path.join(fallbackDir, urlObj.pathname === '/' || urlObj.pathname === '' ? (ftmocksConifg.FALLBACK_DIR_INDEX_FILE || 'index.html') : urlObj.pathname);
272
- console.debug('serving file ', filePath);
370
+ const filePath = path.join(
371
+ fallbackDir,
372
+ urlObj.pathname === "/" || urlObj.pathname === ""
373
+ ? ftmocksConifg.FALLBACK_DIR_INDEX_FILE || "index.html"
374
+ : urlObj.pathname
375
+ );
376
+ console.debug("serving file ", filePath);
273
377
  if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
274
378
  const fileContent = fs.readFileSync(filePath);
275
379
  const ext = path.extname(filePath);
276
- const contentType = {
277
- '.html': 'text/html',
278
- '.css': 'text/css',
279
- '.js': 'application/javascript',
280
- '.json': 'application/json',
281
- '.png': 'image/png',
282
- '.jpg': 'image/jpeg',
283
- }[ext] || 'application/octet-stream';
284
-
285
- console.debug('serving file', filePath);
380
+ const contentType =
381
+ {
382
+ ".html": "text/html",
383
+ ".css": "text/css",
384
+ ".js": "application/javascript",
385
+ ".json": "application/json",
386
+ ".png": "image/png",
387
+ ".jpg": "image/jpeg",
388
+ }[ext] || "application/octet-stream";
389
+
390
+ console.debug("serving file", filePath);
286
391
  await route.fulfill({
287
392
  body: fileContent,
288
- headers: { 'Content-Type': contentType },
393
+ headers: { "Content-Type": contentType },
289
394
  });
290
395
  } else {
291
396
  await route.fallback();
@@ -294,27 +399,36 @@ async function initiatePlaywrightRoutes (page, ftmocksConifg, testName, mockPath
294
399
  });
295
400
  }
296
401
 
297
- async function initiateJestFetch (jest, ftmocksConifg, testName) {
298
- const testMockData = testName ? loadMockDataFromConfig(ftmocksConifg, testName) : [];
299
- resetAllMockStats({testMockData, testConfig: ftmocksConifg, testName});
402
+ async function initiateJestFetch(jest, ftmocksConifg, testName) {
403
+ const testMockData = testName
404
+ ? loadMockDataFromConfig(ftmocksConifg, testName)
405
+ : [];
406
+ resetAllMockStats({ testMockData, testConfig: ftmocksConifg, testName });
300
407
  const defaultMockData = getDefaultMockDataFromConfig(ftmocksConifg);
301
- console.debug('calling initiateJestFetch fetch');
408
+ console.debug("calling initiateJestFetch fetch");
302
409
  global.fetch = jest.fn((url, options = {}) => {
303
- console.debug('got fetch request', url, options);
304
- let mockData = getMatchingMockData({testMockData, defaultMockData, url, options, testConfig: ftmocksConifg, testName});
410
+ console.debug("got fetch request", url, options);
411
+ let mockData = getMatchingMockData({
412
+ testMockData,
413
+ defaultMockData,
414
+ url,
415
+ options,
416
+ testConfig: ftmocksConifg,
417
+ testName,
418
+ });
305
419
  if (mockData) {
306
- console.debug('mocked', url, options);
420
+ console.debug("mocked", url, options);
307
421
  } else {
308
- console.debug('missing mock data', url, options);
422
+ console.debug("missing mock data", url, options);
309
423
  return Promise.resolve({
310
424
  status: 404,
311
- headers: new Map([['Content-Type', 'application/json']]),
312
- json: () => Promise.resolve({ error: 'Mock data not found' }),
425
+ headers: new Map([["Content-Type", "application/json"]]),
426
+ json: () => Promise.resolve({ error: "Mock data not found" }),
313
427
  });
314
428
  }
315
-
429
+
316
430
  const { content, headers, status } = mockData.response;
317
-
431
+
318
432
  return Promise.resolve({
319
433
  status,
320
434
  headers: new Map(Object.entries(headers)),
@@ -322,14 +436,14 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
322
436
  });
323
437
  });
324
438
 
325
- console.debug('calling XMLHttpRequest fetch');
439
+ console.debug("calling XMLHttpRequest fetch");
326
440
  global.XMLHttpRequest = jest.fn(function () {
327
441
  const xhrMock = {
328
442
  open: jest.fn(),
329
443
  send: jest.fn(),
330
444
  setRequestHeader: jest.fn(),
331
445
  getAllResponseHeaders: jest.fn(() => {
332
- return '';
446
+ return "";
333
447
  }),
334
448
  getResponseHeader: jest.fn((header) => {
335
449
  return null;
@@ -337,13 +451,13 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
337
451
  readyState: 4,
338
452
  status: 0,
339
453
  response: null,
340
- responseText: '',
454
+ responseText: "",
341
455
  headers: new Map(Object.entries(headers)),
342
456
  onreadystatechange: null,
343
457
  onload: null,
344
458
  onerror: null,
345
459
  };
346
-
460
+
347
461
  xhrMock.send.mockImplementation(function () {
348
462
  const mockData = getMatchingMockData({
349
463
  testMockData,
@@ -353,16 +467,16 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
353
467
  testConfig: ftmocksConifg,
354
468
  testName,
355
469
  });
356
-
470
+
357
471
  if (mockData) {
358
- console.debug('mocked', xhrMock._url, xhrMock._options);
472
+ console.debug("mocked", xhrMock._url, xhrMock._options);
359
473
  const { content, headers, status } = mockData.response;
360
-
474
+
361
475
  xhrMock.status = status;
362
476
  xhrMock.responseText = content;
363
477
  xhrMock.response = content;
364
478
  xhrMock.headers = new Map(Object.entries(headers));
365
-
479
+
366
480
  if (xhrMock.onreadystatechange) {
367
481
  xhrMock.onreadystatechange();
368
482
  }
@@ -370,12 +484,12 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
370
484
  xhrMock.onload();
371
485
  }
372
486
  } else {
373
- console.debug('missing mock data', xhrMock._url, xhrMock._options);
374
-
487
+ console.debug("missing mock data", xhrMock._url, xhrMock._options);
488
+
375
489
  xhrMock.status = 404;
376
- xhrMock.responseText = JSON.stringify({ error: 'Mock data not found' });
490
+ xhrMock.responseText = JSON.stringify({ error: "Mock data not found" });
377
491
  xhrMock.response = xhrMock.responseText;
378
-
492
+
379
493
  if (xhrMock.onreadystatechange) {
380
494
  xhrMock.onreadystatechange();
381
495
  }
@@ -384,59 +498,62 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
384
498
  }
385
499
  }
386
500
  });
387
-
501
+
388
502
  xhrMock.open.mockImplementation(function (method, url) {
389
503
  xhrMock._options = { method };
390
504
  xhrMock._url = url;
391
505
  });
392
-
506
+
393
507
  return xhrMock;
394
508
  });
395
-
509
+
396
510
  return;
397
- };
511
+ }
398
512
 
399
513
  function initiateConsoleLogs(jest, ftmocksConifg, testName) {
400
- const logsFile = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`, '_logs.json');
514
+ const logsFile = path.join(
515
+ getMockDir(ftmocksConifg),
516
+ `test_${nameToFolder(testName)}`,
517
+ "_logs.json"
518
+ );
401
519
  let logs = [];
402
- if(!fs.existsSync(logsFile)) {
403
- fs.appendFileSync(logsFile, '[]', 'utf8');
520
+ if (!fs.existsSync(logsFile)) {
521
+ fs.appendFileSync(logsFile, "[]", "utf8");
404
522
  } else {
405
- fs.writeFileSync(logsFile, '[]', 'utf8');
523
+ fs.writeFileSync(logsFile, "[]", "utf8");
406
524
  }
407
525
 
408
526
  const writeToFile = (type, params) => {
409
- const logMessage = params.join(' ') + '\n'; // Combine params into a string with spaces
527
+ const logMessage = params.join(" ") + "\n"; // Combine params into a string with spaces
410
528
  logs.push({
411
529
  type,
412
530
  message: logMessage,
413
- time: Date.now()
531
+ time: Date.now(),
414
532
  });
415
- fs.writeFileSync(logsFile, JSON.stringify(logs, null, 2), 'utf8'); // Append the log message to the file
416
- }
417
-
533
+ fs.writeFileSync(logsFile, JSON.stringify(logs, null, 2), "utf8"); // Append the log message to the file
534
+ };
535
+
418
536
  global.console = {
419
537
  ...console,
420
538
  // uncomment to ignore a specific log level
421
539
  log: jest.fn((...params) => {
422
- writeToFile('log', params);
540
+ writeToFile("log", params);
423
541
  }),
424
542
  debug: jest.fn((...params) => {
425
- writeToFile('debug', params);
543
+ writeToFile("debug", params);
426
544
  }),
427
545
  info: jest.fn((...params) => {
428
- writeToFile('info', params);
546
+ writeToFile("info", params);
429
547
  }),
430
548
  warn: jest.fn((...params) => {
431
- writeToFile('warn', params);
549
+ writeToFile("warn", params);
432
550
  }),
433
551
  error: jest.fn((...params) => {
434
- writeToFile('error', params);
552
+ writeToFile("error", params);
435
553
  }),
436
554
  };
437
555
  }
438
556
 
439
-
440
557
  function countFilesInDirectory(directoryPath) {
441
558
  return new Promise((resolve, reject) => {
442
559
  fs.readdir(directoryPath, (err, files) => {
@@ -445,7 +562,7 @@ function countFilesInDirectory(directoryPath) {
445
562
  }
446
563
 
447
564
  // Filter out directories and only count files
448
- const fileCount = files.filter(file => {
565
+ const fileCount = files.filter((file) => {
449
566
  const filePath = path.join(directoryPath, file);
450
567
  return fs.statSync(filePath).isFile();
451
568
  }).length;
@@ -456,62 +573,85 @@ function countFilesInDirectory(directoryPath) {
456
573
  }
457
574
 
458
575
  const saveSnap = async (html, ftmocksConifg, testName) => {
459
- const snapFolder = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`, '_snaps');
460
- const snapTemplate = path.join(getMockDir(ftmocksConifg), 'snap_template.html');
461
-
576
+ const snapFolder = path.join(
577
+ getMockDir(ftmocksConifg),
578
+ `test_${nameToFolder(testName)}`,
579
+ "_snaps"
580
+ );
581
+ const snapTemplate = path.join(
582
+ getMockDir(ftmocksConifg),
583
+ "snap_template.html"
584
+ );
585
+
462
586
  if (!fs.existsSync(snapFolder)) {
463
587
  fs.mkdirSync(snapFolder);
464
588
  }
465
- const fileCount = await (countFilesInDirectory(snapFolder));
589
+ const fileCount = await countFilesInDirectory(snapFolder);
466
590
  const snapFilePath = path.join(snapFolder, `snap_${fileCount + 1}.html`);
467
591
  let resHtml = html;
468
592
  if (fs.existsSync(snapFolder)) {
469
- const templateHtml = fs.readFileSync(snapTemplate, 'utf8');;
470
- resHtml = templateHtml.replace('<!--FtMocks-Snap-Template-To-Be-Replaced-->', html)
593
+ const templateHtml = fs.readFileSync(snapTemplate, "utf8");
594
+ resHtml = templateHtml.replace(
595
+ "<!--FtMocks-Snap-Template-To-Be-Replaced-->",
596
+ html
597
+ );
471
598
  }
472
- fs.writeFileSync(snapFilePath, resHtml)
599
+ fs.writeFileSync(snapFilePath, resHtml);
473
600
  };
474
601
 
475
602
  const deleteAllSnaps = async (ftmocksConifg, testName) => {
476
- const snapFolder = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`, '_snaps');
603
+ const snapFolder = path.join(
604
+ getMockDir(ftmocksConifg),
605
+ `test_${nameToFolder(testName)}`,
606
+ "_snaps"
607
+ );
477
608
  fs.rmSync(snapFolder, { recursive: true, force: true });
478
609
  };
479
610
 
480
611
  const deleteAllLogs = async (ftmocksConifg, testName) => {
481
- const mockDir = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`);
612
+ const mockDir = path.join(
613
+ getMockDir(ftmocksConifg),
614
+ `test_${nameToFolder(testName)}`
615
+ );
482
616
  const logFilePath = path.join(mockDir, `_logs.json`);
483
617
  fs.rmSync(logFilePath, { recursive: true, force: true });
484
618
  };
485
619
 
486
620
  function initiateJestEventSnaps(jest, ftmocksConifg, testName) {
487
- const mouseEvents = ftmocksConifg.snapEvents || ['click', 'change', 'url', 'dblclick', 'contextmenu'];
488
- mouseEvents.forEach(event => {
489
- jest.spyOn(document, 'addEventListener').mockImplementation((e, callback) => {
490
- if (mouseEvents.includes(e)) {
491
- saveSnap(document.outerHTML, ftmocksConifg, testName);
492
- }
493
- });
621
+ const mouseEvents = ftmocksConifg.snapEvents || [
622
+ "click",
623
+ "change",
624
+ "url",
625
+ "dblclick",
626
+ "contextmenu",
627
+ ];
628
+ mouseEvents.forEach((event) => {
629
+ jest
630
+ .spyOn(document, "addEventListener")
631
+ .mockImplementation((e, callback) => {
632
+ if (mouseEvents.includes(e)) {
633
+ saveSnap(document.outerHTML, ftmocksConifg, testName);
634
+ }
635
+ });
494
636
  });
495
637
  }
496
638
 
497
-
498
-
499
639
  // Export functions as a module
500
640
  module.exports = {
501
- compareMockToRequest,
502
- processURL,
503
- isSameRequest,
504
- loadMockDataFromConfig,
505
- getDefaultMockDataFromConfig,
506
- nameToFolder,
507
- compareMockToFetchRequest,
508
- getMatchingMockData,
509
- resetAllMockStats,
510
- initiateJestFetch,
511
- saveSnap,
512
- deleteAllSnaps,
513
- deleteAllLogs,
514
- initiateConsoleLogs,
515
- initiatePlaywrightRoutes,
516
- initiateJestEventSnaps
641
+ compareMockToRequest,
642
+ processURL,
643
+ isSameRequest,
644
+ loadMockDataFromConfig,
645
+ getDefaultMockDataFromConfig,
646
+ nameToFolder,
647
+ compareMockToFetchRequest,
648
+ getMatchingMockData,
649
+ resetAllMockStats,
650
+ initiateJestFetch,
651
+ saveSnap,
652
+ deleteAllSnaps,
653
+ deleteAllLogs,
654
+ initiateConsoleLogs,
655
+ initiatePlaywrightRoutes,
656
+ initiateJestEventSnaps,
517
657
  };