mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 05:50:11 +01:00
Uses playwright
This commit is contained in:
parent
699cae24be
commit
c998a7c80f
7 changed files with 244 additions and 1369 deletions
1056
package-lock.json
generated
1056
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -18,8 +18,10 @@
|
||||||
"package-for-smoketest-webpack-cross-origin": "ts-node ./test/smoke/package-webpack --cross-origin",
|
"package-for-smoketest-webpack-cross-origin": "ts-node ./test/smoke/package-webpack --cross-origin",
|
||||||
"package-for-smoketest-esbuild": "ts-node ./test/smoke/package-esbuild",
|
"package-for-smoketest-esbuild": "ts-node ./test/smoke/package-esbuild",
|
||||||
"package-for-smoketest-vite": "ts-node ./test/smoke/package-vite",
|
"package-for-smoketest-vite": "ts-node ./test/smoke/package-vite",
|
||||||
"smoketest": "node ./test/smoke/runner.js",
|
"smoketest": "playwright test --config=test/smoke/playwright.config.ts",
|
||||||
"smoketest-debug": "node ./test/smoke/runner.js --debug-tests",
|
"smoketest-debug": "playwright test --config=test/smoke/playwright.config.ts --debug",
|
||||||
|
"smoketest-ui": "playwright test --config=test/smoke/playwright.config.ts --ui",
|
||||||
|
"smoketest-headed": "playwright test --config=test/smoke/playwright.config.ts --headed",
|
||||||
"test": "ts-node ./build/check-samples",
|
"test": "ts-node ./build/check-samples",
|
||||||
"deps-all-remove": "ts-node ./build/npm/removeAll",
|
"deps-all-remove": "ts-node ./build/npm/removeAll",
|
||||||
"deps-all-install": "ts-node ./build/npm/installAll",
|
"deps-all-install": "ts-node ./build/npm/installAll",
|
||||||
|
|
@ -37,7 +39,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.53.2",
|
"@playwright/test": "^1.53.2",
|
||||||
"@types/mocha": "^9.1.0",
|
|
||||||
"@types/shelljs": "^0.8.11",
|
"@types/shelljs": "^0.8.11",
|
||||||
"@types/trusted-types": "^1.0.6",
|
"@types/trusted-types": "^1.0.6",
|
||||||
"@typescript/vfs": "^1.3.5",
|
"@typescript/vfs": "^1.3.5",
|
||||||
|
|
@ -52,7 +53,6 @@
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"jsdom": "^19.0.0",
|
"jsdom": "^19.0.0",
|
||||||
"jsonc-parser": "^3.0.0",
|
"jsonc-parser": "^3.0.0",
|
||||||
"mocha": "^9.2.0",
|
|
||||||
"monaco-editor-core": "^0.54.0-dev-20251002",
|
"monaco-editor-core": "^0.54.0-dev-20251002",
|
||||||
"parcel": "^2.7.0",
|
"parcel": "^2.7.0",
|
||||||
"pin-github-action": "^1.8.0",
|
"pin-github-action": "^1.8.0",
|
||||||
|
|
|
||||||
41
test/smoke/playwright.config.ts
Normal file
41
test/smoke/playwright.config.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
const packagers = ['amd', 'webpack', 'esbuild', 'vite'] as const;
|
||||||
|
const browsers = [
|
||||||
|
{ name: 'chromium', device: devices['Desktop Chrome'] },
|
||||||
|
{ name: 'firefox', device: devices['Desktop Firefox'] },
|
||||||
|
{ name: 'webkit', device: devices['Desktop Safari'] }
|
||||||
|
];
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: '.',
|
||||||
|
testMatch: '*.test.ts',
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
timeout: 20000,
|
||||||
|
use: {
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
baseURL: `http://127.0.0.1:${process.env.PORT || 8563}`
|
||||||
|
},
|
||||||
|
|
||||||
|
projects: packagers.flatMap((packager) =>
|
||||||
|
browsers.map((browser) => ({
|
||||||
|
name: `${packager}-${browser.name}`,
|
||||||
|
use: browser.device,
|
||||||
|
metadata: { packager }
|
||||||
|
}))
|
||||||
|
),
|
||||||
|
|
||||||
|
webServer: {
|
||||||
|
command: 'node server.js',
|
||||||
|
url: `http://127.0.0.1:${process.env.PORT || 8563}`,
|
||||||
|
reuseExistingServer: !process.env.CI
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
//@ts-check
|
|
||||||
|
|
||||||
const yaserver = require('yaserver');
|
|
||||||
const http = require('http');
|
|
||||||
const cp = require('child_process');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/** @typedef {import('./common').BrowserKind} BrowserKind */
|
|
||||||
/** @typedef {import('./common').PackagerKind} PackagerKind */
|
|
||||||
/** @typedef {import('./common').TestInfo} TestInfo */
|
|
||||||
|
|
||||||
const DEBUG_TESTS = process.argv.includes('--debug-tests');
|
|
||||||
const REPO_ROOT = path.join(__dirname, '../../');
|
|
||||||
const PORT = 8563;
|
|
||||||
|
|
||||||
yaserver
|
|
||||||
.createServer({
|
|
||||||
rootDir: REPO_ROOT
|
|
||||||
})
|
|
||||||
.then((staticServer) => {
|
|
||||||
const server = http.createServer((request, response) => {
|
|
||||||
return staticServer.handle(request, response);
|
|
||||||
});
|
|
||||||
server.listen(PORT, '127.0.0.1', async () => {
|
|
||||||
try {
|
|
||||||
await runTests();
|
|
||||||
console.log(`All good`);
|
|
||||||
process.exit(0);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
async function runTests() {
|
|
||||||
// uncomment to shortcircuit and run a specific combo
|
|
||||||
// await runTest('webpack', 'chromium'); return;
|
|
||||||
/** @type {PackagerKind[]} */
|
|
||||||
const testTypes = ['webpack', 'esbuild', 'vite', 'amd'];
|
|
||||||
// TODO: add parcel! (this currently fails because parcel replaces process with {})
|
|
||||||
|
|
||||||
for (const type of testTypes) {
|
|
||||||
await runTest(type, 'chromium');
|
|
||||||
await runTest(type, 'firefox');
|
|
||||||
await runTest(type, 'webkit');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {PackagerKind} packager
|
|
||||||
* @param {BrowserKind} browser
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function runTest(packager, browser) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
/** @type TestInfo */
|
|
||||||
const testInfo = {
|
|
||||||
browser,
|
|
||||||
packager,
|
|
||||||
debugTests: DEBUG_TESTS,
|
|
||||||
port: PORT
|
|
||||||
};
|
|
||||||
const env = { MONACO_TEST_INFO: JSON.stringify(testInfo), ...process.env };
|
|
||||||
const proc = cp.spawn(
|
|
||||||
'node',
|
|
||||||
[
|
|
||||||
path.join(REPO_ROOT, 'node_modules/mocha/bin/mocha'),
|
|
||||||
'test/smoke/*.test.js',
|
|
||||||
'--no-delay',
|
|
||||||
'--headless',
|
|
||||||
'--timeout',
|
|
||||||
'20000'
|
|
||||||
],
|
|
||||||
{
|
|
||||||
env,
|
|
||||||
stdio: 'inherit'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
proc.on('error', reject);
|
|
||||||
proc.on('exit', (code) => {
|
|
||||||
if (code === 0) {
|
|
||||||
resolve(undefined);
|
|
||||||
} else {
|
|
||||||
reject(code);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
26
test/smoke/server.js
Normal file
26
test/smoke/server.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
//@ts-check
|
||||||
|
|
||||||
|
const yaserver = require('yaserver');
|
||||||
|
const http = require('http');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const REPO_ROOT = path.join(__dirname, '../../');
|
||||||
|
const PORT = parseInt(process.env.PORT || '8563', 10);
|
||||||
|
|
||||||
|
yaserver
|
||||||
|
.createServer({
|
||||||
|
rootDir: REPO_ROOT
|
||||||
|
})
|
||||||
|
.then((/** @type {any} */ staticServer) => {
|
||||||
|
const server = http.createServer((request, response) => {
|
||||||
|
return staticServer.handle(request, response);
|
||||||
|
});
|
||||||
|
server.listen(PORT, '127.0.0.1', () => {
|
||||||
|
console.log(`Server running at http://127.0.0.1:${PORT}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,215 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
//@ts-check
|
|
||||||
|
|
||||||
const playwright = require('playwright');
|
|
||||||
const { assert } = require('chai');
|
|
||||||
|
|
||||||
/** @typedef {import('./common').BrowserKind} BrowserKind */
|
|
||||||
/** @typedef {import('./common').PackagerKind} PackagerKind */
|
|
||||||
/** @typedef {import('./common').TestInfo} TestInfo */
|
|
||||||
|
|
||||||
/** @type TestInfo */
|
|
||||||
const testInfo = JSON.parse(process.env.MONACO_TEST_INFO || '');
|
|
||||||
|
|
||||||
const URLS = {
|
|
||||||
amd: `http://127.0.0.1:${testInfo.port}/test/smoke/amd/index.html`,
|
|
||||||
webpack: `http://127.0.0.1:${testInfo.port}/test/smoke/webpack/index.html`,
|
|
||||||
esbuild: `http://127.0.0.1:${testInfo.port}/test/smoke/esbuild/index.html`,
|
|
||||||
vite: `http://127.0.0.1:${testInfo.port}/test/smoke/vite/dist/index.html`,
|
|
||||||
parcel: `http://127.0.0.1:${testInfo.port}/test/smoke/parcel/dist/index.html`
|
|
||||||
};
|
|
||||||
const URL = URLS[testInfo.packager];
|
|
||||||
|
|
||||||
suite(`Smoke Test '${testInfo.packager}' on '${testInfo.browser}'`, () => {
|
|
||||||
/** @type {playwright.Browser} */
|
|
||||||
let browser;
|
|
||||||
|
|
||||||
/** @type {playwright.Page} */
|
|
||||||
let page;
|
|
||||||
|
|
||||||
suiteSetup(async () => {
|
|
||||||
browser = await playwright[testInfo.browser].launch({
|
|
||||||
headless: !testInfo.debugTests,
|
|
||||||
devtools: testInfo.debugTests && testInfo.browser === 'chromium'
|
|
||||||
// slowMo: testInfo.debugTests ? 2000 : 0
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
suiteTeardown(async () => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
let pageErrors = [];
|
|
||||||
|
|
||||||
setup(async () => {
|
|
||||||
pageErrors = [];
|
|
||||||
page = await browser.newPage({
|
|
||||||
viewport: {
|
|
||||||
width: 800,
|
|
||||||
height: 600
|
|
||||||
}
|
|
||||||
});
|
|
||||||
page.on('pageerror', (e) => {
|
|
||||||
console.log(e);
|
|
||||||
pageErrors.push(e);
|
|
||||||
});
|
|
||||||
const response = await page.goto(URL);
|
|
||||||
if (!response) {
|
|
||||||
assert.fail('Failed to load page');
|
|
||||||
}
|
|
||||||
assert.strictEqual(response.status(), 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
teardown(async () => {
|
|
||||||
for (const e of pageErrors) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
await page.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} text
|
|
||||||
* @param {string} language
|
|
||||||
* @returns Promise<void>
|
|
||||||
*/
|
|
||||||
async function createEditor(text, language) {
|
|
||||||
return await page.evaluate(
|
|
||||||
`window.ed = monacoAPI.editor.create(document.getElementById('editor-container'), { value: '${text}', language: '${language}' })`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} lineNumber
|
|
||||||
* @param {number} column
|
|
||||||
* @returns Promise<void>
|
|
||||||
*/
|
|
||||||
async function setEditorPosition(lineNumber, column) {
|
|
||||||
return await page.evaluate(
|
|
||||||
`window.ed.setPosition({ lineNumber: ${lineNumber}, column: ${column} });`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} commandId
|
|
||||||
* @param {any} [args]
|
|
||||||
* @returns Promise<void>
|
|
||||||
*/
|
|
||||||
async function triggerEditorCommand(commandId, args) {
|
|
||||||
return await page.evaluate(
|
|
||||||
`window.ed.trigger(null, '${commandId}', ${args ? JSON.stringify(args) : 'undefined'});`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function focusEditor() {
|
|
||||||
await page.evaluate(`window.ed.focus();`);
|
|
||||||
}
|
|
||||||
|
|
||||||
test('`monacoAPI` is exposed as global', async function () {
|
|
||||||
assert.strictEqual(await page.evaluate(`typeof monacoAPI`), 'object');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should be able to create plaintext editor', async function () {
|
|
||||||
await createEditor('hello world', 'plaintext');
|
|
||||||
|
|
||||||
// type a link in it
|
|
||||||
await setEditorPosition(1, 12);
|
|
||||||
await triggerEditorCommand('type', { text: '\nhttps://www.microsoft.com' });
|
|
||||||
|
|
||||||
// check that the link gets highlighted, which indicates that the web worker is healthy
|
|
||||||
await page.waitForSelector('.detected-link');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('css smoke test', async function () {
|
|
||||||
await createEditor('.sel1 { background: red; }\\n.sel2 {}', 'css');
|
|
||||||
|
|
||||||
// check that a squiggle appears, which indicates that the language service is up and running
|
|
||||||
await page.waitForSelector('.squiggly-warning');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('html smoke test', async function () {
|
|
||||||
await createEditor('<title>hi</title>', 'html');
|
|
||||||
|
|
||||||
// we need to try this a couple of times because the web worker might not be ready yet
|
|
||||||
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
||||||
// trigger hover
|
|
||||||
await focusEditor();
|
|
||||||
await setEditorPosition(1, 3);
|
|
||||||
await page.keyboard.press('F1');
|
|
||||||
await page.keyboard.type('Show Hover');
|
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
|
|
||||||
// check that a hover explaining the `<title>` element appears, which indicates that the language service is up and running
|
|
||||||
try {
|
|
||||||
await page.waitForSelector(
|
|
||||||
`text=The title element represents the document's title or name`,
|
|
||||||
{ timeout: 5000 }
|
|
||||||
);
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('json smoke test', async function () {
|
|
||||||
await createEditor('{}', 'json');
|
|
||||||
|
|
||||||
// we need to try this a couple of times because the web worker might not be ready yet
|
|
||||||
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
||||||
// trigger suggestions
|
|
||||||
await focusEditor();
|
|
||||||
await setEditorPosition(1, 2);
|
|
||||||
await triggerEditorCommand('editor.action.triggerSuggest');
|
|
||||||
|
|
||||||
// check that a suggestion item for `$schema` appears, which indicates that the language service is up and running
|
|
||||||
try {
|
|
||||||
await page.waitForSelector(`text=$schema`, { timeout: 5000 });
|
|
||||||
} catch (err) {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('typescript smoke test', async function () {
|
|
||||||
await createEditor('window.add', 'typescript');
|
|
||||||
|
|
||||||
// check that a squiggle appears, which indicates that the language service is up and running
|
|
||||||
await page.waitForSelector('.squiggly-error');
|
|
||||||
|
|
||||||
// at this point we know that the web worker is healthy, so we can trigger suggestions
|
|
||||||
|
|
||||||
// trigger suggestions
|
|
||||||
await focusEditor();
|
|
||||||
await setEditorPosition(1, 11);
|
|
||||||
await triggerEditorCommand('editor.action.triggerSuggest');
|
|
||||||
|
|
||||||
// check that a suggestion item for `addEventListener` appears, which indicates that the language service is up and running
|
|
||||||
await page.waitForSelector(`text=addEventListener`);
|
|
||||||
|
|
||||||
// find the TypeScript worker
|
|
||||||
|
|
||||||
function findAsync(arr, fn) {
|
|
||||||
return Promise.all(arr.map(fn)).then((results) => {
|
|
||||||
return arr.find((_, i) => results[i]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that the TypeScript worker exposes `ts` as a global
|
|
||||||
const tsWorker = await findAsync(
|
|
||||||
page.workers(),
|
|
||||||
async (page) => await page.evaluate(`typeof ts !== 'undefined'`)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!tsWorker) {
|
|
||||||
assert.fail('Could not find TypeScript worker');
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that the TypeScript worker exposes the full `ts` as a global
|
|
||||||
assert.strictEqual(await tsWorker.evaluate(`typeof ts.optionDeclarations`), 'object');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function timeout(ms) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
setTimeout(resolve, ms);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
173
test/smoke/smoke.test.ts
Normal file
173
test/smoke/smoke.test.ts
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { test, expect, type Page } from '@playwright/test';
|
||||||
|
import type { PackagerKind } from './playwright.config';
|
||||||
|
|
||||||
|
const URLS: Record<PackagerKind, string> = {
|
||||||
|
amd: '/test/smoke/amd/index.html',
|
||||||
|
webpack: '/test/smoke/webpack/index.html',
|
||||||
|
esbuild: '/test/smoke/esbuild/index.html',
|
||||||
|
vite: '/test/smoke/vite/dist/index.html',
|
||||||
|
parcel: '/test/smoke/parcel/dist/index.html'
|
||||||
|
};
|
||||||
|
|
||||||
|
test.describe('Monaco Editor Smoke Tests', () => {
|
||||||
|
test.beforeEach(async ({ page }, testInfo) => {
|
||||||
|
const packager = testInfo.project.metadata.packager as PackagerKind;
|
||||||
|
const url = URLS[packager];
|
||||||
|
const response = await page.goto(url);
|
||||||
|
expect(response?.status()).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('`monacoAPI` is exposed as global', async ({ page }) => {
|
||||||
|
const monacoType = await page.evaluate(() => typeof (window as any).monacoAPI);
|
||||||
|
expect(monacoType).toBe('object');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should be able to create plaintext editor', async ({ page }) => {
|
||||||
|
await createEditor(page, 'hello world', 'plaintext');
|
||||||
|
|
||||||
|
// type a link in it
|
||||||
|
await setEditorPosition(page, 1, 12);
|
||||||
|
await triggerEditorCommand(page, 'type', { text: '\nhttps://www.microsoft.com' });
|
||||||
|
|
||||||
|
// check that the link gets highlighted, which indicates that the web worker is healthy
|
||||||
|
await page.waitForSelector('.detected-link');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('css smoke test', async ({ page }) => {
|
||||||
|
await createEditor(page, '.sel1 { background: red; }\n.sel2 {}', 'css');
|
||||||
|
|
||||||
|
// check that a squiggle appears, which indicates that the language service is up and running
|
||||||
|
await page.waitForSelector('.squiggly-warning');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('html smoke test', async ({ page }) => {
|
||||||
|
await createEditor(page, '<title>hi</title>', 'html');
|
||||||
|
|
||||||
|
// we need to try this a couple of times because the web worker might not be ready yet
|
||||||
|
for (let attempt = 1; attempt <= 2; attempt++) {
|
||||||
|
// trigger hover
|
||||||
|
await focusEditor(page);
|
||||||
|
await setEditorPosition(page, 1, 3);
|
||||||
|
await page.keyboard.press('F1');
|
||||||
|
await page.keyboard.type('Show Hover');
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
|
// check that a hover explaining the `<title>` element appears, which indicates that the language service is up and running
|
||||||
|
try {
|
||||||
|
await page.waitForSelector(
|
||||||
|
`text=The title element represents the document's title or name`,
|
||||||
|
{ timeout: 5000 }
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} catch (err) {
|
||||||
|
if (attempt === 2) throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('json smoke test', async ({ page }) => {
|
||||||
|
await createEditor(page, '{}', 'json');
|
||||||
|
|
||||||
|
// we need to try this a couple of times because the web worker might not be ready yet
|
||||||
|
for (let attempt = 1; attempt <= 2; attempt++) {
|
||||||
|
// trigger suggestions
|
||||||
|
await focusEditor(page);
|
||||||
|
await setEditorPosition(page, 1, 2);
|
||||||
|
await triggerEditorCommand(page, 'editor.action.triggerSuggest');
|
||||||
|
|
||||||
|
// check that a suggestion item for `$schema` appears, which indicates that the language service is up and running
|
||||||
|
try {
|
||||||
|
await page.waitForSelector(`text=$schema`, { timeout: 5000 });
|
||||||
|
break;
|
||||||
|
} catch (err) {
|
||||||
|
if (attempt === 2) throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('typescript smoke test', async ({ page }) => {
|
||||||
|
await createEditor(page, 'window.add', 'typescript');
|
||||||
|
|
||||||
|
// check that a squiggle appears, which indicates that the language service is up and running
|
||||||
|
await page.waitForSelector('.squiggly-error');
|
||||||
|
|
||||||
|
// at this point we know that the web worker is healthy, so we can trigger suggestions
|
||||||
|
|
||||||
|
// trigger suggestions
|
||||||
|
await focusEditor(page);
|
||||||
|
await setEditorPosition(page, 1, 11);
|
||||||
|
await triggerEditorCommand(page, 'editor.action.triggerSuggest');
|
||||||
|
|
||||||
|
// check that a suggestion item for `addEventListener` appears, which indicates that the language service is up and running
|
||||||
|
await page.waitForSelector(`text=addEventListener`);
|
||||||
|
|
||||||
|
// find the TypeScript worker
|
||||||
|
// Wait a bit for workers to be ready
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
const workers = page.workers();
|
||||||
|
const tsWorker = await findAsync(workers, async (worker) => {
|
||||||
|
try {
|
||||||
|
return await worker.evaluate(() => typeof (globalThis as any).ts !== 'undefined');
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tsWorker) {
|
||||||
|
throw new Error('Could not find TypeScript worker');
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the TypeScript worker exposes the full `ts` as a global
|
||||||
|
const tsType = await tsWorker.evaluate(() => typeof (globalThis as any).ts.optionDeclarations);
|
||||||
|
expect(tsType).toBe('object');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
|
||||||
|
async function createEditor(page: Page, text: string, language: string): Promise<void> {
|
||||||
|
await page.evaluate(
|
||||||
|
({ text, language }) => {
|
||||||
|
(window as any).ed = (window as any).monacoAPI.editor.create(
|
||||||
|
document.getElementById('editor-container'),
|
||||||
|
{ value: text, language: language }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ text, language }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setEditorPosition(page: Page, lineNumber: number, column: number): Promise<void> {
|
||||||
|
await page.evaluate(
|
||||||
|
({ lineNumber, column }) => {
|
||||||
|
(window as any).ed.setPosition({ lineNumber, column });
|
||||||
|
},
|
||||||
|
{ lineNumber, column }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function triggerEditorCommand(page: Page, commandId: string, args?: any): Promise<void> {
|
||||||
|
await page.evaluate(
|
||||||
|
({ commandId, args }) => {
|
||||||
|
(window as any).ed.trigger(null, commandId, args);
|
||||||
|
},
|
||||||
|
{ commandId, args }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function focusEditor(page: Page): Promise<void> {
|
||||||
|
await page.evaluate(() => {
|
||||||
|
(window as any).ed.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findAsync<T>(arr: T[], fn: (item: T) => Promise<boolean>): Promise<T | undefined> {
|
||||||
|
const results = await Promise.all(arr.map(fn));
|
||||||
|
return arr.find((_, i) => results[i]);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue