smoke.test.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. //@ts-check
  6. const playwright = require('playwright');
  7. const { assert } = require('chai');
  8. /** @typedef {import('./common').BrowserKind} BrowserKind */
  9. /** @typedef {import('./common').PackagerKind} PackagerKind */
  10. /** @typedef {import('./common').TestInfo} TestInfo */
  11. /** @type TestInfo */
  12. const testInfo = JSON.parse(process.env.MONACO_TEST_INFO || '');
  13. const URLS = {
  14. amd: `http://127.0.0.1:${testInfo.port}/test/smoke/amd/index.html`,
  15. webpack: `http://127.0.0.1:${testInfo.port}/test/smoke/webpack/index.html`,
  16. esbuild: `http://127.0.0.1:${testInfo.port}/test/smoke/esbuild/index.html`,
  17. vite: `http://127.0.0.1:${testInfo.port}/test/smoke/vite/dist/index.html`,
  18. parcel: `http://127.0.0.1:${testInfo.port}/test/smoke/parcel/dist/index.html`
  19. };
  20. const URL = URLS[testInfo.packager];
  21. suite(`Smoke Test '${testInfo.packager}' on '${testInfo.browser}'`, () => {
  22. /** @type {playwright.Browser} */
  23. let browser;
  24. /** @type {playwright.Page} */
  25. let page;
  26. suiteSetup(async () => {
  27. browser = await playwright[testInfo.browser].launch({
  28. headless: !testInfo.debugTests,
  29. devtools: testInfo.debugTests && testInfo.browser === 'chromium'
  30. // slowMo: testInfo.debugTests ? 2000 : 0
  31. });
  32. });
  33. suiteTeardown(async () => {
  34. await browser.close();
  35. });
  36. let pageErrors = [];
  37. setup(async () => {
  38. pageErrors = [];
  39. page = await browser.newPage({
  40. viewport: {
  41. width: 800,
  42. height: 600
  43. }
  44. });
  45. page.on('pageerror', (e) => {
  46. console.log(e);
  47. pageErrors.push(e);
  48. });
  49. const response = await page.goto(URL);
  50. if (!response) {
  51. assert.fail('Failed to load page');
  52. }
  53. assert.strictEqual(response.status(), 200);
  54. });
  55. teardown(async () => {
  56. for (const e of pageErrors) {
  57. throw e;
  58. }
  59. await page.close();
  60. });
  61. /**
  62. * @param {string} text
  63. * @param {string} language
  64. * @returns Promise<void>
  65. */
  66. async function createEditor(text, language) {
  67. return await page.evaluate(
  68. `window.ed = monacoAPI.editor.create(document.getElementById('editor-container'), { value: '${text}', language: '${language}' })`
  69. );
  70. }
  71. /**
  72. * @param {number} lineNumber
  73. * @param {number} column
  74. * @returns Promise<void>
  75. */
  76. async function setEditorPosition(lineNumber, column) {
  77. return await page.evaluate(
  78. `window.ed.setPosition({ lineNumber: ${lineNumber}, column: ${column} });`
  79. );
  80. }
  81. /**
  82. * @param {string} commandId
  83. * @param {any} [args]
  84. * @returns Promise<void>
  85. */
  86. async function triggerEditorCommand(commandId, args) {
  87. return await page.evaluate(
  88. `window.ed.trigger(null, '${commandId}', ${args ? JSON.stringify(args) : 'undefined'});`
  89. );
  90. }
  91. async function focusEditor() {
  92. await page.evaluate(`window.ed.focus();`);
  93. }
  94. test('`monacoAPI` is exposed as global', async function () {
  95. assert.strictEqual(await page.evaluate(`typeof monacoAPI`), 'object');
  96. });
  97. test('should be able to create plaintext editor', async function () {
  98. console.log('inside of test');
  99. console.log('REPO_ROOT : ', __dirname + '../../');
  100. await createEditor('hello world', 'plaintext');
  101. // type a link in it
  102. await setEditorPosition(1, 12);
  103. await triggerEditorCommand('type', { text: '\nhttps://www.microsoft.com' });
  104. console.log('triggerEditorCommand');
  105. // check that the link gets highlighted, which indicates that the web worker is healthy
  106. await page.waitForSelector('.detected-link');
  107. });
  108. test('css smoke test', async function () {
  109. console.log('css smoke test');
  110. await createEditor('.sel1 { background: red; }\\n.sel2 {}', 'css');
  111. // check that a squiggle appears, which indicates that the language service is up and running
  112. await page.waitForSelector('.squiggly-warning');
  113. });
  114. test('html smoke test', async function () {
  115. await createEditor('<title>hi</title>', 'html');
  116. // we need to try this a couple of times because the web worker might not be ready yet
  117. for (let attempt = 1; attempt <= 2; attempt++) {
  118. // trigger hover
  119. await focusEditor();
  120. await setEditorPosition(1, 3);
  121. await page.keyboard.press('F1');
  122. await page.keyboard.type('Show Hover');
  123. await page.keyboard.press('Enter');
  124. // check that a hover explaining the `<title>` element appears, which indicates that the language service is up and running
  125. try {
  126. await page.waitForSelector(
  127. `text=The title element represents the document's title or name`,
  128. { timeout: 5000 }
  129. );
  130. } catch (err) {}
  131. }
  132. });
  133. test('json smoke test', async function () {
  134. await createEditor('{}', 'json');
  135. // we need to try this a couple of times because the web worker might not be ready yet
  136. for (let attempt = 1; attempt <= 2; attempt++) {
  137. // trigger suggestions
  138. await focusEditor();
  139. await setEditorPosition(1, 2);
  140. await triggerEditorCommand('editor.action.triggerSuggest');
  141. // check that a suggestion item for `$schema` appears, which indicates that the language service is up and running
  142. try {
  143. await page.waitForSelector(`text=$schema`, { timeout: 5000 });
  144. } catch (err) {}
  145. }
  146. });
  147. test('typescript smoke test', async function () {
  148. await createEditor('window.add', 'typescript');
  149. // check that a squiggle appears, which indicates that the language service is up and running
  150. await page.waitForSelector('.squiggly-error');
  151. // at this point we know that the web worker is healthy, so we can trigger suggestions
  152. // trigger suggestions
  153. await focusEditor();
  154. await setEditorPosition(1, 11);
  155. await triggerEditorCommand('editor.action.triggerSuggest');
  156. // check that a suggestion item for `addEventListener` appears, which indicates that the language service is up and running
  157. await page.waitForSelector(`text=addEventListener`);
  158. // find the TypeScript worker
  159. function findAsync(arr, fn) {
  160. return Promise.all(arr.map(fn)).then((results) => {
  161. return arr.find((_, i) => results[i]);
  162. });
  163. }
  164. // check that the TypeScript worker exposes `ts` as a global
  165. const tsWorker = await findAsync(
  166. page.workers(),
  167. async (page) => await page.evaluate(`typeof ts !== 'undefined'`)
  168. );
  169. if (!tsWorker) {
  170. assert.fail('Could not find TypeScript worker');
  171. }
  172. // check that the TypeScript worker exposes the full `ts` as a global
  173. assert.strictEqual(await tsWorker.evaluate(`typeof ts.optionDeclarations`), 'object');
  174. });
  175. });
  176. function timeout(ms) {
  177. return new Promise((resolve, reject) => {
  178. setTimeout(resolve, ms);
  179. });
  180. }