detox 19.1.0 → 19.3.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 (69) hide show
  1. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-javadoc.jar +0 -0
  2. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{19.1.0/detox-19.1.0-sources.jar → 19.3.0/detox-19.3.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{19.1.0/detox-19.1.0.aar → 19.3.0/detox-19.3.0.aar} +0 -0
  12. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.aar.md5 +1 -0
  13. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.aar.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.aar.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.aar.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/{19.1.0/detox-19.1.0.pom → 19.3.0/detox-19.3.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/19.3.0/detox-19.3.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/android/detox/proguard-rules-app.pro +1 -0
  29. package/android/detox/src/full/java/com/wix/detox/espresso/matcher/ViewAtIndexMatcher.kt +1 -1
  30. package/android/detox/src/testFull/java/com/wix/detox/espresso/matcher/ViewAtIndexMatcherSpec.kt +38 -0
  31. package/detox-native/README.md +1 -1
  32. package/index.d.ts +162 -2
  33. package/package.json +3 -3
  34. package/src/artifacts/screenshot/ScreenshotArtifactPlugin.js +2 -6
  35. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +16 -12
  36. package/src/client/AsyncWebSocket.js +22 -0
  37. package/src/client/Client.js +5 -9
  38. package/src/client/actions/actions.js +134 -7
  39. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +1 -1
  40. package/src/devices/common/drivers/android/exec/AAPT.js +15 -8
  41. package/src/devices/common/drivers/android/tools/ApkValidator.js +52 -0
  42. package/src/devices/common/drivers/android/tools/apk.js +29 -0
  43. package/src/devices/runtime/drivers/android/AndroidDriver.js +37 -12
  44. package/src/devices/runtime/drivers/android/emulator/EmulatorDriver.js +5 -10
  45. package/src/devices/runtime/drivers/android/genycloud/GenyCloudDriver.js +4 -8
  46. package/src/devices/runtime/factories/android.js +2 -0
  47. package/src/errors/DetoxRuntimeError.js +12 -0
  48. package/src/servicelocator/android/index.js +2 -0
  49. package/src/utils/fsext.js +1 -0
  50. package/src/utils/retry.js +4 -2
  51. package/src/utils/sleep.js +7 -2
  52. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-javadoc.jar +0 -0
  53. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-javadoc.jar.md5 +0 -1
  54. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-javadoc.jar.sha1 +0 -1
  55. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-javadoc.jar.sha256 +0 -1
  56. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-javadoc.jar.sha512 +0 -1
  57. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-sources.jar.md5 +0 -1
  58. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-sources.jar.sha1 +0 -1
  59. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-sources.jar.sha256 +0 -1
  60. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0-sources.jar.sha512 +0 -1
  61. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.aar.md5 +0 -1
  62. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.aar.sha1 +0 -1
  63. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.aar.sha256 +0 -1
  64. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.aar.sha512 +0 -1
  65. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.pom.md5 +0 -1
  66. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.pom.sha1 +0 -1
  67. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.pom.sha256 +0 -1
  68. package/Detox-android/com/wix/detox/19.1.0/detox-19.1.0.pom.sha512 +0 -1
  69. package/src/devices/common/drivers/android/tools/APKPath.js +0 -30
@@ -0,0 +1 @@
1
+ d4d970b43d6b113abfd4152017edfab2
@@ -0,0 +1 @@
1
+ f5c22b0b55f8fcf94d5cdeaf3dafd123b1711696
@@ -0,0 +1 @@
1
+ 42175c539b389fee647b5dd3f4d7bb271a1c1900a27663498275b6ebc000a818
@@ -0,0 +1 @@
1
+ 04dd66310a28bb63cf9e71580a3a74c8521bfae01ea872639402cff4b27c641478a14b82787fdd4cbd21ba5560a0023bc8052f27924cb5ceb2af1934f3c31529
@@ -0,0 +1 @@
1
+ eaca9cb551c4d3454431605785da7445
@@ -0,0 +1 @@
1
+ ccc218dc19145f4c3fba84f0777461c92a406dba
@@ -0,0 +1 @@
1
+ 301241bb6f38f53d9f78f41debca66897d25bce9432e4e9ce4bae8a9fc8b7482
@@ -0,0 +1 @@
1
+ 2868b459362e50d440322d5041eac0c57381847c65b27f47ce62baea301be6e27b2de5054d290ebedd17c78a53394950f2a8a5bd74ce9468cbdc4f2fc6ce31cd
@@ -0,0 +1 @@
1
+ 37265557ea2042fc7b84163cc7eb4ddd
@@ -0,0 +1 @@
1
+ 4fa9e0bd79f1e519ba4af43d3a7673052ddad4a9
@@ -0,0 +1 @@
1
+ 75d310142663310ad9592fa8fd306469411b1f7e680fd41748ada4fa2ec5c24b
@@ -0,0 +1 @@
1
+ a40481ba3bcf8a270e7e80bf3f8ca9b7832559bae082242898b13245e3bb6ae67c93c539b30883640b24df671943228c9631e8dc97006dbf189b5eb26c52e148
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox</artifactId>
6
- <version>19.1.0</version>
6
+ <version>19.3.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
+ 7393bc8e3fa71d574801da7f4f64898e
@@ -0,0 +1 @@
1
+ c567f308beec77a64cf8a8627a00ddbdc51654d0
@@ -0,0 +1 @@
1
+ 90f65a4b6f4d01f26c6d15d9ef1790cf7d16447c688d99abe8874dfdbbaab1f7
@@ -0,0 +1 @@
1
+ fd9a10f2bfcdab85fa5a9b7629971137144c3991c67d89f5f0a62d6058e4f37444e94dd80e8c2180e39f001265cb514bcb9763c31f554a2438744e51949ec6f1
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>19.1.0</latest>
7
- <release>19.1.0</release>
6
+ <latest>19.3.0</latest>
7
+ <release>19.3.0</release>
8
8
  <versions>
9
- <version>19.1.0</version>
9
+ <version>19.3.0</version>
10
10
  </versions>
11
- <lastUpdated>20211119165641</lastUpdated>
11
+ <lastUpdated>20211206165152</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 853511665d775584decad75dc265b347
1
+ 84221a4a04e90451e71509a7dbe6ff16
@@ -1 +1 @@
1
- 5a0a9a5eb9e0a763346e78dad55a808c7275cee7
1
+ 93646e96676f5c63194ac7fbb7902b2b7fe0b1dd
@@ -1 +1 @@
1
- 30e924b363eed64c79dda4be3c5f2a75ef7278fbed28e526d7bbbce8e013118d
1
+ 1d70c96ab43da06fc4b86924ae1eb4035c4443eebb3d36138537e2ae598fbd5a
@@ -1 +1 @@
1
- a74a66d1937f3e79943741e64e70b9c81970cab3bc420c7f9fd1f6a8600f9f2c90aee020d3cfd3624f53085caf37c6a149d27e800a1b6749125c5cc4b03b2e97
1
+ 85a5235aad97fc0780472e2d4ab92190b2e6b9c3697853c60f0eb6d580830fcb6ccec5f07f9f314f9e049b938bf9069b2a6b8a319a2d4bfab6e156a4ca861a73
package/Detox-ios-src.tbz CHANGED
Binary file
package/Detox-ios.tbz CHANGED
Binary file
@@ -11,3 +11,4 @@
11
11
  -keep class kotlin.jvm.** { *; }
12
12
  -keep class kotlin.collections.** { *; }
13
13
  -keep class kotlin.text.** { *; }
14
+ -keep class kotlin.io.** { *; }
@@ -21,6 +21,6 @@ class ViewAtIndexMatcher(private val index: Int, private val innerMatcher: Match
21
21
  }
22
22
 
23
23
  override fun describeTo(description: Description) {
24
- description.appendText("matches " + index + "th view.")
24
+ description.appendText("View at index #$index, of those matching MATCHER$innerMatcher")
25
25
  }
26
26
  }
@@ -0,0 +1,38 @@
1
+ package com.wix.detox.espresso.matcher
2
+
3
+ import android.view.View
4
+ import com.nhaarman.mockitokotlin2.*
5
+ import org.hamcrest.Description
6
+ import org.hamcrest.Matcher
7
+ import org.mockito.Matchers
8
+ import org.spekframework.spek2.Spek
9
+ import org.spekframework.spek2.style.specification.describe
10
+
11
+ object ViewAtIndexMatcherSpec: Spek({
12
+ describe("atIndex view-matcher") {
13
+
14
+ lateinit var innerMatcher: Matcher<View>
15
+ lateinit var description: Description
16
+ beforeEachTest {
17
+ innerMatcher = mock()
18
+ whenever(innerMatcher.toString()).thenReturn("(innerMatcher description)")
19
+
20
+ description = mock()
21
+ }
22
+
23
+ describe("describeTo") {
24
+ it("should append a valid description for index 0") {
25
+ val uut = ViewAtIndexMatcher(0, innerMatcher)
26
+ uut.describeTo(description)
27
+ verify(description).appendText("View at index #0, of those matching MATCHER(innerMatcher description)")
28
+ }
29
+
30
+ it("should append a valid description for index≥0") {
31
+ val uut = ViewAtIndexMatcher(7, innerMatcher)
32
+ uut.describeTo(description)
33
+ com.nhaarman.mockitokotlin2.
34
+ verify(description).appendText(Matchers.contains("View at index #7"))
35
+ }
36
+ }
37
+ }
38
+ });
@@ -82,7 +82,7 @@ dependencies {
82
82
  }
83
83
  ```
84
84
 
85
- In your root-project’s `build.gradle` - be sure to add `mavenCentral()` as an artifacts repository:
85
+ In your root-project’s `build.gradle` - be sure to add `mavenCentral()` as an artifacts' repository:
86
86
 
87
87
  ```groovy
88
88
  buildscript {
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // TypeScript definitions for Detox
2
- // Original authors:
2
+ // Original authors (from DefinitelyTyped):
3
3
  // * Jane Smith <jsmith@example.com>
4
4
  // * Tareq El-Masri <https://github.com/TareqElMasri>
5
5
  // * Steve Chun <https://github.com/stevechun>
@@ -8,7 +8,6 @@
8
8
  // * Max Komarychev <https://github.com/maxkomarychev>
9
9
  // * Dor Ben Baruch <https://github.com/Dor256>
10
10
 
11
-
12
11
  declare global {
13
12
  const device: Detox.DetoxExportWrapper['device'];
14
13
  const element: Detox.DetoxExportWrapper['element'];
@@ -1227,6 +1226,24 @@ declare global {
1227
1226
  * });
1228
1227
  */
1229
1228
  takeScreenshot(name: string): Promise<string>;
1229
+
1230
+ /**
1231
+ * Gets the native (OS-dependent) attributes of the element.
1232
+ * For more information, see {@link https://wix.github.io/Detox/docs/api/actions-on-element/#getattributes}
1233
+ *
1234
+ * @example
1235
+ * test('Get the attributes for my text element', async () => {
1236
+ * const attributes = await element(by.id('myText')).getAttributes()
1237
+ * const jestExpect = require('expect');
1238
+ * // 'visible' attribute available on both iOS and Android
1239
+ * jestExpect(attributes.visible).toBe(true);
1240
+ * // 'activationPoint' attribute available on iOS only
1241
+ * jestExpect(attributes.activationPoint.x).toHaveValue(50);
1242
+ * // 'width' attribute available on Android only
1243
+ * jestExpect(attributes.width).toHaveValue(100);
1244
+ * })
1245
+ */
1246
+ getAttributes(): Promise<IosElementAttributes | AndroidElementAttributes | { elements: IosElementAttributes[]; }>;
1230
1247
  }
1231
1248
 
1232
1249
  interface WebExpect<R = Promise<void>> {
@@ -1445,6 +1462,149 @@ declare global {
1445
1462
  };
1446
1463
  }
1447
1464
 
1465
+ // Element Attributes Shared Among iOS and Android
1466
+ interface ElementAttributes {
1467
+ /**
1468
+ * Whether or not the element is enabled for user interaction.
1469
+ */
1470
+ enabled: boolean;
1471
+ /**
1472
+ * The identifier of the element. Matches accessibilityIdentifier on iOS, and the main view tag, on Android - both commonly holding the component's test ID in React Native apps.
1473
+ */
1474
+ identifier: string;
1475
+ /**
1476
+ * Whether the element is visible. On iOS, visibility is calculated for the activation point. On Android, the attribute directly holds the value returned by View.getLocalVisibleRect()).
1477
+ */
1478
+ visible: boolean;
1479
+ /**
1480
+ * The text value of any textual element.
1481
+ */
1482
+ text?: string;
1483
+ /**
1484
+ * The label of the element. Matches accessibilityLabel for ios, and contentDescription for android.
1485
+ */
1486
+ label?: string;
1487
+ /**
1488
+ * The placeholder text value of the element. Matches hint on android.
1489
+ */
1490
+ placeholder?: string;
1491
+ /**
1492
+ * The value of the element, where applicable.
1493
+ * Matches accessibilityValue, on iOS.
1494
+ * For example: the position of a slider, or whether a checkbox has been marked (Android).
1495
+ */
1496
+ value?: unknown;
1497
+ }
1498
+
1499
+ interface IosElementAttributeFrame {
1500
+ y: number;
1501
+ x: number;
1502
+ width: number;
1503
+ height: number;
1504
+ }
1505
+
1506
+ interface IosElementAttributeInsets {
1507
+ right: number;
1508
+ top: number;
1509
+ left: number;
1510
+ bottom: number;
1511
+ }
1512
+
1513
+ // iOS Specific Attributes
1514
+ interface IosElementAttributes extends ElementAttributes {
1515
+ /**
1516
+ * The [activation point]{@link https://developer.apple.com/documentation/objectivec/nsobject/1615179-accessibilityactivationpoint} of the element, in element coordinate space.
1517
+ */
1518
+ activationPoint: Point2D;
1519
+ /**
1520
+ * The activation point of the element, in normalized percentage ([0.0, 1.0]).
1521
+ */
1522
+ normalizedActivationPoint: Point2D;
1523
+ /**
1524
+ * Whether the element is hittable at the activation point.
1525
+ */
1526
+ hittable: boolean;
1527
+ /**
1528
+ * The frame of the element, in screen coordinate space.
1529
+ */
1530
+ frame: IosElementAttributeFrame;
1531
+ /**
1532
+ * The frame of the element, in container coordinate space.
1533
+ */
1534
+ elementFrame: IosElementAttributeFrame;
1535
+ /**
1536
+ * The bounds of the element, in element coordinate space.
1537
+ */
1538
+ elementBounds: IosElementAttributeFrame;
1539
+ /**
1540
+ * The safe area insets of the element, in element coordinate space.
1541
+ */
1542
+ safeAreaInsets: IosElementAttributeInsets;
1543
+ /**
1544
+ * The safe area bounds of the element, in element coordinate space.
1545
+ */
1546
+ elementSafeBounds: IosElementAttributeFrame;
1547
+ /**
1548
+ * The date of the element (if it is a date picker).
1549
+ */
1550
+ date?: string;
1551
+ /**
1552
+ * The normalized slider position (if it is a slider).
1553
+ */
1554
+ normalizedSliderPosition?: number;
1555
+ /**
1556
+ * The content offset (if it is a scroll view).
1557
+ */
1558
+ contentOffset?: Point2D;
1559
+ /**
1560
+ * The content inset (if it is a scroll view).
1561
+ */
1562
+ contentInset?: IosElementAttributeInsets;
1563
+ /**
1564
+ * The adjusted content inset (if it is a scroll view).
1565
+ */
1566
+ adjustedContentInset?: IosElementAttributeInsets;
1567
+ /**
1568
+ * @example "<CALayer: 0x600003f759e0>"
1569
+ */
1570
+ layer: string;
1571
+ }
1572
+
1573
+ // Android Specific Attributes
1574
+ interface AndroidElementAttributes extends ElementAttributes {
1575
+ /**
1576
+ * The OS visibility type associated with the element: visible, invisible or gone.
1577
+ */
1578
+ visibility: 'visible' | 'invisible' | 'gone';
1579
+ /**
1580
+ * Width of the element, in pixels.
1581
+ */
1582
+ width: number;
1583
+ /**
1584
+ * Height of the element, in pixels.
1585
+ */
1586
+ height: number;
1587
+ /**
1588
+ * Elevation of the element.
1589
+ */
1590
+ elevation: number;
1591
+ /**
1592
+ * Alpha value for the element.
1593
+ */
1594
+ alpha: number;
1595
+ /**
1596
+ * Whether the element is the one currently in focus.
1597
+ */
1598
+ focused: boolean;
1599
+ /**
1600
+ * The text size for the text element.
1601
+ */
1602
+ textSize?: number;
1603
+ /**
1604
+ * The length of the text element (character count).
1605
+ */
1606
+ length?: number;
1607
+ }
1448
1608
  }
