From 55d590348c6a39ab4c96fcd7cb9e51a4cb1e111f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 10 May 2019 22:57:27 -0700 Subject: [PATCH] API integration tests Part of #1247 --- azure-pipelines.yml | 11 +++-- demo/client.ts | 10 ++-- demo/server.js | 4 ++ demo/test.html | 12 +++++ package.json | 5 ++ src/public/Terminal.api.ts | 99 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 demo/test.html create mode 100644 src/public/Terminal.api.ts diff --git a/azure-pipelines.yml b/azure-pipelines.yml index db74a4ea..fd65a6a8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,7 +21,12 @@ jobs: displayName: 'Install dependencies and build' - script: | yarn mocha - displayName: 'Test' + displayName: 'Unit tests' + - script: | + yarn start & + sleep 5 + yarn test-api --headless + displayName: 'Integration tests' - script: | yarn lint displayName: 'Lint' @@ -39,7 +44,7 @@ jobs: displayName: 'Install dependencies and build' - script: | yarn mocha - displayName: 'Test' + displayName: 'Unit tests' - script: | yarn lint displayName: 'Lint' @@ -62,7 +67,7 @@ jobs: displayName: 'Install dependencies and build' - script: | yarn mocha - displayName: 'Test' + displayName: 'Unit tests' - script: | yarn lint displayName: 'Lint' diff --git a/demo/client.ts b/demo/client.ts index 90a913d7..b7409109 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -21,6 +21,7 @@ import { Terminal as TerminalType, ITerminalOptions } from 'xterm'; export interface IWindowWithTerminal extends Window { term: TerminalType; + Terminal?: typeof TerminalType; } declare let window: IWindowWithTerminal; @@ -57,8 +58,6 @@ function getSearchOptions(): ISearchOptions { }; } -createTerminal(); - const disposeRecreateButtonHandler = () => { // If the terminal exists dispose of it, otherwise recreate it if (term) { @@ -74,7 +73,12 @@ const disposeRecreateButtonHandler = () => { } }; -document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); +if (document.location.pathname === '/test') { + window.Terminal = Terminal; +} else { + createTerminal(); + document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); +} function createTerminal(): void { // Clean terminal diff --git a/demo/server.js b/demo/server.js index 758023c7..8270a398 100644 --- a/demo/server.js +++ b/demo/server.js @@ -16,6 +16,10 @@ function startServer() { res.sendFile(__dirname + '/index.html'); }); + app.get('/test', function(req, res){ + res.sendFile(__dirname + '/test.html'); + }); + app.get('/style.css', function(req, res){ res.sendFile(__dirname + '/style.css'); }); diff --git a/demo/test.html b/demo/test.html new file mode 100644 index 00000000..275c542d --- /dev/null +++ b/demo/test.html @@ -0,0 +1,12 @@ + + + + xterm.js integration test fixture + + + + +
+ + + diff --git a/package.json b/package.json index 1727af82..615962c4 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/jsdom": "11.0.1", "@types/mocha": "^2.2.33", "@types/node": "6.0.108", + "@types/puppeteer": "^1.12.4", "@types/webpack": "^4.4.11", "browserify": "^13.3.0", "chai": "3.5.0", @@ -54,6 +55,7 @@ "test-debug": "node --inspect-brk node_modules/.bin/gulp test", "test-suite": "gulp mocha-suite --test", "test-coverage": "nyc -x gulpfile.js -x '**/*test*' npm run mocha", + "test-api": "mocha \"**/*.api.js\"", "mocha": "gulp test", "prebuild": "tsc -b ./src/tsconfig.all.json", "build": "gulp build", @@ -61,5 +63,8 @@ "prepublishOnly": "npm run build", "coveralls": "nyc report --reporter=text-lcov | coveralls", "watch": "tsc -b -w ./src/tsconfig.all.json --preserveWatchOutput" + }, + "dependencies": { + "puppeteer": "^1.15.0" } } diff --git a/src/public/Terminal.api.ts b/src/public/Terminal.api.ts new file mode 100644 index 00000000..168a9407 --- /dev/null +++ b/src/public/Terminal.api.ts @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import * as puppeteer from 'puppeteer'; +import { assert } from 'chai'; +import { ITerminalOptions } from '../Types'; + +const APP = 'http://127.0.0.1:3000/test'; + +let browser: puppeteer.Browser; +let page: puppeteer.Page; +const width = 800; +const height = 600; + +describe('API Integration Tests', () => { + before(async function(): Promise { + this.timeout(10000); + browser = await puppeteer.launch({ + headless: process.argv.indexOf('--headless') !== -1, + slowMo: 80, + args: [`--window-size=${width},${height}`] + }); + page = (await browser.pages())[0]; + await page.setViewport({ width, height }); + }); + + after(() => { + browser.close(); + }); + + beforeEach(async () => { + await page.goto(APP); + }); + + it('Default options', async function(): Promise { + this.timeout(10000); + await openTerminal(); + assert.equal(await page.evaluate(`window.term.cols`), 80); + assert.equal(await page.evaluate(`window.term.rows`), 24); + }); + + it('write', async function(): Promise { + this.timeout(10000); + await openTerminal(); + await page.evaluate(` + window.term.write('foo'); + window.term.write('bar'); + `); + assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'foobar'); + }); + + it('writeln', async function(): Promise { + this.timeout(10000); + await openTerminal(); + await page.evaluate(` + window.term.writeln('foo'); + window.term.writeln('bar'); + `); + assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'foo'); + assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(1, true)`), 'bar'); + }); + + it('clear', async function(): Promise { + this.timeout(10000); + await openTerminal({ rows: 5 }); + await page.evaluate(` + window.term.write('test0'); + for (let i = 1; i < 10; i++) { + window.term.write('\\n\\rtest' + i); + } + `); + await page.evaluate(`window.term.clear()`); + assert.equal(await page.evaluate(`window.term._core.buffer.lines.length`), '5'); + assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(0, true)`), 'test9'); + for (let i = 1; i < 5; i++) { + assert.equal(await page.evaluate(`window.term._core.buffer.translateBufferLineToString(${i}, true)`), ''); + } + }); + + it('getOption, setOption', async function(): Promise { + this.timeout(10000); + await openTerminal(); + assert.equal(await page.evaluate(`window.term.getOption('rendererType')`), 'canvas'); + await page.evaluate(`window.term.setOption('rendererType', 'dom')`); + assert.equal(await page.evaluate(`window.term.getOption('rendererType')`), 'dom'); + }); +}); + +async function openTerminal(options: ITerminalOptions = {}): Promise { + await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`); + await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); + if (options.rendererType === 'dom') { + await page.waitForSelector('.xterm-rows'); + } else { + await page.waitForSelector('.xterm-text-layer'); + } +}