ftmocks-utils 1.1.8 → 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.
- package/package.json +1 -1
- package/src/index.js +132 -7
package/package.json
CHANGED
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
|
};
|
|
@@ -44,7 +61,7 @@ const getHeaders = (headers) => {
|
|
|
44
61
|
...Object.entries(capitalizeHeaders(headers)),
|
|
45
62
|
]);
|
|
46
63
|
} catch (e) {
|
|
47
|
-
console.
|
|
64
|
+
console.error("error at getHeaders", e);
|
|
48
65
|
res = new Map([
|
|
49
66
|
["Content-Type", "application/json"],
|
|
50
67
|
["content-type", "application/json"],
|
|
@@ -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.
|
|
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
|
});
|
|
@@ -152,7 +169,7 @@ const loadMockDataFromConfig = (testConfig, _testName) => {
|
|
|
152
169
|
|
|
153
170
|
return mocks;
|
|
154
171
|
} catch (error) {
|
|
155
|
-
console.
|
|
172
|
+
console.error("Error loading test data:", error.message);
|
|
156
173
|
return [];
|
|
157
174
|
}
|
|
158
175
|
};
|
|
@@ -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?:\/\/)?[^\/]+/, "");
|
|
@@ -242,8 +284,35 @@ function compareMockToFetchRequest(mock, fetchReq) {
|
|
|
242
284
|
}
|
|
243
285
|
);
|
|
244
286
|
} catch (e) {
|
|
245
|
-
console.
|
|
246
|
-
console.
|
|
287
|
+
console.error("error at compareMockToFetchRequest", mock, fetchReq);
|
|
288
|
+
console.error(e);
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
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);
|
|
247
316
|
}
|
|
248
317
|
return false;
|
|
249
318
|
}
|
|
@@ -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);
|
|
@@ -635,6 +739,21 @@ function initiateJestEventSnaps(jest, ftmocksConifg, testName) {
|
|
|
635
739
|
});
|
|
636
740
|
}
|
|
637
741
|
|
|
742
|
+
const getTestByName = async (ftmocksConifg, testName) => {
|
|
743
|
+
const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
|
|
744
|
+
let tests = [];
|
|
745
|
+
try {
|
|
746
|
+
// Read existing tests
|
|
747
|
+
const testsData = fs.readFileSync(testsPath, "utf8");
|
|
748
|
+
tests = JSON.parse(testsData);
|
|
749
|
+
const etest = tests.find((tst) => tst.name === testName);
|
|
750
|
+
return etest;
|
|
751
|
+
} catch (error) {
|
|
752
|
+
console.error(`Error reading tests.json:`, error);
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
|
|
638
757
|
const createTest = async (ftmocksConifg, testName) => {
|
|
639
758
|
const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
|
|
640
759
|
let tests = [];
|
|
@@ -763,8 +882,8 @@ async function recordPlaywrightRoutes(
|
|
|
763
882
|
testName,
|
|
764
883
|
mockPath: "**/*",
|
|
765
884
|
pattern: "^/api/.*",
|
|
766
|
-
avoidDuplicatesInTheTest:
|
|
767
|
-
avoidDuplicatesWithDefaultMocks:
|
|
885
|
+
avoidDuplicatesInTheTest: false,
|
|
886
|
+
avoidDuplicatesWithDefaultMocks: false,
|
|
768
887
|
}
|
|
769
888
|
) {
|
|
770
889
|
await page.route(config.mockPath, async (route) => {
|
|
@@ -778,6 +897,11 @@ async function recordPlaywrightRoutes(
|
|
|
778
897
|
}
|
|
779
898
|
}
|
|
780
899
|
|
|
900
|
+
const test = await getTestByName(ftmocksConifg, config.testName);
|
|
901
|
+
if (!test) {
|
|
902
|
+
await createTest(ftmocksConifg, config.testName);
|
|
903
|
+
}
|
|
904
|
+
|
|
781
905
|
if (await saveIfItIsFile(route, config.testName, ftmocksConifg)) {
|
|
782
906
|
return;
|
|
783
907
|
}
|
|
@@ -883,6 +1007,7 @@ async function recordPlaywrightRoutes(
|
|
|
883
1007
|
|
|
884
1008
|
// Export functions as a module
|
|
885
1009
|
module.exports = {
|
|
1010
|
+
getTestByName,
|
|
886
1011
|
compareMockToRequest,
|
|
887
1012
|
processURL,
|
|
888
1013
|
isSameRequest,
|