Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow giving detox config file as param, with fallbacks #906

Closed
wants to merge 17 commits into from
Empty file modified detox-cli/cli.js
100644 → 100755
Empty file.
11 changes: 7 additions & 4 deletions detox/local-cli/detox-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

const _ = require('lodash');
const program = require('commander');
const {getConfigurationFile, getDefaultConfigurationFile} = require('../src/utils/getConfigurationFile');
const path = require('path');
const cp = require('child_process');
program.description(`[convenience method] run the command defined in 'configuration.build'`)
.option('-c, --configuration [device configuration]', 'Select a device configuration from your defined configurations,'
+ 'if not supplied, and there\'s only one configuration, detox will default to it')
.option('--config-path [configPath]',
'Select a device config-file path, if not supplied, detox will default to the package.json, and if not found there, detox will fallback to .detoxrc')
noomorph marked this conversation as resolved.
Show resolved Hide resolved
.option('-c, --configuration [device configuration]', 'Select a device configuration from your defined configurations,' +
'if not supplied, and there\'s only one configuration, detox will default to it', getDefaultConfigurationFile())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oreporan , why getDefaultConfigurationFile()? Come on, it is a string like android.emu.release, ios.sim.debug, why require file? It is the second time I write it to you.

.parse(process.argv);

const config = require(path.join(process.cwd(), 'package.json')).detox;
const config = getConfigurationFile(program.configPath);

let buildScript;
if (program.configuration) {
Expand All @@ -26,4 +29,4 @@ if (buildScript) {
cp.execSync(buildScript, {stdio: 'inherit'});
} else {
throw new Error(`Could not find build script in detox.configurations["${program.configuration}"]`);
}
}
10 changes: 7 additions & 3 deletions detox/local-cli/detox-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const _ = require('lodash');
const environment = require('../src/utils/environment');
const buildDefaultArtifactsRootDirpath = require('../src/artifacts/utils/buildDefaultArtifactsRootDirpath');
const DetoxConfigError = require('../src/errors/DetoxConfigError');
const config = require(path.join(process.cwd(), 'package.json')).detox;
const {getConfigurationFile, getDefaultConfigurationFile} = require('../src/utils/getConfigurationFile');

program
.option('-o, --runner-config [config]',
Expand All @@ -21,6 +21,8 @@ program
'Disable colors in log output')
.option('-c, --configuration [device configuration]',
'Select a device configuration from your defined configurations, if not supplied, and there\'s only one configuration, detox will default to it', getDefaultConfiguration())
.option('--config-path [configPath]',
'Select a device config-file path, if not supplied, detox will default to the package.json, and if not found there, detox will fallback to .detoxrc', getDefaultConfigurationFile())
.option('-r, --reuse',
'Reuse existing installed app (do not delete and re-install) for a faster run.')
.option('-u, --cleanup',
Expand Down Expand Up @@ -49,6 +51,7 @@ program
'Override the device name specified in a configuration. Useful for running a single build configuration on multiple devices.')
.parse(process.argv);

const config = getConfigurationFile(program.configPath);
program.artifactsLocation = buildDefaultArtifactsRootDirpath(program.configuration, program.artifactsLocation);

clearDeviceRegistryLockFile();
Expand Down Expand Up @@ -204,8 +207,9 @@ function clearDeviceRegistryLockFile() {
}

function getDefaultConfiguration() {
if (_.size(config.configurations) === 1) {
return _.keys(config.configurations)[0];
const file = getConfigurationFile();
Copy link
Collaborator

@noomorph noomorph Oct 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I counted that getConfigurationFile() is actually called three times here. It does not look simple and concise, can it be rewritten in a cleaner way?

if (file && _.size(file.configurations) === 1) {
return _.keys(file.configurations)[0];
}
}

Expand Down
30 changes: 30 additions & 0 deletions detox/src/utils/getConfigurationFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const path = require('path');
const packageJson = 'package.json';
const detoxRc = '.detoxrc';

function requireWithRoot(suffix) {
return require(path.resolve(suffix))
}

function getDefaultConfigurationFile() {
return path.resolve(packageJson);
}

function getConfigurationFile(configPath) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the testing question, I struggle to see what's the issue here 😕 especially if you rewrite it in an OOP way, something like this:

class ConfigurationResolver {
  constructor(cwd = process.cwd()) {
    this.cwd = cwd;
  }

  getDetoxConfiguration(configPath) {
    if (configPath) {
      return this.loadConfiguration(configPath);
    }

    const { detox } = this.loadConfiguration('package.json');
    if (detox) {
      return detox;
    }

    return this.loadConfiguration('.detoxrc');
  }

  loadConfiguration(configPath) {
    return require(path.resolve(this.cwd, configPath));
  }
}

ConfigurationResolver.default = new ConfigurationResolver();

module.exports = ConfigurationResolver;

You can instantiate it with any cwd directory and test against it.

let config;

console.log('Using config file', configPath)

// If config path is provided, use it
if (configPath) config = requireWithRoot(configPath);

// if package.json contains detox object, use it
if (!config) config = requireWithRoot(packageJson).detox;

// fallback to .detoxrc
if (!config) config = requireWithRoot(detoxRc);
return config
}

module.exports = {getDefaultConfigurationFile, getConfigurationFile};

2 changes: 2 additions & 0 deletions docs/APIRef.DetoxCLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Initiating your test suite
| -l, --loglevel [value] | Log level: fatal, error, warn, info, verbose, trace |
| --no-color | Disable colors in log output |
| -c, -configuration \<device config\> | Select a device configuration from your defined configurations,if not supplied, and there's only one configuration, detox will default to it |
| --config-path \<configPath\> | Select a device config-file path, if not supplied, detox will default to the package.json, and if not found there, detox will fallback to .detoxrc |
| -r, --reuse | Reuse existing installed app (do not delete and re-tall) for a faster run. |
| -u, --cleanup | Shutdown simulator when test is over, useful for CI ipts, to make sure detox exists cleanly with no residue |
| -d, --debug-synchronization \<value\> | When an action/expectation takes a significant amount time use this option to print device synchronization status. The status will be printed if the ion takes more than [value]ms to complete |
Expand All @@ -71,6 +72,7 @@ Run a command defined in 'configuration.build'
| --- | --- |
| -h, --help | output usage information |
| -c, --configuration \<device config\> | Select a device configuration from your defined configurations,if not supplied, and there's only one configuration, detox will default to it |
| --config-path \<configPath\> | Select a device config-file path, if not supplied, detox will default to the package.json, and if not found there, detox will fallback to .detoxrc |


### run-server
Expand Down
23 changes: 21 additions & 2 deletions docs/Introduction.GettingStarted.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,13 @@ Read the [Jest integration guide](Guide.Jest.md) for more details and gotchas.
npm install mocha --save-dev
```

#### 3. Add Detox config to package.json
#### 3. Add Detox config
By default, detox will search for the configuration the `package.json`.
You can also write your config in a `.detoxrc` file if you prefer to separate between the configuration and the app's `package.json`.
Another option is to create a config file and supply it when calling `detox init`.
Either way the config should look like this:

The basic configuration for Detox should be in your `package.json` file under the `detox` property:
##### in package.json

```json
"detox": {
Expand All @@ -121,6 +125,21 @@ The basic configuration for Detox should be in your `package.json` file under th
}
```

##### in .detoxrc or any config file

```json
{
"configurations": {
"ios.sim.debug": {
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app",
"build": "xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
"type": "ios.simulator",
"name": "iPhone 7"
}
}
}
```

In the above configuration example, change `example` to your actual project name. Under the key `"binaryPath"`, `example.app` should be `<your_project_name>.app`. Under the key `"build"`, `example.xcodeproj` should be `<your_project_name>.xcodeproj` and `-scheme example` should be `-scheme <your_project_name>`.

For iOS apps in a workspace (eg: CocoaPods) use `-workspace ios/example.xcworkspace` instead of `-project`.
Expand Down