detox 20.25.6 → 20.26.2

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 (85) hide show
  1. package/Detox-android/com/wix/detox/{20.25.6/detox-20.25.6-sources.jar → 20.26.2/detox-20.26.2-sources.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.aar +0 -0
  7. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.aar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.aar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.aar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.aar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.25.6/detox-20.25.6.pom → 20.26.2/detox-20.26.2.pom} +12 -12
  12. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.pom.md5 +1 -0
  13. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.pom.sha1 +1 -0
  14. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.pom.sha256 +1 -0
  15. package/Detox-android/com/wix/detox/20.26.2/detox-20.26.2.pom.sha512 +1 -0
  16. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  17. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  18. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  19. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  20. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  21. package/Detox-android/com/wix/detox-legacy/{20.25.6/detox-legacy-20.25.6-sources.jar → 20.26.2/detox-legacy-20.26.2-sources.jar} +0 -0
  22. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2-sources.jar.md5 +1 -0
  23. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2-sources.jar.sha1 +1 -0
  24. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2-sources.jar.sha256 +1 -0
  25. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2-sources.jar.sha512 +1 -0
  26. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.aar +0 -0
  27. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.aar.md5 +1 -0
  28. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.aar.sha1 +1 -0
  29. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.aar.sha256 +1 -0
  30. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.aar.sha512 +1 -0
  31. package/Detox-android/com/wix/detox-legacy/{20.25.6/detox-legacy-20.25.6.pom → 20.26.2/detox-legacy-20.26.2.pom} +12 -12
  32. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.pom.md5 +1 -0
  33. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.pom.sha1 +1 -0
  34. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.pom.sha256 +1 -0
  35. package/Detox-android/com/wix/detox-legacy/20.26.2/detox-legacy-20.26.2.pom.sha512 +1 -0
  36. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +4 -4
  37. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +1 -1
  38. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +1 -1
  39. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +1 -1
  40. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +1 -1
  41. package/Detox-ios-framework.tbz +0 -0
  42. package/Detox-ios-src.tbz +0 -0
  43. package/Detox-ios-xcuitest.tbz +0 -0
  44. package/android/detox/build.gradle +7 -8
  45. package/android/detox/proguard-rules-app.pro +3 -0
  46. package/android/detox/src/full/java/com/wix/detox/Detox.java +5 -0
  47. package/android/detox/src/full/java/com/wix/detox/espresso/assertion/ViewAssertions.java +6 -8
  48. package/android/detox/src/full/java/com/wix/detox/espresso/hierarchy/RootViewsHelper.kt +51 -0
  49. package/android/detox/src/full/java/com/wix/detox/espresso/hierarchy/ViewHierarchyGenerator.kt +128 -0
  50. package/detox.d.ts +12 -0
  51. package/package.json +3 -2
  52. package/src/android/espressoapi/Detox.js +15 -0
  53. package/src/client/Client.js +6 -0
  54. package/src/client/actions/actions.js +21 -1
  55. package/src/copilot/CopilotDriver.js +140 -0
  56. package/src/devices/runtime/RuntimeDevice.js +5 -0
  57. package/src/devices/runtime/drivers/DeviceDriverBase.js +4 -0
  58. package/src/devices/runtime/drivers/android/AndroidDriver.js +5 -0
  59. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +4 -0
  60. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6-sources.jar.md5 +0 -1
  61. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6-sources.jar.sha1 +0 -1
  62. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6-sources.jar.sha256 +0 -1
  63. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6-sources.jar.sha512 +0 -1
  64. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.aar +0 -0
  65. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.aar.md5 +0 -1
  66. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.aar.sha1 +0 -1
  67. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.aar.sha256 +0 -1
  68. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.aar.sha512 +0 -1
  69. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.pom.md5 +0 -1
  70. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.pom.sha1 +0 -1
  71. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.pom.sha256 +0 -1
  72. package/Detox-android/com/wix/detox/20.25.6/detox-20.25.6.pom.sha512 +0 -1
  73. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6-sources.jar.md5 +0 -1
  74. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6-sources.jar.sha1 +0 -1
  75. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6-sources.jar.sha256 +0 -1
  76. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6-sources.jar.sha512 +0 -1
  77. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.aar +0 -0
  78. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.aar.md5 +0 -1
  79. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.aar.sha1 +0 -1
  80. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.aar.sha256 +0 -1
  81. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.aar.sha512 +0 -1
  82. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.pom.md5 +0 -1
  83. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.pom.sha1 +0 -1
  84. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.pom.sha256 +0 -1
  85. package/Detox-android/com/wix/detox-legacy/20.25.6/detox-legacy-20.25.6.pom.sha512 +0 -1
@@ -0,0 +1 @@
1
+ ea98a7bac84cd877ac7a13aa5b9d3cc1
@@ -0,0 +1 @@
1
+ a67071d6d4bdcd041e91bc9f58d5d57637532cb9
@@ -0,0 +1 @@
1
+ 9e325d7b0b5b8dab384773bcf96df7a44e7a76f5375b1afba2e29b9a53c60e7b
@@ -0,0 +1 @@
1
+ 4ca91364a087ff16bd38d1721163b47f3d6435552605e1c2cba38138739e42bf45161458e997bc14be075b0bfa9df2ac8a311c79dc21e67216726b3f8a920db1
@@ -0,0 +1 @@
1
+ 19245568a5b1fc7e18eae4c34019b2d0
@@ -0,0 +1 @@
1
+ dfb1a4d4b6a06bbe8952fe821ab3278364fc3cf2
@@ -0,0 +1 @@
1
+ 294b99bfcfc4acf89c10c76c4cfb07b61dec92d8f45a2ed137092aa766d7e215
@@ -0,0 +1 @@
1
+ 546fa7e195d2c2077d9e41f2b003ead174c820ce45027752e86a366e673023cc41d09b5b5ccd3bdb693f403e6c8b65567af12208ece66e65d85937e9a65f677d
@@ -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.25.6</version>
6
+ <version>20.26.2</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>
@@ -30,22 +30,28 @@
30
30
  <url>https://github.com/wix/detox</url>
