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

Running on windows support #628

Merged
merged 21 commits into from
May 25, 2018
Merged

Running on windows support #628

merged 21 commits into from
May 25, 2018

Conversation

simonbuchan
Copy link
Contributor

@simonbuchan simonbuchan commented Mar 19, 2018

Just a few issues I ran into running on windows. Boils down to:

  • npm scripts (that might run on windows) should be either:
    • node some/script.js (what I've done) or
    • add cross-env dev dep, and use cross-env some/script where there is a some/script with a #! and some/script.bat written for windows cmd.exe. This one is no fun.
  • A few cases of exec('node_modules/.bin/foo'...) which doesn't work in cmd.exe (it tries to run node_modules with /.bin/foo). Not quite sure about my fixes for these, I'm happy to change things.
  • several cases of .split('\n'), which broke at least starting the emulator (looking for foo, not finding foo\r) - fixed this at the source, by replacing \r\n on windows.
  • android.emulator (as opposed to .attached) would start emulator.exe even if it was already running which was for some reason causing it to get stuck (probably due to the output redirection to the log file looks like some weird emulator internal issue) - workaround the issue by first checking for a running device matching the name.

I also noticed detox/scripts/build.sh android was a little out of date while porting, is that code still used?

Been running this for a while now and everything seems to be good, but there will always be something hiding.

@simonbuchan
Copy link
Contributor Author

Also I didn't touch detox-cli - I'm not quite sure what the point is? yarn <bin> and npx <bin> obsolete packages like that. I'm happy to port it to node or batch and test if you like?

@DanielMSchmidt
Copy link
Contributor

@simonbuchan Thank you for taking care of this <3 👍
Would you mind adding some docs? Do you know if we can test some of these things in our CI? Do we need another solution there?

@simonbuchan
Copy link
Contributor Author

There's a lot more rough edges I'd like to iron out first, e.g. when using android.emulator it gets stuck
trying to start the emulator again on the second run (not sure what's happening there), and I'm not sure how to approach the build config step yet, but these get rid of the big blockers for the basic -> detox test flow.

I've got a couple of hacks that could make all the tests pass on windows (all just path separators, AFAICT), but I don't know if that means they actually work right! At least until I've gotten on top of those I'm not sure where a windows CI would help, nor how that would work. You might have noticed I had to ignore the windows branch in exec for coverage to pass, and I'm not sure how that would work cross-platform (collect on all platforms and merge in a final step? Sounds complex!)

So far not sure what docs would change? "Windows will probably mostly work" isn't a great line! And I'd like to see some other users experience with this first before promising more. The big difference would probably be whatever happens with build.

Ideally we will be using this cross-platform quite a bit more in the future, and I'll be happy to follow this up with more support on request (though keep in mind I'm in UTC+12:00).

@simonbuchan
Copy link
Contributor Author

Talking of CI, actually, I noticed there's a pretty complex eslint config that is not being used or followed at all? What's up with that, and should I be following it in scripts?

@simonbuchan
Copy link
Contributor Author

Let me know if the above fix is OK in theory, it seems to be required for windows android.emulator (vs .attached).

@rotemmiz
Copy link
Member

This is something we'll have to test locally, there's no test in CI that verifies that a second e2e works, or is there....

  1. The demo-projects CI job runs two subsequent tests on two different projects, with the same devices.
  2. but there still is no Android E2E in CI, we're currently working on moving to our own CI solution (Jenkins with Mac virtual machines capable of running x86 emulators for those who ask)

@simonbuchan
Copy link
Contributor Author

It seems like it does, since it still has 100% coverage? I might be misunderstanding branch coverage.

@rotemmiz
Copy link
Member

I will be reviewing this soon, sorry for the delay.

@tachtevrenidis
Copy link

is this going to be merged soon? :-)

await this.emulator.boot(name);
}

adbDevices = await this.adb.devices();
Copy link
Member

Choose a reason for hiding this comment

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

Why is this being run twice ?
Does the original implementation cause issues with Windows ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, should be inside the if here - it's refreshing adbDevices after the requested name is booted. See the comments above as to why this is happening, but roughly: on windows trying to start the emulator the way it currently is being done when it's already running causes issues for some reason.

const path = require('path');

program.parse(process.argv);

if (fs.existsSync(path.join(process.cwd(), 'node_modules/.bin/detox-server'))) {
Copy link
Member

Choose a reason for hiding this comment

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

npm and yarn install detox-server at different locations.
it might be either it node_modules or in node_modules/detox/node_modules

I am not familiar with require.resolve('detox-server/package.json'); trick. Will it cover both cases ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it's the standard hack to find the location of an NPM package the same way node does, since every NPM package has a package.json. Remember:

  • require / require.resolve('foo/bar') looks up foo in node_modules, then adds bar to that path
  • without the .../bar it would use the main field, which is likely to be in a nested subdir
  • package.json always exists.

@@ -0,0 +1,8 @@
#!/usr/bin/env node

// Javascript for windows support.
Copy link
Member

Choose a reason for hiding this comment

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

Unnecessary comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

More clearly Using JS instead of shell script to avoid breaking on windows, but I'm happy to remove it!

@rotemmiz
Copy link
Member

Sorry for the delay in reviewing, but it is now done :)

Unfortunately, we have no capacity to run Detox on Windows in CI, therefore I cannot guarantee this will continue working without breaking. We will need to add a disclaimer in the docs, and rely on the community to report issues and fix them. :(
Not ideal, but this is the best we can do right now.

@simonbuchan
Copy link
Contributor Author

If you want to look into CI later, the standard I've seen in open source is https://www.appveyor.com/

@simonbuchan
Copy link
Contributor Author

Looking around, seems like AppVeyor is mostly NuGet packages. Node packages (including typescript, babel and react-native itself) all use https://circleci.com/

@simonbuchan
Copy link
Contributor Author

CI failure

Hmm, not sure what's up: only one config, so seems like it flaked?

CI

Blorg, never mind, CircleCI is mac/linux only.

Looks like:

  • Typescript doesn't run CI on windows? They have CircleCI and Travis running, but both are linux.
  • Same for babel
  • react-native only have circleci.

Weird. Seems like AppVeyor do have decent-ish node support, even if the docs are old. I could look into setting this up, I think the main thing would be installing the android SDK on windows reliably.

Tests

Note that the tests do not all pass on windows yet - here's an example, all 4 failures are trivial path things like this:

  ● APKPath › simple path

    expect(received).toEqual(expected)
    
    Expected value to equal:
      "~/somePath/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk"
    Received:
      "androidTest\\debug\\app-debug-androidTest.apk"

       9 |     const inputApkPath = '~/somePath/build/outputs/apk/debug/app-debug.apk';
      10 |     const expectedTestApkPath = '~/somePath/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk';
    > 11 |     expect(APKPath.getTestApkPath(inputApkPath)).toEqual(expectedTestApkPath);
      12 |   });
      13 | 
      14 |   it(`path for a gradle build flavor`, async () => {
      
      at Object.it (src/devices/android/APKPath.test.js:11:50)

I'm not sure what you want to do here, some options are:

  • switch app and tests to consistently using require('path').posix - these paths normally work fine on windows (except for the executable, hence the binPath changes)
  • have the tests .replace(/\\\\/g, '/'), and get rid of ~ usage.
  • separate windows and posix path tests.
  • input / expected paths based on platform
  • leave it how it is for now, follow up on it later

I do have a Mac Mini for iOS dev now (it's absolutely terrible to work on, but it works 🤷), so I can be more confident I'm not breaking things, I guess.

@rotemmiz
Copy link
Member

Re tests, it sounds reasonable to just use Node's compatibility layer.
BTW, we intend to move our CI to a home brewed Jenkins server on top of MacStadium infrastructure next week, no Windows support is planned though.

@simonbuchan
Copy link
Contributor Author

Re tests, it sounds reasonable to just use Node's compatibility layer.

Are you referring to require('path').posix? (It's not really a compatibility layer, but the implementation of path used by default on POSIX, there's a .win32 also) - that would be pretty easy, but it's not really correct so it might break stuff. In particular it means the win32 absolute path C:\foo\bar\baz\file.apk gets treated as a relative path, and other bad stuff due to \ not being a path separator, but that's solvable by replacing \ with / on user input.

Another, cleaner answer would be to change the tests so they look something like:

const inputApkPath = path.join(_dirname, 'build/outputs/apk/debug/app-debug.apk');
const expectedTestApkPath = path.join(_dirname, 'build/outputs/apk/androidTest/debug/app-debug-androidTest.apk');

but this means the actual diffs depend on the repo working directory path.

Use path module in tests to normalize paths.
Use process.platform to test with actual absolute paths on windows.
@simonbuchan
Copy link
Contributor Author

OK updated tests - should be safe and straightforward changes.

Were there specific things you wanted in terms of doc changes? At the moment, all I can think of is something like "windows should probably work, but be aware that binaryPath and build might not work cross-platform" - eg. cd android && ./gradlew assembleDebug assembleAndroidTest will not work on windows (it needs to be gradlew, no ./) That doesn't seem enough for a whole page, where would you put that?

Other than that I think this is good to go modulo follow-up reviews.

@simonbuchan
Copy link
Contributor Author

While writing some docs noticed I hadn't gotten around to detox-cli (which I don't use myself, because yarn/npx detox works fine for me).

Let me know if these docs are OK, I'm not 100% on the tone or placement.

Hopefully that CI failure was just a flake? Not sure how I could have broken it.

@simonbuchan
Copy link
Contributor Author

Incidentally, while testing build hit the fact that react-native's :ReactAndroid gradle project doesn't seem to even configure on windows, meaning detox/test can't be built. 🙁

@rotemmiz
Copy link
Member

We have two flavors for the test app, fromBin and fromSource. The thing is, even if you build from bin, the fact that the settings.gradle includes ReactAndroid source, it will evaluate its build scripts.

You can remark it in settings.gradle and build.gradle, and build the fromBin flavour.

Tell me if it works.

@simonbuchan
Copy link
Contributor Author

Yeah. that seems to work fine, and the tests pass. (It was complaining about a missing repositoryUrl on the :ReactAndroid project, don't suppose that makes any sense to you?)
Meh, It's only a problem if you want Windows CI at some point.

});

it(`should accept relative path for binary`, async () => {
const actualPath = await launchAndTestBinaryPath('relativePath');
expect(actualPath).toEqual(`${process.cwd()}/abcdef/123`);
expect(actualPath).toEqual(path.join(process.cwd(), 'abcdef/123'));
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be split to path.join(process.cwd(), 'abcdef', '123') ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Path will normalise separators, and windows in fine with either except for binary paths (where they are ambiguous with switches)

@@ -52,10 +52,18 @@ class EmulatorDriver extends AndroidDriver {
}

await this._fixEmulatorConfigIniSkinName(name);
await this.emulator.boot(name);
Copy link
Member

Choose a reason for hiding this comment

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

What was the issue here ? boot should return a valid device, either it's shutdown or already booted. If it doesn't we may have issue with Emulator.js

Copy link
Member

Choose a reason for hiding this comment

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

I now see the comments here.

Not sure how to proceed here. This fix is in bad taste IMO.
So the real issue is creating and removing those emulator log files ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could experiment a bit, I suspect redirecting to different files should fix it, but this was a less user visible change (eg. .gitignore)
Do you not find it logical to only start an emulator if it's not already running?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, gave it a try and it still hangs on startup with no output to the log file even if it's a new file each time.
Killing the first emulator then will hang it, killing it causes the second to start up and detox to continue successfully.
Seems like there's something lower level specific to the android emulator going on, possibly needs to have a separate AVD directory?

@@ -11,6 +11,14 @@ The current API supports addition of multiple platforms, Android is next. This i
### iOS physical device support
Currently detox only supports running on iOS simulators, we plan on adding support for running on devices as well.

### Windows support
There is some work done for running detox on Windows, but it's still fairly untested. Please open issues for anything you run into, but be aware of these limitations:
Copy link
Member

Choose a reason for hiding this comment

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

Detox, not detox

- `binaryPath` can be left as a relative path with `/`, or use `\\` if you don't need cross-platform support.
- `build` should not use `./gradlew ...`, but simply `gradlew ...` - you may prefer scripting the build outside of
detox if you want to maintain cross-platform support - or simply have two configurations!

Copy link
Member

Choose a reason for hiding this comment

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

👌

- Apple doesn't support iOS apps on Windows, obviously, so you're limited to the in-progress Android support.
- `binaryPath` can be left as a relative path with `/`, or use `\\` if you don't need cross-platform support.
- `build` should not use `./gradlew ...`, but simply `gradlew ...` - you may prefer scripting the build outside of
detox if you want to maintain cross-platform support - or simply have two configurations!
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is there a line break here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, should be “Detox”.

### Windows support
There is some work done for running Detox on Windows, but it's still fairly untested. Please open issues for anything you run into, but be aware of these limitations:

- Apple doesn't support iOS apps on Windows, obviously, so you're limited to the in-progress Android support.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let’s please remove the “obviously”.

@simonbuchan
Copy link
Contributor Author

Gah. 🤦‍♂️ Thanks for the reviews guys!
@rotemmiz If the emulator boot is an issue, I could only skip the second boot on win32? I suspect passing a temp dir to -datadir would also work, but that will very likely break people (but would be a neat option to know you're getting a fresh OS install each time / run in parallel?)

@simonbuchan
Copy link
Contributor Author

Hah, just looked the jenkins log and saw a big fat crash stack at the end... then noticed it was the app crash test 😅

@rotemmiz rotemmiz merged commit cde5fd3 into wix:master May 25, 2018
@simonbuchan
Copy link
Contributor Author

🎉🕊 Thanks so much for all the discussion and feedback! This turned out a lot bigger and gnarlier than I expected at the start, but isn't that always the way!

@simonbuchan simonbuchan deleted the windows branch May 25, 2018 09:50
@LeoNatan
Copy link
Contributor

Thank you for all the good work!

@rotemmiz
Copy link
Member

Thanks for the great work, hope you stick around.

@wix wix locked and limited conversation to collaborators Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants