puppeteer.unit.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Run unit tests in headless or headful browser environment using Puppeteer.
  2. // This allows us to run tests in an environment that closely resembles how users would experience them,
  3. // including asset loading and browser-specific APIs,
  4. // while still being able to automate and capture results in a CI/CD pipeline.
  5. // It also enables us to capture console output from the browser and display it in the terminal.
  6. // Unit testing loaders in particular benefit from running in this setup,
  7. // as they require a server to facilitate assets loading,
  8. // and some of them require a browser environment to run in (e.g. ImageLoader => createElementNS('img')).
  9. import puppeteer from 'puppeteer';
  10. const networkTimeout = 5; // 5 minutes, set to 0 to disable
  11. const port = 1234;
  12. let browser;
  13. import { createServer } from '../../utils/server.js';
  14. const server = createServer();
  15. server.listen( port, main );
  16. const color = code => msg => console.log( `\x1b[${code}m${msg}\x1b[39m` );
  17. const white = color( 37 );
  18. const red = color( 31 );
  19. const green = color( 32 );
  20. const yellow = color( 33 );
  21. const blue = color( 34 );
  22. const cyan = color( 36 );
  23. const captureConsole = ( page ) => {
  24. const colors = {
  25. LOG: white,
  26. ERROR: red,
  27. WARN: yellow,
  28. INFO: green,
  29. };
  30. page.on( 'console', async ( message ) => {
  31. const type = message.type().toUpperCase();
  32. const color = colors[ type ] || blue;
  33. color( `${type}: ${message.text()} ` );
  34. } );
  35. };
  36. function main() {
  37. ( async () => {
  38. const flags = [
  39. '--hide-scrollbars',
  40. '--enable-unsafe-webgpu',
  41. '--enable-features=Vulkan',
  42. '--disable-vulkan-surface',
  43. '--ignore-gpu-blocklist',
  44. '--disable-gpu-driver-bug-workarounds',
  45. '--no-sandbox'
  46. ];
  47. let testPage = '';
  48. let testMode = '';
  49. let argvIndex = 2;
  50. if ( process.argv[ argvIndex ].startsWith( '--testPage' ) ) {
  51. testPage = process.argv[ argvIndex ].split( '=' )[ 1 ];
  52. argvIndex ++;
  53. }
  54. if ( process.argv[ argvIndex ].startsWith( '--mode' ) ) {
  55. testMode = process.argv[ argvIndex ].split( '=' )[ 1 ];
  56. argvIndex ++;
  57. }
  58. browser = await puppeteer.launch( {
  59. headless: testMode === 'headless',
  60. args: flags,
  61. env: { ...process.env, VK_DRIVER_FILES: '/usr/share/vulkan/icd.d/lvp_icd.x86_64.json' },
  62. defaultViewport: null,
  63. handleSIGINT: false,
  64. protocolTimeout: 0,
  65. userDataDir: './.puppeteer_profile'
  66. } );
  67. if ( testMode === 'headful' ) {
  68. browser.on( 'targetdestroyed', target => {
  69. // close the process when testing page is closed
  70. if ( target.type() === 'page' ) close( 0 );
  71. } );
  72. }
  73. const page = await browser.newPage();
  74. captureConsole( page );
  75. const testUrl = `http://localhost:${port}/test/unit/${testPage}`;
  76. // Load the test page
  77. await page.goto( testUrl, {
  78. waitUntil: 'networkidle0',
  79. timeout: networkTimeout * 60000
  80. } );
  81. // Wait for the QUnit test results
  82. await page.waitForFunction( () => {
  83. return window.QUnit && window.QUnit.done;
  84. } );
  85. // Get the test results
  86. const stats = await page.evaluate( () => {
  87. // these are set on window in the HTML test page
  88. return window._QUnitStats;
  89. } );
  90. white( `1..${stats.total}` );
  91. green( `# pass ${stats.passed}` );
  92. yellow( `# skip ${stats.skipped}` );
  93. cyan( `# todo ${stats.todo}` );
  94. red( `# fail ${stats.failed}` );
  95. // Keep the process running if testing in headful mode, otherwise close it.
  96. testMode === 'headless' && close( stats.failed > 0 ? 1 : 0 );
  97. } )();
  98. }
  99. process.on( 'SIGINT', () => close() );
  100. function close( exitCode = 1 ) {
  101. browser.close();
  102. server.close();
  103. process.exit( exitCode );
  104. }
粤ICP备19079148号