ftmocks-utils 1.1.7 → 1.1.9

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 +6 -2
  2. package/src/index.js +272 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ftmocks-utils",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "Util functions for FtMocks",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -16,5 +16,9 @@
16
16
  "bugs": {
17
17
  "url": "https://github.com/SodhanaLibrary/ftmocks-utils/issues"
18
18
  },
19
- "homepage": "https://github.com/SodhanaLibrary/ftmocks-utils#readme"
19
+ "homepage": "https://github.com/SodhanaLibrary/ftmocks-utils#readme",
20
+ "dependencies": {
21
+ "uui": "^1.0.7",
22
+ "uuid": "^11.1.0"
23
+ }
20
24
  }
package/src/index.js CHANGED
@@ -1,7 +1,6 @@
1
- // import fs from 'fs';
2
1
  const fs = require("fs");
3
- // import path from 'path';
4
2
  const path = require("path");
3
+ const { v4: uuidv4 } = require("uuid");
5
4
 
6
5
  const nameToFolder = (name) => {
7
6
  return name.replaceAll(" ", "_");
@@ -45,7 +44,7 @@ const getHeaders = (headers) => {
45
44
  ...Object.entries(capitalizeHeaders(headers)),
46
45
  ]);
47
46
  } catch (e) {
48
- console.debug("error at getHeaders", e);
47
+ console.error("error at getHeaders", e);
49
48
  res = new Map([
50
49
  ["Content-Type", "application/json"],
51
50
  ["content-type", "application/json"],
@@ -153,7 +152,7 @@ const loadMockDataFromConfig = (testConfig, _testName) => {
153
152
 
154
153
  return mocks;
155
154
  } catch (error) {
156
- console.debug("Error loading test data:", error.message);
155
+ console.error("Error loading test data:", error.message);
157
156
  return [];
158
157
  }
159
158
  };
@@ -243,8 +242,8 @@ function compareMockToFetchRequest(mock, fetchReq) {
243
242
  }
244
243
  );
245
244
  } catch (e) {
246
- console.debug("error at compareMockToFetchRequest", mock, fetchReq);
247
- console.debug(e);
245
+ console.error("error at compareMockToFetchRequest", mock, fetchReq);
246
+ console.error(e);
248
247
  }
249
248
  return false;
250
249
  }
@@ -636,6 +635,272 @@ function initiateJestEventSnaps(jest, ftmocksConifg, testName) {
636
635
  });
637
636
  }
638
637
 
