1import { element, expect, waitFor, by, device } from 'detox';
2
3const MenuTimeout = 70 * 1000;
4const LauncherMainScreenTimeout = 50 * 1000;
5const LocalAppTimeout = 80 * 1000;
6
7const sleep = (duration: number) =>
8  new Promise<void>((resolve) => setTimeout(() => resolve(), duration));
9
10async function pressMenuButton(buttonString: string) {
11  let button = element(by.text(buttonString));
12
13  await waitFor(button).toBeVisible().withTimeout(MenuTimeout);
14
15  // When we open the dev-menu, we will see an animation.
16  // Unfortunately, if we try to click to button before the
17  // animation finishes, it may not work. We might click different a button.
18  // So try to wait for the animation to finish.
19  await sleep(1000);
20
21  button = element(by.text(buttonString));
22  await waitFor(button).toBeVisible();
23
24  await button.tap();
25}
26
27function getInvocationManager() {
28  // @ts-ignore
29  return global.detox[Object.getOwnPropertySymbols(global.detox)[0]]._invocationManager;
30}
31
32function getLocalIPAddress(): string {
33  if (device.getPlatform() === 'ios') {
34    return 'localhost';
35  }
36  return require('os')
37    .networkInterfaces()
38    .en0.find((elm: { family: string }) => elm.family === 'IPv4').address;
39}
40
41async function openMenu(): Promise<void> {
42  if (device.getPlatform() === 'android') {
43    return getInvocationManager().execute({
44      target: {
45        type: 'Class',
46        value: 'com.testrunner.DevClientDetoxHelper',
47      },
48      method: 'openMenu',
49      args: [],
50    });
51  }
52  return await device.shake();
53}
54
55describe('DevLauncher', () => {
56  beforeEach(async () => {
57    await device.launchApp({ newInstance: true });
58  });
59
60  it('should render main screen', async () => {
61    await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
62  });
63
64  it('should be able to open dev menu', async () => {
65    await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
66
67    await openMenu();
68
69    await waitFor(element(by.id('DevMenuMainScreen')))
70      .toBeVisible()
71      .withTimeout(MenuTimeout);
72  });
73
74  it('should be able to load app from URL', async () => {
75    const urlInput = element(by.id('DevLauncherURLInput'));
76    const loadButton = element(by.id('DevLauncherLoadAppButton'));
77
78    await expect(urlInput).toBeVisible();
79    await expect(loadButton).toBeVisible();
80
81    await urlInput.typeText(`http://${getLocalIPAddress()}:8081`);
82    if (device.getPlatform() === 'android') {
83      // close keyboard
84      await device.pressBack();
85    }
86    await loadButton.multiTap(2);
87
88    await waitFor(element(by.id('LocalAppMainScreen')))
89      .toBeVisible()
90      .withTimeout(LocalAppTimeout);
91  });
92
93  it('should be able to come back to the dev launcher screen', async () => {
94    const urlInput = element(by.id('DevLauncherURLInput'));
95    const loadButton = element(by.id('DevLauncherLoadAppButton'));
96
97    await expect(urlInput).toBeVisible();
98    await expect(loadButton).toBeVisible();
99
100    await urlInput.typeText(`http://${getLocalIPAddress()}:8081`);
101    if (device.getPlatform() === 'android') {
102      // close keyboard
103      await device.pressBack();
104    }
105    await loadButton.multiTap(2);
106
107    await waitFor(element(by.id('LocalAppMainScreen')))
108      .toBeVisible()
109      .withTimeout(LocalAppTimeout);
110
111    await openMenu();
112
113    await pressMenuButton('Back to Launcher');
114
115    await waitFor(element(by.id('DevLauncherMainScreen')))
116      .toBeVisible()
117      .withTimeout(LauncherMainScreenTimeout);
118  });
119});
120