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.
- package/package.json +6 -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.
|
|
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.
|
|
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.
|
|
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.
|
|
247
|
-
console.
|
|
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
|
};
|