@covalent/markdown 0.0.0-COVALENT

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,786 @@
1
+ import {
2
+ TestBed,
3
+ waitForAsync,
4
+ ComponentFixture,
5
+ tick,
6
+ fakeAsync,
7
+ } from '@angular/core/testing';
8
+ import { ApplicationRef, Component } from '@angular/core';
9
+ import { By } from '@angular/platform-browser';
10
+ import { CovalentMarkdownModule } from './markdown.module';
11
+ import { TdMarkdownComponent } from './markdown.component';
12
+
13
+ // Implementing scrollIntoView since its not implemented JSDOM
14
+ window.HTMLElement.prototype.scrollIntoView = function () {
15
+ // noop
16
+ };
17
+ window.scrollTo = function () {
18
+ // noop
19
+ };
20
+
21
+ function anchorTestMarkdown(): string {
22
+ const heading1 = 'Heading 1';
23
+ const heading2 = 'Heading 2';
24
+ let str = `* **[${heading1}](#heading-1)** \n * **[${heading2}](#heading-2)** \n`;
25
+ const arr: number[] = Array(100).fill(0);
26
+ arr.forEach(() => {
27
+ str += '\n * item \n';
28
+ });
29
+ str += `\n # ${heading1} \n`;
30
+ arr.forEach(() => {
31
+ str += '\n * item \n';
32
+ });
33
+ str += `\n # ${heading2} \n`;
34
+ return str;
35
+ }
36
+
37
+ function anchorTestNonEnglishMarkdown(): string {
38
+ const heading1 = 'L10Nテスト';
39
+ const heading2 = 'すべてが楽しいです!';
40
+ const heading3 = '誰もが一生に一度ローカライズする必要があります。';
41
+ let str = `* **[${heading1}](#${heading1})** \n * **[${heading2}](#${heading2})** \n * **[${heading3}](#${heading3})** \n`;
42
+ const arr: number[] = Array(100).fill(0);
43
+ arr.forEach(() => {
44
+ str += '\n * item \n';
45
+ });
46
+ str += `\n # ${heading1} \n`;
47
+ arr.forEach(() => {
48
+ str += '\n * item \n';
49
+ });
50
+ str += `\n # ${heading2} \n`;
51
+ arr.forEach(() => {
52
+ str += '\n * item \n';
53
+ });
54
+ str += `\n # ${heading3} \n`;
55
+ return str;
56
+ }
57
+
58
+ describe('Component: Markdown', () => {
59
+ beforeEach(waitForAsync(() => {
60
+ TestBed.configureTestingModule({
61
+ imports: [
62
+ TdMarkdownEmptyStaticContentTestRenderingComponent,
63
+ TdMarkdownStaticContentTestRenderingComponent,
64
+ TdMarkdownDymanicContentTestRenderingComponent,
65
+ TdMarkdownSimpleLineBreaksTestRenderingComponent,
66
+
67
+ TdMarkdownEmptyStaticContentTestEventsComponent,
68
+ TdMarkdownStaticContentTestEventsComponent,
69
+ TdMarkdownDynamicContentTestEventsComponent,
70
+ TdMarkdownAnchorsTestEventsComponent,
71
+ TdMarkdownLinksTestEventsComponent,
72
+ ],
73
+ });
74
+ TestBed.compileComponents();
75
+ }));
76
+
77
+ describe('Rendering: ', () => {
78
+ it('should render empty static content', waitForAsync(() => {
79
+ const fixture: ComponentFixture<TdMarkdownEmptyStaticContentTestRenderingComponent> =
80
+ TestBed.createComponent(
81
+ TdMarkdownEmptyStaticContentTestRenderingComponent
82
+ );
83
+ const element: HTMLElement = fixture.nativeElement;
84
+
85
+ expect(
86
+ fixture.debugElement
87
+ .query(By.css('td-markdown'))
88
+ .nativeElement.textContent.trim()
89
+ ).toBe(``);
90
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
91
+ fixture.detectChanges();
92
+ fixture.whenStable().then(() => {
93
+ fixture.detectChanges();
94
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
95
+ expect(
96
+ fixture.debugElement
97
+ .query(By.css('td-markdown'))
98
+ .nativeElement.textContent.trim()
99
+ ).toBe('');
100
+ });
101
+ }));
102
+
103
+ it('should render markup from static content', waitForAsync(() => {
104
+ const fixture: ComponentFixture<TdMarkdownStaticContentTestRenderingComponent> =
105
+ TestBed.createComponent(TdMarkdownStaticContentTestRenderingComponent);
106
+ const element: HTMLElement = fixture.nativeElement;
107
+
108
+ expect(
109
+ fixture.debugElement
110
+ .query(By.css('td-markdown'))
111
+ .nativeElement.textContent.trim()
112
+ ).toBe(
113
+ `
114
+ # title
115
+
116
+ * list item`.trim()
117
+ );
118
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
119
+ fixture.detectChanges();
120
+ fixture.whenStable().then(() => {
121
+ fixture.detectChanges();
122
+ expect(element.querySelector('td-markdown div')).toBeTruthy();
123
+ expect(
124
+ element.querySelector('td-markdown div h1')?.textContent?.trim()
125
+ ).toBe('title');
126
+ expect(
127
+ element.querySelector('td-markdown div ul li')?.textContent?.trim()
128
+ ).toBe('list item');
129
+ });
130
+ }));
131
+
132
+ it('should render newlines as <br/> if simpleLineBreaks is true', waitForAsync(() => {
133
+ const fixture: ComponentFixture<TdMarkdownSimpleLineBreaksTestRenderingComponent> =
134
+ TestBed.createComponent(
135
+ TdMarkdownSimpleLineBreaksTestRenderingComponent
136
+ );
137
+ const component: TdMarkdownSimpleLineBreaksTestRenderingComponent =
138
+ fixture.debugElement.componentInstance;
139
+ component.simpleLineBreaks = true;
140
+ const element: HTMLElement = fixture.nativeElement;
141
+
142
+ expect(
143
+ fixture.debugElement
144
+ .query(By.css('td-markdown'))
145
+ .nativeElement.textContent.trim()
146
+ ).toBe(
147
+ `
148
+ first line
149
+ second line
150
+ third line
151
+ `.trim()
152
+ );
153
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
154
+ fixture.detectChanges();
155
+ fixture.whenStable().then(() => {
156
+ fixture.detectChanges();
157
+ fixture.whenStable().then(() => {
158
+ fixture.detectChanges();
159
+ expect(element.querySelector('td-markdown div')).toBeTruthy();
160
+ expect(
161
+ element.querySelector('td-markdown')?.querySelectorAll('br').length
162
+ ).toBe(2);
163
+ });
164
+ });
165
+ }));
166
+
167
+ it('should not render newlines as <br/> if simpleLineBreaks is false', waitForAsync(() => {
168
+ const fixture: ComponentFixture<TdMarkdownSimpleLineBreaksTestRenderingComponent> =
169
+ TestBed.createComponent(
170
+ TdMarkdownSimpleLineBreaksTestRenderingComponent
171
+ );
172
+ const component: TdMarkdownSimpleLineBreaksTestRenderingComponent =
173
+ fixture.debugElement.componentInstance;
174
+ component.simpleLineBreaks = false;
175
+ const element: HTMLElement = fixture.nativeElement;
176
+
177
+ expect(
178
+ fixture.debugElement
179
+ .query(By.css('td-markdown'))
180
+ .nativeElement.textContent.trim()
181
+ ).toBe(
182
+ `
183
+ first line
184
+ second line
185
+ third line
186
+ `.trim()
187
+ );
188
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
189
+ fixture.detectChanges();
190
+ fixture.whenStable().then(() => {
191
+ fixture.detectChanges();
192
+ fixture.whenStable().then(() => {
193
+ fixture.detectChanges();
194
+ expect(element.querySelector('td-markdown div')).toBeTruthy();
195
+ expect(
196
+ element.querySelector('td-markdown')?.querySelectorAll('br').length
197
+ ).toBe(0);
198
+ });
199
+ });
200
+ }));
201
+
202
+ it('should render markup from dynamic content', waitForAsync(() => {
203
+ const fixture: ComponentFixture<TdMarkdownDymanicContentTestRenderingComponent> =
204
+ TestBed.createComponent(TdMarkdownDymanicContentTestRenderingComponent);
205
+ const component: TdMarkdownDymanicContentTestRenderingComponent =
206
+ fixture.debugElement.componentInstance;
207
+ component.content = `
208
+ # another title
209
+
210
+ ## subtitle
211
+
212
+ \`\`\`
213
+ pseudo code
214
+ \`\`\``;
215
+ const element: HTMLElement = fixture.nativeElement;
216
+
217
+ expect(
218
+ fixture.debugElement
219
+ .query(By.css('td-markdown'))
220
+ .nativeElement.textContent.trim()
221
+ ).toBe('');
222
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
223
+ fixture.detectChanges();
224
+ fixture.whenStable().then(() => {
225
+ fixture.detectChanges();
226
+ expect(element.querySelector('td-markdown div')).toBeTruthy();
227
+ expect(
228
+ element.querySelector('td-markdown div h1')?.textContent?.trim()
229
+ ).toBe('another title');
230
+ expect(
231
+ element.querySelector('td-markdown div h2')?.textContent?.trim()
232
+ ).toBe('subtitle');
233
+ expect(
234
+ element.querySelector('td-markdown div code')?.textContent?.trim()
235
+ ).toBe('pseudo code');
236
+ });
237
+ }));
238
+
239
+ it('should render markup from dynamic content incorrectly', waitForAsync(() => {
240
+ const fixture: ComponentFixture<TdMarkdownDymanicContentTestRenderingComponent> =
241
+ TestBed.createComponent(TdMarkdownDymanicContentTestRenderingComponent);
242
+ const component: TdMarkdownDymanicContentTestRenderingComponent =
243
+ fixture.debugElement.componentInstance;
244
+ component.content = `
245
+ # another title
246
+
247
+ ## subtitle`;
248
+ const element: HTMLElement = fixture.nativeElement;
249
+
250
+ expect(
251
+ fixture.debugElement
252
+ .query(By.css('td-markdown'))
253
+ .nativeElement.textContent.trim()
254
+ ).toBe('');
255
+ expect(element.querySelector('td-markdown div')).toBeFalsy();
256
+ fixture.detectChanges();
257
+ fixture.whenStable().then(() => {
258
+ fixture.detectChanges();
259
+ expect(element.querySelector('td-markdown div')).toBeTruthy();
260
+ expect(
261
+ element.querySelector('td-markdown div h1')?.textContent?.trim()
262
+ ).toBe('another title');
263
+ expect(element.querySelector('td-markdown div h2')).toBeFalsy();
264
+ expect(
265
+ element.querySelector('td-markdown div')?.textContent?.trim()
266
+ ).toContain('## subtitle');
267
+ });
268
+ }));
269
+
270
+ it('should jump to anchor when anchor input is changed', waitForAsync(async () => {
271
+ const fixture: ComponentFixture<TdMarkdownAnchorsTestEventsComponent> =
272
+ TestBed.createComponent(TdMarkdownAnchorsTestEventsComponent);
273
+ const component: TdMarkdownAnchorsTestEventsComponent =
274
+ fixture.debugElement.componentInstance;
275
+ component.content = anchorTestMarkdown();
276
+
277
+ fixture.detectChanges();
278
+ await fixture.whenStable();
279
+
280
+ window.scrollTo(0, 0);
281
+ const originalScrollPos: number = window.scrollY;
282
+ component.anchor = 'heading 1';
283
+
284
+ fixture.detectChanges();
285
+ await fixture.whenStable();
286
+
287
+ const heading1ScrollPos: number = window.scrollY;
288
+ expect(heading1ScrollPos).toBeGreaterThanOrEqual(originalScrollPos);
289
+
290
+ component.anchor = 'heading 2';
291
+
292
+ fixture.detectChanges();
293
+ await fixture.whenStable();
294
+
295
+ const heading2ScrollPos: number = window.scrollY;
296
+ expect(heading2ScrollPos).toBeGreaterThanOrEqual(heading1ScrollPos);
297
+
298
+ component.anchor = 'heading 1';
299
+
300
+ fixture.detectChanges();
301
+ await fixture.whenStable();
302
+
303
+ expect(window.scrollY).toBeLessThanOrEqual(heading2ScrollPos);
304
+ }));
305
+
306
+ it('should jump to anchor if an anchor link is clicked', waitForAsync(async () => {
307
+ const fixture: ComponentFixture<TdMarkdownAnchorsTestEventsComponent> =
308
+ TestBed.createComponent(TdMarkdownAnchorsTestEventsComponent);
309
+ const component: TdMarkdownAnchorsTestEventsComponent =
310
+ fixture.debugElement.componentInstance;
311
+ component.content = anchorTestMarkdown();
312
+
313
+ fixture.detectChanges();
314
+ await fixture.whenStable();
315
+
316
+ window.scrollTo(0, 0);
317
+ const originalScrollPos: number = window.scrollY;
318
+ const headings: HTMLElement[] =
319
+ fixture.debugElement.nativeElement.querySelectorAll('a');
320
+ const heading1: HTMLElement = headings[0];
321
+ const heading2: HTMLElement = headings[1];
322
+ heading1.click();
323
+
324
+ fixture.detectChanges();
325
+ await fixture.whenStable();
326
+
327
+ const heading1ScrollPos: number = window.scrollY;
328
+ expect(heading1ScrollPos).toBeGreaterThanOrEqual(originalScrollPos);
329
+
330
+ heading2.click();
331
+
332
+ fixture.detectChanges();
333
+ await fixture.whenStable();
334
+
335
+ const heading2ScrollPos: number = window.scrollY;
336
+ expect(heading2ScrollPos).toBeGreaterThanOrEqual(heading1ScrollPos);
337
+
338
+ heading1.click();
339
+
340
+ fixture.detectChanges();
341
+ await fixture.whenStable();
342
+
343
+ expect(window.scrollY).toBeLessThanOrEqual(heading2ScrollPos);
344
+ }));
345
+
346
+ it('should jump to anchor if an anchor link is clicked but should not run change detection', async () => {
347
+ const fixture: ComponentFixture<TdMarkdownAnchorsTestEventsComponent> =
348
+ TestBed.createComponent(TdMarkdownAnchorsTestEventsComponent);
349
+ const component: TdMarkdownAnchorsTestEventsComponent =
350
+ fixture.debugElement.componentInstance;
351
+ component.content = anchorTestMarkdown();
352
+
353
+ fixture.detectChanges();
354
+ await fixture.whenStable();
355
+
356
+ const appRef: ApplicationRef = TestBed.inject(ApplicationRef);
357
+ jest.spyOn(appRef, 'tick');
358
+
359
+ window.scrollTo(0, 0);
360
+ const originalScrollPos: number = window.scrollY;
361
+ const heading: HTMLElement =
362
+ fixture.debugElement.nativeElement.querySelector('a');
363
+
364
+ const event: Event = new Event('click', { bubbles: true });
365
+ jest.spyOn(event, 'preventDefault');
366
+
367
+ heading.dispatchEvent(event);
368
+
369
+ const headingScrollPos: number = window.scrollY;
370
+
371
+ expect(appRef.tick).not.toHaveBeenCalled();
372
+ expect(event.preventDefault).toHaveBeenCalled();
373
+ expect(headingScrollPos).toBeGreaterThanOrEqual(originalScrollPos);
374
+ });
375
+
376
+ it('should emit `contentReady` and should not run change detection', fakeAsync(() => {
377
+ const contentReadySpy: jest.Mock = jest.fn();
378
+ const fixture: ComponentFixture<TdMarkdownAnchorsTestEventsComponent> =
379
+ TestBed.createComponent(TdMarkdownAnchorsTestEventsComponent);
380
+ const component: TdMarkdownAnchorsTestEventsComponent =
381
+ fixture.debugElement.componentInstance;
382
+ component.anchor = 'heading 1';
383
+ component.content = anchorTestMarkdown();
384
+
385
+ const { componentInstance } = fixture.debugElement.query(
386
+ By.directive(TdMarkdownComponent)
387
+ );
388
+ componentInstance.contentReady.subscribe(contentReadySpy);
389
+
390
+ fixture.detectChanges();
391
+
392
+ const appRef: ApplicationRef = TestBed.inject(ApplicationRef);
393
+ jest.spyOn(appRef, 'tick');
394
+
395
+ tick(250);
396
+
397
+ expect(appRef.tick).not.toHaveBeenCalled();
398
+ expect(contentReadySpy).toHaveBeenCalled();
399
+ }));
400
+
401
+ it('should jump to anchor if an anchor link is clicked regardless of lang', waitForAsync(async () => {
402
+ const fixture: ComponentFixture<TdMarkdownAnchorsTestEventsComponent> =
403
+ TestBed.createComponent(TdMarkdownAnchorsTestEventsComponent);
404
+ const component: TdMarkdownAnchorsTestEventsComponent =
405
+ fixture.debugElement.componentInstance;
406
+ component.content = anchorTestNonEnglishMarkdown();
407
+
408
+ fixture.detectChanges();
409
+ await fixture.whenStable();
410
+
411
+ window.scrollTo(0, 0);
412
+ const originalScrollPos: number = window.scrollY;
413
+ const headings: HTMLElement[] =
414
+ fixture.debugElement.nativeElement.querySelectorAll('a');
415
+ const heading1: HTMLElement = headings[0];
416
+ const heading2: HTMLElement = headings[1];
417
+ heading1.click();
418
+
419
+ fixture.detectChanges();
420
+ await fixture.whenStable();
421
+
422
+ const heading1ScrollPos: number = window.scrollY;
423
+ expect(heading1ScrollPos).toBeGreaterThanOrEqual(originalScrollPos);
424
+
425
+ heading2.click();
426
+
427
+ fixture.detectChanges();
428
+ await fixture.whenStable();
429
+
430
+ const heading2ScrollPos: number = window.scrollY;
431
+ expect(heading2ScrollPos).toBeGreaterThanOrEqual(heading1ScrollPos);
432
+
433
+ heading1.click();
434
+
435
+ fixture.detectChanges();
436
+ await fixture.whenStable();
437
+
438
+ expect(window.scrollY).toBeLessThanOrEqual(heading2ScrollPos);
439
+ }));
440
+
441
+ it('should generate the proper urls', waitForAsync(async () => {
442
+ const fixture: ComponentFixture<TdMarkdownLinksTestEventsComponent> =
443
+ TestBed.createComponent(TdMarkdownLinksTestEventsComponent);
444
+ const component: TdMarkdownLinksTestEventsComponent =
445
+ fixture.debugElement.componentInstance;
446
+
447
+ const ANCHOR = '#anchor';
448
+ const CURRENT_MD_FILE = 'GETTING_STARTED.md';
449
+ const ROOT_MD_FILE = 'README.md';
450
+ const NON_RAW_LINK = 'https://github.com/Teradata/covalent/blob/main/';
451
+ const RAW_LINK =
452
+ 'https://raw.githubusercontent.com/Teradata/covalent/main/';
453
+ const RELATIVE_LINK = 'assets/covalent/';
454
+ const EXTERNAL_URL = 'https://angular.dev/';
455
+ const SUB_DIRECTORY = 'docs/';
456
+ const links: string[][] = [
457
+ [`${ANCHOR}`, `${ANCHOR}`],
458
+ [`${NON_RAW_LINK}${ROOT_MD_FILE}`, `${NON_RAW_LINK}${ROOT_MD_FILE}`],
459
+ [
460
+ `${NON_RAW_LINK}${ROOT_MD_FILE}${ANCHOR}`,
461
+ `${NON_RAW_LINK}${ROOT_MD_FILE}${ANCHOR}`,
462
+ ],
463
+ [`${RAW_LINK}${ROOT_MD_FILE}`, `${RAW_LINK}${ROOT_MD_FILE}`],
464
+ [
465
+ `${RAW_LINK}${ROOT_MD_FILE}${ANCHOR}`,
466
+ `${RAW_LINK}${ROOT_MD_FILE}${ANCHOR}`,
467
+ ],
468
+
469
+ [`${EXTERNAL_URL}${ROOT_MD_FILE}`, `${EXTERNAL_URL}${ROOT_MD_FILE}`],
470
+ [
471
+ `${EXTERNAL_URL}${ROOT_MD_FILE}${ANCHOR}`,
472
+ `${EXTERNAL_URL}${ROOT_MD_FILE}${ANCHOR}`,
473
+ ],
474
+ [`${EXTERNAL_URL}`, `${EXTERNAL_URL}`],
475
+ [`${EXTERNAL_URL}${ANCHOR}`, `${EXTERNAL_URL}${ANCHOR}`],
476
+ ];
477
+
478
+ let markdown = '';
479
+
480
+ links.forEach((link: string[]) => {
481
+ markdown += `* [${link[0]}](${link[0]}) \n`;
482
+ });
483
+ component.content = markdown;
484
+ const anchorElements: HTMLAnchorElement[] =
485
+ fixture.debugElement.nativeElement.querySelectorAll('a');
486
+ function checkAnchors(): void {
487
+ Array.from<HTMLAnchorElement>(anchorElements).forEach(
488
+ (anchorElement: HTMLAnchorElement, index: number) => {
489
+ const href = anchorElement.getAttribute('href');
490
+ const expectedHref: string = links[index][1];
491
+ expect(href).toEqual(expectedHref);
492
+ }
493
+ );
494
+ }
495
+
496
+ component.hostedUrl = `${RAW_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
497
+ fixture.detectChanges();
498
+ await fixture.whenStable();
499
+ checkAnchors();
500
+
501
+ component.hostedUrl = `${NON_RAW_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
502
+ fixture.detectChanges();
503
+ await fixture.whenStable();
504
+ checkAnchors();
505
+
506
+ component.hostedUrl = `${RELATIVE_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
507
+ fixture.detectChanges();
508
+ await fixture.whenStable();
509
+ checkAnchors();
510
+ }));
511
+
512
+ it('should generate the proper image urls', waitForAsync(async () => {
513
+ const fixture: ComponentFixture<TdMarkdownLinksTestEventsComponent> =
514
+ TestBed.createComponent(TdMarkdownLinksTestEventsComponent);
515
+ const component: TdMarkdownLinksTestEventsComponent =
516
+ fixture.debugElement.componentInstance;
517
+
518
+ const CURRENT_MD_FILE = 'readme.md';
519
+ const SIBLING_IMG = 'typescript.jpg';
520
+ const ROOT_IMG = 'angular.png';
521
+ const NON_RAW_LINK = 'https://github.com/Teradata/covalent/blob/main/';
522
+ const RAW_LINK =
523
+ 'https://raw.githubusercontent.com/Teradata/covalent/main/';
524
+ const RELATIVE_LINK = 'assets/covalent/';
525
+ const EXTERNAL_IMG =
526
+ 'https://angular.dev/assets/images/logos/angular/angular.svg';
527
+ const SUB_DIRECTORY = 'dir/';
528
+ const SVG_IMG = 'src/assets/icons/covalent.svg';
529
+ // these are not valid image urls
530
+ const images: string[][] = [
531
+ [`./${SIBLING_IMG}`, `${RAW_LINK}${SUB_DIRECTORY}${SIBLING_IMG}`],
532
+ [`${SIBLING_IMG}`, `${RAW_LINK}${SUB_DIRECTORY}${SIBLING_IMG}`],
533
+ [`../${ROOT_IMG}`, `${RAW_LINK}${ROOT_IMG}`],
534
+ [`/${ROOT_IMG}`, `${RAW_LINK}${ROOT_IMG}`],
535
+ [`${RAW_LINK}${ROOT_IMG}`, `${RAW_LINK}${ROOT_IMG}`],
536
+ [`${EXTERNAL_IMG}`, `${EXTERNAL_IMG}`],
537
+ [
538
+ `${NON_RAW_LINK}${SUB_DIRECTORY}${SIBLING_IMG}`,
539
+ `${RAW_LINK}${SUB_DIRECTORY}${SIBLING_IMG}`,
540
+ ],
541
+ [`${NON_RAW_LINK}${SVG_IMG}`, `${RAW_LINK}${SVG_IMG}?sanitize=true`],
542
+ ];
543
+
544
+ let markdown = '';
545
+
546
+ images.forEach((link: string[]) => {
547
+ markdown += `* ![${link[0]}](${link[0]}) \n`;
548
+ });
549
+ component.content = markdown;
550
+
551
+ const imageElements: HTMLImageElement[] =
552
+ fixture.debugElement.nativeElement.querySelectorAll('img');
553
+ function checkImages(): void {
554
+ Array.from(imageElements).forEach(
555
+ (imageElement: HTMLImageElement, index: number) => {
556
+ const src = imageElement.getAttribute('src');
557
+ const expectedSrc: string = images[index][1];
558
+ expect(src).toEqual(expectedSrc);
559
+ }
560
+ );
561
+ }
562
+
563
+ component.hostedUrl = `${RAW_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
564
+ fixture.detectChanges();
565
+ await fixture.whenStable();
566
+ checkImages();
567
+
568
+ component.hostedUrl = `${NON_RAW_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
569
+ fixture.detectChanges();
570
+ await fixture.whenStable();
571
+ checkImages();
572
+
573
+ component.hostedUrl = `${RELATIVE_LINK}${SUB_DIRECTORY}${CURRENT_MD_FILE}`;
574
+ fixture.detectChanges();
575
+ await fixture.whenStable();
576
+ checkImages();
577
+ }));
578
+ });
579
+
580
+ describe('Event bindings: ', () => {
581
+ describe('contentReady event: ', () => {
582
+ it('should be fired only once after display renders empty static content', waitForAsync(() => {
583
+ const fixture: ComponentFixture<TdMarkdownEmptyStaticContentTestEventsComponent> =
584
+ TestBed.createComponent(
585
+ TdMarkdownEmptyStaticContentTestEventsComponent
586
+ );
587
+ const component: TdMarkdownEmptyStaticContentTestEventsComponent =
588
+ fixture.debugElement.componentInstance;
589
+
590
+ jest.spyOn(component, 'tdMarkdownContentIsReady');
591
+
592
+ fixture.detectChanges();
593
+ fixture.whenStable().then(() => {
594
+ fixture.detectChanges();
595
+ expect(component.tdMarkdownContentIsReady).toHaveBeenCalledTimes(1);
596
+ });
597
+ }));
598
+
599
+ it('should be fired only once after display renders markup from static content', waitForAsync(() => {
600
+ const fixture: ComponentFixture<TdMarkdownStaticContentTestEventsComponent> =
601
+ TestBed.createComponent(TdMarkdownStaticContentTestEventsComponent);
602
+ const component: TdMarkdownStaticContentTestEventsComponent =
603
+ fixture.debugElement.componentInstance;
604
+
605
+ jest.spyOn(component, 'tdMarkdownContentIsReady');
606
+
607
+ fixture.detectChanges();
608
+ fixture.whenStable().then(() => {
609
+ fixture.detectChanges();
610
+ expect(component.tdMarkdownContentIsReady).toHaveBeenCalledTimes(1);
611
+ });
612
+ }));
613
+
614
+ it('should be fired only once after display renders initial markup from dynamic content', waitForAsync(() => {
615
+ const fixture: ComponentFixture<TdMarkdownDynamicContentTestEventsComponent> =
616
+ TestBed.createComponent(TdMarkdownDynamicContentTestEventsComponent);
617
+ const component: TdMarkdownDynamicContentTestEventsComponent =
618
+ fixture.debugElement.componentInstance;
619
+ jest.spyOn(component, 'tdMarkdownContentIsReady');
620
+
621
+ // Inital dynamic content
622
+ component.content = `
623
+ # another title
624
+
625
+ ## subtitle
626
+
627
+ \`\`\`
628
+ pseudo code
629
+ \`\`\``;
630
+
631
+ fixture.detectChanges();
632
+ fixture.whenStable().then(() => {
633
+ fixture.detectChanges();
634
+ expect(component.tdMarkdownContentIsReady).toHaveBeenCalledTimes(1);
635
+ });
636
+ }));
637
+
638
+ it(`should be fired twice after changing the initial rendered markup dynamic content`, waitForAsync(() => {
639
+ const fixture: ComponentFixture<TdMarkdownDynamicContentTestEventsComponent> =
640
+ TestBed.createComponent(TdMarkdownDynamicContentTestEventsComponent);
641
+ const component: TdMarkdownDynamicContentTestEventsComponent =
642
+ fixture.debugElement.componentInstance;
643
+ jest.spyOn(component, 'tdMarkdownContentIsReady');
644
+
645
+ component.content = `
646
+ # another title
647
+
648
+ ## subtitle
649
+
650
+ \`\`\`
651
+ pseudo code
652
+ \`\`\``;
653
+
654
+ fixture.detectChanges();
655
+
656
+ component.content = `
657
+ # changed title
658
+
659
+ ## changed subtitle
660
+
661
+ \`\`\`
662
+ changed pseudo code
663
+ \`\`\``;
664
+
665
+ fixture.detectChanges();
666
+
667
+ fixture.whenStable().then(() => {
668
+ fixture.detectChanges();
669
+ expect(component.tdMarkdownContentIsReady).toHaveBeenCalledTimes(2);
670
+ });
671
+ }));
672
+ });
673
+ });
674
+ });
675
+
676
+ // Use the 3 components below to test the rendering requirements of the TdMarkdown component.
677
+ @Component({
678
+ template: ` <td-markdown></td-markdown> `,
679
+ imports: [TdMarkdownComponent],
680
+ })
681
+ class TdMarkdownEmptyStaticContentTestRenderingComponent {}
682
+
683
+ @Component({
684
+ // prettier-ignore
685
+ template: `
686
+ <td-markdown>
687
+ # title
688
+
689
+ * list item
690
+ </td-markdown>`,
691
+ preserveWhitespaces: true,
692
+ imports: [TdMarkdownComponent],
693
+ })
694
+ class TdMarkdownStaticContentTestRenderingComponent {}
695
+
696
+ @Component({
697
+ template: ` <td-markdown [content]="content"></td-markdown> `,
698
+ imports: [TdMarkdownComponent],
699
+ })
700
+ class TdMarkdownDymanicContentTestRenderingComponent {
701
+ content!: string;
702
+ }
703
+
704
+ @Component({
705
+ // prettier-ignore
706
+ template: `
707
+ <td-markdown [simpleLineBreaks]="simpleLineBreaks">
708
+ first line
709
+ second line
710
+ third line
711
+ </td-markdown>
712
+ `,
713
+ preserveWhitespaces: true,
714
+ imports: [TdMarkdownComponent],
715
+ })
716
+ class TdMarkdownSimpleLineBreaksTestRenderingComponent {
717
+ simpleLineBreaks!: boolean;
718
+ }
719
+
720
+ // Use the 3 components below to test event binding requirements of the TdMarkdown component.
721
+ @Component({
722
+ template: `
723
+ <td-markdown (contentReady)="tdMarkdownContentIsReady()"></td-markdown>
724
+ `,
725
+ imports: [TdMarkdownComponent],
726
+ })
727
+ class TdMarkdownEmptyStaticContentTestEventsComponent {
728
+ tdMarkdownContentIsReady(): void {
729
+ /* Stub */
730
+ }
731
+ }
732
+
733
+ @Component({
734
+ // prettier-ignore
735
+ template: `
736
+ <td-markdown (contentReady)="tdMarkdownContentIsReady()">
737
+ # title
738
+
739
+ * list item
740
+ </td-markdown>`,
741
+ preserveWhitespaces: true,
742
+ imports: [TdMarkdownComponent],
743
+ })
744
+ class TdMarkdownStaticContentTestEventsComponent {
745
+ tdMarkdownContentIsReady(): void {
746
+ /* Stub */
747
+ }
748
+ }
749
+
750
+ @Component({
751
+ template: `
752
+ <td-markdown
753
+ [content]="content"
754
+ (contentReady)="tdMarkdownContentIsReady()"
755
+ ></td-markdown>
756
+ `,
757
+ imports: [TdMarkdownComponent],
758
+ })
759
+ class TdMarkdownDynamicContentTestEventsComponent {
760
+ content!: string;
761
+ tdMarkdownContentIsReady(): void {
762
+ /* Stub */
763
+ }
764
+ }
765
+
766
+ @Component({
767
+ template: `
768
+ <td-markdown [anchor]="anchor" [content]="content"></td-markdown>
769
+ `,
770
+ imports: [TdMarkdownComponent],
771
+ })
772
+ class TdMarkdownAnchorsTestEventsComponent {
773
+ content!: string;
774
+ anchor!: string;
775
+ }
776
+
777
+ @Component({
778
+ template: `
779
+ <td-markdown [content]="content" [hostedUrl]="hostedUrl"></td-markdown>
780
+ `,
781
+ imports: [TdMarkdownComponent],
782
+ })
783
+ class TdMarkdownLinksTestEventsComponent {
784
+ hostedUrl!: string;
785
+ content!: string;
786
+ }