31
31
  </scm>
32
32
  <dependencies>
33
+ <dependency>
34
+ <groupId>org.jetbrains.kotlin</groupId>
35
+ <artifactId>kotlin-stdlib-jdk8</artifactId>
36
+ <version>1.8.0</version>
37
+ <scope>compile</scope>
38
+ </dependency>
33
39
  <dependency>
34
40
  <groupId>androidx.test.espresso</groupId>
35
41
  <artifactId>espresso-core</artifactId>
36
- <version>3.5.1</version>
42
+ <version>3.6.1</version>
37
43
  <scope>compile</scope>
38
44
  </dependency>
39
45
  <dependency>
40
46
  <groupId>androidx.test.espresso</groupId>
41
47
  <artifactId>espresso-web</artifactId>
42
- <version>3.5.1</version>
48
+ <version>3.6.1</version>
43
49
  <scope>compile</scope>
44
50
  </dependency>
45
51
  <dependency>
46
52
  <groupId>androidx.test.espresso</groupId>
47
53
  <artifactId>espresso-contrib</artifactId>
48
- <version>3.5.1</version>
54
+ <version>3.6.1</version>
49
55
  <scope>compile</scope>
50
56
  <exclusions>
51
57
  <exclusion>
@@ -63,13 +69,13 @@
63
69
  <dependency>
64
70
  <groupId>androidx.test</groupId>
65
71
  <artifactId>rules</artifactId>
66
- <version>1.5.0</version>
72
+ <version>1.6.1</version>
67
73
  <scope>compile</scope>
68
74
  </dependency>
69
75
  <dependency>
70
76
  <groupId>androidx.test.ext</groupId>
71
77
  <artifactId>junit</artifactId>
72
- <version>1.1.5</version>
78
+ <version>1.2.1</version>
73
79
  <scope>compile</scope>
74
80
  </dependency>
75
81
  <dependency>
@@ -78,12 +84,6 @@
78
84
  <version>2.2.0</version>
79
85
  <scope>compile</scope>
80
86
  </dependency>
81
- <dependency>
82
- <groupId>org.jetbrains.kotlin</groupId>
83
- <artifactId>kotlin-stdlib-jdk8</artifactId>
84
- <version>1.2.0</version>
85
- <scope>runtime</scope>
86
- </dependency>
87
87
  <dependency>
88
88
  <groupId>org.apache.commons</groupId>
89
89
  <artifactId>commons-lang3</artifactId>
@@ -0,0 +1 @@
1
+ f5574f4b81f29bd42c5da2cbaae85003
@@ -0,0 +1 @@
1
+ 65101d817b9185e67e3d5fb396107ad252a6ade7
@@ -0,0 +1 @@
1
+ 8830fd9064558962e2d7195512f9db4aae71801865f20b240a17ba4cebc21ab4
@@ -0,0 +1 @@
1
+ d026c556f62910b4728822cea8b03745bf74617c2bf3df7d97b29eb0007a1ace87a00af9aec32fa1798f0345e551ed62abd9be7e16f96b59ae56a88950ea46ce
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox</artifactId>
5
5
  <versioning>
6
- <latest>20.25.6</latest>
7
- <release>20.25.6</release>
6
+ <latest>20.26.2</latest>
7
+ <release>20.26.2</release>
8
8
  <versions>
9
- <version>20.25.6</version>
9
+ <version>20.26.2</version>
10
10
  </versions>
11
- <lastUpdated>20240825174403</lastUpdated>
11
+ <lastUpdated>20240905213155</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- 3ebd487874d7ca9ea9e79f14ae8b2228
1
+ 9e3e8a8d05fd018af3b4b1cecac85ceb
@@ -1 +1 @@
1
- 22de2239bc50b05a3d10d735a8435b281aa5aa77
1
+ 49a5d3258b3a4b18d55c0c803f65e9c7bb470c8e
@@ -1 +1 @@
1
- 85fa4bb20d12f08cbc7ea2dfcd7245707cd1b7ba6047bd9f3b45582bceef0227
1
+ f8b05715aaf9d675552325c062d5509e983560df36e2c0964bf858aac906be06
@@ -1 +1 @@
1
- 7a948085b3d47fb26694edba0bfe6fef3805bf069873bd4273e57fa11ee49e36b2cf61e9f74cdd953c9763945b8666c4cd72b2bb3f450eadc0d2bf608f26f29d
1
+ 9f65c4a4e108884baa631feba8abcc34372ee88b3d194b4eb9f94c88162e262fd8a0ed62f4ec94162c3891ea6ca085ba737892d73709ac2ec3b32e1d1e22ae69
@@ -0,0 +1 @@
1
+ 5fe1ece0c6f59a509e44c153a67c0aad
@@ -0,0 +1 @@
1
+ af24ad68bc24fda67b522b4853d47193de81fb59
@@ -0,0 +1 @@
1
+ 56e2fc034e270dd194fbfa0a8fe24e1b95fb298564cfa6a31c1b79d5eeb5f3f2
@@ -0,0 +1 @@
1
+ 109252b02fbd404778467ad18d611ebbb1a442dde9dca1d8e3feb469d81a0d6aff4a5285fb3677dc219b23acc78c88a134f3f3ef5f19487b7b7d3fb06049a4c8
@@ -0,0 +1 @@
1
+ 0dd6f951f83bfb1c258c09e57291b5f3
@@ -0,0 +1 @@
1
+ 54212838677b6cf72c2eb964dc911a9a80cf54a7
@@ -0,0 +1 @@
1
+ c2452ceba0cb3a2a6517086d81a0e990d82ab263395a0e1166b8178769cd8a51
@@ -0,0 +1 @@
1
+ 3d71f12171376fcf35b46ebc6a6cf942e0a7151a8f26287b41b6e2807f4bd8d37704aeaa89b7b0231c2286a301ebbfa3ff77a0a9cee92c02463c0085a4190085
@@ -3,7 +3,7 @@
3
3
  <modelVersion>4.0.0</modelVersion>
4
4
  <groupId>com.wix</groupId>
5
5
  <artifactId>detox-legacy</artifactId>
6
- <version>20.25.6</version>
6
+ <version>20.26.2</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>
@@ -30,22 +30,28 @@
30
30
  <url>https://github.com/wix/detox</url>
31
31
  </scm>
32
32
  <dependencies>
33
+ <dependency>
34
+ <groupId>org.jetbrains.kotlin</groupId>
35
+ <artifactId>kotlin-stdlib-jdk8</artifactId>
36
+ <version>1.8.0</version>
37
+ <scope>compile</scope>
38
+ </dependency>
33
39
  <dependency>
34
40
  <groupId>androidx.test.espresso</groupId>
35
41
  <artifactId>espresso-core</artifactId>
36
- <version>3.5.1</version>
42
+ <version>3.6.1</version>
37
43
  <scope>compile</scope>
38
44
  </dependency>
39
45
  <dependency>
40
46
  <groupId>androidx.test.espresso</groupId>
41
47
  <artifactId>espresso-web</artifactId>
42
- <version>3.5.1</version>
48
+ <version>3.6.1</version>
43
49
  <scope>compile</scope>
44
50
  </dependency>
45
51
  <dependency>
46
52
  <groupId>androidx.test.espresso</groupId>
47
53
  <artifactId>espresso-contrib</artifactId>
48
- <version>3.5.1</version>
54
+ <version>3.6.1</version>
49
55
  <scope>compile</scope>
50
56
  <exclusions>
51
57
  <exclusion>
@@ -63,13 +69,13 @@
63
69
  <dependency>
64
70
  <groupId>androidx.test</groupId>
65
71
  <artifactId>rules</artifactId>
66
- <version>1.5.0</version>
72
+ <version>1.6.1</version>
67
73
  <scope>compile</scope>
68
74
  </dependency>
69
75
  <dependency>
70
76
  <groupId>androidx.test.ext</groupId>
71
77
  <artifactId>junit</artifactId>
72
- <version>1.1.5</version>
78
+ <version>1.2.1</version>
73
79
  <scope>compile</scope>
74
80
  </dependency>
75
81
  <dependency>
@@ -78,12 +84,6 @@
78
84
  <version>2.2.0</version>
79
85
  <scope>compile</scope>
80
86
  </dependency>
81
- <dependency>
82
- <groupId>org.jetbrains.kotlin</groupId>
83
- <artifactId>kotlin-stdlib-jdk8</artifactId>
84
- <version>1.2.0</version>
85
- <scope>runtime</scope>
86
- </dependency>
87
87
  <dependency>
88
88
  <groupId>org.apache.commons</groupId>
89
89
  <artifactId>commons-lang3</artifactId>
@@ -0,0 +1 @@
1
+ 817a01b2f72e4cc9ee814d9aa83a6898
@@ -0,0 +1 @@
1
+ 5ab9e6d2bf60cc87c07b26d73ded613cc4692fe4
@@ -0,0 +1 @@
1
+ 26768c504f24bc35eee880bfe2fcc6c062aac63e5eee306d2196d27c989dbc40
@@ -0,0 +1 @@
1
+ af66500c5a4d075c5d9c739439fc49bcdebe5a7b2f8d364b7e8b1f879fc0901184b928d33ed66b59f3b5d7b89050acc3b6d4e1bfd151e114561ba975c9ca6e59
@@ -3,11 +3,11 @@
3
3
  <groupId>com.wix</groupId>
4
4
  <artifactId>detox-legacy</artifactId>
5
5
  <versioning>
6
- <latest>20.25.6</latest>
7
- <release>20.25.6</release>
6
+ <latest>20.26.2</latest>
7
+ <release>20.26.2</release>
8
8
  <versions>
9
- <version>20.25.6</version>
9
+ <version>20.26.2</version>
10
10
  </versions>
11
- <lastUpdated>20240825174441</lastUpdated>
11
+ <lastUpdated>20240905213242</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- e8677f5e1ebc2db6a82900c05f8d79dc
1
+ 7d1e75f8073d7e8507484042d83103e1
@@ -1 +1 @@
1
- 12b4921860e458ca7333620fec5ca94bec62c05b
1
+ f106fa7fa6ca0ecff78f8b6c7094118a0266de5a
@@ -1 +1 @@
1
- 74491490f648f58107b92765dd805167f3187b42ebf3a94408c017e654c46334
1
+ 8d88d3608dc25dd1305f93cb629d308c3167f6e4ea232efbbc54f309288d5bba
@@ -1 +1 @@
1
- 7ce4eab1a1b798a283d6c22884823a9dfd7aa06b177889c1a7c305661fd3b2095703b8f9d3311907a6652d78763ece4aada1353f70b5f9b71bfd525981d93b70
1
+ ce63462b86b96e3ee62a7817f56fb3f91d30801e93c41e0a9b8e8a0300a3bae285d17c1bd7a07054bc45557f9c1b16da338dcce8ef8197c7957088c327ea4b4d
Binary file
package/Detox-ios-src.tbz CHANGED
Binary file
Binary file
@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
2
2
  apply plugin: 'kotlin-android'
3
3
  apply from: '../rninfo.gradle'
4
4
 
5
- def _kotlinMinVersion = '1.2.0'
5
+ def _kotlinMinVersion = '1.8.0'
6
6
  def _materialMinVersion = '1.11.0'
7
7
 
8
8
  def _ext = rootProject.ext
@@ -111,7 +111,7 @@ android {
111
111
 
112
112
  // Fundamental deps.
113
113
  dependencies {
114
- implementation "org.jetbrains.kotlin:$_kotlinStdlib:$_kotlinMinVersion"
114
+ api "org.jetbrains.kotlin:$_kotlinStdlib:$_kotlinVersion"
115
115
 
116
116
  compileOnly "${_rnNativeArtifact}"
117
117
  }
@@ -123,26 +123,25 @@ dependencies {
123
123
  // Versions are in-sync with the 'androidx-test-1.4.0' release/tag of the android-test github repo,
124
124
  // used by the Detox generator. See https://github.com/android/android-test/releases/tag/androidx-test-1.4.0
125
125
  // Important: Should remain so when generator tag is replaced!
126
- api('androidx.test.espresso:espresso-core:3.5.1') {
126
+ api('androidx.test.espresso:espresso-core:3.6.1') {
127
127
  because 'Needed all across Detox but also makes Espresso seamlessly provided to Detox users with hybrid apps/E2E-tests.'
128
128
  }
129
- api('androidx.test.espresso:espresso-web:3.5.1') {
129
+ api('androidx.test.espresso:espresso-web:3.6.1') {
130
130
  because 'Web-View testing'
131
131
  }
132
- api('androidx.test.espresso:espresso-contrib:3.5.1') {
132
+ api('androidx.test.espresso:espresso-contrib:3.6.1') {
133
133
  because 'Android datepicker support'
134
134
  exclude group: "org.checkerframework", module: "checker"
135
135
  }
136
136
  api('org.hamcrest:hamcrest:2.2') {
137
137
  because 'See https://github.com/wix/Detox/issues/3920. Need to force hamcrest 2.2 win in battle of 2.2 vs. 1.3 (specified by Espresso).'
138
138
  }
139
- api('androidx.test:rules:1.5.0') {
139
+ api('androidx.test:rules:1.6.1') {
140
140
  because 'of ActivityTestRule. Needed by users *and* internally used by Detox.'
141
141
  }
142
- api('androidx.test.ext:junit:1.1.5') {
142
+ api('androidx.test.ext:junit:1.2.1') {
143
143
  because 'Needed so as to seamlessly provide AndroidJUnit4 to Detox users. Depends on junit core.'
144
144
  }
145
-
146
145
  // Version is the latest; Cannot sync with the Github repo (e.g. android/android-test) because the androidx
147
146
  // packaging version of associated classes is simply not there...
148
147
  api('androidx.test.uiautomator:uiautomator:2.2.0') {
@@ -14,11 +14,14 @@
14
14
  -keep class com.reactnativecommunity.slider.** { *; }
15
15
  -keep class com.reactnativecommunity.asyncstorage.** { *; }
16
16
 
17
+ -keep class kotlin.reflect.** { *; }
18
+ -keep class kotlin.coroutines.CoroutineDispatcher { *; }
17
19
  -keep class kotlin.jvm.** { *; }
18
20
  -keep class kotlin.collections.** { *; }
19
21
  -keep class kotlin.text.** { *; }
20
22
  -keep class kotlin.io.** { *; }
21
23
  -keep class okhttp3.** { *; }
24
+ -keep class kotlin.LazyKt { *; }
22
25
 
23
26
  -keep class androidx.concurrent.futures.** { *; }
24
27
 
@@ -7,6 +7,7 @@ import androidx.test.platform.app.InstrumentationRegistry;
7
7
  import androidx.test.rule.ActivityTestRule;
8
8
 
9
9
  import com.wix.detox.config.DetoxConfig;
10
+ import com.wix.detox.espresso.hierarchy.ViewHierarchyGenerator;
10
11
 
11
12
  /**
12
13
  * <p>Static class.</p>
@@ -141,4 +142,8 @@ public final class Detox {
141
142
  private static Context getAppContext() {
142
143
  return InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext();
143
144
  }
145
+
146
+ public static String generateViewHierarchyXml(boolean shouldInjectTestIds) {
147
+ return ViewHierarchyGenerator.generateXml(shouldInjectTestIds);
148
+ }
144
149
  }
@@ -1,16 +1,15 @@
1
1
  package com.wix.detox.espresso.assertion;
2
2
 
3
- import androidx.annotation.NonNull;
4
- import android.view.View;
3
+ import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
5
4
 
6
- import org.hamcrest.Matcher;
7
- import org.hamcrest.StringDescription;
5
+ import android.view.View;
8
6
 
7
+ import androidx.annotation.NonNull;
9
8
  import androidx.test.espresso.NoMatchingViewException;
10
9
  import androidx.test.espresso.ViewAssertion;
11
10
 
12
- import static androidx.test.espresso.core.internal.deps.guava.base.Preconditions.checkNotNull;
13
- import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
11
+ import org.hamcrest.Matcher;
12
+ import org.hamcrest.StringDescription;
14
13
 
15
14
  /**
16
15
  * A custom extension of {@link androidx.test.espresso.assertion.ViewAssertions}.
@@ -24,9 +23,8 @@ public class ViewAssertions {
24
23
  * which is more suitable for Detox' separated interaction-matcher architecture.
25
24
  * See {@link MatchesViewAssertion} for more details.
26
25
  */
27
- @SuppressWarnings("unchecked")
28
26
  public static ViewAssertion matches(final Matcher<? super View> viewMatcher) {
29
- return new MatchesViewAssertion((Matcher<? super View>) checkNotNull(viewMatcher));
27
+ return new MatchesViewAssertion(viewMatcher);
30
28
  }
31
29
 
32
30
  /**
@@ -0,0 +1,51 @@
1
+ package com.wix.detox.espresso.hierarchy
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.view.View
5
+ import java.lang.reflect.Field
6
+ import java.lang.reflect.Method
7
+
8
+ object RootViewsHelper {
9
+
10
+ /**
11
+ * Get rootviews from RootViewImpl instances that are stored in WindowManagerGlobal.
12
+ */
13
+ fun getRootViews(): List<View?>? {
14
+ val rootViewsReflectedObjects = getAllViewRootObjects()
15
+ val rootViews = rootViewsReflectedObjects?.map {
16
+ // Root View is stored in the ViewRootImpl instance
17
+ val getViewMethod = it.javaClass.getDeclaredMethod("getView")
18
+ getViewMethod.isAccessible = true
19
+
20
+ // Invoke the method to get the root View
21
+ getViewMethod.invoke(it) as? View
22
+ }
23
+ return rootViews
24
+ }
25
+
26
+ @SuppressLint("PrivateApi", "DiscouragedPrivateApi")
27
+ private fun getAllViewRootObjects(): List<Any>? {
28
+ return try {
29
+ // Get the WindowManagerGlobal class
30
+ val windowManagerGlobalClass = Class.forName("android.view.WindowManagerGlobal")
31
+
32
+ // Get the getInstance method
33
+ val getInstanceMethod: Method = windowManagerGlobalClass.getDeclaredMethod("getInstance")
34
+ getInstanceMethod.isAccessible = true
35
+
36
+ // Get the single instance of WindowManagerGlobal
37
+ val windowManagerGlobal = getInstanceMethod.invoke(null)
38
+
39
+ // Get the mRoots field, which is a list of ViewRootImpl instances
40
+ val mRootsField: Field = windowManagerGlobalClass.getDeclaredField("mRoots")
41
+ mRootsField.isAccessible = true
42
+
43
+ // Return the list of ViewRootImpl instances
44
+ @Suppress("UNCHECKED_CAST")
45
+ mRootsField.get(windowManagerGlobal) as? List<Any>
46
+ } catch (e: Exception) {
47
+ e.printStackTrace()
48
+ null
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,128 @@
1
+ package com.wix.detox.espresso.hierarchy
2
+
3
+ import android.util.Xml
4
+ import android.view.View
5
+ import android.view.ViewGroup
6
+ import android.widget.TextView
7
+ import com.wix.detox.reactnative.ui.getAccessibilityLabel
8
+ import org.xmlpull.v1.XmlSerializer
9
+ import java.io.StringWriter
10
+
11
+ object ViewHierarchyGenerator {
12
+ @JvmStatic
13
+ fun generateXml(shouldInjectTestIds: Boolean): String {
14
+ val rootViews = RootViewsHelper.getRootViews()
15
+ return generateXmlFromViews(rootViews, shouldInjectTestIds)
16
+ }
17
+
18
+ private fun generateXmlFromViews(rootViews: List<View?>?, shouldInjectTestIds: Boolean): String {
19
+ return StringWriter().use { writer ->
20
+ val serializer = Xml.newSerializer().apply {
21
+ setOutput(writer)
22
+ startDocument(Xml.Encoding.UTF_8.name, true)
23
+ setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true)
24
+ startTag("", "ViewHierarchy")
25
+ }
26
+
27
+ rootViews?.forEach { rootView ->
28
+ rootView?.let {
29
+ serializeViewHierarchy(it, serializer, shouldInjectTestIds, emptyList())
30
+ }
31
+ }
32
+
33
+ serializer.apply {
34
+ endTag("", "ViewHierarchy")
35
+ endDocument()
36
+ }
37
+
38
+ writer.toString()
39
+ }
40
+ }
41
+
42
+ private fun serializeViewHierarchy(
43
+ view: View,
44
+ serializer: XmlSerializer,
45
+ shouldInjectTestIds: Boolean,
46
+ indexPath: List<Int>
47
+ ) {
48
+ serializer.startTag("", view.javaClass.simpleName)
49
+ serializeViewAttributes(view, serializer, shouldInjectTestIds, indexPath)
50
+
51
+ if (view is ViewGroup) {
52
+ for (i in 0 until view.childCount) {
53
+ serializeViewHierarchy(
54
+ view.getChildAt(i),
55
+ serializer,
56
+ shouldInjectTestIds,
57
+ indexPath + i
58
+ )
59
+ }
60
+ }
61
+
62
+ serializer.endTag("", view.javaClass.simpleName)
63
+ }
64
+
65
+ private fun serializeViewAttributes(
66
+ view: View,
67
+ serializer: XmlSerializer,
68
+ shouldInjectTestIds: Boolean,
69
+ indexPath: List<Int>
70
+ ) {
71
+ val attributes = mutableMapOf(
72
+ "class" to view.javaClass.name,
73
+ "width" to view.width.toString(),
74
+ "height" to view.height.toString(),
75
+ "visibility" to view.visibilityToString(),
76
+ "alpha" to view.alpha.toString(),
77
+ "focused" to view.isFocused.toString(),
78
+ "value" to (view.contentDescription?.toString() ?: ""),
79
+ "label" to (view.getAccessibilityLabel()?.toString() ?: "")
80
+ )
81
+
82
+ view.id.takeIf { it != View.NO_ID }?.let {
83
+ attributes["id"] = try {
84
+ view.resources.getResourceName(it)
85
+ } catch (e: Exception) {
86
+ it.toString()
87
+ }
88
+ }
89
+
90
+ val location = IntArray(2).apply { view.getLocationInWindow(this) }
91
+ attributes["x"] = location[0].toString()
92
+ attributes["y"] = location[1].toString()
93
+
94
+ if (view is TextView) {
95
+ attributes["text"] = view.text.toString()
96
+ }
97
+
98
+ val currentTestId = view.tag?.toString() ?: ""
99
+
100
+ val injectedPrefix = "detox_temp_"
101
+ val isTestIdEmpty = currentTestId.isEmpty()
102
+ val isTestIdInjected = currentTestId.startsWith(injectedPrefix)
103
+ val shouldInjectNewTestId = shouldInjectTestIds && (isTestIdEmpty || isTestIdInjected)
104
+
105
+ if (shouldInjectNewTestId) {
106
+ val newTestId = "${injectedPrefix}${indexPath.joinToString("_")}"
107
+ view.tag = newTestId
108
+ attributes["testID"] = newTestId
109
+ } else {
110
+ attributes["testID"] = currentTestId
111
+ }
112
+
113
+ attributes
114
+ .filter { (_, value) ->
115
+ !value.isNullOrEmpty()
116
+ }
117
+ .forEach { (key, value) ->
118
+ serializer.attribute("", key, value)
119
+ }
120
+ }
121
+
122
+ private fun View.visibilityToString() = when (visibility) {
123
+ View.VISIBLE -> "visible"
124
+ View.INVISIBLE -> "invisible"
125
+ View.GONE -> "gone"
126
+ else -> "unknown"
127
+ }
128
+ }
package/detox.d.ts CHANGED
@@ -917,6 +917,18 @@ declare global {
917
917
  */
918
918
  captureViewHierarchy(name?: string): Promise<string>;
919
919
 
920
+ /**
921
+ * Dump the current view hierarchy of the app as an XML string.
922
+ * @param [shouldInjectTestIds=false] whether to inject testIDs into the view hierarchy when missing,
923
+ * to provide an identifiable reference for each element.
924
+ * @returns a string containing the XML representation of the view hierarchy.
925
+ * @example
926
+ * const viewHierarchy = await device.generateViewHierarchyXml();
927
+ * const viewHierarchyWithInjectedTestIds = await device.generateViewHierarchyXml(true);
928
+ * @note enabling shouldInjectTestIds changes the actual elements during the test run, use with caution.
929
+ */
930
+ generateViewHierarchyXml(shouldInjectTestIds?: boolean): Promise<string>;
931
+
920
932
  /**
921
933
  * Simulate shake (iOS Only)
922
934
  */
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.25.6",
4
+ "version": "20.26.2",
5
5
  "bin": {
6
6
  "detox": "local-cli/cli.js"
7
7
  },
@@ -71,6 +71,7 @@
71
71
  "caf": "^15.0.1",
72
72
  "chalk": "^4.0.0",
73
73
  "child-process-promise": "^2.2.0",
74
+ "detox-copilot": "^0.0.0",
74
75
  "execa": "^5.1.1",
75
76
  "find-up": "^5.0.0",
76
77
  "fs-extra": "^11.0.0",
@@ -115,5 +116,5 @@
115
116
  "browserslist": [
116
117
  "node 14"
117
118
  ],
118
- "gitHead": "0aa62157767805969e43dfe997f49d65652f76d2"
119
+ "gitHead": "e0a1fefeeec0382b5dc75613a2076d0f6a05e97f"
119
120
  }
@@ -69,6 +69,21 @@ class Detox {
69
69
  };
70
70
  }
71
71
 
72
+ static generateViewHierarchyXml(shouldInjectTestIds) {
73
+ if (typeof shouldInjectTestIds !== "boolean") throw new Error("shouldInjectTestIds should be a boolean, but got " + (shouldInjectTestIds + (" (" + (typeof shouldInjectTestIds + ")"))));
74
+ return {
75
+ target: {
76
+ type: "Class",
77
+ value: "com.wix.detox.Detox"
78
+ },
79
+ method: "generateViewHierarchyXml",
80
+ args: [{
81
+ type: "boolean",
82
+ value: shouldInjectTestIds
83
+ }]
84
+ };
85
+ }
86
+
72
87
  }
73
88
 
74
89
  module.exports = Detox;
@@ -225,6 +225,12 @@ class Client {
225
225
  }));
226
226
  }
227
227
 
228
+ async generateViewHierarchyXml({ shouldInjectTestIds }) {
229
+ return await this.sendAction(new actions.GenerateViewHierarchyXml({
230
+ shouldInjectTestIds
231
+ }));
232
+ }
233
+
228
234
  async currentStatus() {
229
235
  return await this.sendAction(new actions.CurrentStatus());
230
236
  }
@@ -292,6 +292,25 @@ class SetInstrumentsRecordingState extends Action {
292
292
  }
293
293
  }
294
294
 
295
+ class GenerateViewHierarchyXml extends Action {
296
+ constructor(params) {
297
+ super('generateViewHierarchyXml', params);
298
+ }
299
+
300
+ get isAtomic() {
301
+ return false;
302
+ }
303
+
304
+ get timeout() {
305
+ return 0;
306
+ }
307
+
308
+ async handle(response) {
309
+ this.expectResponseOfType(response, 'generateViewHierarchyXmlResult');
310
+ return response.params.viewHierarchy;
311
+ }
312
+ }
313
+
295
314
  class CaptureViewHierarchy extends Action {
296
315
  constructor(params) {
297
316
  super('captureViewHierarchy', params);
@@ -312,7 +331,7 @@ class CaptureViewHierarchy extends Action {
312
331
  if (captureViewHierarchyError) {
313
332
  throw new DetoxRuntimeError({
314
333
  message: 'Failed to capture view hierarchy. Reason:\n',
315
- debugInfo: captureViewHierarchyError,
334
+ debugInfo: captureViewHierarchyError
316
335
  });
317
336
  }
318
337
 
@@ -336,4 +355,5 @@ module.exports = {
336
355
  SetOrientation,
337
356
  SetInstrumentsRecordingState,
338
357
  CaptureViewHierarchy,
358
+ GenerateViewHierarchyXml
339
359
  };
@@ -0,0 +1,140 @@
1
+ const { device } = require('../..');
2
+
3
+ class DetoxDriver {
4
+ constructor() {
5
+ this.availableAPI = {
6
+ matchers: [
7
+ {
8
+ signature: 'by.id(id: string)',
9
+ description: 'Matches elements by their test ID.',
10
+ example: "element(by.id('loginButton'))",
11
+ guidelines: ['Always use test-ids (accessibility identifiers) from the UI hierarchy to identify elements.']
12
+ },
13
+ {
14
+ signature: 'by.text(text: string)',
15
+ description: 'Matches elements by their text.',
16
+ example: "element(by.text('Login'))",
17
+ guidelines: ['Avoid using text matchers when possible, prefer test-ids.']
18
+ },
19
+ {
20
+ signature: 'by.type(type: string)',
21
+ description: 'Matches elements by their type.',
22
+ example: "element(by.type('RCTTextInput'))",
23
+ guidelines: ['Use type matchers as a last resort, prefer test-ids.']
24
+ }
25
+ ],
26
+ actions: [
27
+ {
28
+ signature: 'tap(point?: Point2D)',
29
+ description: 'Simulates tap on an element',
30
+ example: "await element(by.id('loginButton')).tap();",
31
+ guidelines: ['Use element(by.id(\'testID\')) to locate elements.']
32
+ },
33
+ {
34
+ signature: 'longPress(point?: Point2D, duration?: number)',
35
+ description: 'Simulates long press on an element',
36
+ example: "await element(by.id('menuItem')).longPress();",
37
+ guidelines: ['If the target element is not accessible, interact with its container or the most relevant parent element.']
38
+ },
39
+ {
40
+ signature: 'typeText(text: string)',
41
+ description: 'Types text into a text field',
42
+ example: "await element(by.id('usernameInput')).typeText('myusername');",
43
+ guidelines: ['Typing can only be done on text field elements.']
44
+ },
45
+ {
46
+ signature: 'replaceText(text: string)',
47
+ description: 'Replaces text in a text field',
48
+ example: "await element(by.id('usernameInput')).replaceText('newusername');",
49
+ guidelines: ['Use this to replace existing text in a field.']
50
+ },
51
+ {
52
+ signature: 'clearText()',
53
+ description: 'Clears text from a text field',
54
+ example: "await element(by.id('usernameInput')).clearText();",
55
+ guidelines: ['Use this to clear existing text from a field.']
56
+ },
57
+ {
58
+ signature: 'scrollTo(edge: Direction, startPositionX?: number, startPositionY?: number)',
59
+ description: 'Scrolls to an edge',
60
+ example: "await element(by.id('scrollView')).scrollTo('bottom');",
61
+ guidelines: ['Scrolling must be done only on scroll-view elements.']
62
+ },
63
+ {
64
+ signature: 'scrollToIndex(index: Number)',
65
+ description: 'Scrolls to a specific index',
66
+ example: "await element(by.id('flatList')).scrollToIndex(5);",
67
+ guidelines: ['Use this for scrolling to a specific item in a list.']
68
+ },
69
+ {
70
+ signature: 'adjustSliderToPosition(newPosition: number)',
71
+ description: 'Adjusts slider to a position',
72
+ example: "await element(by.id('slider')).adjustSliderToPosition(0.75);",
73
+ guidelines: ['The position should be a number between 0 and 1.']
74
+ },
75
+ {
76
+ signature: 'setColumnToValue(column: number, value: string)',
77
+ description: 'Sets picker view column to a value (iOS only)',
78
+ example: "await element(by.id('datePicker')).setColumnToValue(1, '2023');",
79
+ guidelines: ['This is only available on iOS.']
80
+ },
81
+ {
82
+ signature: 'performAccessibilityAction(actionName: string)',
83
+ description: 'Triggers an accessibility action',
84
+ example: "await element(by.id('button')).performAccessibilityAction('longpress');",
85
+ guidelines: ['Use the provided value from the intent and do not change it.']
86
+ },
87
+ {
88
+ signature: 'swipe(direction: Direction, speed?: Speed, percentage?: number)',
89
+ description: 'Swipes in the specified direction',
90
+ example: "await element(by.id('card')).swipe('left', 'fast');",
91
+ guidelines: ['Use this for swiping gestures on elements.']
92
+ },
93
+ {
94
+ signature: 'pinch(scale: number, speed?: Speed, angle?: number)',
95
+ description: 'Performs a pinch gesture (iOS only)',
96
+ example: "await element(by.id('image')).pinch(0.5);",
97
+ guidelines: ['This is only available on iOS. Scale < 1 zooms out, scale > 1 zooms in.']
98
+ }
99
+ ],
100
+ assertions: [
101
+ {
102
+ signature: 'toBeVisible()',
103
+ description: 'Asserts that the element is visible',
104
+ example: "await expect(element(by.id('loginButton'))).toBeVisible();",
105
+ guidelines: ['Use this to check if an element is visible on the screen.']
106
+ },
107
+ {
108
+ signature: 'toExist()',
109
+ description: 'Asserts that the element exists',
110
+ example: "await expect(element(by.id('username'))).toExist();",
111
+ guidelines: ['Use this to check if an element exists in the hierarchy, even if not visible.']
112
+ },
113
+ {
114
+ signature: 'toHaveText(text: string)',
115
+ description: 'Asserts that the element has the specified text',
116
+ example: "await expect(element(by.id('label'))).toHaveText('Hello, World!');",
117
+ guidelines: ['Use this to check the text content of an element.']
118
+ },
119
+ {
120
+ signature: 'toHaveValue(value: string)',
121
+ description: 'Asserts that the element has the specified value',
122
+ example: "await expect(element(by.id('slider'))).toHaveValue('0.5');",
123
+ guidelines: ['Use this to check the value of an element.']
124
+ }
125
+ ]
126
+ };
127
+ }
128
+
129
+ async captureSnapshotImage() {
130
+ const fileName = `snapshot_${Date.now()}.png`;
131
+ await device.takeScreenshot(fileName);
132
+ return fileName;
133
+ }
134
+
135
+ async captureViewHierarchyString() {
136
+ return device.generateViewHierarchyXml();
137
+ }
138
+ }
139
+
140
+ module.exports = DetoxDriver;
@@ -20,6 +20,7 @@ class RuntimeDevice {
20
20
  'clearKeychain',
21
21
  'disableSynchronization',
22
22
  'enableSynchronization',
23
+ 'generateViewHierarchyXml',
23
24
  'installApp',
24
25
  'installUtilBinaries',
25
26
  'launchApp',
@@ -195,6 +196,10 @@ class RuntimeDevice {
195
196
  return this.deviceDriver.captureViewHierarchy(name);
196
197
  }
197
198
 
199
+ async generateViewHierarchyXml(shouldInjectTestIds = false) {
200
+ return await this.deviceDriver.generateViewHierarchyXml(shouldInjectTestIds);
201
+ }
202
+
198
203
  async sendToHome() {
199
204
  await this.deviceDriver.sendToHome();
200
205
  await this.deviceDriver.waitForBackground();
@@ -222,6 +222,10 @@ class DeviceDriverBase {
222
222
  async captureViewHierarchy() {
223
223
  return '';
224
224
  }
225
+
226
+ async generateViewHierarchyXml(_shouldInjectTestIds) {
227
+ return '';
228
+ }
225
229
  }
226
230
 
227
231
  module.exports = DeviceDriverBase;
@@ -245,6 +245,11 @@ class AndroidDriver extends DeviceDriverBase {
245
245
  await this.invocationManager.execute(call);
246
246
  }
247
247
 
248
+ async generateViewHierarchyXml(shouldInjectTestIds) {
249
+ const hierarchy = await this.invocationManager.execute(DetoxApi.generateViewHierarchyXml(shouldInjectTestIds));
250
+ return hierarchy.result;
251
+ }
252
+
248
253
  _getAppInstallPaths(_appBinaryPath, _testBinaryPath) {
249
254
  const appBinaryPath = getAbsoluteBinaryPath(_appBinaryPath);
250
255
  const testBinaryPath = _testBinaryPath ? getAbsoluteBinaryPath(_testBinaryPath) : this._getTestApkPath(appBinaryPath);
@@ -194,6 +194,10 @@ class SimulatorDriver extends IosDriver {
194
194
  return viewHierarchyURL;
195
195
  }
196
196
 
197
+ async generateViewHierarchyXml(shouldInjectTestIds) {
198
+ return await this.client.generateViewHierarchyXml({ shouldInjectTestIds });
199
+ }
200
+
197
201
  async setStatusBar(flags) {
198
202
  await this._applesimutils.statusBarOverride(this.udid, flags);
199
203
  }
@@ -1 +0,0 @@
1
- 94c7ef8a28dc964b657eea2fe3b976a0
@@ -1 +0,0 @@
1
- b7253a70da80514f9fb458066ba45f5aeda16686
@@ -1 +0,0 @@
1
- 21b3215e69149679168a08bfa855a0089455f54ba9ab883ef1b268c001ce2216
@@ -1 +0,0 @@
1
- a119637d941ad18e51e753ea1ee6a3cd6d068166cafb54cb0474373f48e84647875c742c4c54670af01f8d3f055c3e1907945b8811c5c1206aec0152c4186460
@@ -1 +0,0 @@
1
- f8f2a2bd622fadc1baf0d5be4f21622f
@@ -1 +0,0 @@
1
- 3ce2c636fb75e7758525c444e9b19f7a69ff7aa2
@@ -1 +0,0 @@
1
- b6d5ba6221494632ff63d50785be381add4d688d167e1696d3f027d76a768042
@@ -1 +0,0 @@
1
- 0b22922e5fb5f7c8d8851661cf96982870f7a942939f5648ad4f72da1711515be0a6198fd9d789c2d45deedb0129452a6167f7068ab68b92c39d890fd2e467aa
@@ -1 +0,0 @@
1
- 48e491ac5e2166bc14b836ac291d9a10
@@ -1 +0,0 @@
1
- 874588e8c8d28d2cf1ef211ece43cb92dd4dd0ba
@@ -1 +0,0 @@
1
- 69b0bb114b00a7419670658bc0326c64dde8b2b4a4ec49c540de1f9186d8c324
@@ -1 +0,0 @@
1
- 472e53824831f47311d2848f3b6093d269f5dab58e01bded5ce08b3421e80916336d4f5001e8b9e1409b1a1e214023fc62de45d46931647aaee268af3c858947
@@ -1 +0,0 @@
1
- 208d53855f5405b6ca2ec1a57b08aa8a
@@ -1 +0,0 @@
1
- 4039b32649b959622a11f2da5640e3cd05d257da
@@ -1 +0,0 @@
1
- 1f35717c6a33f825af51b62048b2d63c8a8f9d1de927f8226af66b33f38ee0ea
@@ -1 +0,0 @@
1
- 2ffecf597779fcbe167e95d8bd43ae895f3484fe4f755624894f1be22e840242b8d6a57edb20996d36276757ea11a41c22cc892517e3a70a5f6952726b6c7032
@@ -1 +0,0 @@
1
- d271489c0570c8529c634b79843bc0a0
@@ -1 +0,0 @@
1
- e0bceb0063fccfb5b5a0c173587a33720eca9d8d
@@ -1 +0,0 @@
1
- 328f2d83c0c54a3ac3e8cc0aadadd27f622c79d5c6f4490c2852ca8ef5f76b8f
@@ -1 +0,0 @@
1
- 22fe1aa0a7686ab99c4c5cb81bbf8c16e35c79039fc2dc070c9c6c14687042cd3182cc554ee0da4c48b5ec8330fa98b9887a8e7cf06f04c66f30612e919cbc2a
@@ -1 +0,0 @@
1
- 3e46d6dfb8ac381ce01685ebc04694e4
@@ -1 +0,0 @@
1
- 08e1e7773a8fb58ce4acac2310157b186767b361
@@ -1 +0,0 @@
1
- 29a7dee48d0b9f065ae740b3da5e2b5f57d208ac7ad856947f8b94db980d431a
@@ -1 +0,0 @@
1
- ad4d04e5db6c1f7d4430107cdbf7a52c3f9da6e5b53c3111288bf328ea8c0598a9fc481681781a7119994457bc0a1ff3968b5fdf38d5d1a36e40363be4cbbbe7