1449
1609
  }
1450
1610
 
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": "19.1.0",
4
+ "version": "19.3.0",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -33,6 +33,7 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/child-process-promise": "^2.2.1",
36
+ "@types/node": "^12.20.37",
36
37
  "@types/ws": "^7.4.0",
37
38
  "eslint": "^4.11.0",
38
39
  "eslint-plugin-import": "^2.23.3",
@@ -119,7 +120,6 @@
119
120
  "src/devices/allocation/factories",
120
121
  "src/devices/allocation/factories/drivers",
121
122
  "src/devices/cookies",
122
- "src/devices/common/drivers/android/exec/AAPT.js",
123
123
  "src/devices/common/drivers/android/exec/ADB.js",
124
124
  "src/devices/common/drivers/android/emulator/exec/EmulatorExec.js",
125
125
  "src/devices/common/drivers/android/tools/EmulatorTelnet.js",
@@ -166,5 +166,5 @@
166
166
  }
167
167
  }
168
168
  },
169
- "gitHead": "4b4d018ca01716802f21dae3bbb941775cc05077"
169
+ "gitHead": "a9db26d8caa157fc39938784c937ce863247f974"
170
170
  }
@@ -14,12 +14,8 @@ class ScreenshotArtifactPlugin extends TwoSnapshotsPerTestPlugin {
14
14
  });
