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

Implement facebook/idb tool (applesimeutils replacement) #1371

Closed
ayelenmarie opened this issue May 7, 2019 · 43 comments
Closed

Implement facebook/idb tool (applesimeutils replacement) #1371

ayelenmarie opened this issue May 7, 2019 · 43 comments

Comments

@ayelenmarie
Copy link

ayelenmarie commented May 7, 2019

Talking with LeoNatan in #629 I mentioned Facebook released a new tool that replaces\includes fbsimctl that is called idb. They will start monitoring and updating that repo instead of the other one and they are suggesting everyone to move to this new tool instead. So it will be great if Detox could migrate as well!

Currently it's under construction but as it supposedly fixes some issues that fbsimctl has, I might as well suggest it here.

Here is the repo for idb : https://github.com/facebook/idb

Note: This tool is only for iOS, I assume it's the equivalent of adb for Android?

Thanks!

@lawrencelomax
Copy link

Hello, one of the authors of the idb project here!

More than happy to give pointers/advice if you need them.

As far as the maturity of the project goes, we've been using this in production for nearly 2 years now and it's only just now that we've open sourced it.

@rotemmiz
Copy link
Member

Hey @lawrencelomax !!

Good to have you here, actually I do have a few questions:

  1. One of the reason that made us ditch fbsimctl (aside from the multi simulator support introduced in Xcode9) was the fact that there were no stable releases, and the only way to install it was through brew at the repo's HEAD. I see that idb is being released regularly, and brew uses the latest version, which is great!
  2. I did not dive into the code, but couldn't find anything in docs regarding ability to pass launch args and environment variables to app on device, Is that possible?
  3. We never really considered running Detox on iOS devices for more than a POC, but if idb can get us closer, this may change they way we approach it. here's the latest status written by @LeoNatan Run on hardware iOS device #95 (comment).

@lawrencelomax
Copy link

One of the reason that made us ditch fbsimctl (aside from the multi simulator support introduced in Xcode9) was the fact that there were no stable releases, and the only way to install it was through brew at the repo's HEAD. I see that idb is being released regularly, and brew uses the latest version, which is great!

I hear you on this as know that this has been a problem in the past. The biggest reason for this is that fbsimctl was very much in maintenance mode whilst we were working on idb itself. We're more than happy to keep changelogs and make regular releases from master.

I did not dive into the code, but couldn't find anything in docs regarding ability to pass launch args and environment variables to app on device, Is that possible?

Device App launching has some interesting constraints, including the app must be a dev build but we do support passing environment variables. This is because the only way of launching an application on a device is to treat it as a debug session, even if you're not interested in running debugger commands.

I think one area that we would need to figure out is the dylib injection that detox uses on sims. The dylib would need to be codesigned and included in the Application bundle. You can't load a dylib on devices unless it's part of Apple's developer tools (i.e. how the view debugger works) or if it's part of the application bundle (i.e. how test bundles work).

You may want to check out how things such as Reveal do this as IIRC they use dylib injection in a similar way to how you'd be interested in doing it in Detox.

@LeoNatan
Copy link
Contributor

Thanks for commenting.

We have always known that signing will be a requirement for running on device. My idea has always been to deduce the signing identity from the user's project and then attempt to sign it with the Detox framework and touched entitlements. This is probably less suitable for device labs, where the signing certificate may not be present on the machine running the test, but since there is no escape from signing, I don't think there is any other way.

What the Reveal guys are doing is to include an integration script that does the heavy lifting (similar to what we do in Detox Instruments). This still requires some changes to the user project. We may go down that road, but it is not planned yet (attaching Detox has repercussions, even if tests are not running).

@ayelenmarie
Copy link
Author

Hi! We are having trouble setting our app's location for testing with Detox, so I wanted to ask for help figuring it out.
In our init.js configuration's beforeAll we have:

beforeAll(async () => {
  await detox.init(config, {
    launchApp: false,
  })
  await device.launchApp({
    permissions: {
      notifications: 'YES',
      location: 'always',
    },
  })

  await device.setLocation(32.0853, 34.7818)
})

