]> git.proxmox.com Git - mirror_xterm.js.git/blame - src/Linkifier.test.ts
Merge pull request #926 from ficristo/search-fix
[mirror_xterm.js.git] / src / Linkifier.test.ts
CommitLineData
26ebc3d9
DI
1/**
2 * @license MIT
3 */
4import jsdom = require('jsdom');
5import { assert } from 'chai';
6import { ITerminal, ILinkifier } from './Interfaces';
7import { Linkifier } from './Linkifier';
7ac4f1a9 8import { LinkMatcher } from './Types';
26ebc3d9 9
15d79143 10class TestLinkifier extends Linkifier {
b0624cad 11 constructor() {
15d79143 12 Linkifier.TIME_BEFORE_LINKIFY = 0;
b0624cad 13 super();
15d79143 14 }
7ac4f1a9
DI
15
16 public get linkMatchers(): LinkMatcher[] { return this._linkMatchers; }
15d79143 17}
26ebc3d9
DI
18
19describe('Linkifier', () => {
d266d995 20 let dom: jsdom.JSDOM;
26ebc3d9
DI
21 let window: Window;
22 let document: Document;
23
24 let container: HTMLElement;
25 let rows: HTMLElement[];
7ac4f1a9 26 let linkifier: TestLinkifier;
26ebc3d9 27
0ea2e9cf 28 beforeEach(() => {
8a574899 29 dom = new jsdom.JSDOM('');
0ea2e9cf
PK
30 window = dom.window;
31 document = window.document;
32 linkifier = new TestLinkifier();
26ebc3d9
DI
33 });
34
8c2db8dd 35 function addRow(html: string) {
26ebc3d9 36 const element = document.createElement('div');
8c2db8dd 37 element.innerHTML = html;
26ebc3d9
DI
38 container.appendChild(element);
39 rows.push(element);
40 }
41
b0624cad
DI
42 describe('before attachToDom', () => {
43 it('should allow link matcher registration', done => {
44 assert.doesNotThrow(() => {
45 const linkMatcherId = linkifier.registerLinkMatcher(/foo/, () => {});
46 assert.isTrue(linkifier.deregisterLinkMatcher(linkMatcherId));
b68180b9 47 done();
26ebc3d9 48 });
b0624cad 49 });
b68180b9
DI
50 });
51
b0624cad
DI
52 describe('after attachToDom', () => {
53 beforeEach(() => {
54 rows = [];
55 linkifier.attachToDom(document, rows);
56 container = document.createElement('div');
57 document.body.appendChild(container);
26ebc3d9
DI
58 });
59
b0624cad
DI
60 function clickElement(element: Node) {
61 const event = document.createEvent('MouseEvent');
62 event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
63 element.dispatchEvent(event);
64 }
b68180b9 65
b0624cad
DI
66 function assertLinkifiesEntireRow(uri: string, done: MochaDone) {
67 addRow(uri);
68 linkifier.linkifyRow(0);
69 setTimeout(() => {
26ebc3d9 70 assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
b0624cad
DI
71 assert.equal((<HTMLElement>rows[0].firstChild).textContent, uri);
72 done();
73 }, 0);
74 }
26ebc3d9 75
b0624cad 76 describe('http links', () => {
fe8334a8
DI
77 function assertLinkifiesEntireRow(uri: string, done: MochaDone) {
78 addRow(uri);
79 linkifier.linkifyRow(0);
80 setTimeout(() => {
26ebc3d9 81 assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
fe8334a8
DI
82 assert.equal((<HTMLElement>rows[0].firstChild).textContent, uri);
83 done();
84 }, 0);
85 }
b0624cad 86 it('should allow ~ character in URI path', done => assertLinkifiesEntireRow('http://foo.com/a~b#c~d?e~f', done));
26ebc3d9 87 });
7ac4f1a9 88
fe8334a8
DI
89 describe('link matcher', () => {
90 function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, expectedHtml: string, done: MochaDone) {
91 addRow(rowText);
92 linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
93 linkifier.linkifyRow(0);
94 // Allow linkify to happen
95 setTimeout(() => {
96 assert.equal(rows[0].innerHTML, expectedHtml);
97 done();
98 }, 0);
99 }
100 it('should match a single link', done => {
101 assertLinkifiesRow('foo', /foo/, '<a>foo</a>', done);
102 });
103 it('should match a single link at the start of a text node', done => {
104 assertLinkifiesRow('foo bar', /foo/, '<a>foo</a> bar', done);
105 });
106 it('should match a single link in the middle of a text node', done => {
107 assertLinkifiesRow('foo bar baz', /bar/, 'foo <a>bar</a> baz', done);
108 });
109 it('should match a single link at the end of a text node', done => {
110 assertLinkifiesRow('foo bar', /bar/, 'foo <a>bar</a>', done);
111 });
112 it('should match a link after a link at the start of a text node', done => {
113 assertLinkifiesRow('foo bar', /foo|bar/, '<a>foo</a> <a>bar</a>', done);
114 });
115 it('should match a link after a link in the middle of a text node', done => {
116 assertLinkifiesRow('foo bar baz', /bar|baz/, 'foo <a>bar</a> <a>baz</a>', done);
117 });
118 it('should match a link immediately after a link at the end of a text node', done => {
119 assertLinkifiesRow('<span>foo bar</span>baz', /bar|baz/, '<span>foo <a>bar</a></span><a>baz</a>', done);
26ebc3d9 120 });
ee1da73a
DI
121 it('should not duplicate text after a unicode character (wrapped in a span)', done => {
122 // This is a regression test for an issue that came about when using
123 // an oh-my-zsh theme that added the large blue diamond unicode
124 // character (U+1F537) which caused the path to be duplicated. See #642.
125 assertLinkifiesRow('echo \'<span class="xterm-normal-char">🔷</span>foo\'', /foo/, 'echo \'<span class="xterm-normal-char">🔷</span><a>foo</a>\'', done);
126 });
7ac4f1a9
DI
127 });
128
b0624cad
DI
129 describe('validationCallback', () => {
130 it('should enable link if true', done => {
131 addRow('test');
132 linkifier.registerLinkMatcher(/test/, () => done(), {
584ec681 133 validationCallback: (url, element, cb) => {
b0624cad
DI
134 cb(true);
135 assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
136 setTimeout(() => clickElement(rows[0].firstChild), 0);
d8140097 137 }
b0624cad
DI
138 });
139 linkifier.linkifyRow(0);
d8140097 140 });
7ac4f1a9 141
b0624cad
DI
142 it('should disable link if false', done => {
143 addRow('test');
144 linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
584ec681 145 validationCallback: (url, element, cb) => {
b0624cad
DI
146 cb(false);
147 assert.equal((<HTMLElement>rows[0].firstChild).tagName, 'A');
148 setTimeout(() => clickElement(rows[0].firstChild), 0);
149 }
150 });
151 linkifier.linkifyRow(0);
152 // Allow time for the click to be performed
153 setTimeout(() => done(), 10);
154 });
7ac4f1a9 155
fe8334a8
DI
156 it('should trigger for multiple link matches on one row', done => {
157 addRow('test test');
158 let count = 0;
159 linkifier.registerLinkMatcher(/test/, () => assert.fail(), {
584ec681 160 validationCallback: (url, element, cb) => {
fe8334a8
DI
161 count += 1;
162 if (count === 2) {
163 done();
164 }
165 cb(false);
166 }
167 });
168 linkifier.linkifyRow(0);
169 });
7ac4f1a9
DI
170 });
171
b0624cad
DI
172 describe('priority', () => {
173 it('should order the list from highest priority to lowest #1', () => {
174 const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 1 });
175 const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: -1 });
176 assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [aId, 0, bId]);
177 });
7ac4f1a9 178
b0624cad
DI
179 it('should order the list from highest priority to lowest #2', () => {
180 const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: -1 });
181 const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 1 });
182 assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [bId, 0, aId]);
183 });
184
185 it('should order items of equal priority in the order they are added', () => {
186 const aId = linkifier.registerLinkMatcher(/a/, () => {}, { priority: 0 });
187 const bId = linkifier.registerLinkMatcher(/b/, () => {}, { priority: 0 });
188 assert.deepEqual(linkifier.linkMatchers.map(lm => lm.id), [0, aId, bId]);
189 });
7ac4f1a9
DI
190 });
191 });
26ebc3d9 192});