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