notebook.spec.ts 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { expect, test } from '@playwright/test';
  4. import { benchmark, galata } from '@jupyterlab/galata';
  5. import path from 'path';
  6. const tmpPath = 'test-performance-open';
  7. const codeNotebook = 'large_code_notebook.ipynb';
  8. const mdNotebook = 'large_md_notebook.ipynb';
  9. const textFile = 'lorem_ipsum.txt';
  10. // Build test parameters list [file, index]
  11. const parameters = [].concat(
  12. ...[codeNotebook, mdNotebook].map(file =>
  13. new Array<number>(benchmark.nSamples)
  14. .fill(0)
  15. .map((_, index) => [file, index])
  16. )
  17. );
  18. test.describe('Benchmark', () => {
  19. // Generate the files for the benchmark
  20. test.beforeAll(async ({ baseURL }) => {
  21. const content = galata.newContentsHelper(baseURL);
  22. const codeContent = galata.Notebook.generateNotebook(300, 'code', [
  23. 'for x in range(OUTPUT_LENGTH):\n',
  24. ' print(f"{PREFIX} {x}")'
  25. ]);
  26. await content.uploadContent(
  27. JSON.stringify(codeContent),
  28. 'text',
  29. `${tmpPath}/${codeNotebook}`
  30. );
  31. const mdContent = galata.Notebook.generateNotebook(300, 'markdown', [
  32. '# Demonstration of proper behaviour with non-LaTeX uses of `$`\n',
  33. '\n',
  34. '## This should be highlighted as a heading\n',
  35. '\n',
  36. 'Sample code:\n',
  37. '\n',
  38. ' ```\n',
  39. ' echo $HOME\n',
  40. ' ```\n',
  41. '\n',
  42. '```shell\n',
  43. 'echo $HOME\n',
  44. '```\n',
  45. '\n',
  46. 'The code block below should be properly highlighted:\n',
  47. '\n',
  48. '```bash\n',
  49. 'echo $HOME\n',
  50. '```\n',
  51. '\n',
  52. '\n',
  53. '### Heading\n',
  54. '\n',
  55. '`$test`\n',
  56. '\n',
  57. '### This heading should be highlighted too'
  58. ]);
  59. await content.uploadContent(
  60. JSON.stringify(mdContent),
  61. 'text',
  62. `${tmpPath}/${mdNotebook}`
  63. );
  64. const loremIpsum =
  65. 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie suscipit libero non volutpat. Suspendisse et tincidunt metus. Proin laoreet magna rutrum egestas tristique. Proin vel neque sit amet lectus egestas pellentesque nec quis nisl. Quisque faucibus condimentum leo, quis euismod eros ultrices in. Vivamus maximus malesuada tempor. Aliquam maximus maximus elit, ac imperdiet tellus posuere nec. Sed at rutrum velit. Etiam et lectus convallis, sagittis nibh sit amet, gravida turpis. Nulla nec velit id est tristique iaculis.\n\nDonec vel finibus mauris, eu tristique justo. Pellentesque turpis lorem, lobortis eu tincidunt non, cursus sit amet ex. Vivamus eget ligula a leo vulputate egestas a eu felis. Donec sollicitudin maximus neque quis condimentum. Cras vestibulum nulla libero, sed semper velit faucibus ac. Phasellus et consequat risus. Sed suscipit ligula est. Etiam ultricies ac lacus sit amet cursus. Nam non leo vehicula, iaculis eros eu, consequat sapien. Ut quis odio quis augue pharetra porttitor sit amet eget nisl. Vestibulum magna eros, rutrum ac nisi non, lobortis varius ipsum. Proin luctus euismod arcu eget sollicitudin. Praesent nec erat gravida, tincidunt diam eget, tempor tortor.';
  66. await content.uploadContent(loremIpsum, 'text', `${tmpPath}/${textFile}`);
  67. });
  68. // Remove benchmark files
  69. test.afterAll(async ({ baseURL }) => {
  70. const content = galata.newContentsHelper(baseURL);
  71. await content.deleteDirectory(tmpPath);
  72. });
  73. // Loop on benchmark files nSamples times
  74. // For each file, benchmark:
  75. // - Open the file
  76. // - Switch to a text file
  77. // - Switch back to the file
  78. // - Close the file
  79. for (const [file, sample] of parameters) {
  80. test(`measure ${file} - ${sample + 1}`, async ({
  81. baseURL,
  82. browserName,
  83. page
  84. }, testInfo) => {
  85. const attachmentCommon = {
  86. nSamples: benchmark.nSamples,
  87. browser: browserName,
  88. file: path.basename(file, '.ipynb'),
  89. project: testInfo.project.name
  90. };
  91. const perf = galata.newPerformanceHelper(page);
  92. await page.goto(baseURL + '?reset');
  93. await page.click('#filebrowser >> .jp-BreadCrumbs-home');
  94. await page.dblclick(`#filebrowser >> text=${tmpPath}`);
  95. const openTime = await perf.measure(async () => {
  96. // Open the notebook and wait for the spinner
  97. await Promise.all([
  98. page.waitForSelector('[role="main"] >> .jp-SpinnerContent'),
  99. page.dblclick(`#filebrowser >> text=${file}`)
  100. ]);
  101. // Wait for spinner to be hidden
  102. await page.waitForSelector('[role="main"] >> .jp-SpinnerContent', {
  103. state: 'hidden'
  104. });
  105. });
  106. // Check the notebook is correctly opened
  107. let panel = await page.$('[role="main"] >> .jp-NotebookPanel');
  108. // Get only the document node to avoid noise from kernel and debugger in the toolbar
  109. let document = await panel.$('.jp-Notebook');
  110. expect(await document.screenshot()).toMatchSnapshot(
  111. `${file.replace('.', '-')}.png`
  112. );
  113. testInfo.attachments.push(
  114. benchmark.addAttachment({
  115. ...attachmentCommon,
  116. test: 'open',
  117. time: openTime
  118. })
  119. );
  120. // Shutdown the kernel to be sure it does not get in our way (especially for the close action)
  121. await page.click('li[role="menuitem"]:has-text("Kernel")');
  122. await page.click('ul[role="menu"] >> text=Shut Down All Kernels…');
  123. await page.click(':nth-match(button:has-text("Shut Down All"), 3)');
  124. // Open text file
  125. const fromTime = await perf.measure(async () => {
  126. await page.dblclick(`#filebrowser >> text=${textFile}`);
  127. await page.waitForSelector(
  128. `div[role="main"] >> .lm-DockPanel-tabBar >> text=${path.basename(
  129. textFile
  130. )}`
  131. );
  132. });
  133. let editorPanel = page.locator(
  134. 'div[role="tabpanel"]:has-text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin mole")'
  135. );
  136. await expect(editorPanel).toBeVisible();
  137. testInfo.attachments.push(
  138. benchmark.addAttachment({
  139. ...attachmentCommon,
  140. test: 'switch-from',
  141. time: fromTime
  142. })
  143. );
  144. // Switch back
  145. const toTime = await perf.measure(async () => {
  146. await page.click(
  147. `div[role="main"] >> .lm-DockPanel-tabBar >> text=${file}`
  148. );
  149. });
  150. // Check the notebook is correctly opened
  151. panel = await page.$('[role="main"] >> .jp-NotebookPanel');
  152. // Get only the document node to avoid noise from kernel and debugger in the toolbar
  153. document = await panel.$('.jp-Notebook');
  154. expect(await document.screenshot()).toMatchSnapshot(
  155. `${file.replace('.', '-')}.png`
  156. );
  157. testInfo.attachments.push(
  158. benchmark.addAttachment({
  159. ...attachmentCommon,
  160. test: 'switch-to',
  161. time: toTime
  162. })
  163. );
  164. // Close notebook
  165. await page.click('li[role="menuitem"]:has-text("File")');
  166. const closeTime = await perf.measure(async () => {
  167. await page.click('ul[role="menu"] >> text=Close Tab');
  168. // Revert changes so we don't measure saving
  169. const dimissButton = page.locator('button:has-text("Discard")');
  170. if (await dimissButton.isVisible({ timeout: 50 })) {
  171. await dimissButton.click();
  172. }
  173. });
  174. editorPanel = page.locator(
  175. 'div[role="tabpanel"]:has-text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin mole")'
  176. );
  177. await expect(editorPanel).toBeVisible();
  178. testInfo.attachments.push(
  179. benchmark.addAttachment({
  180. ...attachmentCommon,
  181. test: 'close',
  182. time: closeTime
  183. })
  184. );
  185. });
  186. }
  187. });