ftmocks-utils 1.0.5 → 1.0.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.
- package/package.json +1 -1
- package/src/index.js +61 -11
- package/src/recorder.js +36 -28
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
const nameToFolder = name => {
|
|
5
5
|
return name.replaceAll(' ', '_');
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
const getMockDir = config => {
|
|
9
|
+
if(!path.isAbsolute(config.MOCK_DIR)) {
|
|
10
|
+
return path.resolve( process.cwd(), config.MOCK_DIR);
|
|
11
|
+
}
|
|
12
|
+
return config.MOCK_DIR;
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
const areJsonEqual = (jsonObj1, jsonObj2) => {
|
|
9
16
|
// Check if both are objects and not null
|
|
10
17
|
if (typeof jsonObj1 === 'object' && jsonObj1 !== null &&
|
|
@@ -34,7 +41,7 @@ const areJsonEqual = (jsonObj1, jsonObj2) => {
|
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
const getDefaultMockDataFromConfig = (testConfig) => {
|
|
37
|
-
const defaultPath = path.join(testConfig
|
|
44
|
+
const defaultPath = path.join(getMockDir(testConfig), 'default.json');
|
|
38
45
|
|
|
39
46
|
try {
|
|
40
47
|
const defaultData = fs.readFileSync(defaultPath, 'utf8');
|
|
@@ -42,7 +49,7 @@ try {
|
|
|
42
49
|
|
|
43
50
|
// Read and attach mock data for each entry in parsedData
|
|
44
51
|
parsedData.forEach(entry => {
|
|
45
|
-
const mockFilePath = path.join(testConfig
|
|
52
|
+
const mockFilePath = path.join(getMockDir(testConfig), 'defaultMocks', `mock_${entry.id}.json`);;
|
|
46
53
|
try {
|
|
47
54
|
const mockData = fs.readFileSync(mockFilePath, 'utf8');
|
|
48
55
|
entry.fileContent = JSON.parse(mockData);
|
|
@@ -64,18 +71,18 @@ const loadMockDataFromConfig = (testConfig, _testName) => {
|
|
|
64
71
|
let testName = _testName;
|
|
65
72
|
if(!testName) {
|
|
66
73
|
// Read the test ID from mockServer.config.json
|
|
67
|
-
const configPath = path.join(testConfig
|
|
74
|
+
const configPath = path.join(getMockDir(testConfig), 'mockServer.config.json');
|
|
68
75
|
const configData = fs.readFileSync(configPath, 'utf8');
|
|
69
76
|
const config = JSON.parse(configData);
|
|
70
77
|
testName = config.testName;
|
|
71
78
|
}
|
|
72
79
|
// Read the tests from testConfig
|
|
73
|
-
const mocksPath = path.join(testConfig
|
|
80
|
+
const mocksPath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, '_mock_list.json');
|
|
74
81
|
const mocksData = fs.readFileSync(mocksPath, 'utf8');
|
|
75
82
|
const mocks = JSON.parse(mocksData);
|
|
76
83
|
|
|
77
84
|
mocks.forEach(mock => {
|
|
78
|
-
const fileContent = JSON.parse(fs.readFileSync(path.join(testConfig
|
|
85
|
+
const fileContent = JSON.parse(fs.readFileSync(path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${mock.id}.json`), 'utf8'));
|
|
79
86
|
mock.fileContent = fileContent;
|
|
80
87
|
});
|
|
81
88
|
|
|
@@ -160,7 +167,7 @@ function getMatchingMockData({testMockData, defaultMockData, url, options, testC
|
|
|
160
167
|
let foundMock = matchedMocks.find(mock => !mock.fileContent.served) ? matchedMocks.find(mock => !mock.fileContent.served) : matchedMocks[matchedMocks.length - 1];
|
|
161
168
|
// updating stats to mock file
|
|
162
169
|
if(foundMock) {
|
|
163
|
-
const mockFilePath = path.join(testConfig
|
|
170
|
+
const mockFilePath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${foundMock.id}.json`);
|
|
164
171
|
foundMock.fileContent.served = true;
|
|
165
172
|
fs.writeFileSync(mockFilePath, JSON.stringify(foundMock.fileContent, null, 2));
|
|
166
173
|
}
|
|
@@ -177,7 +184,7 @@ function getMatchingMockData({testMockData, defaultMockData, url, options, testC
|
|
|
177
184
|
async function resetAllMockStats({testMockData, testConfig, testName}) {
|
|
178
185
|
for(let i=0; i<testMockData.length; i++) {
|
|
179
186
|
const tmd = testMockData[i];
|
|
180
|
-
const mockFilePath = path.join(testConfig
|
|
187
|
+
const mockFilePath = path.join(getMockDir(testConfig), `test_${nameToFolder(testName)}`, `mock_${tmd.id}.json`);
|
|
181
188
|
tmd.fileContent.served = false;
|
|
182
189
|
await fs.writeFileSync(mockFilePath, JSON.stringify(tmd.fileContent, null, 2));
|
|
183
190
|
}
|
|
@@ -281,6 +288,47 @@ async function initiateJestFetch (jest, ftmocksConifg, testName) {
|
|
|
281
288
|
return;
|
|
282
289
|
};
|
|
283
290
|
|
|
291
|
+
|
|
292
|
+
function countFilesInDirectory(directoryPath) {
|
|
293
|
+
return new Promise((resolve, reject) => {
|
|
294
|
+
fs.readdir(directoryPath, (err, files) => {
|
|
295
|
+
if (err) {
|
|
296
|
+
return reject(err); // Handle error
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Filter out directories and only count files
|
|
300
|
+
const fileCount = files.filter(file => {
|
|
301
|
+
const filePath = path.join(directoryPath, file);
|
|
302
|
+
return fs.statSync(filePath).isFile();
|
|
303
|
+
}).length;
|
|
304
|
+
|
|
305
|
+
resolve(fileCount);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const saveSnap = async (html, ftmocksConifg, testName) => {
|
|
311
|
+
const snapFolder = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`, '_snaps');
|
|
312
|
+
const snapTemplate = path.join(getMockDir(ftmocksConifg), 'snap_template.html');
|
|
313
|
+
|
|
314
|
+
if (!fs.existsSync(snapFolder)) {
|
|
315
|
+
fs.mkdirSync(snapFolder);
|
|
316
|
+
}
|
|
317
|
+
const fileCount = await (countFilesInDirectory(snapFolder));
|
|
318
|
+
const snapFilePath = path.join(snapFolder, `snap_${fileCount + 1}.html`);
|
|
319
|
+
let resHtml = html;
|
|
320
|
+
if (fs.existsSync(snapFolder)) {
|
|
321
|
+
const templateHtml = fs.readFileSync(snapTemplate, 'utf8');;
|
|
322
|
+
resHtml = templateHtml.replace('<!--FtMocks-Snap-Template-To-Be-Replaced-->', html)
|
|
323
|
+
}
|
|
324
|
+
fs.writeFileSync(snapFilePath, resHtml)
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const deleteAllSnaps = async (ftmocksConifg, testName) => {
|
|
328
|
+
const snapFolder = path.join(getMockDir(ftmocksConifg), `test_${nameToFolder(testName)}`, '_snaps');
|
|
329
|
+
fs.rmSync(snapFolder, { recursive: true, force: true });
|
|
330
|
+
};
|
|
331
|
+
|
|
284
332
|
// Export functions as a module
|
|
285
333
|
module.exports = {
|
|
286
334
|
compareMockToRequest,
|
|
@@ -292,5 +340,7 @@ module.exports = {
|
|
|
292
340
|
compareMockToFetchRequest,
|
|
293
341
|
getMatchingMockData,
|
|
294
342
|
resetAllMockStats,
|
|
295
|
-
initiateJestFetch
|
|
343
|
+
initiateJestFetch,
|
|
344
|
+
saveSnap,
|
|
345
|
+
deleteAllSnaps
|
|
296
346
|
};
|
package/src/recorder.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
window.FTMOCKS_CONFIG = {
|
|
2
|
+
record_mocks_url: 'http://localhost:5000/api/v1/recordMockdata',
|
|
3
|
+
record_events_url: 'http://localhost:5000/api/v1/recordedEvents'
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
|
|
1
7
|
(function () {
|
|
2
8
|
// Intercept Fetch API
|
|
3
9
|
const originalFetch = window.fetch;
|
|
4
10
|
const recordedTracks = [];
|
|
5
|
-
|
|
11
|
+
|
|
6
12
|
const addTrack = track => {
|
|
7
13
|
track.id = recordedTracks.length ? recordedTracks[recordedTracks.length - 1].id + 1 : 1;
|
|
8
14
|
track.time = new Date();
|
|
15
|
+
track.bodyHtml = document.documentElement.outerHTML.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');;
|
|
16
|
+
|
|
9
17
|
fetch(window.FTMOCKS_CONFIG.record_events_url, {
|
|
10
18
|
method: 'POST',
|
|
11
19
|
headers: {
|
|
@@ -14,8 +22,8 @@
|
|
|
14
22
|
body: JSON.stringify(track),
|
|
15
23
|
}).then(response => response.json());
|
|
16
24
|
};
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
|
|
26
|
+
|
|
19
27
|
window.fetch = async function (url, options = {}) {
|
|
20
28
|
const method = options.method || 'GET';
|
|
21
29
|
const body = options.body;
|
|
@@ -60,10 +68,10 @@
|
|
|
60
68
|
});
|
|
61
69
|
return response;
|
|
62
70
|
};
|
|
63
|
-
|
|
71
|
+
|
|
64
72
|
// Intercept XMLHttpRequest
|
|
65
73
|
const originalXHR = window.XMLHttpRequest;
|
|
66
|
-
|
|
74
|
+
|
|
67
75
|
function MockXHR() {
|
|
68
76
|
const xhr = new originalXHR();
|
|
69
77
|
const originalOpen = xhr.open;
|
|
@@ -72,7 +80,7 @@
|
|
|
72
80
|
let requestDetails = {
|
|
73
81
|
headers: {},
|
|
74
82
|
};
|
|
75
|
-
|
|
83
|
+
|
|
76
84
|
// Override 'open' method
|
|
77
85
|
xhr.open = function (method, url, async, user, password) {
|
|
78
86
|
requestDetails.method = method;
|
|
@@ -83,13 +91,13 @@
|
|
|
83
91
|
requestDetails.queryString = url.includes('?') ? url.split('?')[1] : null;
|
|
84
92
|
originalOpen.apply(xhr, arguments);
|
|
85
93
|
};
|
|
86
|
-
|
|
94
|
+
|
|
87
95
|
// Override 'setRequestHeader' to log headers
|
|
88
96
|
xhr.setRequestHeader = function (header, value) {
|
|
89
97
|
requestDetails.headers[header] = value;
|
|
90
98
|
originalSetRequestHeader.apply(xhr, arguments);
|
|
91
99
|
};
|
|
92
|
-
|
|
100
|
+
|
|
93
101
|
// Override 'send' method
|
|
94
102
|
xhr.send = function (body) {
|
|
95
103
|
requestDetails.body = body;
|
|
@@ -124,63 +132,63 @@
|
|
|
124
132
|
},
|
|
125
133
|
body: JSON.stringify(mockResponse),
|
|
126
134
|
}).then(response => response.json());
|
|
127
|
-
|
|
135
|
+
|
|
128
136
|
}
|
|
129
137
|
}
|
|
130
138
|
if (originalOnReadyStateChange) originalOnReadyStateChange.apply(xhr, arguments);
|
|
131
139
|
};
|
|
132
140
|
originalSend.apply(xhr, arguments);
|
|
133
141
|
};
|
|
134
|
-
|
|
142
|
+
|
|
135
143
|
return xhr;
|
|
136
144
|
}
|
|
137
|
-
|
|
145
|
+
|
|
138
146
|
window.XMLHttpRequest = MockXHR;
|
|
139
|
-
|
|
140
|
-
|
|
147
|
+
|
|
148
|
+
|
|
141
149
|
const generateXPathWithNearestParentId = (element) => {
|
|
142
150
|
let path = '';
|
|
143
151
|
let nearestParentId = null;
|
|
144
|
-
|
|
152
|
+
|
|
145
153
|
// Check if the current element's has an ID
|
|
146
154
|
if (element.id) {
|
|
147
155
|
nearestParentId = element.id;
|
|
148
156
|
}
|
|
149
|
-
|
|
157
|
+
|
|
150
158
|
while (!nearestParentId && element !== document.body && element) {
|
|
151
159
|
const tagName = element.tagName.toLowerCase();
|
|
152
160
|
let index = 1;
|
|
153
161
|
let sibling = element.previousElementSibling;
|
|
154
|
-
|
|
162
|
+
|
|
155
163
|
while (sibling) {
|
|
156
164
|
if (sibling.tagName.toLowerCase() === tagName) {
|
|
157
165
|
index += 1;
|
|
158
166
|
}
|
|
159
167
|
sibling = sibling.previousElementSibling;
|
|
160
168
|
}
|
|
161
|
-
|
|
169
|
+
|
|
162
170
|
if (index === 1) {
|
|
163
171
|
path = `/${tagName}${path}`;
|
|
164
172
|
} else {
|
|
165
173
|
path = `/${tagName}[${index}]${path}`;
|
|
166
174
|
}
|
|
167
|
-
|
|
175
|
+
|
|
168
176
|
// Check if the current element's parent has an ID
|
|
169
177
|
if (element.parentElement && element.parentElement.id) {
|
|
170
178
|
nearestParentId = element.parentElement.id;
|
|
171
179
|
break; // Stop searching when we find the nearest parent with an ID
|
|
172
180
|
}
|
|
173
|
-
|
|
181
|
+
|
|
174
182
|
element = element.parentElement;
|
|
175
183
|
}
|
|
176
|
-
|
|
184
|
+
|
|
177
185
|
if (nearestParentId) {
|
|
178
186
|
path = `//*[@id='${nearestParentId}']${path}`;
|
|
179
187
|
return path;
|
|
180
188
|
}
|
|
181
189
|
return null; // No parent with an ID found
|
|
182
190
|
};
|
|
183
|
-
|
|
191
|
+
|
|
184
192
|
const handleMouseEvent = (type, limit) => event => {
|
|
185
193
|
const target = generateXPathWithNearestParentId(event.target);
|
|
186
194
|
const track = {
|
|
@@ -195,7 +203,7 @@
|
|
|
195
203
|
recordedTracks.push(track);
|
|
196
204
|
addTrack(track);
|
|
197
205
|
};
|
|
198
|
-
|
|
206
|
+
|
|
199
207
|
const handleChange = limit => event => {
|
|
200
208
|
const prevCommand =
|
|
201
209
|
recordedTracks && recordedTracks.length ? recordedTracks[recordedTracks.length - 1] : null;
|
|
@@ -220,7 +228,7 @@
|
|
|
220
228
|
recordedTracks.push(track);
|
|
221
229
|
addTrack(track);
|
|
222
230
|
};
|
|
223
|
-
|
|
231
|
+
|
|
224
232
|
const handleDocumentLoad = limit => () => {
|
|
225
233
|
let oldHref = document.location.href;
|
|
226
234
|
const body = document.querySelector('body');
|
|
@@ -242,15 +250,15 @@
|
|
|
242
250
|
});
|
|
243
251
|
observer.observe(body, { childList: true, subtree: true });
|
|
244
252
|
};
|
|
245
|
-
|
|
253
|
+
|
|
246
254
|
const clearTracks = () => {
|
|
247
255
|
recordedTracks = [];
|
|
248
256
|
};
|
|
249
|
-
|
|
257
|
+
|
|
250
258
|
const getAllTracks = () => {
|
|
251
259
|
return recordedTracks;
|
|
252
260
|
};
|
|
253
|
-
|
|
261
|
+
|
|
254
262
|
const initTracks = (initInfo = {events: ['click', 'change', 'url', 'dblclick', 'contextmenu'], limit: 100}) => {
|
|
255
263
|
const {events, limit} = initInfo;
|
|
256
264
|
const mouseEvents = {
|
|
@@ -276,5 +284,5 @@
|
|
|
276
284
|
});
|
|
277
285
|
};
|
|
278
286
|
initTracks();
|
|
279
|
-
|
|
280
|
-
})();
|
|
287
|
+
|
|
288
|
+
})();
|