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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -1,10 +1,17 @@
1
- import fs from 'fs';
2
- import path from 'path';
1
+ const fs = require('fs')
2
+ const path = require('path')
3
3
 
4
- export const nameToFolder = name => {
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.MOCK_DIR, 'default.json');
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.MOCK_DIR, 'defaultMocks', `mock_${entry.id}.json`);;
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.MOCK_DIR, 'mockServer.config.json');
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.MOCK_DIR, `test_${nameToFolder(testName)}`, '_mock_list.json');
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.MOCK_DIR, `test_${nameToFolder(testName)}`, `mock_${mock.id}.json`), 'utf8'));
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.MOCK_DIR, `test_${nameToFolder(testName)}`, `mock_${foundMock.id}.json`);
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.MOCK_DIR, `test_${nameToFolder(testName)}`, `mock_${tmd.id}.json`);
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
+ })();