detox 20.46.3 → 20.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3-sources.jar → 20.47.0/detox-20.47.0-sources.jar} +0 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.md5 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha512 +1 -0
- package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.pom → 20.47.0/detox-20.47.0.pom} +1 -1
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.md5 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.sha1 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.sha256 +1 -0
- package/Detox-android/com/wix/detox/20.47.0/detox-20.47.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-framework.tbz +0 -0
- package/Detox-ios-src.tbz +0 -0
- package/Detox-ios-xcuitest.tbz +0 -0
- package/detox.d.ts +15 -3
- package/package.json +9 -9
- package/src/android/matchers/native.js +23 -2
- package/src/client/AsyncWebSocket.js +9 -3
- package/src/client/Client.js +3 -2
- package/src/configuration/collectCliConfig.js +1 -0
- package/src/configuration/composeSessionConfig.js +11 -0
- package/src/devices/common/drivers/android/exec/ADB.js +18 -0
- package/src/devices/runtime/RuntimeDevice.js +1 -0
- package/src/devices/runtime/drivers/android/AndroidDriver.js +1 -0
- package/src/errors/DetoxConfigErrorComposer.js +12 -0
- package/src/ios/expectTwo.js +23 -4
- package/src/matchers/semanticTypes.js +137 -0
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.md5 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha512 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.md5 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha1 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha256 +0 -1
- package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha512 +0 -1
- /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar → 20.47.0/detox-20.47.0.aar} +0 -0
- /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar.md5 → 20.47.0/detox-20.47.0.aar.md5} +0 -0
- /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar.sha1 → 20.47.0/detox-20.47.0.aar.sha1} +0 -0
- /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar.sha256 → 20.47.0/detox-20.47.0.aar.sha256} +0 -0
- /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar.sha512 → 20.47.0/detox-20.47.0.aar.sha512} +0 -0
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4a2c6248931fa4d732a3c9e7c64df384
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
d56bcb1dc1bd97142de6fa70f8f073c778f0a105
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
787620fb84a982918daf814c7df4b4d14f991b4ad4a01bcab4ecac0bba90a581
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a73180b8fda58367af996004e9ed7ef31c5c44417815c5598e8f6a4b0779935443fe5c15f8ad48b751d32a76e04e9ed432e0b59ec5eea22510f95a0e5165ad86
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<modelVersion>4.0.0</modelVersion>
|
|
4
4
|
<groupId>com.wix</groupId>
|
|
5
5
|
<artifactId>detox</artifactId>
|
|
6
|
-
<version>20.
|
|
6
|
+
<version>20.47.0</version>
|
|
7
7
|
<packaging>aar</packaging>
|
|
8
8
|
<name>Detox</name>
|
|
9
9
|
<description>Gray box end-to-end testing and automation library for mobile apps</description>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8897b4b97785bf50006a2d99b6a32cc2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7788182e126b5161ad10290029376ee6e6f9f150
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8915215700fe10319c67d9fba1e679a29db386173ee1e03a73484e5b555f8390
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
25d700072c6fe91a83ddcb90b6926c277992b38bca5acadf90403ca069da061323d9ca6db5ace279df567bec48725cd2eed4ae3552954235eae2c805044cc141
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
<groupId>com.wix</groupId>
|
|
4
4
|
<artifactId>detox</artifactId>
|
|
5
5
|
<versioning>
|
|
6
|
-
<latest>20.
|
|
7
|
-
<release>20.
|
|
6
|
+
<latest>20.47.0</latest>
|
|
7
|
+
<release>20.47.0</release>
|
|
8
8
|
<versions>
|
|
9
|
-
<version>20.
|
|
9
|
+
<version>20.47.0</version>
|
|
10
10
|
</versions>
|
|
11
|
-
<lastUpdated>
|
|
11
|
+
<lastUpdated>20260126091115</lastUpdated>
|
|
12
12
|
</versioning>
|
|
13
13
|
</metadata>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
c960a54df8b950d614c9c4d96a7d4c77
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
28758e138cb7fed15377c58d979d49755a9475d7
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3427ee3268354b80962e298697e781cb6ef4cbcb315e10f8df061e1554c18e58
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
d1bae5c6265c48655efa323ab2bb79680c92b92c7cf85566b2ddce257bd530fb4192ab4eb3c46dbf7c36cef778dc983cf6e977b7cc6a85b4e83d5991deb318d0
|
package/Detox-ios-framework.tbz
CHANGED
|
Binary file
|
package/Detox-ios-src.tbz
CHANGED
|
Binary file
|
package/Detox-ios-xcuitest.tbz
CHANGED
|
Binary file
|
package/detox.d.ts
CHANGED
|
@@ -133,6 +133,7 @@ declare global {
|
|
|
133
133
|
interface DetoxSessionConfig {
|
|
134
134
|
autoStart?: boolean;
|
|
135
135
|
debugSynchronization?: number;
|
|
136
|
+
ignoreUnexpectedMessages?: boolean;
|
|
136
137
|
server?: string;
|
|
137
138
|
sessionId?: string;
|
|
138
139
|
}
|
|
@@ -1155,6 +1156,8 @@ declare global {
|
|
|
1155
1156
|
interface NativeElement extends NativeElementActions {
|
|
1156
1157
|
}
|
|
1157
1158
|
|
|
1159
|
+
type SemanticMatchingTypes = 'image' | 'input-field' | 'text' | 'button' | 'scrollview' | 'list' | 'switch' | 'slider' | 'picker' | 'activity-indicator' | 'progress';
|
|
1160
|
+
|
|
1158
1161
|
interface ByFacade {
|
|
1159
1162
|
/**
|
|
1160
1163
|
* by.id will match an id that is given to the view via testID prop.
|
|
@@ -1184,10 +1187,19 @@ declare global {
|
|
|
1184
1187
|
label(label: string | RegExp): NativeMatcher;
|
|
1185
1188
|
|
|
1186
1189
|
/**
|
|
1187
|
-
* Find an element by native view type.
|
|
1188
|
-
*
|
|
1190
|
+
* Find an element by native view type OR semantic type.
|
|
1191
|
+
* Automatically detects if the input is a semantic type or regular class name.
|
|
1192
|
+
* @example
|
|
1193
|
+
* // Semantic types (cross-platform):
|
|
1194
|
+
* await element(by.type('image'));
|
|
1195
|
+
* await element(by.type('button'));
|
|
1196
|
+
* await element(by.type('input-field'));
|
|
1197
|
+
*
|
|
1198
|
+
* // Native class names (platform-specific):
|
|
1199
|
+
* await element(by.type('RCTImageView'));
|
|
1200
|
+
* await element(by.type('android.widget.Button'));
|
|
1189
1201
|
*/
|
|
1190
|
-
type(
|
|
1202
|
+
type(typeOrSemanticType: SemanticMatchingTypes | string): NativeMatcher;
|
|
1191
1203
|
|
|
1192
1204
|
/**
|
|
1193
1205
|
* Find an element with an accessibility trait. (iOS only)
|
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.47.0",
|
|
5
5
|
"bin": "local-cli/cli.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"android",
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"postinstall": "node scripts/postinstall.js"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@react-native-community/cli": "20.0.
|
|
58
|
-
"@react-native-community/cli-platform-android": "20.0.
|
|
59
|
-
"@react-native-community/cli-platform-ios": "20.0.
|
|
60
|
-
"@react-native/babel-preset": "0.
|
|
61
|
-
"@react-native/eslint-config": "0.
|
|
62
|
-
"@react-native/metro-config": "0.
|
|
63
|
-
"@react-native/typescript-config": "0.
|
|
57
|
+
"@react-native-community/cli": "20.0.2",
|
|
58
|
+
"@react-native-community/cli-platform-android": "20.0.2",
|
|
59
|
+
"@react-native-community/cli-platform-ios": "20.0.2",
|
|
60
|
+
"@react-native/babel-preset": "0.83.0",
|
|
61
|
+
"@react-native/eslint-config": "0.83.0",
|
|
62
|
+
"@react-native/metro-config": "0.83.0",
|
|
63
|
+
"@react-native/typescript-config": "0.83.0",
|
|
64
64
|
"@tsconfig/react-native": "^3.0.0",
|
|
65
65
|
"@types/bunyan": "^1.8.8",
|
|
66
66
|
"@types/child-process-promise": "^2.2.1",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"jest-allure2-reporter": "^2.2.6",
|
|
83
83
|
"metro-react-native-babel-preset": "0.76.8",
|
|
84
84
|
"prettier": "^3.1.1",
|
|
85
|
-
"react-native": "0.
|
|
85
|
+
"react-native": "0.83.0",
|
|
86
86
|
"react-native-codegen": "^0.0.8",
|
|
87
87
|
"typescript": "^5.8.3",
|
|
88
88
|
"wtfnode": "^0.9.1"
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
|
|
2
2
|
const invoke = require('../../invoke');
|
|
3
|
+
const semanticTypes = require('../../matchers/semanticTypes');
|
|
3
4
|
const { isRegExp } = require('../../utils/isRegExp');
|
|
4
5
|
const { NativeMatcher } = require('../core/NativeMatcher');
|
|
5
6
|
const DetoxMatcherApi = require('../espressoapi/DetoxMatcher');
|
|
6
7
|
|
|
8
|
+
const createClassMatcher = (className) =>
|
|
9
|
+
new NativeMatcher(invoke.callDirectly(DetoxMatcherApi.matcherForClass(className)));
|
|
10
|
+
|
|
11
|
+
const combineWithOr = (matchers) =>
|
|
12
|
+
matchers.reduce((acc, matcher) => acc.or(matcher));
|
|
13
|
+
|
|
7
14
|
class LabelMatcher extends NativeMatcher {
|
|
8
15
|
constructor(value) {
|
|
9
16
|
super();
|
|
@@ -29,9 +36,23 @@ class IdMatcher extends NativeMatcher {
|
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
class TypeMatcher extends NativeMatcher {
|
|
32
|
-
constructor(
|
|
39
|
+
constructor(typeOrSemanticType) {
|
|
33
40
|
super();
|
|
34
|
-
|
|
41
|
+
|
|
42
|
+
const descriptors = semanticTypes.getClasses(typeOrSemanticType, 'android');
|
|
43
|
+
if (!descriptors.length) {
|
|
44
|
+
throw new DetoxRuntimeError(`No class names found for: ${typeOrSemanticType}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const matchers = descriptors.map(({ className, excludes }) => {
|
|
48
|
+
const includeMatcher = createClassMatcher(className);
|
|
49
|
+
return excludes.length
|
|
50
|
+
? includeMatcher.and(combineWithOr(excludes.map(createClassMatcher)).not)
|
|
51
|
+
: includeMatcher;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const combinedMatcher = combineWithOr(matchers);
|
|
55
|
+
this._call = { ...combinedMatcher._call, rawType: typeOrSemanticType };
|
|
35
56
|
}
|
|
36
57
|
}
|
|
37
58
|
|
|
@@ -15,7 +15,7 @@ const DEFAULT_SEND_OPTIONS = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
class AsyncWebSocket {
|
|
18
|
-
constructor(url) {
|
|
18
|
+
constructor({ url, ignoreUnexpectedMessages = false }) {
|
|
19
19
|
this._url = url;
|
|
20
20
|
this._ws = null;
|
|
21
21
|
this._eventCallbacks = {};
|
|
@@ -23,6 +23,7 @@ class AsyncWebSocket {
|
|
|
23
23
|
this._opening = null;
|
|
24
24
|
this._closing = null;
|
|
25
25
|
this._abortedMessageIds = new Set();
|
|
26
|
+
this._ignoreUnexpectedMessages = ignoreUnexpectedMessages;
|
|
26
27
|
|
|
27
28
|
this.inFlightPromises = {};
|
|
28
29
|
}
|
|
@@ -253,8 +254,13 @@ class AsyncWebSocket {
|
|
|
253
254
|
if (this._abortedMessageIds.has(json.messageId)) {
|
|
254
255
|
log.debug({ messageId: json.messageId }, `late response`);
|
|
255
256
|
} else {
|
|
256
|
-
|
|
257
|
-
|
|
257
|
+
const errorMessage = 'Unexpected message received over the web socket: ' + json.type;
|
|
258
|
+
if (this._ignoreUnexpectedMessages) {
|
|
259
|
+
log.warn({ messageId: json.messageId, type: json.type }, errorMessage + ' (ignored due to configuration)');
|
|
260
|
+
} else {
|
|
261
|
+
throw new DetoxRuntimeError(errorMessage);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
258
264
|
}
|
|
259
265
|
} catch (error) {
|
|
260
266
|
this.rejectAll(new DetoxRuntimeError({
|
package/src/client/Client.js
CHANGED
|
@@ -19,8 +19,9 @@ class Client {
|
|
|
19
19
|
* @param {number} debugSynchronization
|
|
20
20
|
* @param {string} server
|
|
21
21
|
* @param {string} sessionId
|
|
22
|
+
* @param {boolean} [ignoreUnexpectedMessages]
|
|
22
23
|
*/
|
|
23
|
-
constructor({ debugSynchronization, server, sessionId
|
|
24
|
+
constructor({ debugSynchronization, server, sessionId, ignoreUnexpectedMessages }) {
|
|
24
25
|
this._onAppConnected = this._onAppConnected.bind(this);
|
|
25
26
|
this._onAppReady = this._onAppReady.bind(this);
|
|
26
27
|
this._onAppUnresponsive = this._onAppUnresponsive.bind(this);
|
|
@@ -40,7 +41,7 @@ class Client {
|
|
|
40
41
|
this._appTerminationHandle = null;
|
|
41
42
|
|
|
42
43
|
this._successfulTestRun = true; // flag for cleanup
|
|
43
|
-
this._asyncWebSocket = new AsyncWebSocket(server);
|
|
44
|
+
this._asyncWebSocket = new AsyncWebSocket({ url: server, ignoreUnexpectedMessages });
|
|
44
45
|
this._serverUrl = server;
|
|
45
46
|
|
|
46
47
|
this.setEventCallback('appConnected', this._onAppConnected);
|
|
@@ -76,6 +76,7 @@ function collectCliConfig({ argv, errorComposer }) {
|
|
|
76
76
|
useCustomLogger: asBoolean(get('use-custom-logger')),
|
|
77
77
|
retries: asNumber(get('retries')),
|
|
78
78
|
start: get('start'),
|
|
79
|
+
ignoreUnexpectedWsMessages: asBoolean(get('ignore-unexpected-ws-messages')),
|
|
79
80
|
repl,
|
|
80
81
|
inspectBrk,
|
|
81
82
|
}, _.isUndefined);
|
|
@@ -37,10 +37,21 @@ async function composeSessionConfig(options) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
if (session.ignoreUnexpectedMessages != null) {
|
|
41
|
+
const value = session.ignoreUnexpectedMessages;
|
|
42
|
+
if (typeof value !== 'boolean') {
|
|
43
|
+
throw errorComposer.invalidIgnoreUnexpectedMessagesProperty();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
if (Number.parseInt(cliConfig.debugSynchronization, 10) >= 0) {
|
|
41
48
|
session.debugSynchronization = +cliConfig.debugSynchronization;
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
if (cliConfig.ignoreUnexpectedWsMessages != null) {
|
|
52
|
+
session.ignoreUnexpectedMessages = cliConfig.ignoreUnexpectedWsMessages;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
const result = {
|
|
45
56
|
autoStart: !session.server,
|
|
46
57
|
debugSynchronization: 10000,
|
|
@@ -4,10 +4,13 @@ const _ = require('lodash');
|
|
|
4
4
|
const DetoxRuntimeError = require('../../../../../errors/DetoxRuntimeError');
|
|
5
5
|
const { execWithRetriesAndLogs, spawnWithRetriesAndLogs, spawnAndLog } = require('../../../../../utils/childProcess');
|
|
6
6
|
const { getAdbPath } = require('../../../../../utils/environment');
|
|
7
|
+
const logger = require('../../../../../utils/logger');
|
|
7
8
|
const { escape } = require('../../../../../utils/pipeCommands');
|
|
8
9
|
const DeviceHandle = require('../tools/DeviceHandle');
|
|
9
10
|
const EmulatorHandle = require('../tools/EmulatorHandle');
|
|
10
11
|
|
|
12
|
+
const log = logger.child({ cat: 'device' });
|
|
13
|
+
|
|
11
14
|
const DEFAULT_EXEC_OPTIONS = {
|
|
12
15
|
retries: 1,
|
|
13
16
|
};
|
|
@@ -160,6 +163,21 @@ class ADB {
|
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
|
|
166
|
+
async grantAllPermissions(deviceId, packageId) {
|
|
167
|
+
try {
|
|
168
|
+
await this.shell(deviceId, `pm grant --all-permissions ${packageId}`);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
const message = e.stderr || e.message || '';
|
|
171
|
+
if (message.includes('no permission specified')) {
|
|
172
|
+
log.warn(
|
|
173
|
+
`Cannot restore permissions after resetAppState(). Please update Android version to API 35 or higher.`
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
throw e;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
163
181
|
async setLocation(deviceId, lat, lon) {
|
|
164
182
|
// NOTE: QEMU for Android for the telnet part relies on C stdlib
|
|
165
183
|
// function `strtod` which is locale-sensitive, meaning that depending
|
|
@@ -678,6 +678,18 @@ Examine your Detox config${this._atPath()}`,
|
|
|
678
678
|
});
|
|
679
679
|
}
|
|
680
680
|
|
|
681
|
+
invalidIgnoreUnexpectedMessagesProperty() {
|
|
682
|
+
return new DetoxConfigError({
|
|
683
|
+
message: `session.ignoreUnexpectedMessages should be a boolean value`,
|
|
684
|
+
hint: `Check that in your Detox config${this._atPath()}`,
|
|
685
|
+
inspectOptions: { depth: 3 },
|
|
686
|
+
debugInfo: _.omitBy({
|
|
687
|
+
session: _.get(this.contents, ['session']),
|
|
688
|
+
...this._focusOnConfiguration(c => _.pick(c, ['session'])),
|
|
689
|
+
}, _.isEmpty),
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
|
|
681
693
|
invalidTestRunnerProperty(isGlobal) {
|
|
682
694
|
const testRunner = _.get(
|
|
683
695
|
isGlobal
|
package/src/ios/expectTwo.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const fs = require('fs-extra');
|
|
5
5
|
const _ = require('lodash');
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const semanticTypes = require('../matchers/semanticTypes');
|
|
8
8
|
const { assertTraceDescription, assertEnum, assertNormalized } = require('../utils/assertArgument');
|
|
9
9
|
const { removeMilliseconds } = require('../utils/dateUtils');
|
|
10
10
|
const { actionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
|
|
@@ -17,6 +17,18 @@ const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, l
|
|
|
17
17
|
const { systemElement, systemMatcher, systemExpect, isSystemElement } = require('./system');
|
|
18
18
|
const { webElement, webMatcher, webExpect, isWebElement } = require('./web');
|
|
19
19
|
|
|
20
|
+
const createTypePredicate = (className) => ({ type: 'type', value: className });
|
|
21
|
+
const createOrPredicate = (predicates) => ({ type: 'or', predicates });
|
|
22
|
+
const createExclusionPredicate = (className, excludes) => ({
|
|
23
|
+
type: 'and',
|
|
24
|
+
predicates: [
|
|
25
|
+
createTypePredicate(className),
|
|
26
|
+
{
|
|
27
|
+
type: 'not',
|
|
28
|
+
predicate: createOrPredicate(excludes.map(createTypePredicate))
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
});
|
|
20
32
|
|
|
21
33
|
const assertDirection = assertEnum(['left', 'right', 'up', 'down']);
|
|
22
34
|
const assertSpeed = assertEnum(['fast', 'slow']);
|
|
@@ -440,9 +452,16 @@ class Matcher {
|
|
|
440
452
|
return this;
|
|
441
453
|
}
|
|
442
454
|
|
|
443
|
-
|
|
444
|
-
if (typeof
|
|
445
|
-
|
|
455
|
+
type(typeOrSemanticType) {
|
|
456
|
+
if (typeof typeOrSemanticType !== 'string') throw new Error('type should be a string, but got ' + (typeOrSemanticType + (' (' + (typeof typeOrSemanticType + ')'))));
|
|
457
|
+
|
|
458
|
+
const descriptors = semanticTypes.getClasses(typeOrSemanticType, 'ios');
|
|
459
|
+
const predicates = descriptors.map(({ className, excludes }) =>
|
|
460
|
+
excludes.length ? createExclusionPredicate(className, excludes) : createTypePredicate(className)
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
this.predicate = predicates.length > 1 ? createOrPredicate(predicates) : predicates[0];
|
|
464
|
+
this.predicate.rawType = typeOrSemanticType;
|
|
446
465
|
return this;
|
|
447
466
|
}
|
|
448
467
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic type mappings for cross-platform component matching
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Shared class mappings for aliases
|
|
6
|
+
const ACTIVITY_INDICATOR_CLASSES = {
|
|
7
|
+
ios: ['UIActivityIndicatorView'],
|
|
8
|
+
android: [
|
|
9
|
+
{
|
|
10
|
+
include: ['android.widget.ProgressBar', 'androidx.core.widget.ContentLoadingProgressBar'],
|
|
11
|
+
exclude: ['android.widget.AbsSeekBar']
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const SEMANTIC_TYPE_MAPPINGS = {
|
|
17
|
+
// Images
|
|
18
|
+
'image': {
|
|
19
|
+
ios: ['RCTImageView', 'RCTImageComponentView', 'UIImageView'],
|
|
20
|
+
android: ['android.widget.ImageView', 'com.facebook.react.views.image.ReactImageView']
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
// Input fields
|
|
24
|
+
'input-field': {
|
|
25
|
+
ios: ['RCTTextInputView', 'RCTMultilineTextInputView', 'UITextField', 'UITextView'],
|
|
26
|
+
android: ['android.widget.EditText', 'com.facebook.react.views.textinput.ReactEditText']
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
// Text elements (includes both old and new arch classes)
|
|
30
|
+
'text': {
|
|
31
|
+
ios: ['RCTText', 'RCTParagraphComponentView', 'UILabel'],
|
|
32
|
+
android: [
|
|
33
|
+
{
|
|
34
|
+
include: ['android.widget.TextView', 'com.facebook.react.views.text.ReactTextView'],
|
|
35
|
+
exclude: ['android.widget.EditText', 'android.widget.Button']
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Button elements (includes both old and new arch classes)
|
|
41
|
+
'button': {
|
|
42
|
+
ios: ['UIButton', 'RCTTouchableOpacity', 'RCTTouchableHighlight', 'RCTTouchableWithoutFeedback'],
|
|
43
|
+
android: ['android.widget.Button', 'android.widget.ImageButton']
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// Scroll containers - The UITableView inherits from scrollview so it could also show up here...
|
|
47
|
+
'scrollview': {
|
|
48
|
+
ios: ['RCTScrollView', 'RCTScrollViewComponentView', 'UIScrollView'],
|
|
49
|
+
android: ['android.widget.ScrollView', 'androidx.core.widget.NestedScrollView', 'com.facebook.react.views.scroll.ReactScrollView']
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Lists
|
|
53
|
+
'list': {
|
|
54
|
+
ios: ['UITableView', 'UICollectionView', 'RCTScrollView'],
|
|
55
|
+
android: ['android.widget.ListView', 'androidx.recyclerview.widget.RecyclerView', 'com.facebook.react.views.scroll.ReactScrollView']
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Switches/Toggles
|
|
59
|
+
'switch': {
|
|
60
|
+
ios: ['UISwitch'],
|
|
61
|
+
android: ['android.widget.Switch', 'androidx.appcompat.widget.SwitchCompat', 'com.facebook.react.views.switchview.ReactSwitch']
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
// Sliders
|
|
65
|
+
'slider': {
|
|
66
|
+
ios: ['UISlider'],
|
|
67
|
+
android: ['android.widget.SeekBar']
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Picker/Selector
|
|
71
|
+
'picker': {
|
|
72
|
+
ios: ['UIPickerView'],
|
|
73
|
+
android: ['android.widget.Spinner', 'androidx.appcompat.widget.AppCompatSpinner']
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
// Activity indicators/Progress
|
|
77
|
+
'activity-indicator': ACTIVITY_INDICATOR_CLASSES,
|
|
78
|
+
|
|
79
|
+
// Progress (alias for activity-indicator)
|
|
80
|
+
'progress': ACTIVITY_INDICATOR_CLASSES
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get platform-specific class names for a semantic type
|
|
85
|
+
* @param {string} semanticType - The semantic type (e.g., 'image', 'input-field')
|
|
86
|
+
* @param {string} platform - The platform ('ios' or 'android')
|
|
87
|
+
* @returns {Array<string|object>} Array of class names or matcher objects for the platform
|
|
88
|
+
*/
|
|
89
|
+
function getClasses(semanticType, platform) {
|
|
90
|
+
const mapping = SEMANTIC_TYPE_MAPPINGS[semanticType];
|
|
91
|
+
if (!mapping) {
|
|
92
|
+
return [{ className: semanticType, excludes: [] }];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const classNames = mapping[platform];
|
|
96
|
+
if (!classNames) {
|
|
97
|
+
throw new Error(`Platform ${platform} not supported for semantic type ${semanticType}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return classNames.map(item => {
|
|
101
|
+
if (typeof item === 'string') {
|
|
102
|
+
return { className: item, excludes: [] };
|
|
103
|
+
} else if (item.include && item.exclude) {
|
|
104
|
+
if (Array.isArray(item.include)) {
|
|
105
|
+
return item.include.map(className => ({
|
|
106
|
+
className,
|
|
107
|
+
excludes: item.exclude
|
|
108
|
+
}));
|
|
109
|
+
} else {
|
|
110
|
+
return {
|
|
111
|
+
className: item.include,
|
|
112
|
+
excludes: item.exclude
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { className: item, excludes: [] };
|
|
117
|
+
}).flat();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get all available semantic types
|
|
122
|
+
* @returns {string[]} Array of available semantic type names
|
|
123
|
+
*/
|
|
124
|
+
function getTypes() {
|
|
125
|
+
return Object.keys(SEMANTIC_TYPE_MAPPINGS);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function includes(value) {
|
|
129
|
+
return getTypes().includes(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = {
|
|
133
|
+
SEMANTIC_TYPE_MAPPINGS,
|
|
134
|
+
getClasses,
|
|
135
|
+
getTypes,
|
|
136
|
+
includes,
|
|
137
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
393ef737b02fa4912ec360e27f63f510
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
9fd46b19be199b88cec32112808151aaf7e07950
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
c0aee3ad0d61acc1420d133b1ed8f298044639907cc49f264a7021afa60b2d6c
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
65a56bb4b1cac7bd1030c11e780dcf19137b9cafb7c7935d9aafcf64698201927f2a6399b46835516a9748b378a4d9a218c72389b376596efdac41d327fd01a0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
d55b9ff6e9a62f96565eba69c6bfea2f
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
65abef0fec8ba164b1d31bcc75af5956b1322444
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ab6943b9fd288dd1f278e1a0c380e3816f071ef554166b429e411516edf379f3
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
47c42b92f5491ea116f1b9a14cebc93f4833112e1f42525336d18399cf890848e6376267d181a98e3beca3f291174d5a98889ca9e1e8d686b2d3d262e52a99f9
|
/package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar → 20.47.0/detox-20.47.0.aar}
RENAMED
|
File without changes
|
/package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar.md5 → 20.47.0/detox-20.47.0.aar.md5}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|