@@ -10,6 +10,7 @@ const utils = require(`../../../lib/browsers/utils`)
1010const chrome = require ( `../../../lib/browsers/chrome` )
1111const { fs } = require ( `../../../lib/util/fs` )
1212const { BrowserCriClient } = require ( '../../../lib/browsers/browser-cri-client' )
13+ const protocol = require ( `../../../lib/browsers/protocol` )
1314const { expect } = require ( 'chai' )
1415
1516const openOpts = {
@@ -994,4 +995,374 @@ describe('lib/browsers/chrome', () => {
994995 } )
995996 } )
996997 } )
998+
999+ context ( '#_getDefaultChromePreferences' , ( ) => {
1000+ it ( 'returns expected default preferences' , ( ) => {
1001+ const defaultPrefs = chrome . _getDefaultChromePreferences ( )
1002+
1003+ expect ( defaultPrefs ) . to . be . an ( 'object' )
1004+ expect ( defaultPrefs ) . to . have . property ( 'default' )
1005+ expect ( defaultPrefs ) . to . have . property ( 'defaultSecure' )
1006+ expect ( defaultPrefs ) . to . have . property ( 'localState' )
1007+ } )
1008+ } )
1009+
1010+ context ( '#_getChromePreferencesWithDefaults' , ( ) => {
1011+ beforeEach ( ( ) => {
1012+ sinon . stub ( fs , 'readJson' )
1013+ } )
1014+
1015+ afterEach ( ( ) => {
1016+ fs . readJson . restore ( )
1017+ } )
1018+
1019+ it ( 'merges defaults with existing preferences' , ( ) => {
1020+ const mockDefaults = {
1021+ default : {
1022+ fake_preference : {
1023+ value : 'value' ,
1024+ } ,
1025+ } ,
1026+ defaultSecure : {
1027+ fake_secure_preference : {
1028+ value : 'value' ,
1029+ } ,
1030+ } ,
1031+ localState : {
1032+ fake_local_state : {
1033+ value : 'value' ,
1034+ } ,
1035+ } ,
1036+ }
1037+
1038+ sinon . stub ( chrome , '_getDefaultChromePreferences' ) . returns ( mockDefaults )
1039+
1040+ fs . readJson . withArgs ( '/foo/Default/Preferences' ) . resolves ( { existing : 'value' } )
1041+ fs . readJson . withArgs ( '/foo/Default/Secure Preferences' ) . resolves ( { secure : 'value' } )
1042+ fs . readJson . withArgs ( '/foo/Local State' ) . resolves ( { local : 'value' } )
1043+
1044+ return chrome . _getChromePreferencesWithDefaults ( '/foo' )
1045+ . then ( ( result ) => {
1046+ expect ( result ) . to . deep . eq ( mockDefaults )
1047+ } )
1048+ . finally ( ( ) => {
1049+ chrome . _getDefaultChromePreferences . restore ( )
1050+ } )
1051+ } )
1052+
1053+ it ( 'returns defaults when no existing preferences' , ( ) => {
1054+ const mockDefaults = {
1055+ default : { test : 'default' } ,
1056+ defaultSecure : { secure : 'default' } ,
1057+ localState : { local : 'default' } ,
1058+ }
1059+
1060+ sinon . stub ( chrome , '_getDefaultChromePreferences' ) . returns ( mockDefaults )
1061+
1062+ fs . readJson . withArgs ( '/foo/Default/Preferences' ) . rejects ( { code : 'ENOENT' } )
1063+ fs . readJson . withArgs ( '/foo/Default/Secure Preferences' ) . rejects ( { code : 'ENOENT' } )
1064+ fs . readJson . withArgs ( '/foo/Local State' ) . rejects ( { code : 'ENOENT' } )
1065+
1066+ return chrome . _getChromePreferencesWithDefaults ( '/foo' )
1067+ . then ( ( result ) => {
1068+ expect ( result ) . to . deep . eq ( mockDefaults )
1069+ } )
1070+ . finally ( ( ) => {
1071+ chrome . _getDefaultChromePreferences . restore ( )
1072+ } )
1073+ } )
1074+ } )
1075+
1076+ context ( '#_getChromePreferences with IGNORE_CHROME_PREFERENCES' , ( ) => {
1077+ beforeEach ( ( ) => {
1078+ process . env . IGNORE_CHROME_PREFERENCES = 'true'
1079+ } )
1080+
1081+ afterEach ( ( ) => {
1082+ delete process . env . IGNORE_CHROME_PREFERENCES
1083+ } )
1084+
1085+ it ( 'returns empty preferences when IGNORE_CHROME_PREFERENCES is set' , ( ) => {
1086+ return chrome . _getChromePreferences ( '/foo' )
1087+ . then ( ( result ) => {
1088+ expect ( result ) . to . deep . eq ( {
1089+ default : { } ,
1090+ defaultSecure : { } ,
1091+ localState : { } ,
1092+ } )
1093+ } )
1094+ } )
1095+ } )
1096+
1097+ context ( '#_writeChromePreferences with IGNORE_CHROME_PREFERENCES' , ( ) => {
1098+ beforeEach ( ( ) => {
1099+ process . env . IGNORE_CHROME_PREFERENCES = 'true'
1100+ } )
1101+
1102+ afterEach ( ( ) => {
1103+ delete process . env . IGNORE_CHROME_PREFERENCES
1104+ } )
1105+
1106+ it ( 'does not write preferences when IGNORE_CHROME_PREFERENCES is set' , ( ) => {
1107+ const outputJson = sinon . stub ( fs , 'outputJson' )
1108+
1109+ const originalPrefs = { default : { } , defaultSecure : { } , localState : { } }
1110+ const newPrefs = { default : { test : 'value' } , defaultSecure : { } , localState : { } }
1111+
1112+ return chrome . _writeChromePreferences ( '/foo' , originalPrefs , newPrefs )
1113+ . then ( ( ) => {
1114+ expect ( outputJson ) . to . not . be . called
1115+ } )
1116+ } )
1117+ } )
1118+
1119+ context ( '#_mergeChromePreferences with user preferences' , ( ) => {
1120+ it ( 'merges user preferences with defaults correctly' , ( ) => {
1121+ const defaultPrefs = chrome . _getDefaultChromePreferences ( )
1122+ const userPrefs = {
1123+ default : {
1124+ fake_preference : {
1125+ value : 'value' ,
1126+ } ,
1127+ newSetting : 'userValue' , // User adds new setting
1128+ } ,
1129+ defaultSecure : {
1130+ fake_secure_preference : {
1131+ value : 'value' ,
1132+ } ,
1133+ } ,
1134+ localState : {
1135+ fake_local_state : {
1136+ value : 'value' ,
1137+ } ,
1138+ newLocalSetting : 'userValue' , // User adds new setting
1139+ } ,
1140+ }
1141+
1142+ const result = chrome . _mergeChromePreferences ( defaultPrefs , userPrefs )
1143+
1144+ expect ( result . default ) . to . deep . eq ( {
1145+ fake_preference : {
1146+ value : 'value' ,
1147+ } ,
1148+ newSetting : 'userValue' , // User addition
1149+ } )
1150+
1151+ expect ( result . localState ) . to . deep . eq ( {
1152+ fake_local_state : {
1153+ value : 'value' ,
1154+ } ,
1155+ newLocalSetting : 'userValue' , // User addition
1156+ } )
1157+ } )
1158+
1159+ it ( 'handles preference deletion with null values' , ( ) => {
1160+ const originalPrefs = {
1161+ default : {
1162+ keepThis : 'value' ,
1163+ deleteThis : 'value' ,
1164+ } ,
1165+ defaultSecure : {
1166+ keepThis : 'value' ,
1167+ deleteThis : 'value' ,
1168+ } ,
1169+ localState : {
1170+ keepThis : 'value' ,
1171+ deleteThis : 'value' ,
1172+ } ,
1173+ }
1174+
1175+ const newPrefs = {
1176+ default : {
1177+ deleteThis : null , // Should be deleted
1178+ addThis : 'newValue' ,
1179+ } ,
1180+ defaultSecure : {
1181+ deleteThis : null , // Should be deleted
1182+ } ,
1183+ localState : {
1184+ deleteThis : null , // Should be deleted
1185+ addThis : 'newValue' ,
1186+ } ,
1187+ }
1188+
1189+ const result = chrome . _mergeChromePreferences ( originalPrefs , newPrefs )
1190+
1191+ expect ( result . default ) . to . deep . eq ( {
1192+ keepThis : 'value' ,
1193+ addThis : 'newValue' ,
1194+ } )
1195+
1196+ expect ( result . defaultSecure ) . to . deep . eq ( {
1197+ keepThis : 'value' ,
1198+ } )
1199+
1200+ expect ( result . localState ) . to . deep . eq ( {
1201+ keepThis : 'value' ,
1202+ addThis : 'newValue' ,
1203+ } )
1204+ } )
1205+ } )
1206+
1207+ context ( '#_getChromePreferences error handling' , ( ) => {
1208+ beforeEach ( ( ) => {
1209+ sinon . stub ( fs , 'readJson' )
1210+ } )
1211+
1212+ afterEach ( ( ) => {
1213+ fs . readJson . restore ( )
1214+ } )
1215+
1216+ it ( 'handles corrupted preference files gracefully' , ( ) => {
1217+ fs . readJson . withArgs ( '/foo/Default/Preferences' ) . rejects ( { code : 'ENOENT' } )
1218+ fs . readJson . withArgs ( '/foo/Default/Secure Preferences' ) . rejects ( new Error ( 'Invalid JSON' ) )
1219+ fs . readJson . withArgs ( '/foo/Local State' ) . resolves ( { valid : 'data' } )
1220+
1221+ return chrome . _getChromePreferences ( '/foo' )
1222+ . then ( ( ) => {
1223+ expect . fail ( 'Should have thrown an error for corrupted file' )
1224+ } )
1225+ . catch ( ( err ) => {
1226+ expect ( err . message ) . to . include ( 'Invalid JSON' )
1227+ } )
1228+ } )
1229+
1230+ it ( 'handles missing files gracefully' , ( ) => {
1231+ fs . readJson . withArgs ( '/foo/Default/Preferences' ) . rejects ( { code : 'ENOENT' } )
1232+ fs . readJson . withArgs ( '/foo/Default/Secure Preferences' ) . rejects ( { code : 'ENOENT' } )
1233+ fs . readJson . withArgs ( '/foo/Local State' ) . rejects ( { code : 'ENOENT' } )
1234+
1235+ return chrome . _getChromePreferences ( '/foo' )
1236+ . then ( ( result ) => {
1237+ expect ( result ) . to . deep . eq ( {
1238+ default : { } ,
1239+ defaultSecure : { } ,
1240+ localState : { } ,
1241+ } )
1242+ } )
1243+ } )
1244+ } )
1245+
1246+ context ( '#open integration with preferences' , ( ) => {
1247+ beforeEach ( function ( ) {
1248+ // Mock all the dependencies
1249+ this . pageCriClient = {
1250+ send : sinon . stub ( ) . resolves ( ) ,
1251+ Page : { screencastFrame : sinon . stub ( ) . returns ( ) } ,
1252+ close : sinon . stub ( ) . resolves ( ) ,
1253+ on : sinon . stub ( ) ,
1254+ }
1255+
1256+ this . browserCriClient = {
1257+ attachToTargetUrl : sinon . stub ( ) . resolves ( this . pageCriClient ) ,
1258+ close : sinon . stub ( ) . resolves ( ) ,
1259+ getWebSocketDebuggerUrl : sinon . stub ( ) . returns ( 'ws://debugger' ) ,
1260+ resetBrowserTargets : sinon . stub ( ) . resolves ( ) ,
1261+ }
1262+
1263+ this . automation = {
1264+ push : sinon . stub ( ) ,
1265+ use : sinon . stub ( ) . returns ( ) ,
1266+ onServiceWorkerClientEvent : sinon . stub ( ) ,
1267+ }
1268+
1269+ this . launchedBrowser = {
1270+ kill : sinon . stub ( ) . returns ( ) ,
1271+ }
1272+
1273+ sinon . stub ( chrome , '_writeExtension' ) . resolves ( '/path/to/ext' )
1274+ sinon . stub ( BrowserCriClient , 'create' ) . resolves ( this . browserCriClient )
1275+ sinon . stub ( utils , 'getProfileDir' ) . returns ( '/profile/dir' )
1276+ sinon . stub ( utils , 'ensureCleanCache' ) . resolves ( '/profile/dir/CypressCache' )
1277+ sinon . stub ( utils , 'initializeCDP' ) . resolves ( )
1278+ sinon . stub ( utils , 'getDefaultLaunchOptions' ) . returns ( { args : [ ] , preferences : null } )
1279+ sinon . stub ( utils , 'executeBeforeBrowserLaunch' ) . resolves ( { args : [ ] , preferences : null } )
1280+ sinon . stub ( utils , 'executeAfterBrowserLaunch' ) . resolves ( )
1281+ sinon . stub ( protocol , 'getRemoteDebuggingPort' ) . resolves ( 50505 )
1282+ sinon . stub ( launch , 'launch' ) . resolves ( this . launchedBrowser )
1283+
1284+ this . readJson = sinon . stub ( fs , 'readJson' )
1285+ this . readJson . withArgs ( '/profile/dir/Default/Preferences' ) . rejects ( { code : 'ENOENT' } )
1286+ this . readJson . withArgs ( '/profile/dir/Default/Secure Preferences' ) . rejects ( { code : 'ENOENT' } )
1287+ this . readJson . withArgs ( '/profile/dir/Local State' ) . rejects ( { code : 'ENOENT' } )
1288+
1289+ this . outputJson = sinon . stub ( fs , 'outputJson' )
1290+ this . outputJson . resolves ( )
1291+ } )
1292+
1293+ afterEach ( function ( ) {
1294+ launch . launch . restore ( )
1295+ protocol . getRemoteDebuggingPort . restore ( )
1296+ fs . readJson . restore ( )
1297+ fs . outputJson . restore ( )
1298+ } )
1299+
1300+ it ( 'writes default preferences during browser launch' , async function ( ) {
1301+ await chrome . open ( { isHeadless : true } , 'http://localhost:3000' , openOpts , this . automation )
1302+
1303+ // Verify that default preferences were written
1304+ expect ( this . outputJson ) . to . have . been . calledWith (
1305+ '/profile/dir/Default/Preferences' ,
1306+ sinon . match ( {
1307+ fake_preference : {
1308+ value : 'value' ,
1309+ } ,
1310+ } ) ,
1311+ )
1312+
1313+ expect ( this . outputJson ) . to . have . been . calledWith (
1314+ '/profile/dir/Local State' ,
1315+ sinon . match ( {
1316+ fake_local_state : {
1317+ value : 'value' ,
1318+ } ,
1319+ } ) ,
1320+ )
1321+ } )
1322+
1323+ it ( 'merges user preferences with defaults during launch' , async function ( ) {
1324+ const userPreferences = {
1325+ default : {
1326+ fake_preference : {
1327+ value : 'value' ,
1328+ } ,
1329+ customSetting : 'userValue' ,
1330+ } ,
1331+ localState : {
1332+ fake_local_state : {
1333+ value : 'value' ,
1334+ } ,
1335+ } ,
1336+ }
1337+
1338+ utils . executeBeforeBrowserLaunch . resolves ( {
1339+ args : [ ] ,
1340+ preferences : userPreferences ,
1341+ } )
1342+
1343+ await chrome . open ( { isHeadless : true } , 'http://localhost:3000' , openOpts , this . automation )
1344+
1345+ // Verify that merged preferences were written
1346+ expect ( this . outputJson ) . to . have . been . calledWith (
1347+ '/profile/dir/Default/Preferences' ,
1348+ sinon . match ( {
1349+ fake_preference : {
1350+ value : 'value' ,
1351+ } ,
1352+ customSetting : 'userValue' , // User addition
1353+ } ) ,
1354+ )
1355+
1356+ expect ( this . outputJson ) . to . have . been . calledWith (
1357+ '/profile/dir/Local State' ,
1358+ sinon . match ( {
1359+ browser : {
1360+ fake_local_state : {
1361+ value : 'value' ,
1362+ } ,
1363+ } ,
1364+ } ) ,
1365+ )
1366+ } )
1367+ } )
9971368} )
0 commit comments