function signalWhenReady()

in lib/cmds/start.ts [345:467]


function signalWhenReady(
    signal: string, viaIPC: boolean, outputDir: string, seleniumPort: string, appiumPort: string,
    androidSDK: Binary, avdPort: number, avdNames: string[]) {
  const maxWait = 10 * 60 * 1000;  // Ten minutes
  function waitFor(
      getStatus: () => Promise<string>, testStatus: (status: string) => boolean, desc?: string) {
    const checkInterval = 100;
    return new Promise<void>((resolve, reject) => {
      let waited = 0;
      (function recursiveCheck() {
        setTimeout(() => {
          getStatus()
              .then<void>((status: string) => {
                if (!testStatus(status)) {
                  return Promise.reject(
                      'Invalid status' + (desc ? ' for ' + desc : '') + ': ' + status);
                }
              })
              .then(
                  () => {
                    resolve();
                  },
                  (error: any) => {
                    waited += checkInterval;
                    if (waited < maxWait) {
                      recursiveCheck();
                    } else {
                      reject(
                          'Timed out' + (desc ? ' wating for' + desc : '') +
                          '.  Final rejection reason: ' + JSON.stringify(error));
                    }
                  });
        }, checkInterval);
      })();
    });
  };
  function waitForAndroid(avdPort: number, avdName: string, appiumPort: string): Promise<void> {
    let sdkPath = path.resolve(outputDir, androidSDK.executableFilename());
    logger.info('Waiting for ' + avdName + '\'s emulator to start');
    return adb(sdkPath, avdPort, 'wait-for-device', maxWait)
        .then<void>(
            () => {
              logger.info('Waiting for ' + avdName + '\'s OS to boot up');
              return waitFor(
                  () => {
                    return adb(
                        sdkPath, avdPort, 'shell', maxWait, ['getprop', 'sys.boot_completed']);
                  },
                  (status: string) => {
                    return status.trim() == '1';
                  },
                  avdName + '\'s OS');
            },
            (error: {code: string|number, message: string}) => {
              return Promise.reject(
                  'Failed to wait for ' + avdName + '\'s emulator to start (' + error.code + ': ' +
                  error.message + ')');
            })
        .then<string>(() => {
          logger.info('Waiting for ' + avdName + ' to be ready to launch chrome');
          let version = AndroidSDK.VERSIONS[parseInt(avdName.slice('android-'.length))];
          return request('POST', appiumPort, '/wd/hub/session', maxWait, {
                   desiredCapabilities: {
                     browserName: 'chrome',
                     platformName: 'Android',
                     platformVersion: version,
                     deviceName: 'Android Emulator'
                   }
                 })
              .then(
                  (data) => {
                    return JSON.parse(data)['sessionId'];
                  },
                  (error: {code: string|number, message: string}) => {
                    return Promise.reject(
                        'Could not start chrome on ' + avdName + ' (' + error.code + ': ' +
                        error.message + ')');
                  });
        })
        .then<void>((sessionId: string) => {
          logger.info('Shutting down dummy chrome instance for ' + avdName);
          return request('DELETE', appiumPort, '/wd/hub/session/' + sessionId)
              .then<void>(() => {}, (error: {code: string|number, message: string}) => {
                return Promise.reject(
                    'Could not close chrome on ' + avdName + ' (' + error.code + ': ' +
                    error.message + ')');
              });
        });
  }
  let pending = [waitFor(
      () => {
        return request('GET', seleniumPort, '/wd/hub/status', maxWait);
      },
      (status) => {
        return JSON.parse(status).status == 0;
      },
      'selenium server')];
  if (appiumPort) {
    pending.push(waitFor(
        () => {
          return request('GET', appiumPort, '/wd/hub/status', maxWait);
        },
        (status) => {
          return JSON.parse(status).status == 0;
        },
        'appium server'));
  }
  if (androidSDK && avdPort) {
    for (let i = 0; i < avdNames.length; i++) {
      pending.push(waitForAndroid(avdPort + 2 * i, avdNames[i], appiumPort));
    }
  }
  Promise.all(pending).then(
      () => {
        logger.info('Everything started');
        sendStartedSignal(signal, viaIPC);
      },
      (error) => {
        logger.error(error);
        shutdownEverything(seleniumPort);
        process.exitCode = 1;
      });
}