xref: /expo/tools/src/IOSSimulatorTestSuite.ts (revision a272999e)
1eeffdb10STomasz Sapetaimport JUnitReportBuilder from 'junit-report-builder';
2eeffdb10STomasz Sapetaimport path from 'path';
3eeffdb10STomasz Sapeta
4eeffdb10STomasz Sapetaimport * as IOSSimulator from './IOSSimulator';
5eeffdb10STomasz Sapetaimport * as Log from './Log';
6eeffdb10STomasz Sapeta
7eeffdb10STomasz Sapetaconst TEST_SUITE_BUNDLE_ID = 'io.expo.testsuite';
8eeffdb10STomasz Sapetaconst TEST_SUITE_END_SENTINEL = '[TEST-SUITE-END]';
9eeffdb10STomasz Sapeta
10eeffdb10STomasz Sapeta// Keep this type in sync with test-suite
11eeffdb10STomasz Sapetatype TestSuiteResults = {
12eeffdb10STomasz Sapeta  failed: number;
13eeffdb10STomasz Sapeta  failures: string;
14eeffdb10STomasz Sapeta};
15eeffdb10STomasz Sapeta
16eeffdb10STomasz Sapetaexport async function runTestSuiteOnIOSSimulatorAsync(simulatorId, archivePath, reportPath) {
17eeffdb10STomasz Sapeta  Log.collapsed(`Running test-suite on the iOS simulator`);
18eeffdb10STomasz Sapeta  if (!simulatorId) {
19eeffdb10STomasz Sapeta    console.log(`Starting a new simulator`);
20eeffdb10STomasz Sapeta    await IOSSimulator.startSimulatorAsync();
21eeffdb10STomasz Sapeta    simulatorId = 'booted';
22eeffdb10STomasz Sapeta  }
23eeffdb10STomasz Sapeta
24eeffdb10STomasz Sapeta  console.log(`Installing test-suite on the simulator`);
25eeffdb10STomasz Sapeta  await IOSSimulator.installSimulatorAppAsync(simulatorId, path.resolve(archivePath));
26eeffdb10STomasz Sapeta  console.log(`Streaming logs from the simulator`);
27*a272999eSBartosz Kaszubowski  const resultsPromise = _streamSimulatorLogsAsync(simulatorId);
28eeffdb10STomasz Sapeta  console.log(`Launching the test-suite app and waiting for tests to complete`);
29eeffdb10STomasz Sapeta  await IOSSimulator.launchSimulatorAppAsync(simulatorId, TEST_SUITE_BUNDLE_ID);
30eeffdb10STomasz Sapeta
31*a272999eSBartosz Kaszubowski  const results = await resultsPromise;
32eeffdb10STomasz Sapeta  if (results.failed === 0) {
33eeffdb10STomasz Sapeta    console.log(`�� All tests passed`);
34eeffdb10STomasz Sapeta  } else {
35eeffdb10STomasz Sapeta    console.error(`�� ${results.failed} ${results.failed === 1 ? 'test' : 'tests'} failed`);
36eeffdb10STomasz Sapeta  }
37eeffdb10STomasz Sapeta
38eeffdb10STomasz Sapeta  if (reportPath) {
39eeffdb10STomasz Sapeta    _writeJUnitReport(results, reportPath);
40eeffdb10STomasz Sapeta    console.log(`Saved test results to ${reportPath}`);
41eeffdb10STomasz Sapeta  }
42eeffdb10STomasz Sapeta
43eeffdb10STomasz Sapeta  return results;
44eeffdb10STomasz Sapeta}
45eeffdb10STomasz Sapeta
46eeffdb10STomasz Sapetafunction _streamSimulatorLogsAsync(simulatorId: string): Promise<TestSuiteResults> {
47eeffdb10STomasz Sapeta  return new Promise((resolve, reject) => {
48*a272999eSBartosz Kaszubowski    const logProcess = IOSSimulator.getSimulatorLogProcess(
49eeffdb10STomasz Sapeta      simulatorId,
50eeffdb10STomasz Sapeta      '(subsystem == "host.exp.Exponent") && (category == "test")'
51eeffdb10STomasz Sapeta    );
52*a272999eSBartosz Kaszubowski    const logStream = new IOSSimulator.IOSLogStream();
53eeffdb10STomasz Sapeta    logProcess.stdout.pipe(logStream);
54eeffdb10STomasz Sapeta
55eeffdb10STomasz Sapeta    logStream.on('data', (entry) => {
56eeffdb10STomasz Sapeta      // Show the log messages in the CI log
57eeffdb10STomasz Sapeta      console.log(entry.eventMessage);
58eeffdb10STomasz Sapeta
59eeffdb10STomasz Sapeta      if (!entry.eventMessage.startsWith(TEST_SUITE_END_SENTINEL)) {
60eeffdb10STomasz Sapeta        return;
61eeffdb10STomasz Sapeta      }
62eeffdb10STomasz Sapeta
63eeffdb10STomasz Sapeta      try {
64eeffdb10STomasz Sapeta        logStream.removeAllListeners('data');
65eeffdb10STomasz Sapeta
66*a272999eSBartosz Kaszubowski        const resultsJson = entry.eventMessage.substring(TEST_SUITE_END_SENTINEL.length).trim();
67*a272999eSBartosz Kaszubowski        const results = JSON.parse(resultsJson);
68eeffdb10STomasz Sapeta        resolve(results);
69eeffdb10STomasz Sapeta      } catch (e) {
70eeffdb10STomasz Sapeta        reject(e);
71eeffdb10STomasz Sapeta      } finally {
72eeffdb10STomasz Sapeta        console.log(`Terminating simulator log stream`);
73eeffdb10STomasz Sapeta        logProcess.kill('SIGTERM');
74eeffdb10STomasz Sapeta      }
75eeffdb10STomasz Sapeta    });
76eeffdb10STomasz Sapeta  });
77eeffdb10STomasz Sapeta}
78eeffdb10STomasz Sapeta
79eeffdb10STomasz Sapetafunction _writeJUnitReport(results: TestSuiteResults, reportPath: string): void {
80*a272999eSBartosz Kaszubowski  const builder = JUnitReportBuilder.newBuilder();
81eeffdb10STomasz Sapeta  // let suite = builder.testSuite().name('Test Suite');
82eeffdb10STomasz Sapeta
83eeffdb10STomasz Sapeta  // TODO: parse the results
84eeffdb10STomasz Sapeta
85eeffdb10STomasz Sapeta  builder.writeTo(reportPath);
86eeffdb10STomasz Sapeta}
87