2424
2525import { NodeEntry , ResultSetRowEntry } from '@alfresco/js-api' ;
2626import { ComponentFixture , TestBed } from '@angular/core/testing' ;
27- import { By } from '@angular/platform-browser' ;
2827import { first } from 'rxjs/operators' ;
2928import { AppTestingModule } from '../../../testing/app-testing.module' ;
3029import { SearchResultsRowComponent } from './search-results-row.component' ;
3130import { Component , Input } from '@angular/core' ;
31+ import { UnitTestingUtils } from '@alfresco/adf-core' ;
3232
3333@Component ( {
3434 selector : 'aca-datatable-cell-badges' ,
@@ -42,6 +42,7 @@ class MockDatatableCellBadgesComponent {
4242describe ( 'SearchResultsRowComponent' , ( ) => {
4343 let component : SearchResultsRowComponent ;
4444 let fixture : ComponentFixture < SearchResultsRowComponent > ;
45+ let utils : UnitTestingUtils ;
4546
4647 const nodeEntry : NodeEntry = {
4748 entry : {
@@ -59,26 +60,17 @@ describe('SearchResultsRowComponent', () => {
5960 modifiedAt : new Date ( ) ,
6061 isFile : true ,
6162 name : 'Random name' ,
62- properties : { 'cm:title' : 'Random title' , 'cm:description' : 'some random description' } ,
63+ properties : {
64+ 'cm:title' : 'Random title' ,
65+ 'cm:description' : 'some random description'
66+ } ,
6367 search : {
6468 score : 10 ,
6569 highlight : [
66- {
67- field : 'cm:content' ,
68- snippets : [ `Interesting <span class='aca-highlight'>random</span> content` ]
69- } ,
70- {
71- field : 'cm:name' ,
72- snippets : [ `<span class='aca-highlight'>Random</span>` ]
73- } ,
74- {
75- field : 'cm:title' ,
76- snippets : [ `<span class='aca-highlight'>Random</span> title` ]
77- } ,
78- {
79- field : 'cm:description' ,
80- snippets : [ `some <span class='aca-highlight'>random</span> description` ]
81- }
70+ { field : 'cm:content' , snippets : [ `Interesting <span class='aca-highlight'>random</span> content` ] } ,
71+ { field : 'cm:name' , snippets : [ `<span class='aca-highlight'>Random</span>` ] } ,
72+ { field : 'cm:title' , snippets : [ `<span class='aca-highlight'>Random</span> title` ] } ,
73+ { field : 'cm:description' , snippets : [ `some <span class='aca-highlight'>random</span> description` ] }
8274 ]
8375 }
8476 }
@@ -91,50 +83,96 @@ describe('SearchResultsRowComponent', () => {
9183
9284 fixture = TestBed . createComponent ( SearchResultsRowComponent ) ;
9385 component = fixture . componentInstance ;
86+ utils = new UnitTestingUtils ( fixture . debugElement ) ;
9487 } ) ;
9588
89+ const getNameEl = ( ) : HTMLSpanElement => utils . getByCSS ( '.aca-link.aca-crop-text' ) . nativeElement ;
90+ const getTitleEl = ( ) : HTMLSpanElement => utils . getByDataAutomationId ( 'search-results-entry-title' ) . nativeElement ;
91+ const getDescriptionEl = ( ) : HTMLDivElement => utils . getByDataAutomationId ( 'search-results-entry-description' ) . nativeElement ;
92+ const getContentEl = ( ) : HTMLDivElement => utils . getByCSS ( '.aca-result-content.aca-crop-text' ) . nativeElement ;
93+
9694 it ( 'should show the current node' , ( ) => {
9795 component . context = { row : { node : nodeEntry } } ;
9896 fixture . detectChanges ( ) ;
9997
100- const element = fixture . nativeElement . querySelector ( 'div' ) ;
101- expect ( element ) . not . toBeNull ( ) ;
98+ expect ( utils . getByCSS ( 'div' ) ) . not . toBeNull ( ) ;
10299 } ) ;
103100
104101 it ( 'should correctly parse highlights' , ( done ) => {
105102 component . context = { row : { node : resultEntry } } ;
106- component . content$
107- . asObservable ( )
108- . pipe ( first ( ) )
109- . subscribe ( ( ) => {
110- fixture . detectChanges ( ) ;
111-
112- const nameElement : HTMLSpanElement = fixture . debugElement . query ( By . css ( '.aca-link.aca-crop-text' ) ) . nativeElement ;
113- expect ( nameElement . innerHTML ) . toBe ( '<span class="aca-highlight">Random</span>' ) ;
114- expect ( nameElement . title ) . toBe ( 'Random' ) ;
115-
116- const titleElement : HTMLSpanElement = fixture . debugElement . query ( By . css ( '[data-automation-id="search-results-entry-title"]' ) ) . nativeElement ;
117- expect ( titleElement . innerHTML ) . toBe ( ' ( <span class="aca-highlight">Random</span> title )' ) ;
118- expect ( titleElement . title ) . toBe ( 'Random title' ) ;
119-
120- const descriptionElement : HTMLDivElement = fixture . debugElement . query (
121- By . css ( '[data-automation-id="search-results-entry-description"]' )
122- ) . nativeElement ;
123- expect ( descriptionElement . innerHTML ) . toBe ( 'some <span class="aca-highlight">random</span> description' ) ;
124- expect ( descriptionElement . title ) . toBe ( 'some random description' ) ;
125-
126- const contentElement : HTMLDivElement = fixture . debugElement . query ( By . css ( '.aca-result-content.aca-crop-text' ) ) . nativeElement ;
127- expect ( contentElement . innerHTML ) . toBe ( '...Interesting <span class="aca-highlight">random</span> content...' ) ;
128- expect ( contentElement . title ) . toBe ( '...Interesting random content...' ) ;
129- done ( ) ;
130- } ) ;
103+ component . content$ . pipe ( first ( ) ) . subscribe ( ( ) => {
104+ fixture . detectChanges ( ) ;
105+
106+ expect ( getNameEl ( ) . innerHTML ) . toBe ( '<span class="aca-highlight">Random</span>' ) ;
107+ expect ( getNameEl ( ) . title ) . toBe ( 'Random' ) ;
108+
109+ expect ( getTitleEl ( ) . innerHTML ) . toBe ( ' ( <span class="aca-highlight">Random</span> title )' ) ;
110+ expect ( getTitleEl ( ) . title ) . toBe ( 'Random title' ) ;
111+
112+ expect ( getDescriptionEl ( ) . innerHTML ) . toBe ( 'some <span class="aca-highlight">random</span> description' ) ;
113+ expect ( getDescriptionEl ( ) . title ) . toBe ( 'some random description' ) ;
114+
115+ expect ( getContentEl ( ) . innerHTML ) . toBe ( '...Interesting <span class="aca-highlight">random</span> content...' ) ;
116+ expect ( getContentEl ( ) . title ) . toBe ( '...Interesting random content...' ) ;
117+ done ( ) ;
118+ } ) ;
131119 fixture . detectChanges ( ) ;
132120 } ) ;
133121
134122 it ( 'should pass node to badge component' , ( ) => {
135123 component . context = { row : { node : nodeEntry } } ;
136- const badgeElement = fixture . debugElement . query ( By . css ( 'aca-datatable-cell-badges' ) ) ;
124+ fixture . detectChanges ( ) ;
125+
126+ const badgeElement = utils . getByCSS ( 'aca-datatable-cell-badges' ) . componentInstance ;
137127 expect ( badgeElement ) . not . toBe ( null ) ;
138- expect ( badgeElement . componentInstance . node ) . toBe ( component . context . node ) ;
128+ expect ( badgeElement . node ) . toBe ( component . context . row . node ) ;
129+ } ) ;
130+
131+ it ( 'should escape plain < and > in values' , ( done ) => {
132+ const customEntry : ResultSetRowEntry = {
133+ entry : { ...nodeEntry . entry , name : '2 < 5 > 3' , search : { score : 5 } }
134+ } as ResultSetRowEntry ;
135+
136+ component . context = { row : { node : customEntry } } ;
137+ component . name$ . pipe ( first ( ) ) . subscribe ( ( ) => {
138+ fixture . detectChanges ( ) ;
139+
140+ expect ( getNameEl ( ) . innerHTML ) . toBe ( '2 < 5 > 3' ) ;
141+ expect ( getNameEl ( ) . textContent ) . toBe ( '2 < 5 > 3' ) ;
142+ done ( ) ;
143+ } ) ;
144+ fixture . detectChanges ( ) ;
145+ } ) ;
146+
147+ it ( 'should not render script tags as HTML' , ( done ) => {
148+ const customEntry : ResultSetRowEntry = {
149+ entry : { ...nodeEntry . entry , name : '<script>alert("xss")</script>' , search : { score : 5 } }
150+ } as ResultSetRowEntry ;
151+
152+ component . context = { row : { node : customEntry } } ;
153+ component . name$ . pipe ( first ( ) ) . subscribe ( ( ) => {
154+ fixture . detectChanges ( ) ;
155+
156+ expect ( getNameEl ( ) . innerHTML ) . toContain ( '<script>alert("xss")</script>' ) ;
157+ expect ( getNameEl ( ) . textContent ) . toBe ( '<script>alert("xss")</script>' ) ;
158+ done ( ) ;
159+ } ) ;
160+ fixture . detectChanges ( ) ;
161+ } ) ;
162+
163+ it ( 'should allow highlight spans but escape other tags' , ( done ) => {
164+ const customEntry : ResultSetRowEntry = {
165+ entry : { ...nodeEntry . entry , name : '<b><span class="aca-highlight">BoldHighlight</span></b>' , search : { score : 5 } }
166+ } as ResultSetRowEntry ;
167+
168+ component . context = { row : { node : customEntry } } ;
169+ component . name$ . pipe ( first ( ) ) . subscribe ( ( ) => {
170+ fixture . detectChanges ( ) ;
171+
172+ expect ( getNameEl ( ) . innerHTML ) . toBe ( '<b><span class="aca-highlight">BoldHighlight</span></b>' ) ;
173+ expect ( getNameEl ( ) . textContent ) . toBe ( '<b>BoldHighlight</b>' ) ;
174+ done ( ) ;
175+ } ) ;
176+ fixture . detectChanges ( ) ;
139177 } ) ;
140178} ) ;
0 commit comments