ftmocks-utils 1.2.4 → 1.3.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/common-utils.js +171 -0
- package/src/index.js +35 -158
package/package.json
CHANGED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
|
|
4
|
+
const charDifference = (str1, str2) => {
|
|
5
|
+
let count1 = {},
|
|
6
|
+
count2 = {};
|
|
7
|
+
|
|
8
|
+
for (let ch of str1) count1[ch] = (count1[ch] || 0) + 1;
|
|
9
|
+
for (let ch of str2) count2[ch] = (count2[ch] || 0) + 1;
|
|
10
|
+
|
|
11
|
+
let diff = 0;
|
|
12
|
+
let chars = new Set([...Object.keys(count1), ...Object.keys(count2)]);
|
|
13
|
+
|
|
14
|
+
for (let ch of chars) {
|
|
15
|
+
diff += Math.abs((count1[ch] || 0) - (count2[ch] || 0));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return diff;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const nameToFolder = (name) => {
|
|
22
|
+
return name.replaceAll(" ", "_");
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getMockDir = (config) => {
|
|
26
|
+
if (!path.isAbsolute(config.MOCK_DIR)) {
|
|
27
|
+
return path.resolve(process.cwd(), config.MOCK_DIR);
|
|
28
|
+
}
|
|
29
|
+
return config.MOCK_DIR;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getFallbackDir = (config) => {
|
|
33
|
+
if (config.FALLBACK_DIR && !path.isAbsolute(config.FALLBACK_DIR)) {
|
|
34
|
+
return path.resolve(process.cwd(), config.FALLBACK_DIR);
|
|
35
|
+
}
|
|
36
|
+
return config.FALLBACK_DIR;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const capitalizeHeader = (header) => {
|
|
40
|
+
return header
|
|
41
|
+
.split("-")
|
|
42
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
43
|
+
.join("-");
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const capitalizeHeaders = (headers) => {
|
|
47
|
+
return Object.fromEntries(
|
|
48
|
+
Object.entries(headers).map(([key, value]) => [
|
|
49
|
+
capitalizeHeader(key),
|
|
50
|
+
value,
|
|
51
|
+
])
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const areJsonEqual = (jsonObj1, jsonObj2) => {
|
|
56
|
+
// Check if both are objects and not null
|
|
57
|
+
if (
|
|
58
|
+
typeof jsonObj1 === "object" &&
|
|
59
|
+
jsonObj1 !== null &&
|
|
60
|
+
typeof jsonObj2 === "object" &&
|
|
61
|
+
jsonObj2 !== null
|
|
62
|
+
) {
|
|
63
|
+
// Get the keys of both objects
|
|
64
|
+
const keys1 = Object.keys(jsonObj1);
|
|
65
|
+
const keys2 = Object.keys(jsonObj2);
|
|
66
|
+
|
|
67
|
+
// Check if the number of keys is different
|
|
68
|
+
if (keys1.length !== keys2.length) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Recursively check each key-value pair
|
|
73
|
+
for (let key of keys1) {
|
|
74
|
+
if (!keys2.includes(key) || !areJsonEqual(jsonObj1[key], jsonObj2[key])) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
} else {
|
|
81
|
+
// For non-object types, use strict equality comparison
|
|
82
|
+
return jsonObj1 === jsonObj2;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const clearNulls = (postData) => {
|
|
87
|
+
Object.keys(postData || {}).forEach((key) => {
|
|
88
|
+
if (postData[key] === null) {
|
|
89
|
+
delete postData[key];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const processURL = (url, ignoreParams = []) => {
|
|
95
|
+
// Remove the hostname from the URL
|
|
96
|
+
const urlWithoutHost = url.replace(/^(https?:\/\/)?[^\/]+/, "");
|
|
97
|
+
const processedURL = new URL(`http://domain.com${urlWithoutHost}`);
|
|
98
|
+
const params = new URLSearchParams(processedURL.search);
|
|
99
|
+
if (ignoreParams?.length > 0) {
|
|
100
|
+
ignoreParams.forEach((ip) => {
|
|
101
|
+
params.delete(ip);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
params.sort();
|
|
105
|
+
return decodeURIComponent(`${processedURL.pathname}?${params}`);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const getHeaders = (headers) => {
|
|
109
|
+
let res = null;
|
|
110
|
+
try {
|
|
111
|
+
res = new Map([
|
|
112
|
+
...Object.entries(headers),
|
|
113
|
+
...Object.entries(capitalizeHeaders(headers)),
|
|
114
|
+
]);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.error("error at getHeaders", e);
|
|
117
|
+
res = new Map([
|
|
118
|
+
["Content-Type", "application/json"],
|
|
119
|
+
["content-type", "application/json"],
|
|
120
|
+
]);
|
|
121
|
+
}
|
|
122
|
+
return Object.fromEntries(res);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
function countFilesInDirectory(directoryPath) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
fs.readdir(directoryPath, (err, files) => {
|
|
128
|
+
if (err) {
|
|
129
|
+
return reject(err); // Handle error
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Filter out directories and only count files
|
|
133
|
+
const fileCount = files.filter((file) => {
|
|
134
|
+
const filePath = path.join(directoryPath, file);
|
|
135
|
+
return fs.statSync(filePath).isFile();
|
|
136
|
+
}).length;
|
|
137
|
+
|
|
138
|
+
resolve(fileCount);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const getTestByName = async (ftmocksConifg, testName) => {
|
|
144
|
+
const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
|
|
145
|
+
let tests = [];
|
|
146
|
+
try {
|
|
147
|
+
// Read existing tests
|
|
148
|
+
const testsData = fs.readFileSync(testsPath, "utf8");
|
|
149
|
+
tests = JSON.parse(testsData);
|
|
150
|
+
const etest = tests.find((tst) => tst.name === testName);
|
|
151
|
+
return etest;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error(`\x1b[31mError reading tests.json:\x1b[0m`, error);
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
module.exports = {
|
|
159
|
+
charDifference,
|
|
160
|
+
nameToFolder,
|
|
161
|
+
getMockDir,
|
|
162
|
+
getFallbackDir,
|
|
163
|
+
capitalizeHeader,
|
|
164
|
+
capitalizeHeaders,
|
|
165
|
+
areJsonEqual,
|
|
166
|
+
clearNulls,
|
|
167
|
+
processURL,
|
|
168
|
+
getHeaders,
|
|
169
|
+
countFilesInDirectory,
|
|
170
|
+
getTestByName,
|
|
171
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,108 +1,25 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { v4: uuidv4 } = require("uuid");
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
diff += Math.abs((count1[ch] || 0) - (count2[ch] || 0));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return diff;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const nameToFolder = (name) => {
|
|
23
|
-
return name.replaceAll(" ", "_");
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const getMockDir = (config) => {
|
|
27
|
-
if (!path.isAbsolute(config.MOCK_DIR)) {
|
|
28
|
-
return path.resolve(process.cwd(), config.MOCK_DIR);
|
|
29
|
-
}
|
|
30
|
-
return config.MOCK_DIR;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const getFallbackDir = (config) => {
|
|
34
|
-
if (config.FALLBACK_DIR && !path.isAbsolute(config.FALLBACK_DIR)) {
|
|
35
|
-
return path.resolve(process.cwd(), config.FALLBACK_DIR);
|
|
36
|
-
}
|
|
37
|
-
return config.FALLBACK_DIR;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const capitalizeHeader = (header) => {
|
|
41
|
-
return header
|
|
42
|
-
.split("-")
|
|
43
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
44
|
-
.join("-");
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const capitalizeHeaders = (headers) => {
|
|
48
|
-
return Object.fromEntries(
|
|
49
|
-
Object.entries(headers).map(([key, value]) => [
|
|
50
|
-
capitalizeHeader(key),
|
|
51
|
-
value,
|
|
52
|
-
])
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const getHeaders = (headers) => {
|
|
57
|
-
let res = null;
|
|
58
|
-
try {
|
|
59
|
-
res = new Map([
|
|
60
|
-
...Object.entries(headers),
|
|
61
|
-
...Object.entries(capitalizeHeaders(headers)),
|
|
62
|
-
]);
|
|
63
|
-
} catch (e) {
|
|
64
|
-
console.error("error at getHeaders", e);
|
|
65
|
-
res = new Map([
|
|
66
|
-
["Content-Type", "application/json"],
|
|
67
|
-
["content-type", "application/json"],
|
|
68
|
-
]);
|
|
69
|
-
}
|
|
70
|
-
return Object.fromEntries(res);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const areJsonEqual = (jsonObj1, jsonObj2) => {
|
|
74
|
-
// Check if both are objects and not null
|
|
75
|
-
if (
|
|
76
|
-
typeof jsonObj1 === "object" &&
|
|
77
|
-
jsonObj1 !== null &&
|
|
78
|
-
typeof jsonObj2 === "object" &&
|
|
79
|
-
jsonObj2 !== null
|
|
80
|
-
) {
|
|
81
|
-
// Get the keys of both objects
|
|
82
|
-
const keys1 = Object.keys(jsonObj1);
|
|
83
|
-
const keys2 = Object.keys(jsonObj2);
|
|
84
|
-
|
|
85
|
-
// Check if the number of keys is different
|
|
86
|
-
if (keys1.length !== keys2.length) {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Recursively check each key-value pair
|
|
91
|
-
for (let key of keys1) {
|
|
92
|
-
if (!keys2.includes(key) || !areJsonEqual(jsonObj1[key], jsonObj2[key])) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return true;
|
|
98
|
-
} else {
|
|
99
|
-
// For non-object types, use strict equality comparison
|
|
100
|
-
return jsonObj1 === jsonObj2;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
4
|
+
const {
|
|
5
|
+
charDifference,
|
|
6
|
+
nameToFolder,
|
|
7
|
+
getMockDir,
|
|
8
|
+
getFallbackDir,
|
|
9
|
+
areJsonEqual,
|
|
10
|
+
clearNulls,
|
|
11
|
+
processURL,
|
|
12
|
+
getHeaders,
|
|
13
|
+
countFilesInDirectory,
|
|
14
|
+
getTestByName,
|
|
15
|
+
} = require("./common-utils");
|
|
103
16
|
|
|
104
17
|
const getDefaultMockDataFromConfig = (testConfig) => {
|
|
105
|
-
const defaultPath = path.join(
|
|
18
|
+
const defaultPath = path.join(
|
|
19
|
+
getMockDir(testConfig),
|
|
20
|
+
"defaultMocks",
|
|
21
|
+
"_mock_list.json"
|
|
22
|
+
);
|
|
106
23
|
|
|
107
24
|
try {
|
|
108
25
|
const defaultData = fs.readFileSync(defaultPath, "utf8");
|
|
@@ -125,7 +42,7 @@ const getDefaultMockDataFromConfig = (testConfig) => {
|
|
|
125
42
|
});
|
|
126
43
|
return parsedData;
|
|
127
44
|
} catch (error) {
|
|
128
|
-
console.error(`Error reading or parsing default
|
|
45
|
+
console.error(`Error reading or parsing default mocks:`, error);
|
|
129
46
|
return [];
|
|
130
47
|
}
|
|
131
48
|
};
|
|
@@ -174,14 +91,6 @@ const loadMockDataFromConfig = (testConfig, _testName) => {
|
|
|
174
91
|
}
|
|
175
92
|
};
|
|
176
93
|
|
|
177
|
-
const clearNulls = (postData) => {
|
|
178
|
-
Object.keys(postData || {}).forEach((key) => {
|
|
179
|
-
if (postData[key] === null) {
|
|
180
|
-
delete postData[key];
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
};
|
|
184
|
-
|
|
185
94
|
const isSameRequest = (req1, req2) => {
|
|
186
95
|
clearNulls(req1.postData);
|
|
187
96
|
clearNulls(req2.postData);
|
|
@@ -230,20 +139,6 @@ const getSameRequestRank = (req1, req2) => {
|
|
|
230
139
|
return rank;
|
|
231
140
|
};
|
|
232
141
|
|
|
233
|
-
const processURL = (url, ignoreParams = []) => {
|
|
234
|
-
// Remove the hostname from the URL
|
|
235
|
-
const urlWithoutHost = url.replace(/^(https?:\/\/)?[^\/]+/, "");
|
|
236
|
-
const processedURL = new URL(`http://domain.com${urlWithoutHost}`);
|
|
237
|
-
const params = new URLSearchParams(processedURL.search);
|
|
238
|
-
if (ignoreParams?.length > 0) {
|
|
239
|
-
ignoreParams.forEach((ip) => {
|
|
240
|
-
params.delete(ip);
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
params.sort();
|
|
244
|
-
return decodeURIComponent(`${processedURL.pathname}?${params}`);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
142
|
function compareMockToRequest(mock, req) {
|
|
248
143
|
const mockURL = processURL(
|
|
249
144
|
mock.fileContent.url,
|
|
@@ -381,11 +276,18 @@ function getMatchingMockData({
|
|
|
381
276
|
}
|
|
382
277
|
// updating stats to mock file
|
|
383
278
|
if (foundMock) {
|
|
384
|
-
|
|
279
|
+
let mockFilePath = path.join(
|
|
385
280
|
getMockDir(testConfig),
|
|
386
281
|
`test_${nameToFolder(testName)}`,
|
|
387
282
|
`mock_${foundMock.id}.json`
|
|
388
283
|
);
|
|
284
|
+
if (!fs.existsSync(mockFilePath)) {
|
|
285
|
+
mockFilePath = path.join(
|
|
286
|
+
getMockDir(testConfig),
|
|
287
|
+
"defaultMocks",
|
|
288
|
+
`mock_${foundMock.id}.json`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
389
291
|
foundMock.fileContent.served = true;
|
|
390
292
|
fs.writeFileSync(
|
|
391
293
|
mockFilePath,
|
|
@@ -460,12 +362,20 @@ async function initiatePlaywrightRoutes(
|
|
|
460
362
|
};
|
|
461
363
|
|
|
462
364
|
if (file) {
|
|
463
|
-
|
|
365
|
+
let filePath = path.join(
|
|
464
366
|
getMockDir(ftmocksConifg),
|
|
465
367
|
`test_${nameToFolder(testName)}`,
|
|
466
368
|
"_files",
|
|
467
369
|
file
|
|
468
370
|
);
|
|
371
|
+
if (!fs.existsSync(filePath)) {
|
|
372
|
+
filePath = path.join(
|
|
373
|
+
getMockDir(ftmocksConifg),
|
|
374
|
+
"defaultMocks",
|
|
375
|
+
"_files",
|
|
376
|
+
file
|
|
377
|
+
);
|
|
378
|
+
}
|
|
469
379
|
if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
|
|
470
380
|
const fileContent = fs.readFileSync(filePath);
|
|
471
381
|
json.body = fileContent;
|
|
@@ -742,24 +652,6 @@ function initiateConsoleLogs(jest, ftmocksConifg, testName) {
|
|
|
742
652
|
};
|
|
743
653
|
}
|
|
744
654
|
|
|
745
|
-
function countFilesInDirectory(directoryPath) {
|
|
746
|
-
return new Promise((resolve, reject) => {
|
|
747
|
-
fs.readdir(directoryPath, (err, files) => {
|
|
748
|
-
if (err) {
|
|
749
|
-
return reject(err); // Handle error
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// Filter out directories and only count files
|
|
753
|
-
const fileCount = files.filter((file) => {
|
|
754
|
-
const filePath = path.join(directoryPath, file);
|
|
755
|
-
return fs.statSync(filePath).isFile();
|
|
756
|
-
}).length;
|
|
757
|
-
|
|
758
|
-
resolve(fileCount);
|
|
759
|
-
});
|
|
760
|
-
});
|
|
761
|
-
}
|
|
762
|
-
|
|
763
655
|
const saveSnap = async (html, ftmocksConifg, testName) => {
|
|
764
656
|
const snapFolder = path.join(
|
|
765
657
|
getMockDir(ftmocksConifg),
|
|
@@ -824,21 +716,6 @@ function initiateJestEventSnaps(jest, ftmocksConifg, testName) {
|
|
|
824
716
|
});
|
|
825
717
|
}
|
|
826
718
|
|
|
827
|
-
const getTestByName = async (ftmocksConifg, testName) => {
|
|
828
|
-
const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
|
|
829
|
-
let tests = [];
|
|
830
|
-
try {
|
|
831
|
-
// Read existing tests
|
|
832
|
-
const testsData = fs.readFileSync(testsPath, "utf8");
|
|
833
|
-
tests = JSON.parse(testsData);
|
|
834
|
-
const etest = tests.find((tst) => tst.name === testName);
|
|
835
|
-
return etest;
|
|
836
|
-
} catch (error) {
|
|
837
|
-
console.error(`\x1b[31mError reading tests.json:\x1b[0m`, error);
|
|
838
|
-
return null;
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
|
|
842
719
|
const createTest = async (ftmocksConifg, testName) => {
|
|
843
720
|
const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
|
|
844
721
|
let tests = [];
|