638
+ const getTestByName = async (ftmocksConifg, testName) => {
639
+ const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
640
+ let tests = [];
641
+ try {
642
+ // Read existing tests
643
+ const testsData = fs.readFileSync(testsPath, "utf8");
644
+ tests = JSON.parse(testsData);
645
+ const etest = tests.find((tst) => tst.name === testName);
646
+ return etest;
647
+ } catch (error) {
648
+ console.error(`Error reading tests.json:`, error);
649
+ return null;
650
+ }
651
+ };
652
+
653
+ const createTest = async (ftmocksConifg, testName) => {
654
+ const testsPath = path.join(getMockDir(ftmocksConifg), "tests.json");
655
+ let tests = [];
656
+ try {
657
+ // Read existing tests
658
+ const testsData = fs.readFileSync(testsPath, "utf8");
659
+ tests = JSON.parse(testsData);
660
+ const etest = tests.find((tst) => tst.name === testName);
661
+ if (!etest) {
662
+ const newTest = {
663
+ id: uuidv4(),
664
+ name: testName,
665
+ };
666
+ tests.push(newTest);
667
+ fs.writeFileSync(testsPath, JSON.stringify(tests, null, 2));
668
+ const folderPath = path.join(
669
+ getMockDir(ftmocksConifg),
670
+ `test_${nameToFolder(testName)}`
671
+ );
672
+ const mockListFilePath = path.join(folderPath, "_mock_list.json");
673
+ fs.mkdir(folderPath, { recursive: true }, (err) => {
674
+ if (err) {
675
+ console.error("Error creating directory:", err);
676
+ } else {
677
+ console.log("Directory created successfully!");
678
+ }
679
+ });
680
+ await fs.appendFile(mockListFilePath, "[]", () => {
681
+ console.log("mock list file created successfully");
682
+ });
683
+
684
+ return newTest;
685
+ } else {
686
+ throw "Test already exists";
687
+ }
688
+ } catch (error) {
689
+ console.error(`Error reading tests.json:`, error);
690
+ return null;
691
+ }
692
+ };
693
+
694
+ const isSameResponse = (req1, req2) => {
695
+ try {
696
+ let matched = true;
697
+ if (req1.response.status !== req2.response.status) {
698
+ matched = false;
699
+ // console.log('not matched at url', req1.method, req2.method);
700
+ } else if (
701
+ (!req1.response.content && req2.response.content) ||
702
+ (req1.response.content && !req2.response.content)
703
+ ) {
704
+ matched = areJsonEqual(
705
+ JSON.parse(req1.response.content) || {},
706
+ JSON.parse(req2.response.content) || {}
707
+ );
708
+ // console.log('not matched at post Data 0', req1.postData, req2.postData);
709
+ } else if (
710
+ req1.response.content &&
711
+ req2.response.content &&
712
+ !areJsonEqual(
713
+ JSON.parse(req1.response.content) || {},
714
+ JSON.parse(req2.response.content) || {}
715
+ )
716
+ ) {
717
+ matched = false;
718
+ }
719
+ // if (matched) {
720
+ // console.log('matched responses', req1, req2);
721
+ // }
722
+ return matched;
723
+ } catch (error) {
724
+ console.error(error);
725
+ return false;
726
+ }
727
+ };
728
+
729
+ const compareMockToMock = (mock1, mock2, matchResponse) => {
730
+ try {
731
+ if (matchResponse) {
732
+ return isSameRequest(mock1, mock2) && isSameResponse(mock1, mock2);
733
+ } else {
734
+ return isSameRequest(mock1, mock2);
735
+ }
736
+ } catch (error) {
737
+ console.error(error);
738
+ return false;
739
+ }
740
+ };
741
+
742
+ const saveIfItIsFile = async (route, testName, ftmocksConifg) => {
743
+ const urlObj = new URL(route.request().url());
744
+
745
+ // Check if URL contains file extension like .js, .png, .css etc
746
+ const fileExtMatch = urlObj.pathname.match(/\.[a-zA-Z0-9]+$/);
747
+ if (fileExtMatch) {
748
+ const fileExt = fileExtMatch[0];
749
+ // Create directory path matching URL structure
750
+ const dirPath = path.join(
751
+ getMockDir(ftmocksConifg),
752
+ `test_${nameToFolder(testName)}`,
753
+ "_files",
754
+ path.dirname(urlObj.pathname)
755
+ );
756
+
757
+ // Create directories if they don't exist
758
+ fs.mkdirSync(dirPath, { recursive: true });
759
+
760
+ // Save file with original name
761
+ const fileName = path.basename(urlObj.pathname);
762
+ const filePath = path.join(dirPath, fileName);
763
+
764
+ const response = await route.fetch();
765
+ const buffer = await response.body();
766
+ fs.writeFileSync(filePath, buffer);
767
+
768
+ await route.continue();
769
+ return true;
770
+ }
771
+ return false;
772
+ };
773
+
774
+ async function recordPlaywrightRoutes(
775
+ page,
776
+ ftmocksConifg,
777
+ config = {
778
+ testName,
779
+ mockPath: "**/*",
780
+ pattern: "^/api/.*",
781
+ avoidDuplicatesInTheTest: false,
782
+ avoidDuplicatesWithDefaultMocks: false,
783
+ }
784
+ ) {
785
+ await page.route(config.mockPath, async (route) => {
786
+ try {
787
+ const urlObj = new URL(route.request().url());
788
+ if (config.pattern && config.pattern.length > 0) {
789
+ const patternRegex = new RegExp(config.pattern);
790
+ if (!patternRegex.test(urlObj.pathname)) {
791
+ await route.continue();
792
+ return;
793
+ }
794
+ }
795
+
796
+ const test = await getTestByName(ftmocksConifg, config.testName);
797
+ if (!test) {
798
+ await createTest(ftmocksConifg, config.testName);
799
+ }
800
+
801
+ if (await saveIfItIsFile(route, config.testName, ftmocksConifg)) {
802
+ return;
803
+ }
804
+
805
+ const mockData = {
806
+ url: urlObj.pathname + urlObj.search,
807
+ time: new Date().toString(),
808
+ method: route.request().method(),
809
+ request: {
810
+ headers: await route.request().headers(),
811
+ queryString: Array.from(urlObj.searchParams.entries()).map(
812
+ ([name, value]) => ({
813
+ name,
814
+ value,
815
+ })
816
+ ),
817
+ postData: route.request().postData()
818
+ ? {
819
+ mimeType: "application/json",
820
+ text: route.request().postData(),
821
+ }
822
+ : null,
823
+ },
824
+ response: {
825
+ status: (await route.fetch()).status(),
826
+ headers: (await route.fetch()).headers(),
827
+ content: await (await route.fetch()).text(),
828
+ },
829
+ id: crypto.randomUUID(),
830
+ served: false,
831
+ ignoreParams: ftmocksConifg.ignoreParams || [],
832
+ };
833
+
834
+ await createTest(ftmocksConifg, config.testName);
835
+ if (config.avoidDuplicatesInTheTest) {
836
+ // Check if the mock data is a duplicate of a mock data in the test
837
+ const testMockList = loadMockDataFromConfig(
838
+ ftmocksConifg,
839
+ config.testName
840
+ );
841
+ const matchResponse = testMockList.find((mock) =>
842
+ compareMockToMock(mock.fileContent, mockData, true)
843
+ );
844
+ if (matchResponse) {
845
+ console.log("Aborting duplicate mock data in the test");
846
+ await route.continue();
847
+ return;
848
+ }
849
+ }
850
+
851
+ if (config.avoidDuplicatesWithDefaultMocks) {
852
+ // Check if the mock data is a duplicate of a mock data in the test
853
+ const defaultMockList = getDefaultMockDataFromConfig(ftmocksConifg);
854
+ const matchResponse = defaultMockList.find((mock) =>
855
+ compareMockToMock(mock.fileContent, mockData, true)
856
+ );
857
+ if (matchResponse) {
858
+ console.log("Aborting duplicate mock data with default mocks");
859
+ await route.continue();
860
+ return;
861
+ }
862
+ }
863
+
864
+ // Save the mock data to the test
865
+ const mockListPath = path.join(
866
+ getMockDir(ftmocksConifg),
867
+ `test_${nameToFolder(config.testName)}`,
868
+ "_mock_list.json"
869
+ );
870
+ let mockList = [];
871
+ if (fs.existsSync(mockListPath)) {
872
+ mockList = JSON.parse(fs.readFileSync(mockListPath, "utf8"));
873
+ }
874
+ mockList.push({
875
+ id: mockData.id,
876
+ url: mockData.url,
877
+ method: mockData.method,
878
+ time: mockData.time,
879
+ });
880
+
881
+ // Create test directory if it doesn't exist
882
+ const testDir = path.join(
883
+ getMockDir(ftmocksConifg),
884
+ `test_${nameToFolder(config.testName)}`
885
+ );
886
+ if (!fs.existsSync(testDir)) {
887
+ fs.mkdirSync(testDir, { recursive: true });
888
+ }
889
+ fs.writeFileSync(mockListPath, JSON.stringify(mockList, null, 2));
890
+ const mocDataPath = path.join(
891
+ getMockDir(ftmocksConifg),
892
+ `test_${nameToFolder(config.testName)}`,
893
+ `mock_${mockData.id}.json`
894
+ );
895
+ fs.writeFileSync(mocDataPath, JSON.stringify(mockData, null, 2));
896
+ await route.continue();
897
+ } catch (error) {
898
+ console.error(error);
899
+ await route.continue();
900
+ }
901
+ });
902
+ }
903
+
639
904
  // Export functions as a module
640
905
  module.exports = {
641
906
  compareMockToRequest,
@@ -654,4 +919,5 @@ module.exports = {
654
919
  initiateConsoleLogs,
655
920
  initiatePlaywrightRoutes,
656
921
  initiateJestEventSnaps,
922
+ recordPlaywrightRoutes,
657
923
  };