Merge pull request #5079 from Tyriar/more_playwright

Migrate more API tests to playwright
This commit is contained in:
Daniel Imms
2024-07-02 14:57:46 -07:00
committed by GitHub
17 changed files with 969 additions and 797 deletions
@@ -1,50 +0,0 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import WebSocket = require('ws');
import { openTerminal, pollFor, launchBrowser } from '../../../out-test/api/TestUtils';
import { Browser, Page } from '@playwright/test';
const APP = 'http://127.0.0.1:3001/test';
let browser: Browser;
let page: Page;
const width = 800;
const height = 600;
describe('AttachAddon', () => {
before(async function(): Promise<any> {
browser = await launchBrowser();
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
});
after(async () => {
await browser.close();
});
beforeEach(async () => await page.goto(APP));
it('string', async function(): Promise<any> {
await openTerminal(page);
const port = 8080;
const server = new WebSocket.Server({ port });
server.on('connection', socket => socket.send('foo'));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});
it('utf8', async function(): Promise<any> {
await openTerminal(page);
const port = 8080;
const server = new WebSocket.Server({ port });
const data = new Uint8Array([102, 111, 111]);
server.on('connection', socket => socket.send(data));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});
});
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import WebSocket = require('ws');
import test from '@playwright/test';
import { ITestContext, createTestContext, openTerminal, pollFor, timeout } from '../../../out-test/playwright/TestUtils';
let ctx: ITestContext;
test.beforeAll(async ({ browser }) => {
ctx = await createTestContext(browser);
await openTerminal(ctx);
});
test.afterAll(async () => await ctx.page.close());
test.describe('Search Tests', () => {
test.beforeEach(async () => {
await ctx.proxy.reset();
});
test('string', async function(): Promise<any> {
const port = 8080;
const server = new WebSocket.Server({ port });
server.on('connection', socket => socket.send('foo'));
await ctx.page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(ctx.page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});
test('utf8', async function(): Promise<any> {
const port = 8080;
const server = new WebSocket.Server({ port });
const data = new Uint8Array([102, 111, 111]);
server.on('connection', socket => socket.send(data));
await ctx.page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
await pollFor(ctx.page, `window.term.buffer.active.getLine(0).translateToString(true)`, 'foo');
server.close();
});
});
@@ -0,0 +1,35 @@
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: '.',
timeout: 10000,
projects: [
{
name: 'ChromeStable',
use: {
browserName: 'chromium',
channel: 'chrome'
}
},
{
name: 'FirefoxStable',
use: {
browserName: 'firefox'
}
},
{
name: 'WebKit',
use: {
browserName: 'webkit'
}
}
],
reporter: 'list',
webServer: {
command: 'npm run start-server-only',
port: 3000,
timeout: 120000,
reuseExistingServer: !process.env.CI
}
};
export default config;
+19 -3
View File
@@ -3,21 +3,37 @@
"module": "commonjs",
"target": "es2021",
"lib": [
"es2015"
"es2021",
],
"rootDir": ".",
"outDir": "../out-test",
"sourceMap": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"common/*": [
"../../../src/common/*"
],
"browser/*": [
"../../../src/browser/*"
]
},
"strict": true,
"types": [
"../../../node_modules/@types/mocha",
"../../../node_modules/@types/node",
"../../../out-test/api/TestUtils"
"../../../out-test/playwright/TestUtils"
]
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{
"path": "../../../src/common"
},
{
"path": "../../../src/browser"
}
]
}
@@ -1,88 +0,0 @@
/**
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { openTerminal, launchBrowser, writeSync, getBrowserType } from '../../../out-test/api/TestUtils';
import { Browser, BrowserContext, Page } from '@playwright/test';
import { beforeEach } from 'mocha';
const APP = 'http://127.0.0.1:3001/test';
let browser: Browser;
let context: BrowserContext;
let page: Page;
const width = 800;
const height = 600;
describe('ClipboardAddon', () => {
before(async function (): Promise<any> {
browser = await launchBrowser({
// Enable clipboard access in firefox, mainly for readText
firefoxUserPrefs: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'dom.events.testing.asyncClipboard': true,
// eslint-disable-next-line @typescript-eslint/naming-convention
'dom.events.asyncClipboard.readText': true
}
});
context = await browser.newContext();
if (getBrowserType().name() !== 'webkit') {
// Enable clipboard access in chromium without user gesture
context.grantPermissions(['clipboard-read', 'clipboard-write']);
}
page = await context.newPage();
await page.setViewportSize({ width, height });
await page.goto(APP);
await openTerminal(page);
await page.evaluate(`
window.clipboardAddon = new ClipboardAddon();
window.term.loadAddon(window.clipboardAddon);
`);
});
after(() => {
browser.close();
});
beforeEach(async () => {
await page.evaluate(`window.term.reset()`);
});
const testDataEncoded = 'aGVsbG8gd29ybGQ=';
const testDataDecoded = 'hello world';
describe('write data', async function (): Promise<any> {
it('simple string', async () => {
await writeSync(page, `\x1b]52;c;${testDataEncoded}\x07`);
assert.deepEqual(await page.evaluate(() => window.navigator.clipboard.readText()), testDataDecoded);
});
it('invalid base64 string', async () => {
await writeSync(page, `\x1b]52;c;${testDataEncoded}invalid\x07`);
assert.deepEqual(await page.evaluate(() => window.navigator.clipboard.readText()), '');
});
it('empty string', async () => {
await writeSync(page, `\x1b]52;c;${testDataEncoded}\x07`);
await writeSync(page, `\x1b]52;c;\x07`);
assert.deepEqual(await page.evaluate(() => window.navigator.clipboard.readText()), '');
});
});
describe('read data', async function (): Promise<any> {
it('simple string', async () => {
await page.evaluate(`
window.data = [];
window.term.onData(e => data.push(e));
`);
await page.evaluate(() => window.navigator.clipboard.writeText('hello world'));
await writeSync(page, `\x1b]52;c;?\x07`);
assert.deepEqual(await page.evaluate('window.data'), [`\x1b]52;c;${testDataEncoded}\x07`]);
});
it('clear clipboard', async () => {
await writeSync(page, `\x1b]52;c;!\x07`);
await writeSync(page, `\x1b]52;c;?\x07`);
assert.deepEqual(await page.evaluate(() => window.navigator.clipboard.readText()), '');
});
});
});
@@ -0,0 +1,78 @@
/**
* Copyright (c) 2023 The xterm.js authors. All rights reserved.
* @license MIT
*/
import test from '@playwright/test';
import { deepEqual, ok, strictEqual } from 'assert';
import { ITestContext, createTestContext, launchBrowser, openTerminal, timeout } from '../../../out-test/playwright/TestUtils';
let ctx: ITestContext;
test.beforeAll(async ({ browser }, testInfo) => {
ctx = await createTestContext(browser);
await openTerminal(ctx);
});
test.afterAll(async () => {
await ctx.page.close();
});
test.describe('ClipboardAddon', () => {
test.beforeEach(async ({}, testInfo) => {
// DEBT: This test doesn't work since the migration to @playwright/test
if (ctx.browser.browserType().name() !== 'chromium') {
testInfo.skip();
return;
}
if (ctx.browser.browserType().name() === 'chromium') {
// Enable clipboard access in chromium without user gesture
await ctx.page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
}
await ctx.page.evaluate(`
window.term.reset()
window.clipboard?.dispose();
window.clipboard = new ClipboardAddon();
window.term.loadAddon(window.clipboard);
`);
});
test.beforeEach(async () => {
await ctx.proxy.reset();
});
const testDataEncoded = 'aGVsbG8gd29ybGQ=';
const testDataDecoded = 'hello world';
test.describe('write data', async function (): Promise<any> {
test('simple string', async () => {
await ctx.proxy.write(`\x1b]52;c;${testDataEncoded}\x07`);
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), testDataDecoded);
});
test('invalid base64 string', async () => {
await ctx.proxy.write(`\x1b]52;c;${testDataEncoded}invalid\x07`);
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), '');
});
test('empty string', async () => {
await ctx.proxy.write(`\x1b]52;c;${testDataEncoded}\x07`);
await ctx.proxy.write(`\x1b]52;c;\x07`);
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), '');
});
});
test.describe('read data', async function (): Promise<any> {
test('simple string', async () => {
await ctx.page.evaluate(`
window.data = [];
window.term.onData(e => data.push(e));
`);
await ctx.page.evaluate(() => window.navigator.clipboard.writeText('hello world'));
await ctx.proxy.write(`\x1b]52;c;?\x07`);
deepEqual(await ctx.page.evaluate('window.data'), [`\x1b]52;c;${testDataEncoded}\x07`]);
});
test('clear clipboard', async () => {
await ctx.proxy.write(`\x1b]52;c;!\x07`);
await ctx.proxy.write(`\x1b]52;c;?\x07`);
deepEqual(await ctx.page.evaluate(() => window.navigator.clipboard.readText()), '');
});
});
});
@@ -0,0 +1,35 @@
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: '.',
timeout: 10000,
projects: [
{
name: 'ChromeStable',
use: {
browserName: 'chromium',
channel: 'chrome'
}
},
{
name: 'FirefoxStable',
use: {
browserName: 'firefox'
}
},
{
name: 'WebKit',
use: {
browserName: 'webkit'
}
}
],
reporter: 'list',
webServer: {
command: 'npm run start-server-only',
port: 3000,
timeout: 120000,
reuseExistingServer: !process.env.CI
}
};
export default config;
+19 -3
View File
@@ -3,21 +3,37 @@
"module": "commonjs",
"target": "es2021",
"lib": [
"es2015"
"es2021",
],
"rootDir": ".",
"outDir": "../out-test",
"sourceMap": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"common/*": [
"../../../src/common/*"
],
"browser/*": [
"../../../src/browser/*"
]
},
"strict": true,
"types": [
"../../../node_modules/@types/mocha",
"../../../node_modules/@types/node",
"../../../out-test/api/TestUtils"
"../../../out-test/playwright/TestUtils"
]
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{
"path": "../../../src/common"
},
{
"path": "../../../src/browser"
}
]
}
-135
View File
@@ -1,135 +0,0 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { openTerminal, launchBrowser, timeout } from '../../../out-test/api/TestUtils';
import { Browser, Page } from '@playwright/test';
const APP = 'http://127.0.0.1:3001/test';
let browser: Browser;
let page: Page;
const width = 1024;
const height = 768;
describe('FitAddon', () => {
before(async function(): Promise<any> {
browser = await launchBrowser();
page = await (await browser.newContext()).newPage();
await page.setViewportSize({ width, height });
await page.goto(APP);
});
beforeEach(async function(): Promise<any> {
await page.evaluate(`document.querySelector('#terminal-container').style.display=''`);
await openTerminal(page);
});
after(async () => {
await browser.close();
});
afterEach(async function(): Promise<any> {
await page.evaluate(`window.term.dispose()`);
});
it('no terminal', async function(): Promise<any> {
await page.evaluate(`window.fit = new FitAddon();`);
assert.equal(await page.evaluate(`window.fit.proposeDimensions()`), undefined);
});
describe('proposeDimensions', () => {
afterEach(() => unloadFit());
it('default', async function(): Promise<any> {
await loadFit();
const dimensions: {cols: number, rows: number} = await page.evaluate(`window.fit.proposeDimensions()`);
assert.isAbove(dimensions.cols, 85);
assert.isBelow(dimensions.cols, 88);
assert.isAbove(dimensions.rows, 24);
assert.isBelow(dimensions.rows, 29);
});
it('width', async function(): Promise<any> {
await loadFit(1008);
const dimensions: {cols: number, rows: number} = await page.evaluate(`window.fit.proposeDimensions()`);
assert.isAbove(dimensions.cols, 108);
assert.isBelow(dimensions.cols, 111);
assert.isAbove(dimensions.rows, 24);
assert.isBelow(dimensions.rows, 29);
});
it('small', async function(): Promise<any> {
await loadFit(1, 1);
assert.deepEqual(await page.evaluate(`window.fit.proposeDimensions()`), {
cols: 2,
rows: 1
});
});
it('hidden', async function(): Promise<any> {
await page.evaluate(`window.term.dispose()`);
await page.evaluate(`document.querySelector('#terminal-container').style.display='none'`);
await page.evaluate(`window.term = new Terminal()`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
await loadFit();
const dimensions: { cols: number, rows: number } | undefined = await page.evaluate(`window.fit.proposeDimensions()`);
// The value of dims will be undefined if the char measure strategy falls back to the DOM
// method, so only assert if it's not undefined.
if (dimensions) {
assert.isAbove(dimensions.cols, 85);
assert.isBelow(dimensions.cols, 88);
assert.isAbove(dimensions.rows, 24);
assert.isBelow(dimensions.rows, 29);
}
});
});
describe('fit', () => {
afterEach(() => unloadFit());
it('default', async function(): Promise<any> {
await loadFit();
await page.evaluate(`window.fit.fit()`);
const cols: number = await page.evaluate(`window.term.cols`);
const rows: number = await page.evaluate(`window.term.rows`);
assert.isAbove(cols, 85);
assert.isBelow(cols, 88);
assert.isAbove(rows, 24);
assert.isBelow(rows, 29);
});
it('width', async function(): Promise<any> {
await loadFit(1008);
await page.evaluate(`window.fit.fit()`);
const cols: number = await page.evaluate(`window.term.cols`);
const rows: number = await page.evaluate(`window.term.rows`);
assert.isAbove(cols, 108);
assert.isBelow(cols, 111);
assert.isAbove(rows, 24);
assert.isBelow(rows, 29);
});
it('small', async function(): Promise<any> {
await loadFit(1, 1);
await page.evaluate(`window.fit.fit()`);
assert.equal(await page.evaluate(`window.term.cols`), 2);
assert.equal(await page.evaluate(`window.term.rows`), 1);
});
});
});
async function loadFit(width: number = 800, height: number = 450): Promise<void> {
await page.evaluate(`
window.fit = new FitAddon();
window.term.loadAddon(window.fit);
document.querySelector('#terminal-container').style.width='${width}px';
document.querySelector('#terminal-container').style.height='${height}px';
`);
}
async function unloadFit(): Promise<void> {
await page.evaluate(`window.fit.dispose();`);
}
+138
View File
@@ -0,0 +1,138 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import test from '@playwright/test';
import { deepEqual, ok, strictEqual } from 'assert';
import { ITestContext, createTestContext, openTerminal, timeout } from '../../../out-test/playwright/TestUtils';
let ctx: ITestContext;
test.beforeAll(async ({ browser }) => {
ctx = await createTestContext(browser);
await openTerminal(ctx);
});
test.afterAll(async () => await ctx.page.close());
test.describe('FitAddon', () => {
test.beforeEach(async function(): Promise<any> {
await ctx.page.evaluate(`
window.term.reset()
window.fit?.dispose();
window.fit = new FitAddon();
window.term.loadAddon(window.fit);
`);
});
// test.beforeEach(async function(): Promise<any> {
// await ctx.page.evaluate(`document.querySelector('#terminal-container').style.display=''`);
// await openTerminal(page);
// });
// after(async () => {
// await browser.close();
// });
// afterEach(async function(): Promise<any> {
// await ctx.proxy.dispose();
// });
test('no terminal', async function(): Promise<any> {
await ctx.page.evaluate(`window.fit = new FitAddon();`);
strictEqual(await ctx.page.evaluate(`window.fit.proposeDimensions()`), undefined);
});
test.describe('proposeDimensions', () => {
// test.afterEach(() => unloadFit());
test('default', async function(): Promise<any> {
await loadFit();
const dimensions: {cols: number, rows: number} = await ctx.page.evaluate(`window.fit.proposeDimensions()`);
ok(dimensions.cols > 85);
ok(dimensions.cols < 88);
ok(dimensions.rows > 24);
ok(dimensions.rows < 29);
});
test('width', async function(): Promise<any> {
await loadFit(1008);
const dimensions: {cols: number, rows: number} = await ctx.page.evaluate(`window.fit.proposeDimensions()`);
ok(dimensions.cols > 108);
ok(dimensions.cols < 111);
ok(dimensions.rows > 24);
ok(dimensions.rows < 29);
});
test('small', async function(): Promise<any> {
await loadFit(1, 1);
deepEqual(await ctx.page.evaluate(`window.fit.proposeDimensions()`), {
cols: 2,
rows: 1
});
});
test('hidden', async function(): Promise<any> {
await ctx.proxy.dispose();
await ctx.page.evaluate(`document.querySelector('#terminal-container').style.display='none'`);
await ctx.page.evaluate(`window.term = new Terminal()`);
await ctx.page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
await loadFit();
const dimensions: { cols: number, rows: number } | undefined = await ctx.page.evaluate(`window.fit.proposeDimensions()`);
// The value of dims will be undefined if the char measure strategy falls back to the DOM
// method, so only assert if it's not undefined.
if (dimensions) {
ok(dimensions.cols > 85);
ok(dimensions.cols < 88);
ok(dimensions.rows > 24);
ok(dimensions.rows < 29);
}
await ctx.page.evaluate(`document.querySelector('#terminal-container').style.display='block'`);
});
});
test.describe('fit', () => {
test.afterEach(() => unloadFit());
test('default', async function(): Promise<any> {
await loadFit();
await ctx.page.evaluate(`window.fit.fit()`);
const cols: number = await ctx.proxy.cols;
const rows: number = await ctx.proxy.rows;
ok(cols > 85);
ok(cols < 88);
ok(rows > 24);
ok(rows < 29);
});
test('width', async function(): Promise<any> {
await loadFit(1008);
await ctx.page.evaluate(`window.fit.fit()`);
const cols: number = await ctx.proxy.cols;
const rows: number = await ctx.proxy.rows;
ok(cols > 108);
ok(cols < 111);
ok(rows > 24);
ok(rows < 29);
});
test('small', async function(): Promise<any> {
await loadFit(1, 1);
await ctx.page.evaluate(`window.fit.fit()`);
strictEqual(await ctx.proxy.cols, 2);
strictEqual(await ctx.proxy.rows, 1);
});
});
});
async function loadFit(width: number = 800, height: number = 450): Promise<void> {
await ctx.page.evaluate(`
window.fit = new FitAddon();
window.term.loadAddon(window.fit);
document.querySelector('#terminal-container').style.width='${width}px';
document.querySelector('#terminal-container').style.height='${height}px';
`);
}
async function unloadFit(): Promise<void> {
await ctx.page.evaluate(`window.fit.dispose();`);
}
@@ -0,0 +1,35 @@
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: '.',
timeout: 10000,
projects: [
{
name: 'ChromeStable',
use: {
browserName: 'chromium',
channel: 'chrome'
}
},
{
name: 'FirefoxStable',
use: {
browserName: 'firefox'
}
},
{
name: 'WebKit',
use: {
browserName: 'webkit'
}
}
],
reporter: 'list',
webServer: {
command: 'npm run start-server-only',
port: 3000,
timeout: 120000,
reuseExistingServer: !process.env.CI
}
};
export default config;
+19 -3
View File
@@ -3,21 +3,37 @@
"module": "commonjs",
"target": "es2021",
"lib": [
"es2015"
"es2021",
],
"rootDir": ".",
"outDir": "../out-test",
"sourceMap": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"common/*": [
"../../../src/common/*"
],
"browser/*": [
"../../../src/browser/*"
]
},
"strict": true,
"types": [
"../../../node_modules/@types/mocha",
"../../../node_modules/@types/node",
"../../../out-test/api/TestUtils"
"../../../out-test/playwright/TestUtils"
]
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{
"path": "../../../src/common"
},
{
"path": "../../../src/browser"
}
]
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,489 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import test from '@playwright/test';
import { deepStrictEqual, strictEqual } from 'assert';
import { readFile } from 'fs';
import { resolve } from 'path';
import { ITestContext, createTestContext, openTerminal, timeout } from '../../../out-test/playwright/TestUtils';
let ctx: ITestContext;
test.beforeAll(async ({ browser }) => {
ctx = await createTestContext(browser);
await openTerminal(ctx);
});
test.afterAll(async () => await ctx.page.close());
test.describe('Search Tests', () => {
test.beforeEach(async () => {
await ctx.page.evaluate(`
window.term.reset()
window.search?.dispose();
window.search = new SearchAddon();
window.term.loadAddon(window.search);
`);
});
test('Simple Search', async () => {
await ctx.proxy.write('dafhdjfldshafhldsahfkjhldhjkftestlhfdsakjfhdjhlfdsjkafhjdlk');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('test')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), 'test');
});
test('Scrolling Search', async () => {
let dataString = '';
for (let i = 0; i < 100; i++) {
if (i === 52) {
dataString += '$^1_3{}test$#';
}
dataString += makeData(50);
}
await ctx.proxy.write(dataString);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('$^1_3{}test$#')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), '$^1_3{}test$#');
});
test('Incremental Find Previous', async () => {
await ctx.proxy.writeln(`package.jsonc\n`);
await ctx.proxy.write('package.json pack package.lock');
await ctx.page.evaluate(`window.search.findPrevious('pack', {incremental: true})`);
let selectionPosition: { start: { x: number, y: number }, end: { x: number, y: number } } = (await ctx.proxy.getSelectionPosition())!;
let line: string = await (await ctx.proxy.buffer.active.getLine(selectionPosition.start.y))!.translateToString();
// We look further ahead in the line to ensure that pack was selected from package.lock
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x + 8), 'package.lock');
await ctx.page.evaluate(`window.search.findPrevious('package.j', {incremental: true})`);
selectionPosition = (await ctx.proxy.getSelectionPosition())!;
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x + 3), 'package.json');
await ctx.page.evaluate(`window.search.findPrevious('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
selectionPosition = (await ctx.proxy.getSelectionPosition())!;
line = await (await ctx.proxy.buffer.active.getLine(selectionPosition.start.y))!.translateToString();
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x), 'package.jsonc');
});
test('Incremental Find Next', async () => {
await ctx.proxy.writeln(`package.lock pack package.json package.ups\n`);
await ctx.proxy.write('package.jsonc');
await ctx.page.evaluate(`window.search.findNext('pack', {incremental: true})`);
let selectionPosition: { start: { x: number, y: number }, end: { x: number, y: number } } = (await ctx.proxy.getSelectionPosition())!;
let line: string = await (await ctx.proxy.buffer.active.getLine(selectionPosition.start.y))!.translateToString();
// We look further ahead in the line to ensure that pack was selected from package.lock
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x + 8), 'package.lock');
await ctx.page.evaluate(`window.search.findNext('package.j', {incremental: true})`);
selectionPosition = (await ctx.proxy.getSelectionPosition())!;
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x + 3), 'package.json');
await ctx.page.evaluate(`window.search.findNext('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
selectionPosition = (await ctx.proxy.getSelectionPosition())!;
line = await (await ctx.proxy.buffer.active.getLine(selectionPosition.start.y))!.translateToString();
deepStrictEqual(line.substring(selectionPosition.start.x, selectionPosition.end.x), 'package.jsonc');
});
test('Simple Regex', async () => {
await ctx.proxy.write('abc123defABCD');
await ctx.page.evaluate(`window.search.findNext('[a-z]+', {regex: true})`);
deepStrictEqual(await ctx.proxy.getSelection(), 'abc');
await ctx.page.evaluate(`window.search.findNext('[A-Z]+', {regex: true, caseSensitive: true})`);
deepStrictEqual(await ctx.proxy.getSelection(), 'ABCD');
});
test('Search for single result twice should not unselect it', async () => {
await ctx.proxy.write('abc def');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('abc')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), 'abc');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('abc')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), 'abc');
});
test('Search for result bounding with wide unicode chars', async () => {
await ctx.proxy.write('中文xx𝄞𝄞');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('中')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), '中');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('xx')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), 'xx');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('𝄞')`), true);
deepStrictEqual(await ctx.proxy.getSelection(), '𝄞');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('𝄞')`), true);
deepStrictEqual(await ctx.proxy.getSelectionPosition(), {
start: {
x: 7,
y: 0
},
end: {
x: 8,
y: 0
}
});
});
test.describe('onDidChangeResults', async () => {
test.describe('findNext', () => {
test('should not fire unless the decorations option is set', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc');
strictEqual(await ctx.page.evaluate(`window.search.findNext('a')`), true);
strictEqual(await ctx.page.evaluate('window.calls.length'), 0);
strictEqual(await ctx.page.evaluate(`window.search.findNext('b', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate('window.calls.length'), 1);
});
test('should fire with correct event values', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc bc c');
strictEqual(await ctx.page.evaluate(`window.search.findNext('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findNext('b', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findNext('d', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), false);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 0, resultIndex: -1 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findNext('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate(`window.search.findNext('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate(`window.search.findNext('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 0, resultIndex: -1 },
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 3, resultIndex: 1 },
{ resultCount: 3, resultIndex: 2 }
]);
});
test('should fire with correct event values (incremental)', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('d abc aabc d');
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('a', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('ab', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('abc', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('abc', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('d', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('abcd', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), false);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 0, resultIndex: -1 }
]);
});
test('should fire with more than 1k matches', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
const data = ('a bc'.repeat(10) + '\\n\\r').repeat(150);
await ctx.proxy.write(data);
strictEqual(await ctx.page.evaluate(`window.search.findNext('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: 0 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findNext('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: 0 },
{ resultCount: 1000, resultIndex: 1 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findNext('bc', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: 0 },
{ resultCount: 1000, resultIndex: 1 },
{ resultCount: 1000, resultIndex: 1 }
]);
});
test('should fire when writing to terminal', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc bc c\\n\\r'.repeat(2));
strictEqual(await ctx.page.evaluate(`window.search.findNext('abc', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 2, resultIndex: 0 }
]);
await ctx.proxy.write('abc bc c\\n\\r');
await timeout(300);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 3, resultIndex: 0 }
]);
});
});
test.describe('findPrevious', () => {
test('should not fire unless the decorations option is set', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc');
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('a')`), true);
strictEqual(await ctx.page.evaluate('window.calls.length'), 0);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('b', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate('window.calls.length'), 1);
});
test('should fire with correct event values', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc bc c');
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 }
]);
await ctx.page.evaluate(`window.term.clearSelection()`);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('b', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 }
]);
await timeout(2000);
strictEqual(await ctx.page.evaluate(`debugger; window.search.findPrevious('d', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), false);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 0, resultIndex: -1 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('c', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 0, resultIndex: -1 },
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 3, resultIndex: 1 },
{ resultCount: 3, resultIndex: 0 }
]);
});
test('should fire with correct event values (incremental)', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('d abc aabc d');
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('a', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('ab', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 2, resultIndex: 1 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('abc', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('abc', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 0 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('d', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 }
]);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('abcd', { incremental: true, decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), false);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 3, resultIndex: 2 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 2, resultIndex: 0 },
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 0, resultIndex: -1 }
]);
});
test('should fire with more than 1k matches', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
const data = ('a bc'.repeat(10) + '\\n\\r').repeat(150);
await ctx.proxy.write(data);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: -1 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('a', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: -1 },
{ resultCount: 1000, resultIndex: -1 }
]);
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('bc', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 1000, resultIndex: -1 },
{ resultCount: 1000, resultIndex: -1 },
{ resultCount: 1000, resultIndex: -1 }
]);
});
test('should fire when writing to terminal', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
await ctx.proxy.write('abc bc c\\n\\r'.repeat(2));
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('abc', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 2, resultIndex: 1 }
]);
await ctx.proxy.write('abc bc c\\n\\r');
await timeout(300);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 2, resultIndex: 1 },
{ resultCount: 3, resultIndex: 1 }
]);
});
});
});
test.describe('Regression tests', () => {
test.describe('#2444 wrapped line content not being found', () => {
let fixture: string;
test.beforeAll(async () => {
fixture = (await new Promise<Buffer>(r => readFile(resolve(__dirname, '../fixtures/issue-2444'), (err, data) => r(data)))).toString();
});
test('should find all occurrences using findNext', async () => {
await ctx.proxy.write(fixture);
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
let selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 53 }, end: { x: 30, y: 53 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 76 }, end: { x: 30, y: 76 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 96 }, end: { x: 30, y: 96 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 114 }, end: { x: 7, y: 114 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 115 }, end: { x: 17, y: 115 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 126 }, end: { x: 7, y: 126 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 127 }, end: { x: 17, y: 127 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 135 }, end: { x: 7, y: 135 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 136 }, end: { x: 17, y: 136 } });
// Wrap around to first result
deepStrictEqual(await ctx.page.evaluate(`window.search.findNext('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 53 }, end: { x: 30, y: 53 } });
});
test('should y all occurrences using findPrevious', async () => {
await ctx.proxy.write(fixture);
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
let selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 136 }, end: { x: 17, y: 136 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 135 }, end: { x: 7, y: 135 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 127 }, end: { x: 17, y: 127 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 126 }, end: { x: 7, y: 126 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 115 }, end: { x: 17, y: 115 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 1, y: 114 }, end: { x: 7, y: 114 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 96 }, end: { x: 30, y: 96 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 76 }, end: { x: 30, y: 76 } });
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 24, y: 53 }, end: { x: 30, y: 53 } });
// Wrap around to first result
deepStrictEqual(await ctx.page.evaluate(`window.search.findPrevious('opencv')`), true);
selectionPosition = await ctx.proxy.getSelectionPosition();
deepStrictEqual(selectionPosition, { start: { x: 11, y: 136 }, end: { x: 17, y: 136 } });
});
});
});
test.describe('#3834 lines with null characters before search terms', () => {
// This case can be triggered by the prompt when using starship under conpty
test('should find all matches on a line containing null characters', async () => {
await ctx.page.evaluate(`
window.calls = [];
window.search.onDidChangeResults(e => window.calls.push(e));
`);
// Move cursor forward 1 time to create a null character, as opposed to regular whitespace
await ctx.proxy.write('\\x1b[CHi Hi');
strictEqual(await ctx.page.evaluate(`window.search.findPrevious('h', { decorations: { activeMatchColorOverviewRuler: '#ff0000' } })`), true);
deepStrictEqual(await ctx.page.evaluate('window.calls'), [
{ resultCount: 2, resultIndex: 1 }
]);
});
});
});
function makeData(length: number): string {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
@@ -0,0 +1,35 @@
import { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
testDir: '.',
timeout: 10000,
projects: [
{
name: 'Chrome Stable',
use: {
browserName: 'chromium',
channel: 'chrome'
}
},
{
name: 'Firefox Stable',
use: {
browserName: 'firefox'
}
},
{
name: 'WebKit',
use: {
browserName: 'webkit'
}
}
],
reporter: 'list',
webServer: {
command: 'npm run start-server-only',
port: 3000,
timeout: 120000,
reuseExistingServer: !process.env.CI
}
};
export default config;
+18 -2
View File
@@ -9,15 +9,31 @@
"outDir": "../out-test",
"sourceMap": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"common/*": [
"../../../src/common/*"
],
"browser/*": [
"../../../src/browser/*"
]
},
"strict": true,
"types": [
"../../../node_modules/@types/mocha",
"../../../node_modules/@types/node",
"../../../out-test/api/TestUtils"
"../../../out-test/playwright/TestUtils"
]
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{
"path": "../../../src/common"
},
{
"path": "../../../src/browser"
}
]
}
+7 -3
View File
@@ -18,9 +18,13 @@ while (argv.some(e => e.startsWith('--suite='))) {
}
let configs = [
{ name: 'core', path: 'out-test/playwright/playwright.config.js' },
{ name: 'addon-canvas', path: 'addons/addon-canvas/out-test/playwright.config.js' },
{ name: 'addon-webgl', path: 'addons/addon-webgl/out-test/playwright.config.js' }
{ name: 'core', path: 'out-test/playwright/playwright.config.js' },
{ name: 'addon-attach', path: 'addons/addon-attach/out-test/playwright.config.js' },
{ name: 'addon-canvas', path: 'addons/addon-canvas/out-test/playwright.config.js' },
{ name: 'addon-clipboard', path: 'addons/addon-clipboard/out-test/playwright.config.js' },
{ name: 'addon-fit', path: 'addons/addon-fit/out-test/playwright.config.js' },
{ name: 'addon-search', path: 'addons/addon-search/out-test/playwright.config.js' },
{ name: 'addon-webgl', path: 'addons/addon-webgl/out-test/playwright.config.js' }
];
if (suiteFilter) {