diff --git a/detox/src/devices/Device.js b/detox/src/devices/Device.js index c4bca2e6f1..6dc526bca1 100644 --- a/detox/src/devices/Device.js +++ b/detox/src/devices/Device.js @@ -161,6 +161,10 @@ class Device { await this.deviceDriver.disableSynchronization(); } + async resetContentAndSettings() { + await this.deviceDriver.resetContentAndSettings(this._deviceId); + } + getPlatform() { return this.deviceDriver.getPlatform(this._deviceId); } diff --git a/detox/src/devices/Device.test.js b/detox/src/devices/Device.test.js index a7b4ad5dcc..86fb97c5b4 100644 --- a/detox/src/devices/Device.test.js +++ b/detox/src/devices/Device.test.js @@ -389,6 +389,13 @@ describe('Device', () => { expect(device.deviceDriver.disableSynchronization).toHaveBeenCalledTimes(1); }); + it(`resetContentAndSettings() should pass to device driver`, async () => { + device = validDevice(); + await device.resetContentAndSettings(); + + expect(device.deviceDriver.resetContentAndSettings).toHaveBeenCalledTimes(1); + }); + it(`getPlatform() should pass to device driver`, async () => { device = validDevice(); device.getPlatform(); diff --git a/detox/src/devices/DeviceDriverBase.js b/detox/src/devices/DeviceDriverBase.js index d27c03b7e4..c3ae187819 100644 --- a/detox/src/devices/DeviceDriverBase.js +++ b/detox/src/devices/DeviceDriverBase.js @@ -87,6 +87,10 @@ class DeviceDriverBase { return await Promise.resolve(''); } + async resetContentAndSettings() { + return await Promise.resolve(''); + } + defaultLaunchArgsPrefix() { return ''; } diff --git a/detox/src/devices/Fbsimctl.js b/detox/src/devices/Fbsimctl.js index a49dab9def..62ca57a521 100644 --- a/detox/src/devices/Fbsimctl.js +++ b/detox/src/devices/Fbsimctl.js @@ -173,6 +173,14 @@ class Fbsimctl { await this._execFbsimctlCommand(options); } + async resetContentAndSettings(udid) { + await this.shutdown(udid); + const result = await exec.execWithRetriesAndLogs(`/usr/bin/xcrun simctl erase ${udid}`); + const resultCode = parseInt(result.stdout.trim().split(':')[1]); + await this.boot(udid); + return resultCode; + } + async _execFbsimctlCommand(options, statusLogs, retries, interval) { const bin = `fbsimctl --json`; return await exec.execWithRetriesAndLogs(bin, options, statusLogs, retries, interval); diff --git a/detox/src/devices/Fbsimctl.test.js b/detox/src/devices/Fbsimctl.test.js index c02a1af6a8..ab77b21581 100644 --- a/detox/src/devices/Fbsimctl.test.js +++ b/detox/src/devices/Fbsimctl.test.js @@ -168,6 +168,17 @@ describe('Fbsimctl', () => { await validateFbsimctlisCalledOn(fbsimctl, async () => fbsimctl.setLocation(simUdid)); }); + it(`resetContentAndSettings() - is triggering shutdown, exec and boot`, async() => { + fs.existsSync.mockReturnValue(true); + exec.mockReturnValue({stdout: "appId: 22 \n"}); + fbsimctl.shutdown = jest.fn(); + fbsimctl.boot = jest.fn(); + await fbsimctl.resetContentAndSettings(simUdid); + expect(fbsimctl.shutdown).toHaveBeenCalledTimes(1); + expect(exec).toHaveBeenCalledTimes(1); + expect(fbsimctl.boot).toHaveBeenCalledTimes(1); + }); + it(`exec simulator command successfully`, async() => { const result = returnSuccessfulWithValue(""); exec.mockReturnValue(Promise.resolve(result)); diff --git a/detox/src/devices/SimulatorDriver.js b/detox/src/devices/SimulatorDriver.js index 75b5170b5b..71c6da3258 100644 --- a/detox/src/devices/SimulatorDriver.js +++ b/detox/src/devices/SimulatorDriver.js @@ -65,6 +65,10 @@ class SimulatorDriver extends IosDriver { await this._applesimutils.setPermissions(deviceId, bundleId, permissions); } + async resetContentAndSettings(deviceId) { + return await this._fbsimctl.resetContentAndSettings(deviceId); + } + validateDeviceConfig(deviceConfig) { if (!deviceConfig.binaryPath) { configuration.throwOnEmptyBinaryPath(); diff --git a/detox/test/e2e/f-device.js b/detox/test/e2e/f-device.js index 44483d4d3e..71be8c9aba 100644 --- a/detox/test/e2e/f-device.js +++ b/detox/test/e2e/f-device.js @@ -39,6 +39,15 @@ describe('Device', () => { await expect(element(by.label('Hello!!!'))).toBeVisible(); }); + it('resetContentAndSettings() + install() + relaunch() - should tap successfully', async () => { + await device.resetContentAndSettings(); + await device.installApp(); + await device.launchApp({ newInstance: true }); + await element(by.label('Sanity')).tap(); + await element(by.label('Say Hello')).tap(); + await expect(element(by.label('Hello!!!'))).toBeVisible(); + }); + describe('device orientation', () => { beforeEach(async() => { await device.reloadReactNative(); diff --git a/docs/APIRef.DeviceObjectAPI.md b/docs/APIRef.DeviceObjectAPI.md index f9a24fa0d9..c4a9f05d01 100644 --- a/docs/APIRef.DeviceObjectAPI.md +++ b/docs/APIRef.DeviceObjectAPI.md @@ -18,6 +18,7 @@ - [`device.setURLBlacklist([urls])`](#deviceseturlblacklisturls) - [`device.enableSynchronization()`](#deviceenablesynchronization) - [`device.disableSynchronization()`](#devicedisablesynchronization) +- [`device.resetContentAndSettings()`](#resetcontentandsettings) ### `device.launchApp(params)` Launch the app defined in the current [`configuration`](APIRef.Configuration.md). @@ -190,4 +191,13 @@ Disable [EarlGrey's synchronization mechanism](https://github.com/google/EarlGre ```js await device.disableSynchronization(); -``` \ No newline at end of file +``` + + +### `device.resetContentAndSettings()` +Resets the Simulator to clean state (like the Simulator > Reset Content and Settings... menu item), especially removing +previously set permissions. + +```js +await device.resetContentAndSettings(); +```