The device.setLocation seems to not be working, it just stays at the current location. We know this needs fbsimctl to work but I know it's deprecated and now part of idb and wanted to know if there is a chance this was somewhat implemented on an latest update, otherwise I would like to know the proper way to address this case.

Thanks!

@LeoNatan
Copy link
Contributor

Hello,

Unfortunately, I didn't implement idb support in Detox. I did play a little with the tool and was met with some issues. It felt to me that the tool is not ready yet. That was a while back, but I have not had time to further investigate.

PRs are welcome.

I'd say "as a workaround, use fbsimctl for now", but idb seems to be incompatible with fbsimctl... 😂
Instead, don't call setLocation. Obtain the device identifier from the device internals and run the idb command directly inside your test, providing the device identifier as input to the command.

@ayelenmarie
Copy link
Author

ayelenmarie commented Aug 14, 2019

@LeoNatan how would you recommend running the idb command inside the test? Making a script that runs along with detox test or do you mean adding that command somehow inside each test?

I've tried running idb set-location command by its own and it works, but doesn't if I run a test with Detox. Also, where would you add the device identifier to that command? I believe it only receives LAT LONG. https://www.fbidb.io/docs/commands#set-a-simulators-location

@LeoNatan
Copy link
Contributor

Detox tests run in node, so you can use standard node facilities to call idb manually.

Regarding device identifier, could be that the entire simulator runtime uses the same coordinates, so a specific device needs not be provided. That makes your life even easier, because you don't need to find the device identifier from the Detox internals. So just call the set-location command where you need to using node API.

@OisinOKeeffe
Copy link

OisinOKeeffe commented Aug 14, 2019

in case anyone was wondering how to do it, after installing idb replaced my device.setLocation call with:

exec("idb list-targets | grep -n 'Booted'", (err, stdout, stderr) => {
      console.log("idb list-targets - ", err, stdout, stderr);
      const tempDevice = stdout.split("|")[1].trim();
      exec(
        "idb set-location --udid " + tempDevice + " 32.0853 34.7818",
        (err, stdout, stderr) => {
          console.log("setLocation - ", err, stdout, stderr);
        }
      );
    });

@LeoNatan
Copy link
Contributor

Please note that you should not assume only one booted device, or apply to all booted. It’s best to extract the current sim udid from internals.

@OisinOKeeffe
Copy link

OisinOKeeffe commented Aug 14, 2019

How would one go about using the internals?

@ayelenmarie
Copy link
Author

I've tried @OisinOKeeffe approach and whenever I run a test, it spends a lot of time to even start the first test, and then when it finishes, every test has failed even though I saw it pass. I have a coulple of errors in my console:

First, it says that signal 4 was flaged

4 Detox 0x00000001087fa776 -[DetoxManager notifyOnCrashWithDetails:] + 293

It also fails every test with a timeout (which I believe is the time it takes to even start the test suite):

Timeout - Async callback was not invoked within the 120000ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 120000ms timeout specified by jest.setTimeout.

Also, some of the tests say that the app crashed because we should only have exactly one subview and that is why they fail.

The logs that @OisinOKeeffe puts in the code bring me this:

console.log e2e/init.js:27
    idb list-targets -  null 21:iPhone Xʀ | F4941326-C918-4242-9882-A1388CFFF1FE | Booted | simulator | iOS 12.4 | x86_64 | :0
     

  console.log e2e/init.js:30
    setLocation - 

Despite all this, I can see location has changed to the one I selected ¯_(ツ)_/¯

@LeoNatan
Copy link
Contributor

LeoNatan commented Aug 14, 2019

You can obtain the device id using device._deviceId.

The crash doesn’t seem related to me.

@ayelenmarie
Copy link
Author

ayelenmarie commented Aug 15, 2019

I was able to fix it by writing it this way:

  const { stdout, stderr } = await exec("idb list-targets | grep -n 'Booted'")
  console.log('idb list-targets - ', stdout, stderr)
  const tempDevice = stdout.split('|')[1].trim()
  exec(`idb set-location --udid ${tempDevice} 40.6501 -73.94958`)
  console.log('setLocation - ', stdout, stderr) 

