From 26ebc3d94479f080c0604b238e6a32340864c468 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Mon, 27 Feb 2017 11:00:12 -0800 Subject: [PATCH] Use jsdom instead of phantomjs for linkifier test --- package.json | 1 + src/Linkifier.phantom.ts | 76 ---------------------------------------- src/Linkifier.test.ts | 71 +++++++++++++++++++++++++++++++++++++ src/Linkifier.ts | 19 +++++----- src/xterm.js | 2 +- 5 files changed, 84 insertions(+), 85 deletions(-) delete mode 100644 src/Linkifier.phantom.ts create mode 100644 src/Linkifier.test.ts diff --git a/package.json b/package.json index e657c1d1..3acacd10 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "gulp-sourcemaps": "1.9.1", "gulp-typescript": "^3.1.3", "jsdoc": "3.4.3", + "jsdom": "^9.11.0", "merge-stream": "^1.0.1", "node-pty": "^0.4.1", "nodemon": "1.10.2", diff --git a/src/Linkifier.phantom.ts b/src/Linkifier.phantom.ts deleted file mode 100644 index 01de4efc..00000000 --- a/src/Linkifier.phantom.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @license MIT - */ -import { ITerminal, ILinkifier } from './Interfaces'; - -declare var assert: Chai.Assert; -declare var Terminal: ITerminal; - -// Do not describe tests unless in PhantomJS environment -if (typeof Terminal !== 'undefined') { - - const Linkifier = (Terminal).Linkifier; - Linkifier.setTimeBeforeLinkifyForTest(0); - - describe('Linkifier', () => { - let container: HTMLElement; - let rows: HTMLElement[]; - let linkifier: ILinkifier; - - beforeEach(() => { - container = document.createElement('div'); - document.querySelector('#xterm').appendChild(container); - rows = []; - linkifier = new Linkifier(rows); - }); - - afterEach(() => { - while (rows.length) { - container.removeChild(rows.pop()); - } - document.querySelector('#xterm').removeChild(container); - }); - - function addRow(text: string) { - const element = document.createElement('div'); - element.textContent = text; - container.appendChild(element); - rows.push(element); - } - - function clickElement(element: Node) { - const event = document.createEvent('MouseEvent'); - event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); - element.dispatchEvent(event); - } - - describe('validationCallback', () => { - it('should enable link if true', done => { - addRow('test'); - linkifier.registerLinkMatcher(/test/, () => done(), { - validationCallback: (url, cb) => { - cb(true); - assert.equal((rows[0].firstChild).tagName, 'A'); - setTimeout(() => clickElement(rows[0].firstChild), 0); - } - }); - linkifier.linkifyRow(0); - }); - - it('should disable link if false', done => { - addRow('test'); - linkifier.registerLinkMatcher(/test/, () => assert.fail(), { - validationCallback: (url, cb) => { - cb(false); - assert.equal((rows[0].firstChild).tagName, 'A'); - setTimeout(() => clickElement(rows[0].firstChild), 0); - } - }); - linkifier.linkifyRow(0); - // Allow time for the click to be performed - setTimeout(() => done(), 10); - }); - }); - }); - -} diff --git a/src/Linkifier.test.ts b/src/Linkifier.test.ts new file mode 100644 index 00000000..bdab5cb2 --- /dev/null +++ b/src/Linkifier.test.ts @@ -0,0 +1,71 @@ +/** + * @license MIT + */ +import jsdom = require('jsdom'); +import { assert } from 'chai'; +import { ITerminal, ILinkifier } from './Interfaces'; +import { Linkifier } from './Linkifier'; + +Linkifier.setTimeBeforeLinkifyForTest(0); + +describe('Linkifier', () => { + let window: Window; + let document: Document; + + let container: HTMLElement; + let rows: HTMLElement[]; + let linkifier: ILinkifier; + + beforeEach(done => { + rows = []; + jsdom.env('', (err, w) => { + window = w; + document = window.document; + linkifier = new Linkifier(document, rows); + container = document.createElement('div'); + document.body.appendChild(container); + done(); + }); + }); + + function addRow(text: string) { + const element = document.createElement('div'); + element.textContent = text; + container.appendChild(element); + rows.push(element); + } + + function clickElement(element: Node) { + const event = document.createEvent('MouseEvent'); + event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + element.dispatchEvent(event); + } + + describe('validationCallback', () => { + it('should enable link if true', done => { + addRow('test'); + linkifier.registerLinkMatcher(/test/, () => done(), { + validationCallback: (url, cb) => { + cb(true); + assert.equal((rows[0].firstChild).tagName, 'A'); + setTimeout(() => clickElement(rows[0].firstChild), 0); + } + }); + linkifier.linkifyRow(0); + }); + + it('should disable link if false', done => { + addRow('test'); + linkifier.registerLinkMatcher(/test/, () => assert.fail(), { + validationCallback: (url, cb) => { + cb(false); + assert.equal((rows[0].firstChild).tagName, 'A'); + setTimeout(() => clickElement(rows[0].firstChild), 0); + } + }); + linkifier.linkifyRow(0); + // Allow time for the click to be performed + setTimeout(() => done(), 10); + }); + }); +}); diff --git a/src/Linkifier.ts b/src/Linkifier.ts index 9f29ba58..f15cfe65 100644 --- a/src/Linkifier.ts +++ b/src/Linkifier.ts @@ -47,12 +47,14 @@ let TIME_BEFORE_LINKIFY = 200; * The Linkifier applies links to rows shortly after they have been refreshed. */ export class Linkifier { + private _document: Document; private _rows: HTMLElement[]; private _rowTimeoutIds: number[]; private _linkMatchers: LinkMatcher[]; private _nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID; - constructor(rows: HTMLElement[]) { + constructor(document: Document, rows: HTMLElement[]) { + this._document = document; this._rows = rows; this._rowTimeoutIds = []; this._linkMatchers = []; @@ -169,7 +171,8 @@ export class Linkifier { const linkElement = this._createAnchorElement(uri, handler); if (node.textContent.length === uri.length) { // Matches entire string - if (node.nodeType === Node.TEXT_NODE) { + + if (node.nodeType === 3 /*Node.TEXT_NODE*/) { this._replaceNode(node, linkElement); } else { const element = (node); @@ -209,7 +212,7 @@ export class Linkifier { * @return {HTMLAnchorElement} The link. */ private _createAnchorElement(uri: string, handler: LinkMatcherHandler): HTMLAnchorElement { - const element = document.createElement('a'); + const element = this._document.createElement('a'); element.textContent = uri; if (handler) { element.addEventListener('click', () => { @@ -249,7 +252,7 @@ export class Linkifier { */ private _replaceNodeSubstringWithNode(targetNode: Node, newNode: Node, substring: string, substringIndex: number): void { let node = targetNode; - if (node.nodeType !== Node.TEXT_NODE) { + if (node.nodeType !== 3/*Node.TEXT_NODE*/) { node = node.childNodes[0]; } @@ -265,19 +268,19 @@ export class Linkifier { if (substringIndex === 0) { // Replace with const rightText = fullText.substring(substring.length); - const rightTextNode = document.createTextNode(rightText); + const rightTextNode = this._document.createTextNode(rightText); this._replaceNode(node, newNode, rightTextNode); } else if (substringIndex === targetNode.textContent.length - substring.length) { // Replace with const leftText = fullText.substring(0, substringIndex); - const leftTextNode = document.createTextNode(leftText); + const leftTextNode = this._document.createTextNode(leftText); this._replaceNode(node, leftTextNode, newNode); } else { // Replace with const leftText = fullText.substring(0, substringIndex); - const leftTextNode = document.createTextNode(leftText); + const leftTextNode = this._document.createTextNode(leftText); const rightText = fullText.substring(substringIndex + substring.length); - const rightTextNode = document.createTextNode(rightText); + const rightTextNode = this._document.createTextNode(rightText); this._replaceNode(node, leftTextNode, newNode, rightTextNode); } } diff --git a/src/xterm.js b/src/xterm.js index 4d5f0205..9e68f47c 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -612,7 +612,7 @@ Terminal.prototype.open = function(parent) { this.rowContainer.classList.add('xterm-rows'); this.element.appendChild(this.rowContainer); this.children = []; - this.linkifier = new Linkifier(this.children); + this.linkifier = new Linkifier(document, this.children); // Create the container that will hold helpers like the textarea for // capturing DOM Events. Then produce the helpers.