browser-test.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * Copyright (c) Jupyter Development Team.
  3. * Distributed under the terms of the Modified BSD License.
  4. */
  5. const playwright = require('playwright');
  6. const path = require('path');
  7. const fs = require('fs');
  8. // eslint-disable-next-line no-redeclare
  9. const URL = process.argv[2];
  10. const BROWSER_VAR = 'JLAB_BROWSER_TYPE';
  11. const BROWSER = process.env[BROWSER_VAR] || 'chromium';
  12. const HEADLESS_VAR = 'JLAB_BROWSER_HEADLESS';
  13. const HEADLESS = process.env[HEADLESS_VAR] === 'false' ? false : true;
  14. const OUTPUT_VAR = 'JLAB_BROWSER_CHECK_OUTPUT';
  15. const OUTPUT = process.env[OUTPUT_VAR];
  16. let nextScreenshot = 0;
  17. const screenshotStem = `screenshot-${+new Date()}`;
  18. if (OUTPUT) {
  19. console.log(`Screenshots will be saved in ${OUTPUT}...`);
  20. if (!fs.existsSync(OUTPUT)) {
  21. console.log(`Creating ${OUTPUT}...`);
  22. fs.mkdirSync(OUTPUT, { recursive: true });
  23. }
  24. }
  25. async function main() {
  26. /* eslint-disable no-console */
  27. console.info(`Starting headless ${BROWSER}...`);
  28. let testError = null;
  29. const pwBrowser = playwright[BROWSER];
  30. const browser = await pwBrowser.launch({
  31. headless: HEADLESS,
  32. logger: {
  33. isEnabled: () => !!OUTPUT,
  34. log: (name, severity, message, args) => console.log(name, message)
  35. }
  36. });
  37. const context = await browser.newContext();
  38. const page = await context.newPage();
  39. async function screenshot() {
  40. if (!OUTPUT) {
  41. return;
  42. }
  43. const screenshotPath = path.join(
  44. OUTPUT,
  45. `${screenshotStem}-${++nextScreenshot}.png`
  46. );
  47. console.log(`Capturing screenshot ${screenshotPath}...`);
  48. await page.screenshot({
  49. type: 'png',
  50. path: screenshotPath
  51. });
  52. }
  53. console.info('Navigating to page:', URL);
  54. await page.goto(URL);
  55. console.info('Waiting for page to load...');
  56. // Wait for the local file to redirect on notebook >= 6.0
  57. await page.waitForNavigation();
  58. console.log('Waiting for page content..');
  59. try {
  60. await page.locator('#jupyter-config-data').waitFor({ state: 'attached' });
  61. } catch (reason) {
  62. console.error('Error loading JupyterLab page:', reason);
  63. // Limit to 1000 characters
  64. console.error((await page.content()).substring(0, 1000));
  65. testError = reason;
  66. }
  67. console.log('Waiting for #main selector...');
  68. await page.waitForSelector('#main', { timeout: 100000 });
  69. console.log('Waiting for #browserTest selector...');
  70. const el = await page.waitForSelector('#browserTest', {
  71. timeout: 100000,
  72. state: 'attached'
  73. });
  74. console.log('Waiting for application to start...');
  75. try {
  76. await page.waitForSelector('.completed', { state: 'attached' });
  77. } catch (e) {
  78. testError = e;
  79. }
  80. await screenshot();
  81. const textContent = await el.getProperty('textContent');
  82. const errors = JSON.parse(await textContent.jsonValue());
  83. for (let error of errors) {
  84. console.error(`Parsed an error from text content: ${error.message}`, error);
  85. testError = true;
  86. }
  87. await browser.close();
  88. if (testError) {
  89. throw testError;
  90. }
  91. console.info('Browser test complete');
  92. }
  93. // Stop the process if an error is raised in the async function.
  94. process.on('unhandledRejection', up => {
  95. throw up;
  96. });
  97. void main();