@OisinOKeeffe how do you run the idb companion? Manually, before the test suite? Without it, set-location does not work. I would like to know if there is an easier way for it than executing it everytime.

@LeoNatan
Copy link
Contributor

Instead of using the booted device, try the following line:

const tempDevice = device._deviceId

@OisinOKeeffe
Copy link

Very cool, based off of @LeoNatan's response I think I am going to do the following to make sure I am targeting the right device.

exec(idb set-location --udid ${device._deviceId} 40.6501 -73.94958)

@ayelenmarie when I ran my test all I had to do was ensure that the aforementioned was run in place of device.setLocation and my simulator location was updated without having to do anything else. Why would I need to run idb companion?

@ayelenmarie
Copy link
Author

@OisinOKeeffe mine does not work unless I don't have that simulator's companion running. Which version of fb-idb did you install with pip?

@OisinOKeeffe
Copy link

@ayelenmarie I wasn't following until today when I attempted to execute the idb command again and got some message about not being able to connect to the bridge. After some troubleshooting a restart seems to have cleared up my issue and I am able to execute the command again without any issue.

Try idb kill followed by idb daemon and if the latter fails restart and try idb set-location --udid {your device udid} 40.6501 -73.94958 and it should work.

@ayelenmarie
Copy link
Author

ayelenmarie commented Aug 20, 2019

It works now! Thanks @OisinOKeeffe for your insight. Restarting it worked for me as well as the idb kill.

@LeoNatan aside from device._deviceId, is there any other information available from the simulator that is running Detox? Such as the name or the OS. IT should be helpful to log it instead of the ID, so it's easier to check.

@LeoNatan
Copy link
Contributor

I don't think so.

@noomorph ?

@OisinOKeeffe
Copy link

OisinOKeeffe commented Aug 21, 2019

its not details on the simulator but you can access details of the detox config that is being run like so (here I am accessing the type )

device._deviceConfig.type

@JanithaR
Copy link

JanithaR commented Oct 3, 2019

Hi, hopping on the conversation since the problems I just started having led me here.

  1. I just upgraded to Detox 14.3.4 from 12.3.0
  2. I'm launching the app as follows,
export const launchApp = async (launchParams) => {
    await device.launchApp({
        newInstance: true,
        permissions: {
            notifications: 'YES',
            location: 'inuse'
        },
        ...launchParams
    });

    await device.setLocation(office.lat, office.lon);
};
  1. I get the following errors,

detox[15258] ERROR: [exec.js/EXEC_FAIL, #15] "fbsimctl 2BC36BD5-6557-49EF-A693-40A4336FCB4B set_location 6.9055934 79.8545685" failed with code = 1, stdout and stderr:

detox[15258] ERROR: [exec.js/EXEC_FAIL, #15]
detox[15258] ERROR: [exec.js/EXEC_FAIL, #15] '["2BC36BD5-6557-49EF-A693-40A4336FCB4B", "set_location", "6.9055934", "79.8545685"]' does not match '[fbsimctl print [action]

To my knowledge so far, I'm running into errors due to fbsimctl not being compatible or updated in a long time. (I'm testing against iPhone X, iOS 13.0)
fbsimctl is deprecated in favour of idb.
Detox has not yet made this move hence relying on fbsimctl still which is kind of 'broken'.
Therefore, for the moment the best course of action would be to install idb, implement,

const setLocation = async (latitude, longitude) => {
    const { stdout, stderr } = await exec("idb list-targets | grep -n 'Booted'");
    console.log('idb list-targets - ', stdout, stderr);
    // const tempDevice = stdout.split('|')[1].trim();
    exec(`idb set-location --udid ${device._deviceId} ${latitude} ${longitude}`);
    console.log('setLocation - ', stdout, stderr);
};

(Thanks @ayelenmarie and @OisinOKeeffe )
and use it like so until Detox start using idb.

...
// await device.setLocation(office.lat, office.lon);
    await setLocation(office.lat, office.lon);
...

Does that sound about right?

@Annihil
Copy link
Contributor

Annihil commented Oct 19, 2019

I tried idb and lyft/set-simulator-location, none of them work when the ios simulator is running headless (like on CircleCI) =(

@JanithaR
Copy link

JanithaR commented Nov 8, 2019

Yeah, it seems idb is a broken mess. I'm wondering whether I should downgrade Detox at this point, not sure whether it would help.

@LeoNatan
Copy link
Contributor

LeoNatan commented Nov 8, 2019

It might be a limitation of the simulator runtime.

@alexsegura
Copy link

For people coming here, here is how to install idb before using @JanithaR workaround

brew tap facebook/fb
brew install idb-companion
pip install fb-idb

@DaniyarJakupov
Copy link

And don't forget to import exec if you are running function from the same js file as a main detox setup:

import { exec } from 'child_process';

@bars0um
Copy link

bars0um commented Sep 23, 2020

@ayelenmarie @LeoNatan Thanks for your input on this issue, it has been quite helpful. I've been rummaging for days on how to first get fbsimctl to work and finally hit upon your thread and accordingly dumped it for idb.

I had issues with finding idb on the system and had to hardcode the absolute path to the binary, otherwise it was failing silently and the stdout you had doesn't really show me the error... The way I got it running was as follows:

const idbPATH = '/Users/myuser/Library/Python/3.8/bin/';
await exec(
    `${idbPATH}idb set-location --udid ${device._deviceId} ${latitude} ${longitude}`,
    (error, stdout, stderr) => {
      if (error) {
        console.log(`error: ${error.message}`);
        return;
      }
      if (stderr) {
        console.log(`stderr: ${stderr}`);
        return;
      }
      console.log(`stdout: ${stdout}`);
    },
  );

@fabOnReact
Copy link

fabOnReact commented Nov 9, 2020

had the same issue with idb, I had to use something like export PATH="$HOME/Library/Python/3.8/bin:$PATH" in my bash_profile to add all those python libraries binaries (including idb) to my $PATH env variable.

@noomorph
Copy link
Collaborator

noomorph commented Mar 9, 2021

@d4vidi, sounds like it is high time to start moving towards idb support. I'd add it to the roadmap.

@noomorph noomorph self-assigned this Mar 9, 2021
@d4vidi
Copy link
Collaborator

d4vidi commented Mar 9, 2021

It sounds like an interesting thing to do but I'm not sure why now is the right time, tbh

@LeoNatan
Copy link
Contributor

LeoNatan commented Mar 9, 2021

fbsimctl is used only for location changing. It can also probably be implemented as part of AppleSimUtils.

@noomorph
Copy link
Collaborator

noomorph commented Mar 9, 2021

@d4vidi, it is already deleted from the master branch - next iOS/macOS versions might not support it at all, so it is good to have it covered towards June-September 2021.

@LeoNatan, that's an option as well. I just wonder if idb can provide something beyond the current scope of AppleSimUtils... 🤔 Nevertheless, I'm fine with both the options - that's more a matter of human&time resources/capacities.

@LeoNatan
Copy link
Contributor

LeoNatan commented Mar 9, 2021

@noomorph Last I tried, idb was buggy. Those bugs are still open:
facebook/idb#522
facebook/idb#523
facebook/idb#524

The reason we moved away from fbsimctl and just used xcrun simctl for process management was because it was also buggy and not very well maintained. We kept fbsimctl only for location spoofing for simulators, which, at the time, I did not have time to investigate and include in AppleSimUtils. We've had very few requests/questions about this topic, so I guess not many users needed location spoofing. I can't think of other use of fbsimctl/idb that would be worth the hassle.

@JanithaR
Copy link

JanithaR commented Mar 10, 2021

I would suggest making this apparent in the README if there's no effort going to be put into rectifying it. A simple link to the issue would do, because from a user's perspective and mostly new ones, idb supposed to be the better solution but it is not and having to debug something like this is very time-consuming. That time could be saved.

@LeoNatan
Copy link
Contributor

@d4vidi
Copy link
Collaborator

d4vidi commented Mar 11, 2021

@LeoNatan merged. We will release, test and hopefully bin fbsimctl.
@noomorph @alon-ha Note to selves: must get rid of this warning when done - #2674

@d4vidi d4vidi added this to the Q2/2021 (codename Davaj ux) milestone Apr 14, 2021
@d4vidi d4vidi changed the title Implement facebook/idb tool (fbsimctl replacement) Implement facebook/idb tool (applesimeutils replacement) Jul 14, 2021
@zacharyweidenbach
Copy link

zacharyweidenbach commented Oct 13, 2021

I have attempted to use the applesimutils and the child_process.exec command based on my readings here.

The problem I'm encountering is that the command appears to execute successfully when the tests run, but the iOS simulator is not able to retrieve the current location.

import { exec } from 'child_process';
import { device } from 'detox';

const execPromise = (command: string) => {
  return new Promise((resolve, reject) => {
    exec(command, (err, stdout, stderr) => {
      if (err) {
        reject(err);
      } else if (stderr) {
        reject(new Error(stderr));
      } else {
        resolve(stdout);
      }
    });
  });
};

const setDeviceLocation = (lat: number, long: number) => {
  if (device.getPlatform() === 'android') {
    return device.setLocation(lat, long);
  } else {
    return execPromise(`applesimutils --byId ${device.id} --setLocation "[${lat}, ${long}]"`);
  }
}

However, if I run the command directly in my terminal, the simulator is able to retrieve the current location. I do not see any errors thrown from the exec call, it appears to run successfully.

  • Edit:
    Some more detail. It appears requests to get the current position of the device will continue to fail as if the location is none, even if I directly run the applesimutils --setLocation command from the terminal. It appears the only way the simulator location will get set is if there is a request to get the current position of the simulator in flight when I run the applesimutils --setLocation from the terminal. I am using the https://github.com/react-native-geolocation/react-native-geolocation library to retrieve the current position. Prior to that I was using https://github.com/transistorsoft/react-native-background-geolocation but the behavior is the same. An asynchronous request to retrieve the phone's current location must be in flight when the applesimutils --setLocation command is run. This seems like it actually may be a bug with the applesimutils --setLocation functionality itself.

@d4vidi
Copy link
Collaborator

d4vidi commented Oct 18, 2021

Thanks @zacharyweidenbach! We will revisit applesimutils --setLocation in the context of issue #2736, which in-favor-of I'll be closing this one. In any case, it seems your insight could in fact come in handy.

@d4vidi d4vidi closed this as completed Oct 18, 2021
@Livijn
Copy link

Livijn commented Mar 1, 2022

@zacharyweidenbach Did you manage to get this working? I am also experiencing the same issue.

@zacharyweidenbach
Copy link

zacharyweidenbach commented Mar 4, 2022

@Livijn

Unfortunately no. For now, we've accepted that we cannot get e2e test coverage on features that require control over the device's location on iOS. Back when I was troubleshooting this, it appeared to be a bug with applesimutils. If what I found still holds true - that setting the device location doesn't work unless there is a request asking for the device location in flight - then a hacky workaround might look like launching the app with a custom launch arg to initiate a request for device's location, and at the same time, trigger the applesimutils --setLocation. But I would expect that to be flaky due to the race condition of whether the app starts asking for its location before applesimutils --setLocation attempts to set the device's location.

@mushtaque87
Copy link

mushtaque87 commented Jun 3, 2023

This worked for me

const { exec } = require('child_process');

const setLocation = async () => {
      log.info('setLocation **');
      if (device.getPlatform() === 'ios') {
        exec(
          "idb list-targets | grep -n 'Booted'",
          (err: any, stdout: any, stderr: any) => {
            log.info('idb list-targets - ', err, stdout, stderr);
            log.info(
              'Execute Command to set Location for iOS **',
              'idb set-location --udid ' + device.id + ' 25.2769 55.2962',
            );
            exec(
              'idb set-location --udid ' + device.id + ' 25.2769 55.2962',
              (err: any, stdout: any, stderr: any) => {
                log.info('setLocation - ', err, stdout, stderr);
              },
            );
          },
        );
      } else {
        await device.setLocation(25.2769, 55.2962);
      }
    };

@d4vidi
Copy link
Collaborator

d4vidi commented Jun 8, 2023

Let's move further location-related discussions to #3240 🙏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests