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