blob: fcb2af21e00c99545e253f836e7d5f75bdc69dec [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001import sinon from 'sinon';
2import {assert} from 'chai';
3import {autolink} from './autolink.js';
4import {prpcClient} from 'prpc-client-instance.js';
5
6const components = autolink.Components;
7const markupAutolinks = autolink.markupAutolinks;
8
9describe('autolink', () => {
10 describe('crbug component functions', () => {
11 const {extractRefs, refRegs, replacer} = components.get('01-tracker-crbug');
12
13 it('Extract crbug project and local ids', () => {
14 const match = refRegs[0].exec('https://crbug.com/monorail/1234');
15 refRegs[0].lastIndex = 0;
16 const ref = extractRefs(match);
17 assert.deepEqual(ref, [{projectName: 'monorail', localId: '1234'}]);
18 });
19
20 it('Extract crbug default project name', () => {
21 const match = refRegs[0].exec('http://crbug.com/1234');
22 refRegs[0].lastIndex = 0;
23 const ref = extractRefs(match);
24 assert.deepEqual(ref, [{projectName: 'chromium', localId: '1234'}]);
25 });
26
27 it('Extract crbug passed project name is ignored', () => {
28 const match = refRegs[0].exec('https://crbug.com/1234');
29 refRegs[0].lastIndex = 0;
30 const ref = extractRefs(match, 'foo');
31 assert.deepEqual(ref, [{projectName: 'chromium', localId: '1234'}]);
32 });
33
34 it('Replace crbug with found components', () => {
35 const str = 'crbug.com/monorail/1234';
36 const match = refRegs[0].exec(str);
37 refRegs[0].lastIndex = 0;
38 const components = {
39 closedRefs: [
40 {summary: 'Issue summary', localId: 1234, projectName: 'monorail'},
41 {},
42 ]};
43 const actualRun = replacer(match, components);
44 assert.deepEqual(
45 actualRun,
46 [{
47 tag: 'a',
48 css: 'strike-through',
49 href: '/p/monorail/issues/detail?id=1234',
50 title: 'Issue summary',
51 content: str,
52 }],
53 );
54 });
55
56 it('Replace crbug with found components, with comment', () => {
57 const str = 'crbug.com/monorail/1234#c1';
58 const match = refRegs[0].exec(str);
59 refRegs[0].lastIndex = 0;
60 const components = {
61 closedRefs: [
62 {summary: 'Issue summary', localId: 1234, projectName: 'monorail'},
63 {},
64 ]};
65 const actualRun = replacer(match, components);
66 assert.deepEqual(
67 actualRun,
68 [{
69 tag: 'a',
70 css: 'strike-through',
71 href: '/p/monorail/issues/detail?id=1234#c1',
72 title: 'Issue summary',
73 content: str,
74 }],
75 );
76 });
77
78 it('Replace crbug with default project_name', () => {
79 const str = 'crbug.com/1234';
80 const match = refRegs[0].exec(str);
81 refRegs[0].lastIndex = 0;
82 const components = {
83 openRefs: [
84 {localId: 134},
85 {summary: 'Issue 1234', localId: 1234, projectName: 'chromium'},
86 ],
87 };
88 const actualRun = replacer(match, components);
89 assert.deepEqual(
90 actualRun,
91 [{
92 tag: 'a',
93 href: '/p/chromium/issues/detail?id=1234',
94 css: '',
95 title: 'Issue 1234',
96 content: str,
97 }],
98 );
99 });
100
101 it('Replace crbug incomplete responses', () => {
102 const str = 'crbug.com/1234';
103 const match = refRegs[0].exec(str);
104 refRegs[0].lastIndex = 0;
105 const components = {
106 openRefs: [{localId: 1234}, {projectName: 'chromium'}],
107 closedRefs: [{localId: 1234}, {projectName: 'chromium'}],
108 };
109 const actualRun = replacer(match, components);
110 assert.deepEqual(actualRun, [{content: str}]);
111 });
112
113 it('Replace crbug passed project name is ignored', () => {
114 const str = 'crbug.com/1234';
115 const match = refRegs[0].exec(str);
116 refRegs[0].lastIndex = 0;
117 const components = {
118 openRefs: [
119 {localId: 134},
120 {summary: 'Issue 1234', localId: 1234, projectName: 'chromium'},
121 ],
122 };
123 const actualRun = replacer(match, components, 'foo');
124 assert.deepEqual(
125 actualRun,
126 [{
127 tag: 'a',
128 href: '/p/chromium/issues/detail?id=1234',
129 css: '',
130 title: 'Issue 1234',
131 content: str,
132 }],
133 );
134 });
135
136 it('Replace crbug with no found components', () => {
137 const str = 'crbug.com/1234';
138 const match = refRegs[0].exec(str);
139 refRegs[0].lastIndex = 0;
140 const components = {};
141 const actualRun = replacer(match, components);
142 assert.deepEqual(actualRun, [{content: str}]);
143 });
144
145 it('Replace crbug with no issue summary', () => {
146 const str = 'crbug.com/monorail/1234';
147 const match = refRegs[0].exec(str);
148 refRegs[0].lastIndex = 0;
149 const components = {
150 closedRefs: [
151 {localId: 1234, projectName: 'monorail'},
152 {},
153 ]};
154 const actualRun = replacer(match, components);
155 assert.deepEqual(
156 actualRun,
157 [{
158 tag: 'a',
159 css: 'strike-through',
160 href: '/p/monorail/issues/detail?id=1234',
161 title: '',
162 content: str,
163 }],
164 );
165 });
166 });
167
168 describe('regular tracker component functions', () => {
169 const {extractRefs, refRegs, replacer} =
170 components.get('04-tracker-regular');
171 const str = 'bugs=123, monorail:234 or #345 and PROJ:#456';
172 const match = refRegs[0].exec(str);
173 refRegs[0].lastIndex = 0;
174
175 it('Extract tracker projects and local ids', () => {
176 const actualRefs = extractRefs(match, 'foo-project');
177 assert.deepEqual(
178 actualRefs,
179 [{projectName: 'foo-project', localId: '123'},
180 {projectName: 'monorail', localId: '234'},
181 {projectName: 'monorail', localId: '345'},
182 {projectName: 'PROJ', localId: '456'}]);
183 });
184
185 it('Replace tracker refs.', () => {
186 const components = {
187 openRefs: [
188 {summary: 'sum', projectName: 'monorail', localId: 888},
189 {summary: 'ma', projectName: 'chromium', localId: '123'},
190 ],
191 closedRefs: [
192 {summary: 'ry', projectName: 'proj', localId: 456},
193 ],
194 };
195 const actualTextRuns = replacer(match, components, 'chromium');
196 assert.deepEqual(
197 actualTextRuns,
198 [
199 {content: 'bugs='},
200 {
201 tag: 'a',
202 href: '/p/chromium/issues/detail?id=123',
203 css: '',
204 title: 'ma',
205 content: '123',
206 },
207 {content: ', '},
208 {content: 'monorail:234'},
209 {content: ' or '},
210 {content: '#345'},
211 {content: ' and '},
212 {
213 tag: 'a',
214 href: '/p/PROJ/issues/detail?id=456',
215 css: 'strike-through',
216 title: 'ry',
217 content: 'PROJ:#456',
218 },
219 ],
220 );
221 });
222
223 it('Replace tracker refs mixed case refs.', () => {
224 const components = {
225 openRefs: [
226 {projectName: 'mOnOrAIl', localId: 234},
227 ],
228 closedRefs: [
229 {projectName: 'LeMuR', localId: 123},
230 ],
231 };
232 const actualTextRuns = replacer(match, components, 'lEmUr');
233 assert.deepEqual(
234 actualTextRuns,
235 [
236 {content: 'bugs='},
237 {
238 tag: 'a',
239 href: '/p/lEmUr/issues/detail?id=123',
240 css: 'strike-through',
241 title: '',
242 content: '123',
243 },
244 {content: ', '},
245 {
246 tag: 'a',
247 href: '/p/monorail/issues/detail?id=234',
248 css: '',
249 title: '',
250 content: 'monorail:234',
251 },
252 {content: ' or '},
253 {content: '#345'},
254 {content: ' and '},
255 {content: 'PROJ:#456'},
256 ],
257 );
258 });
259
260 it('Recognizes Fixed: syntax', () => {
261 const str = 'Fixed : 123, proj:456';
262 const match = refRegs[0].exec(str);
263 refRegs[0].lastIndex = 0;
264
265 const components = {
266 openRefs: [
267 {summary: 'summ', projectName: 'chromium', localId: 123},
268 ],
269 closedRefs: [
270 {summary: 'ary', projectName: 'proj', localId: 456},
271 ],
272 };
273
274 const actualTextRuns = replacer(match, components, 'chromium');
275 assert.deepEqual(
276 actualTextRuns,
277 [
278 {
279 tag: 'a',
280 href: '/p/chromium/issues/detail?id=123',
281 css: '',
282 title: 'summ',
283 content: 'Fixed : 123',
284 },
285 {content: ', '},
286 {
287 tag: 'a',
288 href: '/p/proj/issues/detail?id=456',
289 css: 'strike-through',
290 title: 'ary',
291 content: 'proj:456',
292 },
293 ],
294 );
295 });
296 });
297
298 describe('user email component functions', () => {
299 const {extractRefs, refRegs, replacer} = components.get('03-user-emails');
300 const str = 'We should ask User1@gmail.com to confirm.';
301 const match = refRegs[0].exec(str);
302 refRegs[0].lastIndex = 0;
303
304 it('Extract user email', () => {
305 const actualEmail = extractRefs(match, 'unusedProjectName');
306 assert.equal('User1@gmail.com', actualEmail);
307 });
308
309 it('Replace existing user.', () => {
310 const components = {
311 users: [{displayName: 'user2@gmail.com'},
312 {displayName: 'user1@gmail.com'}]};
313 const actualTextRun = replacer(match, components);
314 assert.deepEqual(
315 actualTextRun,
316 [{tag: 'a', href: '/u/User1@gmail.com', content: 'User1@gmail.com'}],
317 );
318 });
319
320 it('Replace non-existent user.', () => {
321 const actualTextRun = replacer(match, {});
322 assert.deepEqual(
323 actualTextRun,
324 [{
325 tag: 'a',
326 href: 'mailto:User1@gmail.com',
327 content: 'User1@gmail.com',
328 }],
329 );
330 });
331 });
332
333 describe('full url component functions.', () => {
334 const {refRegs, replacer} = components.get('02-full-urls');
335
336 it('test full link regex string', () => {
337 const isLinkRE = refRegs[0];
338 const str =
339 'https://www.go.com ' +
340 'nospacehttps://www.blah.com http://website.net/other="(}])"><)';
341 let match;
342 const actualMatches = [];
343 while ((match = isLinkRE.exec(str)) !== null) {
344 actualMatches.push(match[0]);
345 }
346 assert.deepEqual(
347 actualMatches,
348 ['https://www.go.com', 'http://website.net/other="(}])">']);
349 });
350
351 it('Replace URL existing http', () => {
352 const match = refRegs[0].exec('link here: (https://website.net/other="here").');
353 refRegs[0].lastIndex = 0;
354 const actualTextRuns = replacer(match);
355 assert.deepEqual(
356 actualTextRuns,
357 [{tag: 'a',
358 href: 'https://website.net/other="here"',
359 content: 'https://website.net/other="here"',
360 },
361 {content: ').'}],
362 );
363 });
364
365 it('Replace URL with short-link as substring', () => {
366 const match = refRegs[0].exec('https://website.net/who/me/yes/you');
367 refRegs[0].lastIndex = 0;
368 const actualTextRuns = replacer(match);
369
370 assert.deepEqual(
371 actualTextRuns,
372 [{tag: 'a',
373 href: 'https://website.net/who/me/yes/you',
374 content: 'https://website.net/who/me/yes/you',
375 }],
376 );
377 });
378
379 it('Replace URL with email as substring', () => {
380 const match = refRegs[0].exec('https://website.net/who/foo@example.com');
381 refRegs[0].lastIndex = 0;
382 const actualTextRuns = replacer(match);
383
384 assert.deepEqual(
385 actualTextRuns,
386 [{tag: 'a',
387 href: 'https://website.net/who/foo@example.com',
388 content: 'https://website.net/who/foo@example.com',
389 }],
390 );
391 });
392 });
393
394 describe('shorthand url component functions.', () => {
395 const {refRegs, replacer} = components.get('05-linkify-shorthand');
396
397 it('Short link does not match URL with short-link as substring', () => {
398 refRegs[0].lastIndex = 0;
399 assert.isNull(refRegs[0].exec('https://website.net/who/me/yes/you'));
400 });
401
402 it('test short link regex string', () => {
403 const shortLinkRE = refRegs[0];
404 const str =
405 'go/shortlinks ./_go/shortlinks bo/short bo/1234 ' +
406 'https://who/shortlinks go/hey/?wct=(go)';
407 let match;
408 const actualMatches = [];
409 while ((match = shortLinkRE.exec(str)) !== null) {
410 actualMatches.push(match[0]);
411 }
412 assert.deepEqual(
413 actualMatches,
414 ['go/shortlinks', ' https://who/shortlinks', ' go/hey/?wct=(go)'],
415 );
416 });
417
418 it('test numeric short link regex string', () => {
419 const shortNumLinkRE = refRegs[1];
420 const str = 'go/nono omg/ohno omg/123 .cl/123 b/1234';
421 let match;
422 const actualMatches = [];
423 while ((match = shortNumLinkRE.exec(str)) !== null) {
424 actualMatches.push(match[0]);
425 }
426 assert.deepEqual(actualMatches, [' omg/123', ' b/1234']);
427 });
428
429 it('test fuchsia short links', () => {
430 const shortNumLinkRE = refRegs[1];
431 const str = 'ignore fxr/123 fxrev/789 fxb/456 tqr/123 ';
432 let match;
433 const actualMatches = [];
434 while ((match = shortNumLinkRE.exec(str)) !== null) {
435 actualMatches.push(match[0]);
436 }
437 assert.deepEqual(actualMatches, [' fxr/123', ' fxrev/789', ' fxb/456',
438 ' tqr/123']);
439 });
440
441 it('test implied link regex string', () => {
442 const impliedLinkRE = refRegs[2];
443 const str = 'incomplete.com .help.com hey.net/other="(blah)"';
444 let match;
445 const actualMatches = [];
446 while ((match = impliedLinkRE.exec(str)) !== null) {
447 actualMatches.push(match[0]);
448 }
449 assert.deepEqual(
450 actualMatches, ['incomplete.com', ' hey.net/other="(blah)"']);
451 });
452
453 it('test implied link alternate domains', () => {
454 const impliedLinkRE = refRegs[2];
455 const str = 'what.net hey.edu google.org fuchsia.dev ignored.domain';
456 let match;
457 const actualMatches = [];
458 while ((match = impliedLinkRE.exec(str)) !== null) {
459 actualMatches.push(match[0]);
460 }
461 assert.deepEqual(
462 actualMatches, ['what.net', ' hey.edu', ' google.org',
463 ' fuchsia.dev']);
464 });
465
466 it('Replace URL plain text', () => {
467 const match = refRegs[2].exec('link here: (website.net/other="here").');
468 refRegs[2].lastIndex = 0;
469 const actualTextRuns = replacer(match);
470 assert.deepEqual(
471 actualTextRuns,
472 [{content: '('},
473 {tag: 'a',
474 href: 'https://website.net/other="here"',
475 content: 'website.net/other="here"',
476 },
477 {content: ').'}],
478 );
479 });
480
481 it('Replace short link existing http', () => {
482 const match = refRegs[0].exec('link here: (http://who/me).');
483 refRegs[0].lastIndex = 0;
484 const actualTextRuns = replacer(match);
485 assert.deepEqual(
486 actualTextRuns,
487 [{content: '('},
488 {tag: 'a',
489 href: 'http://who/me',
490 content: 'http://who/me',
491 },
492 {content: ').'}],
493 );
494 });
495
496 it('Replace short-link plain text', () => {
497 const match = refRegs[0].exec('link here: (who/me).');
498 refRegs[0].lastIndex = 0;
499 const actualTextRuns = replacer(match);
500 assert.deepEqual(
501 actualTextRuns,
502 [{content: '('},
503 {tag: 'a',
504 href: 'http://who/me',
505 content: 'who/me',
506 },
507 {content: ').'}],
508 );
509 });
510
511 it('Replace short-link plain text initial characters', () => {
512 const match = refRegs[0].exec('link here: who/me');
513 refRegs[0].lastIndex = 0;
514 const actualTextRuns = replacer(match);
515 assert.deepEqual(
516 actualTextRuns,
517 [{content: ' '},
518 {tag: 'a',
519 href: 'http://who/me',
520 content: 'who/me',
521 }],
522 );
523 });
524
525 it('Replace URL short link', () => {
526 ['go', 'g', 'shortn', 'who', 'teams'].forEach((prefix) => {
527 const match = refRegs[0].exec(`link here: (${prefix}/abcd).`);
528 refRegs[0].lastIndex = 0;
529 const actualTextRuns = replacer(match);
530 assert.deepEqual(
531 actualTextRuns,
532 [{content: '('},
533 {tag: 'a',
534 href: `http://${prefix}/abcd`,
535 content: `${prefix}/abcd`,
536 },
537 {content: ').'}],
538 );
539 });
540 });
541
542 it('Replace URL numeric short link', () => {
543 ['b', 't', 'o', 'omg', 'cl', 'cr'].forEach((prefix) => {
544 const match = refRegs[1].exec(`link here: (${prefix}/1234).`);
545 refRegs[1].lastIndex = 0;
546 const actualTextRuns = replacer(match);
547 assert.deepEqual(
548 actualTextRuns,
549 [{content: '('},
550 {tag: 'a',
551 href: `http://${prefix}/1234`,
552 content: `${prefix}/1234`,
553 }],
554 );
555 });
556 });
557 });
558
559 describe('versioncontrol component functions.', () => {
560 const {refRegs, replacer} = components.get('06-versioncontrol');
561
562 it('test git hash regex', () => {
563 const gitHashRE = refRegs[0];
564 const str =
565 'r63b72a71d5fbce6739c51c3846dd94bd62b91091 blha blah ' +
566 'Revision 63b72a71d5fbce6739c51c3846dd94bd62b91091 blah balh ' +
567 '63b72a71d5fbce6739c51c3846dd94bd62b91091 ' +
568 'Revision63b72a71d5fbce6739c51c3846dd94bd62b91091';
569 let match;
570 const actualMatches = [];
571 while ((match = gitHashRE.exec(str)) !== null) {
572 actualMatches.push(match[0]);
573 }
574 assert.deepEqual(
575 actualMatches, [
576 'r63b72a71d5fbce6739c51c3846dd94bd62b91091',
577 'Revision 63b72a71d5fbce6739c51c3846dd94bd62b91091',
578 '63b72a71d5fbce6739c51c3846dd94bd62b91091',
579 ]);
580 });
581
582 it('test svn regex', () => {
583 const svnRE = refRegs[1];
584 const str =
585 'r1234 blah blah ' +
586 'Revision 123456 blah balh ' +
587 'r12345678' +
588 '1234';
589 let match;
590 const actualMatches = [];
591 while ((match = svnRE.exec(str)) !== null) {
592 actualMatches.push(match[0]);
593 }
594 assert.deepEqual(
595 actualMatches, [
596 'r1234',
597 'Revision 123456',
598 ]);
599 });
600
601 it('replace revision refs plain text', () => {
602 const str = 'r63b72a71d5fbce6739c51c3846dd94bd62b91091';
603 const match = refRegs[0].exec(str);
604 const actualTextRuns = replacer(
605 match, null, null, 'https://crrev.com/{revnum}');
606 refRegs[0].lastIndex = 0;
607 assert.deepEqual(
608 actualTextRuns,
609 [{
610 content: 'r63b72a71d5fbce6739c51c3846dd94bd62b91091',
611 tag: 'a',
612 href: 'https://crrev.com/63b72a71d5fbce6739c51c3846dd94bd62b91091',
613 }]);
614 });
615
616 it('replace revision refs plain text different template', () => {
617 const str = 'r63b72a71d5fbce6739c51c3846dd94bd62b91091';
618 const match = refRegs[0].exec(str);
619 const actualTextRuns = replacer(
620 match, null, null, 'https://foo.bar/{revnum}/baz');
621 refRegs[0].lastIndex = 0;
622 assert.deepEqual(
623 actualTextRuns,
624 [{
625 content: 'r63b72a71d5fbce6739c51c3846dd94bd62b91091',
626 tag: 'a',
627 href: 'https://foo.bar/63b72a71d5fbce6739c51c3846dd94bd62b91091/baz',
628 }]);
629 });
630 });
631
632
633 describe('markupAutolinks tests', () => {
634 const componentRefs = new Map();
635 componentRefs.set('01-tracker-crbug', {
636 openRefs: [],
637 closedRefs: [{projectName: 'chromium', localId: 99}],
638 });
639 componentRefs.set('04-tracker-regular', {
640 openRefs: [{summary: 'monorail', projectName: 'monorail', localId: 123}],
641 closedRefs: [{projectName: 'chromium', localId: 456}],
642 });
643 componentRefs.set('03-user-emails', {
644 users: [{displayName: 'user2@example.com'}],
645 });
646
647 it('empty string does not cause error', () => {
648 const actualTextRuns = markupAutolinks('', componentRefs);
649 assert.deepEqual(actualTextRuns, []);
650 });
651
652 it('no nested autolinking', () => {
653 const plainString = 'test <b>autolinking go/testlink</b> is not nested';
654 const actualTextRuns = markupAutolinks(plainString, componentRefs);
655 assert.deepEqual(
656 actualTextRuns, [
657 {content: 'test '},
658 {content: 'autolinking go/testlink', tag: 'b'},
659 {content: ' is not nested'},
660 ]);
661 });
662
663 it('URLs are autolinked', () => {
664 const plainString = 'this http string contains http://google.com for you';
665 const actualTextRuns = markupAutolinks(plainString, componentRefs);
666 assert.deepEqual(
667 actualTextRuns, [
668 {content: 'this http string contains '},
669 {content: 'http://google.com', tag: 'a', href: 'http://google.com'},
670 {content: ' for you'},
671 ]);
672 });
673
674 it('different component types are correctly linked', () => {
675 const plainString = 'test (User2@example.com and crbug.com/99) get link';
676 const actualTextRuns = markupAutolinks(plainString, componentRefs);
677 assert.deepEqual(
678 actualTextRuns,
679 [
680 {
681 content: 'test (',
682 },
683 {
684 content: 'User2@example.com',
685 tag: 'a',
686 href: '/u/User2@example.com',
687 },
688 {
689 content: ' and ',
690 },
691 {
692 content: 'crbug.com/99',
693 tag: 'a',
694 href: '/p/chromium/issues/detail?id=99',
695 title: '',
696 css: 'strike-through',
697 },
698 {
699 content: ') get link',
700 },
701 ],
702 );
703 });
704
705 it('Invalid issue refs do not get linked', () => {
706 const plainString =
707 'bug123, bug 123a, bug-123 and https://bug:123.example.com ' +
708 'do not get linked.';
709 const actualTextRuns= markupAutolinks(
710 plainString, componentRefs, 'chromium');
711 assert.deepEqual(
712 actualTextRuns,
713 [
714 {
715 content: 'bug123, bug 123a, bug-123 and ',
716 },
717 {
718 content: 'https://bug:123.example.com',
719 tag: 'a',
720 href: 'https://bug:123.example.com',
721 },
722 {
723 content: ' do not get linked.',
724 },
725 ]);
726 });
727
728 it('Only existing issues get linked', () => {
729 const plainString =
730 'only existing bugs = 456, monorail:123, 234 and chromium:345 get ' +
731 'linked';
732 const actualTextRuns = markupAutolinks(
733 plainString, componentRefs, 'chromium');
734 assert.deepEqual(
735 actualTextRuns,
736 [
737 {
738 content: 'only existing ',
739 },
740 {
741 content: 'bugs = ',
742 },
743 {
744 content: '456',
745 tag: 'a',
746 href: '/p/chromium/issues/detail?id=456',
747 title: '',
748 css: 'strike-through',
749 },
750 {
751 content: ', ',
752 },
753 {
754 content: 'monorail:123',
755 tag: 'a',
756 href: '/p/monorail/issues/detail?id=123',
757 title: 'monorail',
758 css: '',
759 },
760 {
761 content: ', ',
762 },
763 {
764 content: '234',
765 },
766 {
767 content: ' and ',
768 },
769 {
770 content: 'chromium:345',
771 },
772 {
773 content: ' ',
774 },
775 {
776 content: 'get linked',
777 },
778 ],
779 );
780 });
781
782 it('multilined bolds are not bolded', () => {
783 const plainString =
784 '<b>no multiline bolding \n' +
785 'not allowed go/survey is still linked</b>';
786 const actualTextRuns = markupAutolinks(plainString, componentRefs);
787 assert.deepEqual(
788 actualTextRuns, [
789 {content: '<b>no multiline bolding '},
790 {tag: 'br'},
791 {content: 'not allowed'},
792 {content: ' '},
793 {content: 'go/survey', tag: 'a', href: 'http://go/survey'},
794 {content: ' is still linked</b>'},
795 ]);
796
797 const plainString2 =
798 '<b>no multiline bold \rwith carriage \r\nreturns</b>';
799 const actualTextRuns2 = markupAutolinks(plainString2, componentRefs);
800
801 assert.deepEqual(
802 actualTextRuns2, [
803 {content: '<b>no multiline bold '},
804 {tag: 'br'},
805 {content: 'with carriage '},
806 {tag: 'br'},
807 {content: 'returns</b>'},
808 ]);
809 });
810
811 // Check that comment references are properly linked.
812 it('comments are correctly linked', () => {
813 const plainString =
814 'comment1, comment : 5, Comment =10, comment #4, #c57';
815 const actualTextRuns = markupAutolinks(plainString, componentRefs);
816 assert.deepEqual(
817 actualTextRuns, [
818 {
819 content: 'comment1',
820 tag: 'a',
821 href: '#c1',
822 },
823 {
824 content: ', ',
825 },
826 {
827 content: 'comment : 5',
828 tag: 'a',
829 href: '#c5',
830 },
831 {
832 content: ', ',
833 },
834 {
835 content: 'Comment =10',
836 tag: 'a',
837 href: '#c10',
838 },
839 {
840 content: ', ',
841 },
842 {
843 content: 'comment #4',
844 tag: 'a',
845 href: '#c4',
846 },
847 {
848 content: ', ',
849 },
850 {
851 content: '#c57',
852 tag: 'a',
853 href: '#c57',
854 },
855 ],
856 );
857 });
858
859 // Check that improperly formatted comment references do not get linked.
860 it('comments that should not be linked', () => {
861 const plainString =
862 'comment number 4, comment-4, comment= # 5, comment#c56';
863 const actualTextRuns = markupAutolinks(plainString, componentRefs);
864 assert.deepEqual(
865 actualTextRuns, [
866 {
867 content: 'comment number 4, comment-4, comment= # 5, comment#c56',
868 },
869 ],
870 );
871 });
872
873 // Check that issue/comment references are properly linked.
874 it('issue/comment that should be linked', () => {
875 const plainString =
876 'issue 2 comment 3, issue2 comment 9, bug #3 comment=4';
877 const actualTextRuns = markupAutolinks(plainString, componentRefs);
878 assert.deepEqual(
879 actualTextRuns, [
880 {
881 content: 'issue 2 comment 3',
882 tag: 'a',
883 href: '?id=2#c3',
884 },
885 {
886 content: ', ',
887 },
888 {
889 content: 'issue2 comment 9',
890 tag: 'a',
891 href: '?id=2#c9',
892 },
893 {
894 content: ', ',
895 },
896 {
897 content: 'bug #3 comment=4',
898 tag: 'a',
899 href: '?id=3#c4',
900 },
901 ],
902 );
903 });
904
905 // Check that improperly formatted issue/comment references do not get linked.
906 it('issue/comment that should not be linked', () => {
907 const plainString =
908 'theissue 2comment 3, issue2comment 9';
909 const actualTextRuns = markupAutolinks(plainString, componentRefs);
910 assert.deepEqual(
911 actualTextRuns, [
912 {
913 content: 'theissue 2comment 3, issue2comment 9',
914 },
915 ],
916 );
917 });
918 });
919
920 describe('getReferencedArtifacts', () => {
921 beforeEach(() => {
922 sinon.stub(prpcClient, 'call').returns(Promise.resolve({}));
923 });
924
925 afterEach(() => {
926 prpcClient.call.restore();
927 });
928
929 it('filters invalid issue refs', async () => {
930 const comments = [
931 {
932 content: 'issue 0 issue 1 Bug: chromium:3 Bug: chromium:0',
933 },
934 ];
935 autolink.getReferencedArtifacts(comments, 'proj');
936 assert.isTrue(prpcClient.call.calledWith(
937 'monorail.Issues',
938 'ListReferencedIssues',
939 {
940 issueRefs: [
941 {projectName: 'proj', localId: '1'},
942 {projectName: 'chromium', localId: '3'},
943 ],
944 },
945 ));
946 });
947 });
948});