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