ftmocks-utils 1.1.9 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +106 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.1.9",
3
+ "version": "1.2.0",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -2,6 +2,23 @@ const fs = require("fs");
2
2
  const path = require("path");
3
3
  const { v4: uuidv4 } = require("uuid");
4
4
 
5
+ function charDifference(str1, str2) {
6
+ let count1 = {},
7
+ count2 = {};
8
+
9
+ for (let ch of str1) count1[ch] = (count1[ch] || 0) + 1;
10
+ for (let ch of str2) count2[ch] = (count2[ch] || 0) + 1;
11
+
12
+ let diff = 0;
13
+ let chars = new Set([...Object.keys(count1), ...Object.keys(count2)]);
14
+
15
+ for (let ch of chars) {
16
+ diff += Math.abs((count1[ch] || 0) - (count2[ch] || 0));
17
+ }
18
+
19
+ return diff;
20
+ }
21
+
5
22
  const nameToFolder = (name) => {
6
23
  return name.replaceAll(" ", "_");
7
24
  };
@@ -102,7 +119,7 @@ const getDefaultMockDataFromConfig = (testConfig) => {
102
119
  const mockData = fs.readFileSync(mockFilePath, "utf8");
103
120
  entry.fileContent = JSON.parse(mockData);
104
121
  } catch (error) {
105
- console.error(`Error reading mock data for ${entry.path}:`, error);
122
+ console.error(`Error reading mock data for ${entry.id}:`, error);
106
123
  return entry; // Return the original entry if there's an error
107
124
  }
108
125
  });
@@ -188,6 +205,31 @@ const isSameRequest = (req1, req2) => {
188
205
  return matched;
189
206
  };
190
207
 
208
+ const getSameRequestRank = (req1, req2) => {
209
+ let rank = 1;
210
+ clearNulls(req1.postData);
211
+ clearNulls(req2.postData);
212
+ // Compare path names
213
+ const url1 = new URL(`http://domain.com${req1.url}`);
214
+ const url2 = new URL(`http://domain.com${req2.url}`);
215
+ if (url1.pathname !== url2.pathname) {
216
+ rank = 0;
217
+ } else if (url1.method?.toLowerCase() !== url2.method?.toLowerCase()) {
218
+ rank = 0;
219
+ } else {
220
+ // Compare query strings
221
+ const queryDiff = charDifference(url1.search || "", url2.search || "");
222
+ rank = rank + queryDiff;
223
+ // Compare post data
224
+ const charDiff = charDifference(
225
+ JSON.stringify(req1.postData || {}),
226
+ JSON.stringify(req2.postData || {})
227
+ );
228
+ rank = rank + charDiff;
229
+ }
230
+ return rank;
231
+ };
232
+
191
233
  const processURL = (url, ignoreParams = []) => {
192
234
  // Remove the hostname from the URL
193
235
  const urlWithoutHost = url.replace(/^(https?:\/\/)?[^\/]+/, "");
@@ -248,6 +290,33 @@ function compareMockToFetchRequest(mock, fetchReq) {
248
290
  return false;
249
291
  }
250
292
 
293
+ function getCompareRankMockToFetchRequest(mock, fetchReq) {
294
+ try {
295
+ const mockURL = processURL(
296
+ mock.fileContent.url,
297
+ mock.fileContent.ignoreParams
298
+ );
299
+ const reqURL = processURL(fetchReq.url, mock.fileContent.ignoreParams);
300
+ const postData = mock.fileContent.request?.postData?.text
301
+ ? JSON.parse(mock.fileContent.request?.postData?.text)
302
+ : mock.fileContent.request?.postData;
303
+ return getSameRequestRank(
304
+ { url: mockURL, method: mock.fileContent.method, postData },
305
+ {
306
+ method: fetchReq.options.method || "GET",
307
+ postData: fetchReq.options.body?.length
308
+ ? JSON.parse(fetchReq.options.body)
309
+ : fetchReq.options.body,
310
+ url: reqURL,
311
+ }
312
+ );
313
+ } catch (e) {
314
+ console.error("error at getCompareRankMockToFetchRequest", mock, fetchReq);
315
+ console.error(e);
316
+ }
317
+ return false;
318
+ }
319
+
251
320
  function getMatchingMockData({
252
321
  testMockData,
253
322
  defaultMockData,
@@ -255,6 +324,7 @@ function getMatchingMockData({
255
324
  options,
256
325
  testConfig,
257
326
  testName,
327
+ mode,
258
328
  }) {
259
329
  let served = false;
260
330
  let matchedMocks =
@@ -290,6 +360,38 @@ function getMatchingMockData({
290
360
  })
291
361
  );
292
362
  }
363
+
364
+ if (!foundMock && mode !== "strict") {
365
+ const mockRanks = {};
366
+ testMockData.forEach((tm) => {
367
+ const rank = getCompareRankMockToFetchRequest(tm, {
368
+ url,
369
+ options,
370
+ });
371
+ if (rank > 0) {
372
+ mockRanks[tm.id] = rank;
373
+ }
374
+ });
375
+ defaultMockData.forEach((tm) => {
376
+ const rank = getCompareRankMockToFetchRequest(tm, {
377
+ url,
378
+ options,
379
+ });
380
+ if (rank > 0) {
381
+ mockRanks[tm.id] = rank;
382
+ }
383
+ });
384
+ // Sort by rank to find the best match
385
+ const sortedRanks = Object.entries(mockRanks).sort((a, b) => a[1] - b[1]);
386
+ if (sortedRanks.length > 0) {
387
+ const bestMockId = sortedRanks?.[0]?.[0];
388
+ if (bestMockId) {
389
+ foundMock = [...testMockData, ...defaultMockData].find(
390
+ (mock) => mock.id === bestMockId
391
+ );
392
+ }
393
+ }
394
+ }
293
395
  return foundMock ? foundMock.fileContent : null;
294
396
  }
295
397
 
@@ -320,6 +422,7 @@ async function initiatePlaywrightRoutes(
320
422
  ? loadMockDataFromConfig(ftmocksConifg, testName)
321
423
  : [];
322
424
  resetAllMockStats({ testMockData, testConfig: ftmocksConifg, testName });
425
+ const test = await getTestByName(ftmocksConifg, config.testName);
323
426
  const defaultMockData = getDefaultMockDataFromConfig(ftmocksConifg);
324
427
  console.debug("calling initiatePlaywrightRoutes fetch");
325
428
  await page.route(mockPath, async (route, request) => {
@@ -346,6 +449,7 @@ async function initiatePlaywrightRoutes(
346
449
  options,
347
450
  testConfig: ftmocksConifg,
348
451
  testName,
452
+ mode: test.mode || "loose",
349
453
  });
350
454
  if (mockData) {
351
455
  console.debug("mocked", url, options);
@@ -903,6 +1007,7 @@ async function recordPlaywrightRoutes(
903
1007
 
904
1008
  // Export functions as a module
905
1009
  module.exports = {
1010
+ getTestByName,
906
1011
  compareMockToRequest,
907
1012
  processURL,
908
1013
  isSameRequest,