1. #!/usr/bin/env node
    
  2. 
    
  3. 'use strict';
    
  4. 
    
  5. const {spawn} = require('child_process');
    
  6. const {join} = require('path');
    
  7. 
    
  8. const ROOT_PATH = join(__dirname, '..', '..');
    
  9. const reactVersion = process.argv[2];
    
  10. const inlinePackagePath = join(ROOT_PATH, 'packages', 'react-devtools-inline');
    
  11. const shellPackagePath = join(ROOT_PATH, 'packages', 'react-devtools-shell');
    
  12. const screenshotPath = join(ROOT_PATH, 'tmp', 'screenshots');
    
  13. 
    
  14. const {SUCCESSFUL_COMPILATION_MESSAGE} = require(
    
  15.   join(shellPackagePath, 'constants.js')
    
  16. );
    
  17. 
    
  18. let buildProcess = null;
    
  19. let serverProcess = null;
    
  20. let testProcess = null;
    
  21. 
    
  22. function format(loggable) {
    
  23.   return `${loggable}`
    
  24.     .split('\n')
    
  25.     .filter(line => {
    
  26.       return line.trim() !== '';
    
  27.     })
    
  28.     .map(line => `  ${line}`)
    
  29.     .join('\n');
    
  30. }
    
  31. 
    
  32. function logBright(loggable) {
    
  33.   console.log(`\x1b[1m${loggable}\x1b[0m`);
    
  34. }
    
  35. 
    
  36. function logDim(loggable) {
    
  37.   const formatted = format(loggable, 2);
    
  38.   if (formatted !== '') {
    
  39.     console.log(`\x1b[2m${formatted}\x1b[0m`);
    
  40.   }
    
  41. }
    
  42. 
    
  43. function logError(loggable) {
    
  44.   const formatted = format(loggable, 2);
    
  45.   if (formatted !== '') {
    
  46.     console.error(`\x1b[31m${formatted}\x1b[0m`);
    
  47.   }
    
  48. }
    
  49. 
    
  50. function buildInlinePackage() {
    
  51.   logBright('Building inline packages');
    
  52. 
    
  53.   buildProcess = spawn('yarn', ['build'], {cwd: inlinePackagePath});
    
  54.   buildProcess.stdout.on('data', data => {
    
  55.     logDim(data);
    
  56.   });
    
  57.   buildProcess.stderr.on('data', data => {
    
  58.     if (`${data}`.includes('Warning')) {
    
  59.       logDim(data);
    
  60.     } else {
    
  61.       logError(`Error:\n${data}`);
    
  62. 
    
  63.       exitWithCode(1);
    
  64.     }
    
  65.   });
    
  66.   buildProcess.on('close', code => {
    
  67.     logBright('Inline package built');
    
  68. 
    
  69.     runTestShell();
    
  70.   });
    
  71. }
    
  72. 
    
  73. function runTestShell() {
    
  74.   const timeoutID = setTimeout(() => {
    
  75.     // Assume the test shell server failed to start.
    
  76.     logError('Testing shell server failed to start');
    
  77.     exitWithCode(1);
    
  78.   }, 60 * 1000);
    
  79. 
    
  80.   logBright('Starting testing shell server');
    
  81. 
    
  82.   if (!reactVersion) {
    
  83.     serverProcess = spawn('yarn', ['start'], {cwd: shellPackagePath});
    
  84.   } else {
    
  85.     serverProcess = spawn('yarn', ['start'], {
    
  86.       cwd: shellPackagePath,
    
  87.       env: {...process.env, REACT_VERSION: reactVersion},
    
  88.     });
    
  89.   }
    
  90. 
    
  91.   serverProcess.stdout.on('data', data => {
    
  92.     if (`${data}`.includes(SUCCESSFUL_COMPILATION_MESSAGE)) {
    
  93.       logBright('Testing shell server running');
    
  94. 
    
  95.       clearTimeout(timeoutID);
    
  96. 
    
  97.       runEndToEndTests();
    
  98.     }
    
  99.   });
    
  100. 
    
  101.   serverProcess.stderr.on('data', data => {
    
  102.     if (`${data}`.includes('EADDRINUSE')) {
    
  103.       // Something is occupying this port;
    
  104.       // We could kill the process and restart but probably better to prompt the user to do this.
    
  105. 
    
  106.       logError('Free up the port and re-run tests:');
    
  107.       logBright('  kill -9 $(lsof -ti:8080)');
    
  108. 
    
  109.       exitWithCode(1);
    
  110.     } else if (`${data}`.includes('ERROR')) {
    
  111.       logError(`Error:\n${data}`);
    
  112. 
    
  113.       exitWithCode(1);
    
  114.     } else {
    
  115.       // Non-fatal stuff like Babel optimization warnings etc.
    
  116.       logDim(data);
    
  117.     }
    
  118.   });
    
  119. }
    
  120. 
    
  121. async function runEndToEndTests() {
    
  122.   logBright('Running e2e tests');
    
  123.   if (!reactVersion) {
    
  124.     testProcess = spawn('yarn', ['test:e2e', `--output=${screenshotPath}`], {
    
  125.       cwd: inlinePackagePath,
    
  126.     });
    
  127.   } else {
    
  128.     testProcess = spawn('yarn', ['test:e2e', `--output=${screenshotPath}`], {
    
  129.       cwd: inlinePackagePath,
    
  130.       env: {...process.env, REACT_VERSION: reactVersion},
    
  131.     });
    
  132.   }
    
  133. 
    
  134.   testProcess.stdout.on('data', data => {
    
  135.     // Log without formatting because Playwright applies its own formatting.
    
  136.     const formatted = format(data);
    
  137.     if (formatted !== '') {
    
  138.       console.log(formatted);
    
  139.     }
    
  140.   });
    
  141.   testProcess.stderr.on('data', data => {
    
  142.     // Log without formatting because Playwright applies its own formatting.
    
  143.     const formatted = format(data);
    
  144.     if (formatted !== '') {
    
  145.       console.error(formatted);
    
  146.     }
    
  147. 
    
  148.     exitWithCode(1);
    
  149.   });
    
  150.   testProcess.on('close', code => {
    
  151.     logBright(`Tests completed with code: ${code}`);
    
  152. 
    
  153.     exitWithCode(code);
    
  154.   });
    
  155. }
    
  156. 
    
  157. function exitWithCode(code) {
    
  158.   if (buildProcess !== null) {
    
  159.     try {
    
  160.       logBright('Shutting down build process');
    
  161.       buildProcess.kill();
    
  162.     } catch (error) {
    
  163.       logError(error);
    
  164.     }
    
  165.   }
    
  166. 
    
  167.   if (serverProcess !== null) {
    
  168.     try {
    
  169.       logBright('Shutting down shell server process');
    
  170.       serverProcess.kill();
    
  171.     } catch (error) {
    
  172.       logError(error);
    
  173.     }
    
  174.   }
    
  175. 
    
  176.   if (testProcess !== null) {
    
  177.     try {
    
  178.       logBright('Shutting down test process');
    
  179.       testProcess.kill();
    
  180.     } catch (error) {
    
  181.       logError(error);
    
  182.     }
    
  183.   }
    
  184. 
    
  185.   process.exit(code);
    
  186. }
    
  187. 
    
  188. buildInlinePackage();