Detox icon indicating copy to clipboard operation
Detox copied to clipboard

Android support for running tests on multiple connected devices or emulators

Open hoda0013 opened this issue 7 years ago • 4 comments

Description

In the Android Gradle Plugin there is a Gradle task called connectedCheck. This Gradle task identifies any devices connected to adb and then runs all tests on all connected devices then generates a test report. As far as I can tell this functionality is not possible in Detox.

It would be nice if there were a way to write the Detox configuration that would allow us to test on all connected devices and not have to specify a name (or type for that matter). This would make things possible such as creating a device farm by plugging devices into a build agent and having the build agent run functional tests on all connected devices as part of a build pipeline.

hoda0013 avatar Feb 13 '18 22:02 hoda0013

Detox doesn't actually use module-level values that much, so It's possible to run detox in parallel by poking into the detox internals:

parallel-detox.js
const ADB = require('detox/src/devices/android/ADB');
const Detox = require('detox/src/Detox');

async function main() {
  const devices = await new ADB().devices();
  await Promise.all(devices.map(async device => {
    const deviceConfig = {
      binaryPath: 'path/to/output/apk/your-app.apk',
      type: 'android.emulator',
      name: device.name,
    };
    const detoxGlobals = await getDetoxGlobals(deviceConfig);
    await runTestsWith(detoxGlobals);
  });
}

async function getDetoxGlobals(deviceConfig) {
  const detox = new Detox({ deviceConfig });
  await detox.init({ initGlobals: false });

  const { device } = detox;
  const { expect, element, by, waitFor } = detox.deviceDriver.expect;
  return { detox, device, expect, element, by, waitFor };
}

main().catch(error => {
  console.error(error);
  process.exit(1);
});

You probably shouldn't do this, but it seems to work?

So the problem becomes how do you run this in the context of jest or whatever, where it expects to be calling you? In theory, you could do something like:

for (const device of await new ADB().devices()) {
  describe(`Device: ${device.name}`, async () => {
    const { ... } = await getDetoxGlobals(...);
    it(...);
  };
}

but:

  • You can't await at module level
  • Jest/mocha etc. will all want the describe() to be sync called on module evaluation
  • How does this work across test files?

I played around a bit and ended up generating a detox config JSON, then invoking detox test --configuration ${name} for each in parallel:

test-all.js
const cp = require('child_process');
const fs = require('fs');
const util = require('util');

const ADB = require('detox/src/devices/android/ADB');

new ADB().devices().then(devices => {
  const detoxConfig = {
    configurations: {},
  };

  for (const device of devices) {
    detoxConfig.configurations[device.name] = {
      binaryPath: '...',
      type: 'android.emulator',
      name: device.name,
    };
  }

  fs.writeFileSync(
    `${__dirname}/detox.json`,
    JSON.stringify(detoxConfig, null, 2));

  return Promise.all(devices.map(device => {
    return util.promisify(cp.spawn)(
      `yarn detox test --configuration ${device.name}`,
      { stdio: 'inherit', shell: true });
  }));
}).catch(error => {
  console.error(error);
  process.exit(1);
});

then in your tests use detox.init(require('./detox.json')).

This seems to work OK, though detox could definitely make it easier!

simonbuchan avatar Mar 22 '18 22:03 simonbuchan

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe the issue is still relevant, please test on the latest Detox and report back.

Thank you for your contributions!

For more information on bots in this reporsitory, read this discussion.

stale[bot] avatar Jun 18 '22 16:06 stale[bot]

The issue has been closed for inactivity.

stale[bot] avatar Jun 27 '22 20:06 stale[bot]

We might add support for that one day 😄 If we do, it would be through a thought-out, dedicated API.

d4vidi avatar Jul 05 '22 12:07 d4vidi