@@ -40,6 +40,28 @@ describe("data-catalog", () => {
4040 enabled : true ,
4141 deviceId : "mock-device" ,
4242 } ) ;
43+ // Default npm API mock that returns high downloads so packages pass the threshold check
44+ // Individual tests can override this with msw.use() for specific scenarios
45+ // Use wildcard pattern to capture scoped packages like @cloudflare /workers-types
46+ msw . use (
47+ http . get (
48+ "https://api.npmjs.org/downloads/point/last-year/*" ,
49+ ( { request } ) => {
50+ const url = new URL ( request . url ) ;
51+ // Extract package name from URL path (handles scoped packages)
52+ const packageName = url . pathname . replace (
53+ "/downloads/point/last-year/" ,
54+ ""
55+ ) ;
56+ return HttpResponse . json ( {
57+ downloads : 100000 ,
58+ start : "2025-03-06" ,
59+ end : "2026-03-06" ,
60+ package : packageName ,
61+ } ) ;
62+ }
63+ )
64+ ) ;
4365 } ) ;
4466
4567 afterEach ( ( ) => {
@@ -794,6 +816,324 @@ describe("data-catalog", () => {
794816 ) ;
795817 } ) ;
796818
819+ it ( "should include packages with npm downloads above threshold" , async ( {
820+ expect,
821+ } ) => {
822+ let capturedBody : { projectDependencies ?: Record < string , unknown > } = { } ;
823+ msw . use (
824+ http . post ( TEST_DATA_CATALOG_WORKER_URL , async ( { request } ) => {
825+ capturedBody = ( await request . json ( ) ) as typeof capturedBody ;
826+ return HttpResponse . json ( { success : true } ) ;
827+ } ) ,
828+ http . get (
829+ "https://api.npmjs.org/downloads/point/last-year/*" ,
830+ ( { request } ) => {
831+ const url = new URL ( request . url ) ;
832+ const packageName = url . pathname . replace (
833+ "/downloads/point/last-year/" ,
834+ ""
835+ ) ;
836+ // Return downloads above the 10,000 threshold
837+ return HttpResponse . json ( {
838+ downloads : 50000 ,
839+ start : "2025-03-06" ,
840+ end : "2026-03-06" ,
841+ package : packageName ,
842+ } ) ;
843+ }
844+ )
845+ ) ;
846+
847+ vi . mocked ( getInstalledPackageJson ) . mockImplementation ( ( packageName ) => {
848+ if ( packageName === "hono" ) {
849+ return { name : "hono" , version : "4.0.0" } ;
850+ }
851+ return undefined ;
852+ } ) ;
853+
854+ await seed ( {
855+ "package.json" : JSON . stringify ( {
856+ name : "test-project" ,
857+ dependencies : {
858+ hono : "^4.0.0" ,
859+ } ,
860+ } ) ,
861+ } ) ;
862+
863+ await sendDeploymentToTelemetryDataCatalog ( {
864+ accountId : TEST_ACCOUNT_ID ,
865+ workerName : TEST_WORKER_NAME ,
866+ projectPath : "." ,
867+ bindings : { } ,
868+ complianceConfig : TEST_COMPLIANCE_CONFIG ,
869+ } ) ;
870+
871+ // Package with downloads above threshold should be included
872+ expect ( capturedBody . projectDependencies ) . toHaveProperty ( "hono" ) ;
873+ expect ( capturedBody . projectDependencies ?. hono ) . toEqual ( {
874+ packageJsonVersion : "^4.0.0" ,
875+ installedVersion : "4.0.0" ,
876+ } ) ;
877+ } ) ;
878+
879+ it ( "should exclude packages with npm downloads below threshold" , async ( {
880+ expect,
881+ } ) => {
882+ let capturedBody : { projectDependencies ?: Record < string , unknown > } = { } ;
883+ msw . use (
884+ http . post ( TEST_DATA_CATALOG_WORKER_URL , async ( { request } ) => {
885+ capturedBody = ( await request . json ( ) ) as typeof capturedBody ;
886+ return HttpResponse . json ( { success : true } ) ;
887+ } ) ,
888+ http . get (
889+ "https://api.npmjs.org/downloads/point/last-year/*" ,
890+ ( { request } ) => {
891+ const url = new URL ( request . url ) ;
892+ const packageName = url . pathname . replace (
893+ "/downloads/point/last-year/" ,
894+ ""
895+ ) ;
896+ if ( packageName === "popular-pkg" ) {
897+ return HttpResponse . json ( {
898+ downloads : 50000 ,
899+ start : "2025-03-06" ,
900+ end : "2026-03-06" ,
901+ package : packageName ,
902+ } ) ;
903+ }
904+ // Return downloads below the 10,000 threshold for unpopular package
905+ return HttpResponse . json ( {
906+ downloads : 500 ,
907+ start : "2025-03-06" ,
908+ end : "2026-03-06" ,
909+ package : packageName ,
910+ } ) ;
911+ }
912+ )
913+ ) ;
914+
915+ vi . mocked ( getInstalledPackageJson ) . mockImplementation ( ( packageName ) => {
916+ if ( packageName === "popular-pkg" ) {
917+ return { name : "popular-pkg" , version : "1.0.0" } ;
918+ }
919+ if ( packageName === "unpopular-pkg" ) {
920+ return { name : "unpopular-pkg" , version : "2.0.0" } ;
921+ }
922+ return undefined ;
923+ } ) ;
924+
925+ await seed ( {
926+ "package.json" : JSON . stringify ( {
927+ name : "test-project" ,
928+ dependencies : {
929+ "popular-pkg" : "^1.0.0" ,
930+ "unpopular-pkg" : "^2.0.0" ,
931+ } ,
932+ } ) ,
933+ } ) ;
934+
935+ await sendDeploymentToTelemetryDataCatalog ( {
936+ accountId : TEST_ACCOUNT_ID ,
937+ workerName : TEST_WORKER_NAME ,
938+ projectPath : "." ,
939+ bindings : { } ,
940+ complianceConfig : TEST_COMPLIANCE_CONFIG ,
941+ } ) ;
942+
943+ // Package with downloads above threshold should be included
944+ expect ( capturedBody . projectDependencies ) . toHaveProperty ( "popular-pkg" ) ;
945+
946+ // Package with downloads below threshold should be excluded
947+ expect ( capturedBody . projectDependencies ) . not . toHaveProperty (
948+ "unpopular-pkg"
949+ ) ;
950+ } ) ;
951+
952+ it ( "should exclude packages when npm API returns an error" , async ( {
953+ expect,
954+ } ) => {
955+ let capturedBody : { projectDependencies ?: Record < string , unknown > } = { } ;
956+ msw . use (
957+ http . post ( TEST_DATA_CATALOG_WORKER_URL , async ( { request } ) => {
958+ capturedBody = ( await request . json ( ) ) as typeof capturedBody ;
959+ return HttpResponse . json ( { success : true } ) ;
960+ } ) ,
961+ http . get (
962+ "https://api.npmjs.org/downloads/point/last-year/*" ,
963+ ( { request } ) => {
964+ const url = new URL ( request . url ) ;
965+ const packageName = url . pathname . replace (
966+ "/downloads/point/last-year/" ,
967+ ""
968+ ) ;
969+ if ( packageName === "valid-pkg" ) {
970+ return HttpResponse . json ( {
971+ downloads : 50000 ,
972+ start : "2025-03-06" ,
973+ end : "2026-03-06" ,
974+ package : packageName ,
975+ } ) ;
976+ }
977+ // Return 404 for unknown package
978+ return new HttpResponse ( null , { status : 404 } ) ;
979+ }
980+ )
981+ ) ;
982+
983+ vi . mocked ( getInstalledPackageJson ) . mockImplementation ( ( packageName ) => {
984+ if ( packageName === "valid-pkg" ) {
985+ return { name : "valid-pkg" , version : "1.0.0" } ;
986+ }
987+ if ( packageName === "unknown-pkg" ) {
988+ return { name : "unknown-pkg" , version : "1.0.0" } ;
989+ }
990+ return undefined ;
991+ } ) ;
992+
993+ await seed ( {
994+ "package.json" : JSON . stringify ( {
995+ name : "test-project" ,
996+ dependencies : {
997+ "valid-pkg" : "^1.0.0" ,
998+ "unknown-pkg" : "^1.0.0" ,
999+ } ,
1000+ } ) ,
1001+ } ) ;
1002+
1003+ await sendDeploymentToTelemetryDataCatalog ( {
1004+ accountId : TEST_ACCOUNT_ID ,
1005+ workerName : TEST_WORKER_NAME ,
1006+ projectPath : "." ,
1007+ bindings : { } ,
1008+ complianceConfig : TEST_COMPLIANCE_CONFIG ,
1009+ } ) ;
1010+
1011+ // Valid package should be included
1012+ expect ( capturedBody . projectDependencies ) . toHaveProperty ( "valid-pkg" ) ;
1013+
1014+ // Package that returns 404 from npm API should be excluded
1015+ expect ( capturedBody . projectDependencies ) . not . toHaveProperty (
1016+ "unknown-pkg"
1017+ ) ;
1018+ } ) ;
1019+
1020+ it ( "should handle npm API network failures gracefully" , async ( {
1021+ expect,
1022+ } ) => {
1023+ let capturedBody : { projectDependencies ?: Record < string , unknown > } = { } ;
1024+ msw . use (
1025+ http . post ( TEST_DATA_CATALOG_WORKER_URL , async ( { request } ) => {
1026+ capturedBody = ( await request . json ( ) ) as typeof capturedBody ;
1027+ return HttpResponse . json ( { success : true } ) ;
1028+ } ) ,
1029+ http . get ( "https://api.npmjs.org/downloads/point/last-year/*" , ( ) => {
1030+ // Simulate network error
1031+ return HttpResponse . error ( ) ;
1032+ } )
1033+ ) ;
1034+
1035+ vi . mocked ( getInstalledPackageJson ) . mockImplementation ( ( packageName ) => {
1036+ if ( packageName === "some-pkg" ) {
1037+ return { name : "some-pkg" , version : "1.0.0" } ;
1038+ }
1039+ return undefined ;
1040+ } ) ;
1041+
1042+ await seed ( {
1043+ "package.json" : JSON . stringify ( {
1044+ name : "test-project" ,
1045+ dependencies : {
1046+ "some-pkg" : "^1.0.0" ,
1047+ } ,
1048+ } ) ,
1049+ } ) ;
1050+
1051+ // Should not throw
1052+ await sendDeploymentToTelemetryDataCatalog ( {
1053+ accountId : TEST_ACCOUNT_ID ,
1054+ workerName : TEST_WORKER_NAME ,
1055+ projectPath : "." ,
1056+ bindings : { } ,
1057+ complianceConfig : TEST_COMPLIANCE_CONFIG ,
1058+ } ) ;
1059+
1060+ // Package should be excluded when npm API fails
1061+ expect ( capturedBody . projectDependencies ) . not . toHaveProperty ( "some-pkg" ) ;
1062+ } ) ;
1063+
1064+ it ( "should exclude packages when npm API returns mismatched package name" , async ( {
1065+ expect,
1066+ } ) => {
1067+ let capturedBody : { projectDependencies ?: Record < string , unknown > } = { } ;
1068+ msw . use (
1069+ http . post ( TEST_DATA_CATALOG_WORKER_URL , async ( { request } ) => {
1070+ capturedBody = ( await request . json ( ) ) as typeof capturedBody ;
1071+ return HttpResponse . json ( { success : true } ) ;
1072+ } ) ,
1073+ http . get (
1074+ "https://api.npmjs.org/downloads/point/last-year/*" ,
1075+ ( { request } ) => {
1076+ const url = new URL ( request . url ) ;
1077+ const packageName = url . pathname . replace (
1078+ "/downloads/point/last-year/" ,
1079+ ""
1080+ ) ;
1081+ if ( packageName === "correct-pkg" ) {
1082+ return HttpResponse . json ( {
1083+ downloads : 50000 ,
1084+ start : "2025-03-06" ,
1085+ end : "2026-03-06" ,
1086+ package : packageName ,
1087+ } ) ;
1088+ }
1089+ // Return response with mismatched package name
1090+ return HttpResponse . json ( {
1091+ downloads : 50000 ,
1092+ start : "2025-03-06" ,
1093+ end : "2026-03-06" ,
1094+ package : "different-package-name" ,
1095+ } ) ;
1096+ }
1097+ )
1098+ ) ;
1099+
1100+ vi . mocked ( getInstalledPackageJson ) . mockImplementation ( ( packageName ) => {
1101+ if ( packageName === "correct-pkg" ) {
1102+ return { name : "correct-pkg" , version : "1.0.0" } ;
1103+ }
1104+ if ( packageName === "mismatched-pkg" ) {
1105+ return { name : "mismatched-pkg" , version : "1.0.0" } ;
1106+ }
1107+ return undefined ;
1108+ } ) ;
1109+
1110+ await seed ( {
1111+ "package.json" : JSON . stringify ( {
1112+ name : "test-project" ,
1113+ dependencies : {
1114+ "correct-pkg" : "^1.0.0" ,
1115+ "mismatched-pkg" : "^1.0.0" ,
1116+ } ,
1117+ } ) ,
1118+ } ) ;
1119+
1120+ await sendDeploymentToTelemetryDataCatalog ( {
1121+ accountId : TEST_ACCOUNT_ID ,
1122+ workerName : TEST_WORKER_NAME ,
1123+ projectPath : "." ,
1124+ bindings : { } ,
1125+ complianceConfig : TEST_COMPLIANCE_CONFIG ,
1126+ } ) ;
1127+
1128+ // Package with correct response should be included
1129+ expect ( capturedBody . projectDependencies ) . toHaveProperty ( "correct-pkg" ) ;
1130+
1131+ // Package with mismatched name in response should be excluded
1132+ expect ( capturedBody . projectDependencies ) . not . toHaveProperty (
1133+ "mismatched-pkg"
1134+ ) ;
1135+ } ) ;
1136+
7971137 it ( "should skip execution for fedramp_high compliance region when env URL is not set" , async ( {
7981138 expect,
7991139 } ) => {
0 commit comments