15
15
  }
16
16
 
17
- async preparePathForSnapshot(testSummary, name) {
18
- const artifactName = name.endsWith('/')
19
- ? name.slice(0, -1)
20
- : `${name}.png`;
21
-
22
- return this.api.preparePathForArtifact(artifactName, testSummary);
17
+ async preparePathForSnapshot(testSummary, artifactName) {
18
+ return this.api.preparePathForArtifact(`${artifactName}.png`, testSummary);
23
19
  }
24
20
 
25
21
  async onBeforeCleanup(e) {
@@ -1,3 +1,5 @@
1
+ const path = require('path');
2
+
1
3
  const fs = require('../../utils/fsext');
2
4
  const log = require('../../utils/logger').child({ __filename });
3
5
  const FileArtifact = require('../templates/artifact/FileArtifact');
@@ -51,19 +53,21 @@ class SimulatorScreenshotPlugin extends ScreenshotArtifactPlugin {
51
53
  }
52
54
 
53
55
  _onInvokeFailure({ params }) {
54
- const artifacts = {
55
- visibilityFailingScreenshots: params.visibilityFailingScreenshotsURL,
56
- visibilityFailingRects: params.visibilityFailingRectsURL,
57
- };
58
-
59
- for (const [key, artifactPath] of Object.entries(artifacts)) {
60
- if (!artifactPath || fs.isDirEmptySync(artifactPath)) {
61
- continue;
56
+ const visibilityArtifactDirs = [
57
+ params.visibilityFailingScreenshotsURL,
58
+ params.visibilityFailingRectsURL
59
+ ].filter(Boolean);
60
+
61
+ for (const visibilityDir of visibilityArtifactDirs) {
62
+ for (const innerFile of fs.readdirSync(visibilityDir)) {
63
+ const ext = path.extname(innerFile);
64
+ if (ext === '.png') {
65
+ const artifactName = path.basename(innerFile, ext).replace(/ /g, '_');
66
+ this._registerSnapshot(artifactName, new FileArtifact({
67
+ temporaryPath: path.join(visibilityDir, innerFile),
68
+ }));
69
+ }
62
70
  }
63
-
64
- this._registerSnapshot(`${key}/`, new FileArtifact({
65
- temporaryPath: artifactPath,
66
- }));
67
71
  }
68
72
  }
69
73
 
@@ -95,6 +95,9 @@ class AsyncWebSocket {
95
95
 
96
96
  const messageId = message.messageId;
97
97
  const inFlight = this.inFlightPromises[messageId] = new InflightRequest(message).withTimeout(options.timeout);
98
+
99
+ this.handleMultipleNonAtomicPendingActions();
100
+
98
101
  const messageAsString = JSON.stringify(message);
99
102
  this._log.trace(EVENTS.SEND, messageAsString);
100
103
  this._ws.send(messageAsString);
@@ -102,6 +105,25 @@ class AsyncWebSocket {
102
105
  return inFlight.promise;
103
106
  }
104
107
 
108
+ handleMultipleNonAtomicPendingActions() {
109
+ const pendingNonAtomicRequests = this.getNonAtomicPendingActions();
110
+ for (const inflight of pendingNonAtomicRequests) {
111
+ inflight.reject(new DetoxRuntimeError({
112
+ message: 'Detox has detected multiple interactions taking place simultaneously. Have you forgotten to apply an await over one of the Detox actions in your test code?',
113
+ }));
114
+ }
115
+ }
116
+
117
+ getNonAtomicPendingActions() {
118
+ const remaining = Object.keys(this.inFlightPromises).map((key) => {
119
+ return this.inFlightPromises[key];
120
+ }).filter(item => {
121
+ return item.message.isAtomic === true;
122
+ });
123
+
124
+ return remaining.length > 1 ? remaining : [];
125
+ }
126
+
105
127
  setEventCallback(event, callback) {
106
128
  if (_.isEmpty(this._eventCallbacks[event])) {
107
129
  this._eventCallbacks[event] = [callback];
@@ -131,22 +131,18 @@ class Client {
131
131
  }
132
132
 
133
133
  async sendAction(action) {
134
- const { queryStatus, ...options } = this._inferSendOptions(action);
134
+ const { shouldQueryStatus, ...options } = this._inferSendOptions(action);
135
135
 
136
- return await (queryStatus
136
+ return await (shouldQueryStatus
137
137
  ? this._sendMonitoredAction(action, options)
138
138
  : this._doSendAction(action, options));
139
139
  }
140
140
 
141
141
  _inferSendOptions(action) {
142
- if ( action instanceof actions.CurrentStatus
143
- || action instanceof actions.Login
144
- || action instanceof actions.Cleanup
145
- ) {
146
- return { queryStatus: false, timeout: 5000 };
147
- }
142
+ const timeout = action.timeout;
143
+ const shouldQueryStatus = timeout === 0;
148
144
 
149
- return { queryStatus: true, timeout: 0 };
145
+ return { shouldQueryStatus, timeout };
150
146
  }
151
147
 
152
148
  async _sendMonitoredAction(action, options) {