From 355c5dabea80330952705570cd0e48ef1633a3fc Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Mon, 12 Dec 2022 18:03:58 +0100 Subject: [PATCH] fix: Update Simulator preferences configuration (#347) --- lib/simulator-xcode-6.js | 2 +- lib/simulator-xcode-9.js | 82 +++++++++++++++++++++++++- test/functional/simulator-e2e-specs.js | 19 +----- 3 files changed, 85 insertions(+), 18 deletions(-) diff --git a/lib/simulator-xcode-6.js b/lib/simulator-xcode-6.js index c4e66bc..b493d09 100644 --- a/lib/simulator-xcode-6.js +++ b/lib/simulator-xcode-6.js @@ -756,7 +756,7 @@ class SimulatorXcode6 extends EventEmitter { * @param {boolean} authorized - Whether or not to authorize. */ async updateLocationSettings (bundleId, authorized) { - return await settings.updateLocationSettings(this, bundleId, authorized); + await this.setPermission(bundleId, 'location', authorized ? 'always' : 'never'); } /** diff --git a/lib/simulator-xcode-9.js b/lib/simulator-xcode-9.js index fde59e6..af9101a 100644 --- a/lib/simulator-xcode-9.js +++ b/lib/simulator-xcode-9.js @@ -5,12 +5,13 @@ import { fs, timing, util } from '@appium/support'; import AsyncLock from 'async-lock'; import log from './logger'; import { waitForCondition } from 'asyncbox'; -import { toBiometricDomainComponent, getDeveloperRoot } from './utils.js'; +import { toBiometricDomainComponent, getDeveloperRoot, MOBILE_SAFARI_BUNDLE_ID } from './utils.js'; import { NSUserDefaults, generateDefaultsCommandArgs } from './defaults-utils'; import B from 'bluebird'; import { EventEmitter } from 'events'; import { getPath as getXcodePath } from 'appium-xcode'; import { exec } from 'teen_process'; +import { PLIST_IDENTIFIER } from './settings'; const SIMULATOR_SHUTDOWN_TIMEOUT = 15 * 1000; const startupLock = new AsyncLock(); @@ -587,6 +588,85 @@ class SimulatorXcode9 extends SimulatorXcode8 { return true; } + /** + * Since Xcode 9 Simulator Safari has been moved to a container, and its settings + * are not being exposed globally anymore. + * + * @override + */ + async updateSafariGlobalSettings (updates) { + await this.updateSafariSettings(updates); + } + + /** + * + * @param {object} updates An object containing Safari settings to be updated. + * The list of available setting names and their values could be retrived by + * changing the corresponding Safari settings in the UI and then inspecting + * 'Library/Preferences/com.apple.mobilesafari.plist' file inside of + * com.apple.mobilesafari app container. + * The full path to the Mobile Safari's container could be retrieved from + * `xcrun simctl get_app_container com.apple.mobilesafari data` + * command output. + * Use the `xcrun simctl spawn defaults read ` command + * to print the plist content to the Terminal. + * + * @override + */ + async updateSafariSettings (updates) { + if (_.isEmpty(updates)) { + return false; + } + + const containerRoot = await this.simctl.getAppContainer(MOBILE_SAFARI_BUNDLE_ID, 'data'); + const plistPath = path.join(containerRoot, 'Library', 'Preferences', 'com.apple.mobilesafari.plist'); + return await this.updateSettings(plistPath, updates); + } + + /** + * @override + */ + async setReduceMotion (reduceMotion = true) { + return await this.updateSettings('com.apple.Accessibility', { + ReduceMotionEnabled: Number(reduceMotion) + }); + } + + /** + * @override + */ + async setReduceTransparency (reduceTransparency) { + return await this.updateSettings('com.apple.Accessibility', { + EnhancedBackgroundContrastEnabled: Number(reduceTransparency) + }); + } + + /** + * Allows to update Simulator preferences in runtime. + * + * @param {string} domain The name of preferences domain to be updated, + * for example, 'com.apple.Preferences' or 'com.apple.Accessibility' or + * full path to a plist file on the local file system. + * @param {object} updates Mapping of keys/values to be updated + * + * @override + */ + async updateSettings (domain, updates) { + if (_.isEmpty(updates)) { + return false; + } + + if (_.keys(PLIST_IDENTIFIER).includes(domain)) { + // TODO: This is to keep the backward compatibility + return await super.updateSettings(domain, updates); + } + + const argChunks = generateDefaultsCommandArgs(updates); + await B.all(argChunks.map((args) => this.simctl.spawnProcess([ + 'defaults', 'write', domain, ...args + ]))); + return true; + } } export default SimulatorXcode9; diff --git a/test/functional/simulator-e2e-specs.js b/test/functional/simulator-e2e-specs.js index 4045239..e4ae0de 100644 --- a/test/functional/simulator-e2e-specs.js +++ b/test/functional/simulator-e2e-specs.js @@ -433,24 +433,11 @@ describe('advanced features', function () { }); describe('updateSafariGlobalSettings', function () { - it('should set an arbitrary preference on the global Safari plist', async function () { + it('should set arbitrary preferences on Safari', async function () { await sim.updateSafariGlobalSettings({ - DidImportBuiltinBookmarks: true, + ShowTabBar: 1, + DidImportBuiltinBookmarks: 1, }); - let setSettings = await readSettings(sim, PLIST_IDENTIFIER.GLOBAL_MOBILE_SAFARI); - for (const [file, settings] of _.toPairs(setSettings)) { - file.endsWith('data/Library/Preferences/com.apple.mobilesafari.plist').should.be.true; - settings.DidImportBuiltinBookmarks.should.eql(true); - } - - await sim.updateSafariGlobalSettings({ - DidImportBuiltinBookmarks: false, - }); - setSettings = await readSettings(sim, PLIST_IDENTIFIER.GLOBAL_MOBILE_SAFARI); - for (const [file, settings] of _.toPairs(setSettings)) { - file.endsWith('data/Library/Preferences/com.apple.mobilesafari.plist').should.be.true; - settings.DidImportBuiltinBookmarks.should.eql(false); - } }); }); });