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.
Files changed (44) hide show
  1. 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
  2. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.pom → 20.47.0/detox-20.47.0.pom} +1 -1
  7. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.47.0/detox-20.47.0.pom.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  12. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  13. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  14. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  15. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  16. package/Detox-ios-framework.tbz +0 -0
  17. package/Detox-ios-src.tbz +0 -0
  18. package/Detox-ios-xcuitest.tbz +0 -0
  19. package/detox.d.ts +15 -3
  20. package/package.json +9 -9
  21. package/src/android/matchers/native.js +23 -2
  22. package/src/client/AsyncWebSocket.js +9 -3
  23. package/src/client/Client.js +3 -2
  24. package/src/configuration/collectCliConfig.js +1 -0
  25. package/src/configuration/composeSessionConfig.js +11 -0
  26. package/src/devices/common/drivers/android/exec/ADB.js +18 -0
  27. package/src/devices/runtime/RuntimeDevice.js +1 -0
  28. package/src/devices/runtime/drivers/android/AndroidDriver.js +1 -0
  29. package/src/errors/DetoxConfigErrorComposer.js +12 -0
  30. package/src/ios/expectTwo.js +23 -4
  31. package/src/matchers/semanticTypes.js +137 -0
  32. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.md5 +0 -1
  33. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha1 +0 -1
  34. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha256 +0 -1
  35. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3-sources.jar.sha512 +0 -1
  36. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.md5 +0 -1
  37. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha1 +0 -1
  38. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha256 +0 -1
  39. package/Detox-android/com/wix/detox/20.46.3/detox-20.46.3.pom.sha512 +0 -1
  40. /package/Detox-android/com/wix/detox/{20.46.3/detox-20.46.3.aar → 20.47.0/detox-20.47.0.aar} +0 -0
  41. /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
  42. /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
  43. /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
  44. /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
@@ -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.46.3</version>
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.46.3</latest>
7
- <release>20.46.3</release>
6
+ <latest>20.47.0</latest>
7
+ <release>20.47.0</release>
8
8
  <versions>
9
- <version>20.46.3</version>
9
+ <version>20.47.0</version>
10
10
  </versions>
11
- <lastUpdated>20251227212352</lastUpdated>
11
+ <lastUpdated>20260126091115</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 52a014de4af4570ef7dcc37b76174c66
1
+ c960a54df8b950d614c9c4d96a7d4c77
@@ -1 +1 @@
1
- 8ec2bac7f5f07ad8ea2965f878f40ff8e0b35fec
1
+ 28758e138cb7fed15377c58d979d49755a9475d7
@@ -1 +1 @@
1
- 569a92343188142a18b2a59ee696412482338398b03a47cd4ac993fc9a132d7d
1
+ 3427ee3268354b80962e298697e781cb6ef4cbcb315e10f8df061e1554c18e58
@@ -1 +1 @@
1
- 26bc4ce6c81cd609d8dc5a99b3a8830831b1b8d4bbfc1208d86ba44c3fb9f7341158b9b7f9a5ada1d2e9ad9d0dc48b9bf0836114334d0b0318b3706fe991e188
1
+ d1bae5c6265c48655efa323ab2bb79680c92b92c7cf85566b2ddce257bd530fb4192ab4eb3c46dbf7c36cef778dc983cf6e977b7cc6a85b4e83d5991deb318d0
Binary file
package/Detox-ios-src.tbz CHANGED
Binary file
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
- * @example await element(by.type('RCTImageView'));
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(nativeViewType: string): NativeMatcher;
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.46.3",
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.0",
58
- "@react-native-community/cli-platform-android": "20.0.0",
59
- "@react-native-community/cli-platform-ios": "20.0.0",
60
- "@react-native/babel-preset": "0.82.0",
61
- "@react-native/eslint-config": "0.82.0",
62
- "@react-native/metro-config": "0.82.0",
63
- "@react-native/typescript-config": "0.82.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.82.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(value) {
39
+ constructor(typeOrSemanticType) {
33
40
  super();
34
- this._call = invoke.callDirectly(DetoxMatcherApi.matcherForClass(value));
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
- throw new DetoxRuntimeError('Unexpected message received over the web socket: ' + json.type);
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({
@@ -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
@@ -63,6 +63,7 @@ class RuntimeDevice {
63
63
  this._emitter = eventEmitter;
64
64
  this._errorComposer = runtimeErrorComposer;
65
65
 
66
+ /** @type {Detox.DetoxAppConfig | null} */
66
67
  this._currentApp = null;
67
68
  this._currentAppLaunchArgs = new LaunchArgsEditor();
68
69
  this._processes = {};
@@ -87,6 +87,7 @@ class AndroidDriver extends DeviceDriverBase {
87
87
  async resetAppState(...bundleIds) {
88
88
  for (const bundleId of bundleIds) {
89
89
  await this.adb.clearAppData(this.adbName, bundleId);
90
+ await this.adb.grantAllPermissions(this.adbName, bundleId);
90
91
  }
91
92
  }
92
93
 
@@ -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
@@ -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
- type(type) {
444
- if (typeof type !== 'string') throw new Error('type should be a string, but got ' + (type + (' (' + (typeof type + ')'))));
445
- this.predicate = { type: 'type', value: type };
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