detox 20.15.1-prerelease.0 → 20.16.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.js +0 -4
- package/Detox-android/com/wix/detox/{20.15.0-prerelease.0/detox-20.15.0-prerelease.0-javadoc.jar → 20.16.0/detox-20.16.0-javadoc.jar} +0 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-javadoc.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-javadoc.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-javadoc.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-javadoc.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.15.0-prerelease.0/detox-20.15.0-prerelease.0-sources.jar → 20.16.0/detox-20.16.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.aar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.aar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.aar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.aar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.15.0-prerelease.0/detox-20.15.0-prerelease.0.pom → 20.16.0/detox-20.16.0.pom} +1 -1
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.16.0/detox-20.16.0.pom.sha512 +1 -0
- package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
- package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
- package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios.tbz +0 -0
- package/android/detox/proguard-rules-app.pro +1 -2
- package/android/detox/src/full/java/com/wix/detox/espresso/DetoxAction.java +11 -6
- package/android/detox/src/main/java/com/wix/detox/espresso/DeviceDisplay.kt +1 -1
- package/android/detox/src/main/java/com/wix/detox/espresso/scroll/ScrollHelper.java +113 -16
- package/android/detox/src/testFull/java/com/wix/detox/espresso/scroll/ScrollHelperTest.kt +188 -0
- package/detox.d.ts +26 -20
- package/jest.config.js +1 -1
- package/local-cli/init.js +1 -1
- package/package.json +16 -16
- package/runners/jest/testEnvironment/index.js +24 -9
- package/src/DetoxWorker.js +1 -1
- package/src/android/actions/native.js +2 -2
- package/src/android/core/NativeElement.js +3 -4
- package/src/android/espressoapi/DetoxAction.js +9 -1
- package/src/android/interactions/native.js +2 -2
- package/src/android/matchers/native.js +1 -1
- package/src/artifacts/providers/index.js +1 -1
- package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +0 -1
- package/src/artifacts/templates/artifact/Artifact.js +1 -1
- package/src/client/AsyncWebSocket.js +2 -2
- package/src/client/Client.js +2 -2
- package/src/devices/allocation/drivers/android/attached/AttachedAndroidAllocDriver.js +0 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +0 -1
- package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +1 -1
- package/src/devices/allocation/drivers/ios/SimulatorAllocDriver.js +0 -1
- package/src/devices/allocation/factories/android.js +1 -1
- package/src/devices/allocation/factories/ios.js +1 -1
- package/src/devices/common/drivers/android/exec/ADB.js +1 -2
- package/src/devices/common/drivers/android/tools/ApkValidator.js +1 -1
- package/src/devices/common/drivers/android/tools/AppInstallHelper.js +0 -2
- package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +111 -15
- package/src/devices/runtime/drivers/android/AndroidDriver.js +1 -1
- package/src/devices/runtime/drivers/android/emulator/EmulatorDriver.js +0 -1
- package/src/devices/runtime/factories/ios.js +0 -2
- package/src/ios/expectTwo.js +6 -3
- package/src/ipc/IPCClient.js +2 -2
- package/src/ipc/IPCServer.js +4 -4
- package/src/realms/DetoxContext.js +3 -3
- package/src/realms/DetoxPrimaryContext.js +74 -29
- package/src/realms/DetoxSecondaryContext.js +2 -2
- package/src/utils/childProcess/exec.js +3 -2
- package/src/utils/invocationTraceDescriptions.js +3 -2
- package/tsconfig.json +1 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-javadoc.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-javadoc.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-javadoc.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-javadoc.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.aar +0 -0
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.aar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.aar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.aar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.aar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.15.0-prerelease.0/detox-20.15.0-prerelease.0.pom.sha512 +0 -1
package/detox.d.ts
CHANGED
@@ -214,7 +214,7 @@ declare global {
|
|
214
214
|
* This flag tells Detox to print messages like these every time the device gets assigned to a specific suite:
|
215
215
|
*
|
216
216
|
* ```plain text
|
217
|
-
* 18:03:29.869 detox[40125] i starter.test.js is assigned to 4EC84833-C7EA-4CA3-A6E9-5C30A29EA596 (iPhone
|
217
|
+
* 18:03:29.869 detox[40125] i starter.test.js is assigned to 4EC84833-C7EA-4CA3-A6E9-5C30A29EA596 (iPhone 15)
|
218
218
|
* ```
|
219
219
|
*
|
220
220
|
* @default true
|
@@ -644,10 +644,11 @@ declare global {
|
|
644
644
|
*/
|
645
645
|
selectApp(app: string): Promise<void>;
|
646
646
|
|
647
|
+
// TODO: document permissions types.
|
647
648
|
/**
|
648
649
|
* Launch the app.
|
649
650
|
*
|
650
|
-
* <p>For info regarding launch arguments, refer to the [dedicated guide](https://wix.github.io/Detox/docs/
|
651
|
+
* <p>For info regarding launch arguments, refer to the [dedicated guide](https://wix.github.io/Detox/docs/guide/launch-args).
|
651
652
|
*
|
652
653
|
* @example
|
653
654
|
* // Terminate the app and launch it again. If set to false, the simulator will try to bring app from background,
|
@@ -1363,10 +1364,13 @@ declare global {
|
|
1363
1364
|
|
1364
1365
|
/**
|
1365
1366
|
* Scroll to edge.
|
1366
|
-
* @
|
1367
|
+
* @param edge - left|right|top|bottom
|
1368
|
+
* @param startPositionX - the X starting scroll position, in percentage; valid input: `[0.0, 1.0]`, `NaN`; default: `NaN`—choose the best value automatically
|
1369
|
+
* @param startPositionY - the Y starting scroll position, in percentage; valid input: `[0.0, 1.0]`, `NaN`; default: `NaN`—choose the best value automatically
|
1370
|
+
* @example await element(by.id('scrollView')).scrollTo('bottom', NaN, 0.85);
|
1367
1371
|
* @example await element(by.id('scrollView')).scrollTo('top');
|
1368
1372
|
*/
|
1369
|
-
scrollTo(edge: Direction): Promise<void>;
|
1373
|
+
scrollTo(edge: Direction, startPositionX?: number, startPositionY?: number): Promise<void>;
|
1370
1374
|
|
1371
1375
|
/**
|
1372
1376
|
* Adjust slider to position.
|
@@ -1621,23 +1625,25 @@ declare global {
|
|
1621
1625
|
userTracking?: UserTrackingPermission;
|
1622
1626
|
}
|
1623
1627
|
|
1628
|
+
type BasicPermissionState = 'YES' | 'NO' | 'unset';
|
1629
|
+
type ExtendedPermissionState = 'YES' | 'NO' | 'unset' | 'limited';
|
1624
1630
|
type LocationPermission = 'always' | 'inuse' | 'never' | 'unset';
|
1625
|
-
|
1626
|
-
type CameraPermission =
|
1627
|
-
type ContactsPermission =
|
1628
|
-
type CalendarPermission =
|
1629
|
-
type HealthPermission =
|
1630
|
-
type HomekitPermission =
|
1631
|
-
type MediaLibraryPermission =
|
1632
|
-
type MicrophonePermission =
|
1633
|
-
type MotionPermission =
|
1634
|
-
type PhotosPermission =
|
1635
|
-
type RemindersPermission =
|
1636
|
-
type SiriPermission =
|
1637
|
-
type SpeechPermission =
|
1638
|
-
type NotificationsPermission =
|
1639
|
-
type FaceIDPermission =
|
1640
|
-
type UserTrackingPermission =
|
1631
|
+
|
1632
|
+
type CameraPermission = BasicPermissionState;
|
1633
|
+
type ContactsPermission = ExtendedPermissionState;
|
1634
|
+
type CalendarPermission = BasicPermissionState;
|
1635
|
+
type HealthPermission = BasicPermissionState;
|
1636
|
+
type HomekitPermission = BasicPermissionState;
|
1637
|
+
type MediaLibraryPermission = BasicPermissionState;
|
1638
|
+
type MicrophonePermission = BasicPermissionState;
|
1639
|
+
type MotionPermission = BasicPermissionState;
|
1640
|
+
type PhotosPermission = ExtendedPermissionState;
|
1641
|
+
type RemindersPermission = BasicPermissionState;
|
1642
|
+
type SiriPermission = BasicPermissionState;
|
1643
|
+
type SpeechPermission = BasicPermissionState;
|
1644
|
+
type NotificationsPermission = BasicPermissionState;
|
1645
|
+
type FaceIDPermission = BasicPermissionState;
|
1646
|
+
type UserTrackingPermission = BasicPermissionState;
|
1641
1647
|
|
1642
1648
|
interface DeviceLaunchAppConfig {
|
1643
1649
|
/**
|
package/jest.config.js
CHANGED
package/local-cli/init.js
CHANGED
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "detox",
|
3
3
|
"description": "E2E tests and automation for mobile",
|
4
|
-
"version": "20.
|
4
|
+
"version": "20.16.0",
|
5
5
|
"bin": {
|
6
6
|
"detox": "local-cli/cli.js"
|
7
7
|
},
|
@@ -36,27 +36,26 @@
|
|
36
36
|
"devDependencies": {
|
37
37
|
"@types/bunyan": "^1.8.8",
|
38
38
|
"@types/child-process-promise": "^2.2.1",
|
39
|
-
"@types/fs-extra": "^
|
40
|
-
"@types/jest": "^
|
39
|
+
"@types/fs-extra": "^11.0.4",
|
40
|
+
"@types/jest": "^29.0.0",
|
41
41
|
"@types/node": "^14.18.33",
|
42
42
|
"@types/node-ipc": "^9.2.0",
|
43
43
|
"@types/ws": "^7.4.0",
|
44
|
-
"@typescript-eslint/eslint-plugin": "^
|
45
|
-
"@typescript-eslint/parser": "^
|
44
|
+
"@typescript-eslint/eslint-plugin": "^6.16.0",
|
45
|
+
"@typescript-eslint/parser": "^6.16.0",
|
46
46
|
"cross-env": "^7.0.3",
|
47
|
-
"eslint": "^8.
|
48
|
-
"eslint-plugin-ecmascript-compat": "^3.
|
49
|
-
"eslint-plugin-import": "^2.
|
47
|
+
"eslint": "^8.56.0",
|
48
|
+
"eslint-plugin-ecmascript-compat": "^3.1.0",
|
49
|
+
"eslint-plugin-import": "^2.29.1",
|
50
50
|
"eslint-plugin-no-only-tests": "^3.1.0",
|
51
51
|
"eslint-plugin-node": "^11.1.0",
|
52
|
-
"eslint-plugin-unicorn": "^
|
53
|
-
"jest": "^
|
54
|
-
"jest-allure2-reporter": "2.0.0-
|
55
|
-
"
|
56
|
-
"prettier": "^2.4.1",
|
52
|
+
"eslint-plugin-unicorn": "^50.0.1",
|
53
|
+
"jest": "^29.0.0",
|
54
|
+
"jest-allure2-reporter": "^2.0.0-beta.4",
|
55
|
+
"prettier": "^3.1.1",
|
57
56
|
"react-native": "0.71.10",
|
58
57
|
"react-native-codegen": "^0.0.8",
|
59
|
-
"typescript": "^
|
58
|
+
"typescript": "^5.3.3",
|
60
59
|
"wtfnode": "^0.9.1"
|
61
60
|
},
|
62
61
|
"dependencies": {
|
@@ -72,6 +71,7 @@
|
|
72
71
|
"funpermaproxy": "^1.1.0",
|
73
72
|
"glob": "^8.0.3",
|
74
73
|
"ini": "^1.3.4",
|
74
|
+
"jest-environment-emit": "^1.0.5",
|
75
75
|
"json-cycle": "^1.3.0",
|
76
76
|
"lodash": "^4.17.11",
|
77
77
|
"multi-sort-stream": "^1.0.3",
|
@@ -104,10 +104,10 @@
|
|
104
104
|
}
|
105
105
|
},
|
106
106
|
"engines": {
|
107
|
-
"node": ">=14.
|
107
|
+
"node": ">=14.14.0"
|
108
108
|
},
|
109
109
|
"browserslist": [
|
110
110
|
"node 14"
|
111
111
|
],
|
112
|
-
"gitHead": "
|
112
|
+
"gitHead": "3d7cb5de27cf768dca7216e60806819672553f4a"
|
113
113
|
}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
const path = require('path');
|
2
2
|
|
3
|
+
const WithEmitter = require('jest-environment-emit').default;
|
3
4
|
const resolveFrom = require('resolve-from');
|
4
5
|
const maybeNodeEnvironment = require(resolveFrom(process.cwd(), 'jest-environment-node'));
|
5
6
|
/** @type {typeof import('@jest/environment').JestEnvironment} */
|
@@ -31,7 +32,7 @@ const log = detox.log.child({ cat: 'lifecycle,jest-environment' });
|
|
31
32
|
/**
|
32
33
|
* @see https://www.npmjs.com/package/jest-circus#overview
|
33
34
|
*/
|
34
|
-
class DetoxCircusEnvironment extends NodeEnvironment {
|
35
|
+
class DetoxCircusEnvironment extends WithEmitter(NodeEnvironment) {
|
35
36
|
constructor(config, context) {
|
36
37
|
super(assertJestCircus27(config), assertExistingContext(context));
|
37
38
|
|
@@ -62,6 +63,8 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
62
63
|
SpecReporter,
|
63
64
|
WorkerAssignReporter,
|
64
65
|
});
|
66
|
+
|
67
|
+
this.testEvents.on('*', this._onTestEvent.bind(this));
|
65
68
|
}
|
66
69
|
|
67
70
|
/** @override */
|
@@ -72,19 +75,14 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
72
75
|
|
73
76
|
// @ts-expect-error TS2425
|
74
77
|
async handleTestEvent(event, state) {
|
78
|
+
// @ts-expect-error TS2855
|
79
|
+
await super.handleTestEvent(event, state);
|
80
|
+
|
75
81
|
if (detox.session.unsafe_earlyTeardown) {
|
76
82
|
if (event.name === 'test_fn_start' || event.name === 'hook_start') {
|
77
83
|
throw new Error('Detox halted test execution due to an early teardown request');
|
78
84
|
}
|
79
85
|
}
|
80
|
-
|
81
|
-
this._timer.schedule(state.testTimeout != null ? state.testTimeout : this.setupTimeout);
|
82
|
-
|
83
|
-
if (SYNC_CIRCUS_EVENTS.has(event.name)) {
|
84
|
-
this._handleTestEventSync(event, state);
|
85
|
-
} else {
|
86
|
-
await this._handleTestEventAsync(event, state);
|
87
|
-
}
|
88
86
|
}
|
89
87
|
|
90
88
|
/** @override */
|
@@ -147,6 +145,23 @@ class DetoxCircusEnvironment extends NodeEnvironment {
|
|
147
145
|
}
|
148
146
|
}
|
149
147
|
|
148
|
+
/** @private */
|
149
|
+
_onTestEvent({ type, event, state }) {
|
150
|
+
const timeout = state && state.testTimeout != null ? state.testTimeout : this.setupTimeout;
|
151
|
+
|
152
|
+
this._timer.schedule(timeout);
|
153
|
+
|
154
|
+
if (event) {
|
155
|
+
if (SYNC_CIRCUS_EVENTS.has(event.name)) {
|
156
|
+
this._handleTestEventSync(event, state);
|
157
|
+
} else {
|
158
|
+
return this._handleTestEventAsync(event, state);
|
159
|
+
}
|
160
|
+
} else {
|
161
|
+
return this._handleTestEventAsync({ name: type }, null);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
150
165
|
/** @private */
|
151
166
|
async _handleTestEventAsync(event, state = null) {
|
152
167
|
const description = `handling ${state ? 'jest-circus' : 'jest-environment'} "${event.name}" event`;
|
package/src/DetoxWorker.js
CHANGED
@@ -132,7 +132,7 @@ class DetoxWorker {
|
|
132
132
|
};
|
133
133
|
|
134
134
|
this._artifactsManager = artifactsManagerFactory.createArtifactsManager(this._artifactsConfig, commonDeps);
|
135
|
-
this._deviceCookie = yield this._context[symbols.allocateDevice]();
|
135
|
+
this._deviceCookie = yield this._context[symbols.allocateDevice](this._deviceConfig);
|
136
136
|
|
137
137
|
this.device = runtimeDeviceFactory.createRuntimeDevice(
|
138
138
|
this._deviceCookie,
|
@@ -81,10 +81,10 @@ class ScrollAmountStopAtEdgeAction extends Action {
|
|
81
81
|
}
|
82
82
|
|
83
83
|
class ScrollEdgeAction extends Action {
|
84
|
-
constructor(edge) {
|
84
|
+
constructor(edge, startPositionX = -1, startPositionY = -1) {
|
85
85
|
super();
|
86
86
|
|
87
|
-
this._call = invoke.callDirectly(DetoxActionApi.scrollToEdge(edge));
|
87
|
+
this._call = invoke.callDirectly(DetoxActionApi.scrollToEdge(edge, startPositionX, startPositionY));
|
88
88
|
}
|
89
89
|
}
|
90
90
|
|
@@ -93,12 +93,12 @@ class NativeElement {
|
|
93
93
|
return await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
94
94
|
}
|
95
95
|
|
96
|
-
async scrollTo(edge) {
|
96
|
+
async scrollTo(edge, startPositionX, startPositionY) {
|
97
97
|
// override the user's element selection with an extended matcher that looks for UIScrollView children
|
98
98
|
this._matcher = this._matcher._extendToDescendantScrollViews();
|
99
99
|
|
100
|
-
const action = new actions.ScrollEdgeAction(edge);
|
101
|
-
const traceDescription = actionDescription.scrollTo(edge);
|
100
|
+
const action = new actions.ScrollEdgeAction(edge, startPositionX, startPositionY);
|
101
|
+
const traceDescription = actionDescription.scrollTo(edge, startPositionX, startPositionY);
|
102
102
|
return await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
103
103
|
}
|
104
104
|
|
@@ -140,7 +140,6 @@ class NativeElement {
|
|
140
140
|
}
|
141
141
|
|
142
142
|
async takeScreenshot(screenshotName) {
|
143
|
-
// TODO this should be moved to a lower-layer handler of this use-case
|
144
143
|
const action = new actions.TakeElementScreenshot();
|
145
144
|
const traceDescription = actionDescription.takeScreenshot(screenshotName);
|
146
145
|
const resultBase64 = await new ActionInteraction(this._invocationManager, this._matcher, action, traceDescription).execute();
|
@@ -68,8 +68,10 @@ class DetoxAction {
|
|
68
68
|
};
|
69
69
|
}
|
70
70
|
|
71
|
-
static scrollToEdge(edge) {
|
71
|
+
static scrollToEdge(edge, startOffsetPercentX, startOffsetPercentY) {
|
72
72
|
if (typeof edge !== "string") throw new Error("edge should be a string, but got " + (edge + (" (" + (typeof edge + ")"))));
|
73
|
+
if (typeof startOffsetPercentX !== "number") throw new Error("startOffsetPercentX should be a number, but got " + (startOffsetPercentX + (" (" + (typeof startOffsetPercentX + ")"))));
|
74
|
+
if (typeof startOffsetPercentY !== "number") throw new Error("startOffsetPercentY should be a number, but got " + (startOffsetPercentY + (" (" + (typeof startOffsetPercentY + ")"))));
|
73
75
|
return {
|
74
76
|
target: {
|
75
77
|
type: "Class",
|
@@ -79,6 +81,12 @@ class DetoxAction {
|
|
79
81
|
args: [{
|
80
82
|
type: "Integer",
|
81
83
|
value: sanitize_android_edge(edge)
|
84
|
+
}, {
|
85
|
+
type: "Double",
|
86
|
+
value: startOffsetPercentX
|
87
|
+
}, {
|
88
|
+
type: "Double",
|
89
|
+
value: startOffsetPercentY
|
82
90
|
}]
|
83
91
|
};
|
84
92
|
}
|
@@ -28,7 +28,7 @@ class ActionInteraction extends Interaction {
|
|
28
28
|
constructor(invocationManager, matcher, action, traceDescription) {
|
29
29
|
super(invocationManager, traceDescription);
|
30
30
|
this._call = EspressoDetoxApi.perform(matcher, action._call);
|
31
|
-
// TODO: move this.execute() here from the caller
|
31
|
+
// TODO [2024-12-01]: move this.execute() here from the caller
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
@@ -39,7 +39,7 @@ class MatcherAssertionInteraction extends Interaction {
|
|
39
39
|
|
40
40
|
matcher = notCondition ? matcher.not : matcher;
|
41
41
|
this._call = DetoxAssertionApi.assertMatcher(call(element._call), matcher._call.value);
|
42
|
-
// TODO: move this.execute() here from the caller
|
42
|
+
// TODO [2024-12-01]: move this.execute() here from the caller
|
43
43
|
}
|
44
44
|
}
|
45
45
|
|
@@ -76,7 +76,7 @@ class ToggleMatcher extends NativeMatcher {
|
|
76
76
|
}
|
77
77
|
}
|
78
78
|
|
79
|
-
//
|
79
|
+
// NOTE: Please be aware, that this is just a dummy matcher
|
80
80
|
class TraitsMatcher extends NativeMatcher {
|
81
81
|
constructor(value) {
|
82
82
|
super();
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ArtifactPluginsProvider {
|
2
|
-
declareArtifactPlugins({ client }) {} // eslint-disable-line no-unused-vars
|
2
|
+
declareArtifactPlugins({ client }) {} // eslint-disable-line no-unused-vars,@typescript-eslint/no-unused-vars
|
3
3
|
}
|
4
4
|
|
5
5
|
class AndroidArtifactPluginsProvider extends ArtifactPluginsProvider {
|
@@ -1,7 +1,6 @@
|
|
1
1
|
const path = require('path');
|
2
2
|
|
3
3
|
const fs = require('../../utils/fsext');
|
4
|
-
const log = require('../../utils/logger').child({ cat: 'artifacts-plugin,artifacts' });
|
5
4
|
const FileArtifact = require('../templates/artifact/FileArtifact');
|
6
5
|
const temporaryPath = require('../utils/temporaryPath');
|
7
6
|
|
@@ -134,7 +134,7 @@ class AsyncWebSocket {
|
|
134
134
|
}
|
135
135
|
}
|
136
136
|
|
137
|
-
// TODO: handle this leaked abstraction some day
|
137
|
+
// TODO [2024-12-01]: handle this leaked abstraction some day
|
138
138
|
hasPendingActions() {
|
139
139
|
return _.some(this.inFlightPromises, p => p.message.type !== 'currentStatus');
|
140
140
|
}
|
@@ -168,7 +168,7 @@ class AsyncWebSocket {
|
|
168
168
|
case WebSocket.CONNECTING: return 'opening';
|
169
169
|
case WebSocket.OPEN: return 'open';
|
170
170
|
/* istanbul ignore next */
|
171
|
-
default:
|
171
|
+
default:
|
172
172
|
return undefined;
|
173
173
|
}
|
174
174
|
}
|
package/src/client/Client.js
CHANGED
@@ -187,14 +187,14 @@ class Client {
|
|
187
187
|
this._whenAppIsReady = new Deferred();
|
188
188
|
|
189
189
|
await this._whenAppIsConnected.promise;
|
190
|
-
// TODO: optimize traffic (!) - we can just listen for 'ready' event
|
190
|
+
// TODO [2024-12-01]: optimize traffic (!) - we can just listen for 'ready' event
|
191
191
|
// if app always sends it upon load completion. On iOS it works,
|
192
192
|
// but not on Android. Afterwards, this will suffice:
|
193
193
|
//
|
194
194
|
// await this._whenAppIsReady.promise;
|
195
195
|
}
|
196
196
|
|
197
|
-
// TODO: move to else branch after the optimization
|
197
|
+
// TODO [2024-12-01]: move to else branch after the optimization ↑↑
|
198
198
|
if (!this._whenAppIsReady.isResolved()) {
|
199
199
|
this._whenAppIsReady = new Deferred();
|
200
200
|
await this.sendAction(new actions.Ready());
|
@@ -7,7 +7,7 @@ class EmulatorVersionResolver {
|
|
7
7
|
this.version = undefined;
|
8
8
|
}
|
9
9
|
|
10
|
-
async resolve(isHeadless = false) {
|
10
|
+
async resolve(isHeadless = false) {
|
11
11
|
if (!this.version) {
|
12
12
|
this.version = await this._resolve(isHeadless);
|
13
13
|
}
|
@@ -39,7 +39,6 @@ class SimulatorAllocDriver {
|
|
39
39
|
async allocate(deviceConfig) {
|
40
40
|
const deviceQuery = new SimulatorQuery(deviceConfig.device);
|
41
41
|
|
42
|
-
// TODO Delegate this onto a well tested allocator class
|
43
42
|
const udid = await this._deviceRegistry.registerDevice(async () => {
|
44
43
|
return await this._findOrCreateDevice(deviceQuery);
|
45
44
|
});
|
@@ -42,7 +42,7 @@ class AndroidEmulator extends DeviceAllocatorFactory {
|
|
42
42
|
}
|
43
43
|
|
44
44
|
class AndroidAttached extends DeviceAllocatorFactory {
|
45
|
-
_createDriver({ detoxSession
|
45
|
+
_createDriver({ detoxSession }) {
|
46
46
|
const serviceLocator = require('../../servicelocator/android');
|
47
47
|
const adb = serviceLocator.adb;
|
48
48
|
const DeviceRegistry = require('../../allocation/DeviceRegistry');
|
@@ -2,7 +2,7 @@
|
|
2
2
|
const DeviceAllocatorFactory = require('./base');
|
3
3
|
|
4
4
|
class IosSimulator extends DeviceAllocatorFactory {
|
5
|
-
_createDriver({ detoxConfig, detoxSession
|
5
|
+
_createDriver({ detoxConfig, detoxSession }) {
|
6
6
|
const AppleSimUtils = require('../../../devices/common/drivers/ios/tools/AppleSimUtils');
|
7
7
|
const applesimutils = new AppleSimUtils();
|
8
8
|
|
@@ -8,7 +8,7 @@ const { escape } = require('../../../../../utils/pipeCommands');
|
|
8
8
|
const DeviceHandle = require('../tools/DeviceHandle');
|
9
9
|
const EmulatorHandle = require('../tools/EmulatorHandle');
|
10
10
|
|
11
|
-
const INSTALL_TIMEOUT = 45000;
|
11
|
+
const INSTALL_TIMEOUT = 45000;
|
12
12
|
|
13
13
|
class ADB {
|
14
14
|
constructor() {
|
@@ -345,7 +345,6 @@ class ADB {
|
|
345
345
|
return this.adbCmd(deviceId, `emu kill`);
|
346
346
|
}
|
347
347
|
|
348
|
-
// TODO refactor the whole thing so as to make usage of BinaryExec -- similar to EmulatorExec
|
349
348
|
async adbCmd(deviceId, params, options = {}) {
|
350
349
|
const serial = `${deviceId ? `-s ${deviceId}` : ''}`;
|
351
350
|
const cmd = `"${this.adbBin}" ${serial} ${params}`;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
const DetoxRuntimeError = require('../../../../../errors/DetoxRuntimeError');
|
2
2
|
|
3
|
-
const setupGuideHint = 'For further assistance, visit the
|
3
|
+
const setupGuideHint = 'For further assistance, visit the project setup guide (select the Android tabs): https://wix.github.io/Detox/docs/introduction/project-setup';
|
4
4
|
|
5
5
|
class ApkValidator {
|
6
6
|
constructor(aapt) {
|
@@ -10,21 +10,123 @@ const environment = require('../../../../../utils/environment');
|
|
10
10
|
const log = require('../../../../../utils/logger').child({ cat: 'device' });
|
11
11
|
const { quote } = require('../../../../../utils/shellQuote');
|
12
12
|
|
13
|
+
const PERMISSIONS_VALUES = {
|
14
|
+
YES: 'YES',
|
15
|
+
NO: 'NO',
|
16
|
+
UNSET: 'unset',
|
17
|
+
LIMITED: 'limited',
|
18
|
+
};
|
19
|
+
|
20
|
+
const SIMCTL_SET_PERMISSION_ACTIONS ={
|
21
|
+
GRANT: 'grant',
|
22
|
+
REVOKE: 'revoke',
|
23
|
+
RESET: 'reset',
|
24
|
+
};
|
25
|
+
|
13
26
|
class AppleSimUtils {
|
14
27
|
async setPermissions(udid, bundleId, permissionsObj) {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
28
|
+
for (const [service, value] of Object.entries(permissionsObj)) {
|
29
|
+
switch (service) {
|
30
|
+
case 'location':
|
31
|
+
switch (value) {
|
32
|
+
case 'always':
|
33
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.GRANT, 'location-always');
|
34
|
+
break;
|
35
|
+
|
36
|
+
case 'inuse':
|
37
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.GRANT, 'location');
|
38
|
+
break;
|
39
|
+
|
40
|
+
case 'never':
|
41
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.REVOKE, 'location');
|
42
|
+
break;
|
43
|
+
|
44
|
+
case 'unset':
|
45
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.RESET, 'location');
|
46
|
+
break;
|
47
|
+
}
|
48
|
+
|
49
|
+
break;
|
50
|
+
|
51
|
+
case 'contacts':
|
52
|
+
if (value === PERMISSIONS_VALUES.LIMITED) {
|
53
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.GRANT, 'contacts-limited');
|
54
|
+
} else {
|
55
|
+
await this.setPermissionWithAppleSimUtils(udid, bundleId, service, value);
|
56
|
+
}
|
57
|
+
break;
|
58
|
+
|
59
|
+
case 'photos':
|
60
|
+
if (value === PERMISSIONS_VALUES.LIMITED) {
|
61
|
+
await this.setPermissionWithSimctl(udid, bundleId, SIMCTL_SET_PERMISSION_ACTIONS.GRANT, 'photos-add');
|
62
|
+
} else {
|
63
|
+
await this.setPermissionWithAppleSimUtils(udid, bundleId, service, value);
|
64
|
+
}
|
65
|
+
break;
|
66
|
+
|
67
|
+
// eslint-disable-next-line no-fallthrough
|
68
|
+
case 'calendar':
|
69
|
+
case 'camera':
|
70
|
+
case 'medialibrary':
|
71
|
+
case 'microphone':
|
72
|
+
case 'motion':
|
73
|
+
case 'reminders':
|
74
|
+
case 'siri':
|
75
|
+
// Simctl uses kebab-case for service names.
|
76
|
+
const simctlService = service.replace('medialibrary', 'media-library');
|
77
|
+
await this.setPermissionWithSimctl(udid, bundleId, this.basicPermissionValueToSimctlAction(value), simctlService);
|
78
|
+
break;
|
79
|
+
|
80
|
+
// Requires AppleSimUtils: unsupported by latest Simctl at the moment of writing this code.
|
81
|
+
// eslint-disable-next-line no-fallthrough
|
82
|
+
case 'notifications':
|
83
|
+
case 'health':
|
84
|
+
case 'homekit':
|
85
|
+
case 'speech':
|
86
|
+
case 'faceid':
|
87
|
+
case 'userTracking':
|
88
|
+
await this.setPermissionWithAppleSimUtils(udid, bundleId, service, value);
|
89
|
+
break;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
basicPermissionValueToSimctlAction(value) {
|
95
|
+
switch (value) {
|
96
|
+
case PERMISSIONS_VALUES.YES:
|
97
|
+
return SIMCTL_SET_PERMISSION_ACTIONS.GRANT;
|
98
|
+
|
99
|
+
case PERMISSIONS_VALUES.NO:
|
100
|
+
return SIMCTL_SET_PERMISSION_ACTIONS.REVOKE;
|
101
|
+
|
102
|
+
case PERMISSIONS_VALUES.UNSET:
|
103
|
+
return SIMCTL_SET_PERMISSION_ACTIONS.RESET;
|
104
|
+
}
|
105
|
+
}
|
19
106
|
|
107
|
+
async setPermissionWithSimctl(udid, bundleId, action, service) {
|
20
108
|
const options = {
|
21
|
-
|
109
|
+
cmd: `privacy ${udid} ${action} ${service} ${bundleId}`,
|
22
110
|
statusLogs: {
|
23
|
-
trying: `Trying to set permissions...`,
|
24
|
-
successful:
|
111
|
+
trying: `Trying to set permissions with Simctl: ${action} ${service}...`,
|
112
|
+
successful: `${service} permissions are set`
|
25
113
|
},
|
26
114
|
retries: 1,
|
27
115
|
};
|
116
|
+
|
117
|
+
await this._execSimctl(options);
|
118
|
+
}
|
119
|
+
|
120
|
+
async setPermissionWithAppleSimUtils(udid, bundleId, service, value) {
|
121
|
+
const options = {
|
122
|
+
args: `--byId ${udid} --bundle ${bundleId} --restartSB --setPermissions ${service}=${value}`,
|
123
|
+
statusLogs: {
|
124
|
+
trying: `Trying to set permissions with AppleSimUtils: ${service}=${value}...`,
|
125
|
+
successful: `${service} permissions are set`
|
126
|
+
},
|
127
|
+
retries: 1,
|
128
|
+
};
|
129
|
+
|
28
130
|
await this._execAppleSimUtils(options);
|
29
131
|
}
|
30
132
|
|
@@ -33,6 +135,7 @@ class AppleSimUtils {
|
|
33
135
|
args: `--list ${joinArgs(query)}`,
|
34
136
|
retries: 1,
|
35
137
|
statusLogs: listOptions.trying ? { trying: listOptions.trying } : undefined,
|
138
|
+
maxBuffer: 4 * 1024 * 1024,
|
36
139
|
};
|
37
140
|
const response = await this._execAppleSimUtils(options);
|
38
141
|
const parsed = this._parseResponseFromAppleSimUtils(response);
|
@@ -318,14 +421,7 @@ class AppleSimUtils {
|
|
318
421
|
}
|
319
422
|
|
320
423
|
async setLocation(udid, lat, lon) {
|
321
|
-
|
322
|
-
if (_.get(result, 'stdout')) {
|
323
|
-
await childProcess.execWithRetriesAndLogs(`fbsimctl ${udid} set_location ${lat} ${lon}`, { retries: 1 });
|
324
|
-
} else {
|
325
|
-
throw new DetoxRuntimeError(`setLocation currently supported only through fbsimctl.
|
326
|
-
Install fbsimctl using:
|
327
|
-
"brew tap facebook/fb && export CODE_SIGNING_REQUIRED=NO && brew install fbsimctl"`);
|
328
|
-
}
|
424
|
+
await this._execSimctl({ cmd: `location ${udid} set ${lat},${lon}` });
|
329
425
|
}
|
330
426
|
|
331
427
|
async resetContentAndSettings(udid) {
|