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