detox 20.21.0 → 20.21.1-smoke.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0-sources.jar → 20.21.1-smoke.0/detox-20.21.1-smoke.0-sources.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0-sources.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0-sources.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0-sources.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0-sources.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.pom → 20.21.1-smoke.0/detox-20.21.1-smoke.0.pom} +1 -1
  7. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0.pom.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0.pom.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.0.pom.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.21.1-smoke.0/detox-20.21.1-smoke.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-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0-sources.jar → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0-sources.jar} +0 -0
  17. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0-sources.jar.md5 +1 -0
  18. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0-sources.jar.sha1 +1 -0
  19. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0-sources.jar.sha256 +1 -0
  20. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0-sources.jar.sha512 +1 -0
  21. package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.pom → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.pom} +1 -1
  22. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.pom.md5 +1 -0
  23. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.pom.sha1 +1 -0
  24. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.pom.sha256 +1 -0
  25. package/Detox-android/com/wix/detox-legacy/20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.pom.sha512 +1 -0
  26. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml +4 -4
  27. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.md5 +1 -1
  28. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha1 +1 -1
  29. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha256 +1 -1
  30. package/Detox-android/com/wix/detox-legacy/maven-metadata.xml.sha512 +1 -1
  31. package/Detox-ios-framework.tbz +0 -0
  32. package/Detox-ios-src.tbz +0 -0
  33. package/Detox-ios-xcuitest.tbz +0 -0
  34. package/detox.d.ts +78 -1
  35. package/globals.d.ts +2 -0
  36. package/local-cli/build-framework-cache.js +19 -11
  37. package/local-cli/clean-framework-cache.js +19 -14
  38. package/local-cli/rebuild-framework-cache.js +20 -16
  39. package/local-cli/utils/frameworkUtils.js +77 -0
  40. package/package.json +4 -4
  41. package/scripts/build_framework.ios.sh +26 -60
  42. package/scripts/build_local_framework.ios.sh +62 -0
  43. package/scripts/build_local_xcuitest.ios.sh +53 -0
  44. package/scripts/build_xcuitest.ios.sh +18 -0
  45. package/scripts/pack_ios.sh +18 -9
  46. package/scripts/postinstall.js +11 -4
  47. package/src/android/AndroidExpect.js +5 -0
  48. package/src/android/matchers/index.js +7 -0
  49. package/src/ios/XCUITestRunner.js +52 -0
  50. package/src/ios/expectTwo.js +49 -28
  51. package/src/ios/system.js +124 -0
  52. package/src/ios/web.js +3 -4
  53. package/src/matchers/factories/index.js +15 -8
  54. package/src/utils/assertArgument.js +11 -2
  55. package/src/utils/environment.js +34 -14
  56. package/src/utils/invocationTraceDescriptions.js +4 -0
  57. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0-sources.jar.md5 +0 -1
  58. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0-sources.jar.sha1 +0 -1
  59. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0-sources.jar.sha256 +0 -1
  60. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0-sources.jar.sha512 +0 -1
  61. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0.pom.md5 +0 -1
  62. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0.pom.sha1 +0 -1
  63. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0.pom.sha256 +0 -1
  64. package/Detox-android/com/wix/detox/20.21.0/detox-20.21.0.pom.sha512 +0 -1
  65. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0-sources.jar.md5 +0 -1
  66. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0-sources.jar.sha1 +0 -1
  67. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0-sources.jar.sha256 +0 -1
  68. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0-sources.jar.sha512 +0 -1
  69. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0.pom.md5 +0 -1
  70. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0.pom.sha1 +0 -1
  71. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0.pom.sha256 +0 -1
  72. package/Detox-android/com/wix/detox-legacy/20.21.0/detox-legacy-20.21.0.pom.sha512 +0 -1
  73. package/Detox-ios.tbz +0 -0
  74. package/scripts/build_universal_framework.sh +0 -14
  75. package/scripts/build_universal_framework_legacy.sh +0 -76
  76. package/scripts/build_universal_framework_modern.sh +0 -28
  77. /package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.aar → 20.21.1-smoke.0/detox-20.21.1-smoke.0.aar} +0 -0
  78. /package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.aar.md5 → 20.21.1-smoke.0/detox-20.21.1-smoke.0.aar.md5} +0 -0
  79. /package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.aar.sha1 → 20.21.1-smoke.0/detox-20.21.1-smoke.0.aar.sha1} +0 -0
  80. /package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.aar.sha256 → 20.21.1-smoke.0/detox-20.21.1-smoke.0.aar.sha256} +0 -0
  81. /package/Detox-android/com/wix/detox/{20.21.0/detox-20.21.0.aar.sha512 → 20.21.1-smoke.0/detox-20.21.1-smoke.0.aar.sha512} +0 -0
  82. /package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.aar → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.aar} +0 -0
  83. /package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.aar.md5 → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.aar.md5} +0 -0
  84. /package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.aar.sha1 → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.aar.sha1} +0 -0
  85. /package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.aar.sha256 → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.aar.sha256} +0 -0
  86. /package/Detox-android/com/wix/detox-legacy/{20.21.0/detox-legacy-20.21.0.aar.sha512 → 20.21.1-smoke.0/detox-legacy-20.21.1-smoke.0.aar.sha512} +0 -0
@@ -0,0 +1,62 @@
1
+ #!/bin/bash -e
2
+
3
+ # Ensure Xcode is installed or print a warning message and return.
4
+ xcodebuild -version &>/dev/null || { echo "WARNING: Xcode is not installed on this machine. Skipping iOS framework build phase"; exit 0; }
5
+
6
+ detoxRootPath="$(dirname "$(dirname "$0")")"
7
+ detoxVersion=`node -p "require('${detoxRootPath}/package.json').version"`
8
+
9
+ sha1=`(echo "${detoxVersion}" && xcodebuild -version) | shasum | awk '{print $1}' #"${2}"`
10
+ detoxFrameworkDirPath="$HOME/Library/Detox/ios/framework/${sha1}"
11
+ detoxFrameworkPath="${detoxFrameworkDirPath}/Detox.framework"
12
+
13
+
14
+ function prepareAndBuildFramework () {
15
+ if [ -d "$detoxRootPath"/ios ]; then
16
+ detoxSourcePath="${detoxRootPath}"/ios
17
+ echo "Dev mode, building from ${detoxSourcePath}"
18
+ buildFramework "${detoxSourcePath}"
19
+ else
20
+ extractFramework
21
+ fi
22
+ }
23
+
24
+ function extractFramework () {
25
+ echo "Extracting Detox framework..."
26
+ mkdir -p "${detoxFrameworkDirPath}"
27
+ tar -xjf "${detoxRootPath}"/Detox-ios-framework.tbz -C "${detoxFrameworkDirPath}"
28
+ }
29
+
30
+ function buildFramework () {
31
+ detoxSourcePath="${1}"
32
+ echo "Building Detox.framework from ${detoxSourcePath} into ${detoxFrameworkDirPath}"
33
+ mkdir -p "${detoxFrameworkDirPath}"
34
+ logPath="${detoxFrameworkDirPath}"/detox_ios.log
35
+ echo "Build log: ${logPath}"
36
+ echo -n "" > "${logPath}"
37
+ "${detoxRootPath}"/scripts/build_framework.ios.sh "${detoxSourcePath}"/Detox.xcodeproj "${detoxFrameworkDirPath}" &> "${logPath}" || {
38
+ echo -e "#################################\nError building Detox.framework:\n----------------------------------\n"
39
+ cat "${logPath}"
40
+ echo "#################################"
41
+ exit 1
42
+ }
43
+ }
44
+
45
+ function main () {
46
+ if [ -d "${detoxFrameworkDirPath}" ]; then
47
+ if [ ! -d "${detoxFrameworkPath}" ]; then
48
+ echo "${detoxFrameworkDirPath} was found, but could not find Detox.framework inside it. This means that the Detox framework build process was interrupted.
49
+ deleting ${detoxFrameworkDirPath} and trying to rebuild."
50
+ rm -rf "${detoxFrameworkDirPath}"
51
+ prepareAndBuildFramework
52
+ else
53
+ echo "Detox.framework exists, skipping..."
54
+ fi
55
+ else
56
+ prepareAndBuildFramework
57
+ fi
58
+
59
+ echo "Done"
60
+ }
61
+
62
+ main
@@ -0,0 +1,53 @@
1
+ #!/bin/bash -e
2
+
3
+ # Ensure Xcode is installed or print a warning message and return.
4
+ xcodebuild -version &>/dev/null || { echo "WARNING: Xcode is not installed on this machine. Skipping iOS xctest runner build phase"; exit 0; }
5
+
6
+ detoxRootPath="$(dirname "$(dirname "$0")")"
7
+ detoxVersion=`node -p "require('${detoxRootPath}/package.json').version"`
8
+
9
+ sha1=`(echo "${detoxVersion}" && xcodebuild -version) | shasum | awk '{print $1}' #"${2}"`
10
+ detoxXctestRunnerDirPath="$HOME/Library/Detox/ios/xcuitest-runner/${sha1}"
11
+
12
+ function prepareAndBuildXctestRunner () {
13
+ if [ -d "$detoxRootPath"/ios ]; then
14
+ detoxSourcePath="${detoxRootPath}"/ios
15
+ echo "Dev mode, building XCUITest runner from ${detoxSourcePath}"
16
+ buildXctestRunner "${detoxSourcePath}"
17
+ else
18
+ extractXctestRunner
19
+ fi
20
+ }
21
+
22
+ function extractXctestRunner () {
23
+ echo "Extracting Detox XCUITest runner..."
24
+ mkdir -p "${detoxXctestRunnerDirPath}"
25
+ tar -xjf "${detoxRootPath}"/Detox-ios-xcuitest.tbz -C "${detoxXctestRunnerDirPath}"
26
+ }
27
+
28
+ function buildXctestRunner () {
29
+ detoxSourcePath="${1}"
30
+ echo "Building XCUITest runner from ${detoxSourcePath} into ${detoxXctestRunnerDirPath}"
31
+ mkdir -p "${detoxXctestRunnerDirPath}"
32
+ logPath="${detoxXctestRunnerDirPath}"/detox_ios_xcuitest.log
33
+ echo "Build log: ${logPath}"
34
+ echo -n "" > "${logPath}"
35
+ "${detoxRootPath}"/scripts/build_xcuitest.ios.sh "${detoxSourcePath}"/DetoxXCUITestRunner/DetoxXCUITestRunner.xcodeproj "${detoxXctestRunnerDirPath}" &> "${logPath}" || {
36
+ echo -e "#################################\nError building DetoxXCUITestRunner.xctestrun:\n----------------------------------\n"
37
+ cat "${logPath}"
38
+ echo "#################################"
39
+ exit 1
40
+ }
41
+ }
42
+
43
+ function main () {
44
+ if [ ! -d "${detoxXctestRunnerDirPath}" ]; then
45
+ prepareAndBuildXctestRunner
46
+ else
47
+ echo "XCUITest-runner exists, skipping..."
48
+ fi
49
+
50
+ echo "Done"
51
+ }
52
+
53
+ main
@@ -0,0 +1,18 @@
1
+ #!/bin/bash -e
2
+
3
+ XCODEPROJ=$1
4
+ XCUITEST_OUTPUT_DIR=$2
5
+ CONFIGURATION=Release
6
+ PROJECT_NAME=DetoxXCUITestRunner
7
+
8
+ # Clean up the output directory
9
+
10
+ rm -fr "${XCUITEST_OUTPUT_DIR}"
11
+
12
+ # Make sure the output directory exists
13
+
14
+ mkdir -p "${XCUITEST_OUTPUT_DIR}"
15
+
16
+ # Build Simulator version
17
+
18
+ xcodebuild -project "${XCODEPROJ}" -scheme "${PROJECT_NAME}" -UseNewBuildSystem="YES" -configuration "${CONFIGURATION}" -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath "${XCUITEST_OUTPUT_DIR}" build-for-testing -quiet
@@ -1,23 +1,32 @@
1
1
  #!/bin/bash -e
2
2
 
3
3
  rm -rf Detox-ios-src.tbz
4
- rm -rf Detox-ios.tbz
4
+ rm -rf Detox-ios-framework.tbz
5
+ rm -rf Detox-ios-xcuitest.tbz
5
6
  rm -rf build_temp
6
7
 
7
8
  find ./ios -name Build -type d -exec rm -rf {} \;
8
9
 
9
- #Package sources
10
- pushd . &> /dev/null
10
+ # Package sources
11
11
  cd ios
12
12
  tar --exclude-from=.tbzignore -cjf ../Detox-ios-src.tbz .
13
- popd &> /dev/null
13
+ cd ..
14
14
 
15
- #Package prebuilt framework
15
+ echo "Packaging iOS sources and prebuilt frameworks"
16
+
17
+ # Create temp build directory
16
18
  mkdir build_temp
17
- scripts/build_universal_framework.sh "ios/Detox.xcodeproj" "build_temp" &> build_temp/detox_ios.log
18
- pushd . &> /dev/null
19
+
20
+ # Package prebuilt framework
21
+ scripts/build_framework.ios.sh "ios/Detox.xcodeproj" "build_temp"
22
+
23
+ # Package prebuilt XCUITest runner
24
+ scripts/build_xcuitest.ios.sh "ios/DetoxXCUITestRunner/DetoxXCUITestRunner.xcodeproj" "build_temp"
25
+
19
26
  cd build_temp
20
- tar --exclude-from=../ios/.tbzignore -cjf ../Detox-ios.tbz .
21
- popd &> /dev/null
27
+ tar --exclude-from=../ios/.tbzignore -cjf ../Detox-ios-xcuitest.tbz .
28
+ tar --exclude-from=../ios/.tbzignore -cjf ../Detox-ios-framework.tbz .
29
+ cd ..
22
30
 
31
+ # Cleanup
23
32
  rm -fr build_temp
@@ -1,8 +1,15 @@
1
+ const { platform, env } = process;
2
+
1
3
  const { setGradleVersionByRNVersion } = require('./updateGradle');
2
- if (process.platform === 'darwin' && !process.env.DETOX_DISABLE_POSTINSTALL) {
3
- require('child_process').execFileSync(`${__dirname}/build_framework.ios.sh`, {
4
- stdio: 'inherit'
5
- });
6
4
 
5
+ const isDarwin = platform === 'darwin';
6
+ const shouldInstallDetox = !env.DETOX_DISABLE_POSTINSTALL;
7
+
8
+ if (isDarwin && shouldInstallDetox) {
9
+ const execFileSync = require('child_process').execFileSync;
10
+
11
+ execFileSync(`${__dirname}/build_local_framework.ios.sh`, { stdio: 'inherit' });
12
+ execFileSync(`${__dirname}/build_local_xcuitest.ios.sh`, { stdio: 'inherit' });
7
13
  }
14
+
8
15
  setGradleVersionByRNVersion();
@@ -21,6 +21,7 @@ class AndroidExpect {
21
21
  this.waitFor = this.waitFor.bind(this);
22
22
  this.web = this.web.bind(this);
23
23
  this.web.element = (...args) => this.web().element(...args);
24
+ this.system = { element: (...args) => this.systemElement(...args) };
24
25
  }
25
26
 
26
27
  element(matcher) {
@@ -45,6 +46,10 @@ class AndroidExpect {
45
46
  throw new DetoxRuntimeError(`web() argument is invalid, expected a native matcher, but got ${typeof element}`);
46
47
  }
47
48
 
49
+ systemElement(_matcher) {
50
+ throw new DetoxRuntimeError('System interactions are not supported on Android, use UiDevice APIs directly instead');
51
+ }
52
+
48
53
  expect(element) {
49
54
  if (element instanceof WebElement) return new WebExpectElement(this._invocationManager, element);
50
55
  if (element instanceof NativeElement) return new NativeExpectElement(this._invocationManager, element);
@@ -1,3 +1,5 @@
1
+ const { DetoxRuntimeError } = require('../../errors');
2
+
1
3
  const native = require('./native');
2
4
  const web = require('./web');
3
5
 
@@ -20,4 +22,9 @@ module.exports = {
20
22
  href: (value) => new web.LinkTextMatcher(value),
21
23
  hrefContains: (value) => new web.PartialLinkTextMatcher(value),
22
24
  },
25
+
26
+ system: {
27
+ label: (_value) => { throw new DetoxRuntimeError('System interactions are not supported on Android, use UiDevice APIs directly instead'); },
28
+ type: (_value) => { throw new DetoxRuntimeError('System interactions are not supported on Android, use UiDevice APIs directly instead'); },
29
+ }
23
30
  };
@@ -0,0 +1,52 @@
1
+ const { exec } = require('child-process-promise');
2
+
3
+ const DetoxRuntimeError = require('../errors/DetoxRuntimeError');
4
+ const environment = require('../utils/environment');
5
+ const log = require('../utils/logger').child({ cat: 'xcuitest-runner' });
6
+
7
+ class XCUITestRunner {
8
+ constructor({ simulatorId }) {
9
+ this.simulatorId = simulatorId;
10
+ }
11
+
12
+ async execute(invocationParams) {
13
+ log.trace(
14
+ { event: 'XCUITEST_RUNNER' },
15
+ 'invocation params: %j, simulator id: %s', invocationParams, this.simulatorId
16
+ );
17
+
18
+ const base64InvocationParams = Buffer.from(JSON.stringify(invocationParams)).toString('base64');
19
+
20
+ const runnerPath = await environment.getXCUITestRunnerPath();
21
+ if (!runnerPath) {
22
+ throw new DetoxRuntimeError({
23
+ message: 'XCUITest runner path could not be found',
24
+ hint: DetoxRuntimeError.reportIssue,
25
+ });
26
+ }
27
+
28
+ const flags = [
29
+ '-xctestrun', runnerPath,
30
+ '-sdk', 'iphonesimulator',
31
+ '-destination', `"platform=iOS Simulator,id=${this.simulatorId}"`,
32
+ 'test-without-building',
33
+ ];
34
+
35
+ try {
36
+ return await exec(`TEST_RUNNER_PARAMS="${base64InvocationParams}" xcodebuild ${flags.join(' ')}`);
37
+ } catch (e) {
38
+ const stdout = e.stdout.toString();
39
+ const innerError = this.findInnerError(stdout);
40
+ throw new DetoxRuntimeError(innerError);
41
+ }
42
+ }
43
+
44
+ findInnerError(stdout) {
45
+ const match = stdout.match(/DTXError: .*/);
46
+ return match ?
47
+ match[0].split('DTXError: ')[1] :
48
+ `XCUITest runner failed with no error message. Runner stdout: ${stdout}`;
49
+ }
50
+ }
51
+
52
+ module.exports = XCUITestRunner;
@@ -1,13 +1,11 @@
1
1
  // @ts-nocheck
2
- const assert = require('assert');
3
2
  const path = require('path');
4
3
 
5
4
  const fs = require('fs-extra');
6
5
  const _ = require('lodash');
7
6
  const tempfile = require('tempfile');
8
7
 
9
-
10
- const { assertEnum, assertNormalized } = require('../utils/assertArgument');
8
+ const { assertTraceDescription, assertEnum, assertNormalized } = require('../utils/assertArgument');
11
9
  const { removeMilliseconds } = require('../utils/dateUtils');
12
10
  const { actionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
13
11
  const { isRegExp } = require('../utils/isRegExp');
@@ -15,8 +13,10 @@ const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
15
13
  const mapLongPressArguments = require('../utils/mapLongPressArguments');
16
14
  const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);
17
15
 
16
+ const { systemElement, systemMatcher, systemExpect, isSystemElement } = require('./system');
18
17
  const { webElement, webMatcher, webExpect, isWebElement } = require('./web');
19
18
 
19
+
20
20
  const assertDirection = assertEnum(['left', 'right', 'up', 'down']);
21
21
  const assertSpeed = assertEnum(['fast', 'slow']);
22
22
 
@@ -27,6 +27,11 @@ class Expect {
27
27
  this.modifiers = [];
28
28
  }
29
29
 
30
+ get not() {
31
+ this.modifiers.push('not');
32
+ return this;
33
+ }
34
+
30
35
  toBeVisible(percent) {
31
36
  if (percent !== undefined && (!Number.isSafeInteger(percent) || percent < 1 || percent > 100)) {
32
37
  throw new Error('`percent` must be an integer between 1 and 100, but got '
@@ -104,11 +109,6 @@ class Expect {
104
109
  return this.toHaveValue(`${Number(value)}`);
105
110
  }
106
111
 
107
- get not() {
108
- this.modifiers.push('not');
109
- return this;
110
- }
111
-
112
112
  createInvocation(expectation, ...params) {
113
113
  const definedParams = _.without(params, undefined);
114
114
  return {
@@ -122,7 +122,7 @@ class Expect {
122
122
  }
123
123
 
124
124
  expect(expectation, traceDescription, ...params) {
125
- assert(traceDescription, `must provide trace description for expectation: \n ${JSON.stringify(expectation)}`);
125
+ assertTraceDescription(traceDescription);
126
126
 
127
127
  const invocation = this.createInvocation(expectation, ...params);
128
128
  traceDescription = expectDescription.full(traceDescription, this.modifiers.includes('not'));
@@ -374,6 +374,14 @@ class InternalElement extends Element {
374
374
  }
375
375
 
376
376
  class By {
377
+ get web() {
378
+ return webMatcher();
379
+ }
380
+
381
+ get system() {
382
+ return systemMatcher();
383
+ }
384
+
377
385
  id(id) {
378
386
  return new Matcher().id(id);
379
387
  }
@@ -401,13 +409,18 @@ class By {
401
409
  value(value) {
402
410
  return new Matcher().value(value);
403
411
  }
404
-
405
- get web() {
406
- return webMatcher();
407
- }
408
412
  }
409
413
 
410
414
  class Matcher {
415
+ /** @private */
416
+ static *predicates(matcher) {
417
+ if (matcher.predicate.type === 'and') {
418
+ yield* matcher.predicate.predicates;
419
+ } else {
420
+ yield matcher.predicate;
421
+ }
422
+ }
423
+
411
424
  accessibilityLabel(label) {
412
425
  return this.label(label);
413
426
  }
@@ -477,15 +490,6 @@ class Matcher {
477
490
 
478
491
  return result;
479
492
  }
480
-
481
- /** @private */
482
- static *predicates(matcher) {
483
- if (matcher.predicate.type === 'and') {
484
- yield* matcher.predicate.predicates;
485
- } else {
486
- yield matcher.predicate;
487
- }
488
- }
489
493
  }
490
494
 
491
495
  class WaitFor {
@@ -496,6 +500,11 @@ class WaitFor {
496
500
  this._emitter = emitter;
497
501
  }
498
502
 
503
+ get not() {
504
+ this.expectation.not;
505
+ return this;
506
+ }
507
+
499
508
  toBeVisible(percent) {
500
509
  this.expectation = this.expectation.toBeVisible(percent);
501
510
  return this;
@@ -566,11 +575,6 @@ class WaitFor {
566
575
  return this;
567
576
  }
568
577
 
569
- get not() {
570
- this.expectation.not;
571
- return this;
572
- }
573
-
574
578
  withTimeout(timeout) {
575
579
  if (typeof timeout !== 'number') throw new Error('text should be a number, but got ' + (timeout + (' (' + (typeof timeout + ')'))));
576
580
  if (timeout < 0) throw new Error('timeout must be larger than 0');
@@ -735,6 +739,7 @@ function element(invocationManager, emitter, matcher) {
735
739
  if (!(matcher instanceof Matcher)) {
736
740
  throwMatcherError(matcher);
737
741
  }
742
+
738
743
  return new Element(invocationManager, emitter, matcher);
739
744
  }
740
745
 
@@ -742,6 +747,7 @@ function expect(invocationManager, element) {
742
747
  if (!(element instanceof Element)) {
743
748
  throwMatcherError(element);
744
749
  }
750
+
745
751
  return new Expect(invocationManager, element);
746
752
  }
747
753
 
@@ -753,8 +759,9 @@ function waitFor(invocationManager, emitter, element) {
753
759
  }
754
760
 
755
761
  class IosExpect {
756
- constructor({ invocationManager, emitter }) {
762
+ constructor({ invocationManager, xcuitestRunner, emitter }) {
757
763
  this._invocationManager = invocationManager;
764
+ this._xcuitestRunner = xcuitestRunner;
758
765
  this._emitter = emitter;
759
766
  this.element = this.element.bind(this);
760
767
  this.expect = this.expect.bind(this);
@@ -762,6 +769,8 @@ class IosExpect {
762
769
  this.by = new By();
763
770
  this.web = this.web.bind(this);
764
771
  this.web.element = this.web().element;
772
+ this.system = this.system.bind(this);
773
+ this.system.element = this.system().element;
765
774
  }
766
775
 
767
776
  element(matcher) {
@@ -769,6 +778,10 @@ class IosExpect {
769
778
  }
770
779
 
771
780
  expect(element) {
781
+ if (isSystemElement(element)) {
782
+ return systemExpect(this._xcuitestRunner, element);
783
+ }
784
+
772
785
  if (isWebElement(element)) {
773
786
  return webExpect(this._invocationManager, element);
774
787
  }
@@ -798,6 +811,14 @@ class IosExpect {
798
811
  }
799
812
  };
800
813
  }
814
+
815
+ system() {
816
+ return {
817
+ element: systemMatcher => {
818
+ return systemElement(this._xcuitestRunner, systemMatcher);
819
+ }
820
+ };
821
+ }
801
822
  }
802
823
 
803
824
  function _assertValidPoint(point) {
@@ -0,0 +1,124 @@
1
+ const { DetoxRuntimeError } = require('../errors');
2
+ const { assertTraceDescription } = require('../utils/assertArgument');
3
+ const { systemActionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
4
+ const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
5
+ const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);
6
+
7
+
8
+ class SystemExpect {
9
+ constructor(xcuitestRunner, element) {
10
+ this._xcuitestRunner = xcuitestRunner;
11
+ this.element = element;
12
+ this.modifiers = [];
13
+ }
14
+
15
+ toExist() {
16
+ const traceDescription = expectDescription.toExist();
17
+ return this.expect('toExist', traceDescription);
18
+ }
19
+
20
+ get not() {
21
+ this.modifiers.push('not');
22
+ return this;
23
+ }
24
+
25
+ createInvocation(systemExpectation) {
26
+ return {
27
+ type: 'systemExpectation',
28
+ systemPredicate: this.element.matcher.predicate,
29
+ ...(this.element.index !== undefined && { systemAtIndex: this.element.index }),
30
+ ...(this.modifiers.length !== 0 && { systemModifiers: this.modifiers }),
31
+ systemExpectation
32
+ };
33
+ }
34
+
35
+ expect(expectation, traceDescription) {
36
+ assertTraceDescription(traceDescription);
37
+
38
+ const invocation = this.createInvocation(expectation);
39
+ traceDescription = expectDescription.full(traceDescription, this.modifiers.includes('not'));
40
+ return _executeInvocation(this._xcuitestRunner, invocation, traceDescription);
41
+ }
42
+ }
43
+
44
+ class SystemElement {
45
+ constructor(xcuitestRunner, matcher, index) {
46
+ this._xcuitestRunner = xcuitestRunner;
47
+ this.matcher = matcher;
48
+ this.index = index;
49
+ }
50
+
51
+ atIndex(index) {
52
+ if (typeof index !== 'number' || index < 0) throw new DetoxRuntimeError(`index should be an integer, got ${index} (${typeof index})`);
53
+ this.index = index;
54
+ return this;
55
+ }
56
+
57
+ tap() {
58
+ const traceDescription = systemActionDescription.tap();
59
+ return this.withAction('tap', traceDescription);
60
+ }
61
+
62
+ withAction(action, traceDescription) {
63
+ assertTraceDescription(traceDescription);
64
+
65
+ const invocation = {
66
+ type: 'systemAction',
67
+ systemPredicate: this.matcher.predicate,
68
+ ...(this.index !== undefined && { systemAtIndex: this.index }),
69
+ systemAction: action
70
+ };
71
+ traceDescription = systemActionDescription.full(traceDescription);
72
+ return _executeInvocation(this._xcuitestRunner, invocation, traceDescription);
73
+ }
74
+ }
75
+
76
+ class SystemElementMatcher {
77
+ label(label) {
78
+ if (typeof label !== 'string') throw new DetoxRuntimeError('label should be a string, but got ' + (label + (' (' + typeof label + ')')));
79
+ this.predicate = { type: 'label', value: label.toString() };
80
+ return this;
81
+ }
82
+
83
+ type(type) {
84
+ if (typeof type !== 'string') throw new DetoxRuntimeError('type should be a string, but got ' + (type + (' (' + typeof type + ')')));
85
+ this.predicate = { type: 'type', value: type.toString() };
86
+ return this;
87
+ }
88
+ }
89
+
90
+ function systemMatcher() {
91
+ return new SystemElementMatcher();
92
+ }
93
+
94
+ function systemElement(xcuitestRunner, matcher) {
95
+ if (!(matcher instanceof SystemElementMatcher)) {
96
+ throwSystemMatcherError(matcher);
97
+ }
98
+
99
+ return new SystemElement(xcuitestRunner, matcher);
100
+ }
101
+
102
+ function throwSystemMatcherError(param) {
103
+ const paramDescription = JSON.stringify(param);
104
+ throw new DetoxRuntimeError(`${paramDescription} is not a Detox system matcher. More about system matchers here: https://wix.github.io/Detox/docs/api/system`);
105
+ }
106
+
107
+ function systemExpect(xcuitestRunner, element) {
108
+ return new SystemExpect(xcuitestRunner, element);
109
+ }
110
+
111
+ function _executeInvocation(xcuitestRunner, invocation, traceDescription) {
112
+ return traceInvocationCall(traceDescription, invocation, xcuitestRunner.execute(invocation));
113
+ }
114
+
115
+ function isSystemElement(element) {
116
+ return element instanceof SystemElement;
117
+ }
118
+
119
+ module.exports = {
120
+ systemMatcher,
121
+ systemElement,
122
+ systemExpect,
123
+ isSystemElement
124
+ };
package/src/ios/web.js CHANGED
@@ -1,8 +1,7 @@
1
- const assert = require('assert');
2
-
3
1
  const _ = require('lodash');
4
2
 
5
3
  const { DetoxRuntimeError } = require('../errors');
4
+ const { assertTraceDescription } = require('../utils/assertArgument');
6
5
  const { webViewActionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
7
6
  const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
8
7
  const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);
@@ -48,7 +47,7 @@ class WebExpect {
48
47
  }
49
48
 
50
49
  expect(expectation, traceDescription, ...params) {
51
- assert(traceDescription, `must provide trace description for expectation: \n ${JSON.stringify(expectation)}`);
50
+ assertTraceDescription(traceDescription);
52
51
 
53
52
  const invocation = this.createInvocation(expectation, ...params);
54
53
  traceDescription = expectDescription.full(traceDescription, this.modifiers.includes('not'));
@@ -170,7 +169,7 @@ class WebElement {
170
169
  }
171
170
 
172
171
  withAction(action, traceDescription, ...params) {
173
- assert(traceDescription, `must provide trace description for action: \n ${JSON.stringify(action)}`);
172
+ assertTraceDescription(traceDescription);
174
173
 
175
174
  const invocation = {
176
175
  type: 'webAction',
@@ -12,19 +12,20 @@ class Android extends MatchersFactory {
12
12
  }
13
13
 
14
14
  class Ios extends MatchersFactory {
15
- createMatchers({ invocationManager, eventEmitter }) {
15
+ createMatchers({ invocationManager, runtimeDevice, eventEmitter }) {
16
16
  const IosExpect = require('../../ios/expectTwo');
17
- return new IosExpect({ invocationManager, emitter: eventEmitter });
17
+ const XCUITestRunner = require('../../ios/XCUITestRunner');
18
+ const xcuitestRunner = new XCUITestRunner({ simulatorId: runtimeDevice.id });
19
+
20
+ return new IosExpect({
21
+ invocationManager,
22
+ xcuitestRunner,
23
+ emitter: eventEmitter
24
+ });
18
25
  }
19
26
  }
20
27
 
21
28
  class External extends MatchersFactory {
22
- static validateModule(module, path) {
23
- if (!module.ExpectClass) {
24
- throw new DetoxRuntimeError(`The custom driver at '${path}' does not export the ExpectClass property`);
25
- }
26
- }
27
-
28
29
  constructor(module, path) {
29
30
  super();
30
31
  External.validateModule(module, path);
@@ -32,6 +33,12 @@ class External extends MatchersFactory {
32
33
  this._module = module;
33
34
  }
34
35
 
36
+ static validateModule(module, path) {
37
+ if (!module.ExpectClass) {
38
+ throw new DetoxRuntimeError(`The custom driver at '${path}' does not export the ExpectClass property`);
39
+ }
40
+ }
41
+
35
42
  createMatchers(deps) {
36
43
  return new this._module.ExpectClass(deps);
37
44
  }