Skip to content

Commit 4f5aa8d

Browse files
chore: resolved comments
1 parent e93b717 commit 4f5aa8d

File tree

2 files changed

+712
-0
lines changed

2 files changed

+712
-0
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import {
4+
createRowDataParam,
5+
getOrgDetailsForReport,
6+
createFilterGroupParam,
7+
getAssessmentReportNameHeaders,
8+
} from '../../../src/utils/reportGenerator/reportUtil';
9+
import { OmnistudioOrgDetails } from '../../../src/utils/orgUtils';
10+
import * as dataModelService from '../../../src/utils/dataModelService';
11+
12+
describe('reportUtil', () => {
13+
let sandbox: sinon.SinonSandbox;
14+
15+
beforeEach(() => {
16+
sandbox = sinon.createSandbox();
17+
});
18+
19+
afterEach(() => {
20+
sandbox.restore();
21+
});
22+
23+
describe('createRowDataParam', () => {
24+
it('should create basic row data param without escaping', () => {
25+
const result = createRowDataParam('testKey', 'testValue', true, 1, 1, false);
26+
27+
expect(result).to.deep.equal({
28+
key: 'testKey',
29+
value: 'testValue',
30+
title: 'testValue',
31+
searchable: true,
32+
rowspan: 1,
33+
colspan: 1,
34+
isHref: false,
35+
uri: undefined,
36+
customClass: '',
37+
});
38+
});
39+
40+
it('should escape HTML content when escapeHtmlContent is true', () => {
41+
const htmlContent = '<script>alert("XSS")</script>';
42+
const result = createRowDataParam('testKey', htmlContent, true, 1, 1, false, undefined, undefined, '', true);
43+
44+
expect(result.value).to.equal('&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;');
45+
expect(result.title).to.equal('&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;');
46+
});
47+
48+
it('should not escape HTML content when escapeHtmlContent is false or undefined', () => {
49+
const htmlContent = '<div>Test</div>';
50+
const result1 = createRowDataParam('testKey', htmlContent, true, 1, 1, false, undefined, undefined, '', false);
51+
const result2 = createRowDataParam('testKey', htmlContent, true, 1, 1, false);
52+
53+
expect(result1.value).to.equal('<div>Test</div>');
54+
expect(result2.value).to.equal('<div>Test</div>');
55+
});
56+
57+
it('should handle special characters with escaping', () => {
58+
const specialChars = '< > & " \'';
59+
const result = createRowDataParam('testKey', specialChars, true, 1, 1, false, undefined, undefined, '', true);
60+
61+
// Verify all special characters are escaped (library-independent)
62+
expect(result.value).to.include('&lt;'); // < is escaped
63+
expect(result.value).to.include('&gt;'); // > is escaped
64+
expect(result.value).to.include('&amp;'); // & is escaped
65+
expect(result.value).to.include('&quot;'); // " is escaped
66+
// Single quote can be &#39; (decimal) or &#x27; (hexadecimal) - both are valid
67+
expect(result.value).to.match(/&#(39|x27);/); // ' is escaped in either format
68+
69+
// Verify NO unescaped characters remain
70+
expect(result.value).to.not.match(/<(?!\/|!)/); // No unescaped <
71+
expect(result.value).to.not.match(/(?<!&)>/); // No unescaped >
72+
expect(result.value).to.not.include('&"'); // No unescaped & followed by "
73+
});
74+
75+
it('should use custom title when provided as string', () => {
76+
const result = createRowDataParam('testKey', 'value', true, 1, 1, false, undefined, 'Custom Title');
77+
78+
expect(result.title).to.equal('Custom Title');
79+
expect(result.value).to.equal('value');
80+
});
81+
82+
it('should filter and use title array when provided', () => {
83+
const titleArray = ['Title 1', ' ', 'Title 2', '', 'Title 3'];
84+
const result = createRowDataParam('testKey', 'value', true, 1, 1, false, undefined, titleArray);
85+
86+
expect(result.title).to.deep.equal(['Title 1', 'Title 2', 'Title 3']);
87+
});
88+
89+
it('should escape title when escapeHtmlContent is true and title is not provided', () => {
90+
const htmlValue = '<b>Bold</b>';
91+
const result = createRowDataParam('testKey', htmlValue, true, 1, 1, false, undefined, undefined, '', true);
92+
93+
expect(result.title).to.equal('&lt;b&gt;Bold&lt;/b&gt;');
94+
});
95+
96+
it('should handle href with uri', () => {
97+
const result = createRowDataParam('testKey', 'Click here', true, 1, 1, true, 'https://example.com', 'Link Title');
98+
99+
expect(result.isHref).to.be.true;
100+
expect(result.uri).to.equal('https://example.com');
101+
expect(result.title).to.equal('Link Title');
102+
});
103+
104+
it('should set custom class when provided', () => {
105+
const result = createRowDataParam('testKey', 'value', true, 1, 1, false, undefined, undefined, 'custom-class');
106+
107+
expect(result.customClass).to.equal('custom-class');
108+
});
109+
110+
it('should handle empty string values', () => {
111+
const result = createRowDataParam('testKey', '', true, 1, 1, false);
112+
113+
expect(result.value).to.equal('');
114+
expect(result.title).to.equal('');
115+
});
116+
117+
it('should handle rowspan and colspan correctly', () => {
118+
const result = createRowDataParam('testKey', 'value', true, 3, 2, false);
119+
120+
expect(result.rowspan).to.equal(3);
121+
expect(result.colspan).to.equal(2);
122+
});
123+
124+
it('should escape complex HTML with nested tags', () => {
125+
const complexHtml = '<div class="container"><span onclick="malicious()">Text</span></div>';
126+
const result = createRowDataParam('testKey', complexHtml, true, 1, 1, false, undefined, undefined, '', true);
127+
128+
expect(result.value).to.include('&lt;div');
129+
expect(result.value).to.include('&gt;');
130+
expect(result.value).to.not.include('<div');
131+
});
132+
133+
it('should handle title array with escaping when custom title is provided', () => {
134+
const htmlTitle = '<script>alert("test")</script>';
135+
const result = createRowDataParam('testKey', 'value', true, 1, 1, false, undefined, htmlTitle, '', false);
136+
137+
// Title should not be escaped because escapeHtmlContent is false
138+
expect(result.title).to.equal('<script>alert("test")</script>');
139+
});
140+
141+
it('should handle empty title array', () => {
142+
const result = createRowDataParam('testKey', 'value', true, 1, 1, false, undefined, ['', ' ', ' ']);
143+
144+
expect(result.title).to.deep.equal([]);
145+
});
146+
147+
it('should handle null and undefined values gracefully with escaping', () => {
148+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
149+
const result = createRowDataParam('testKey', null as any, true, 1, 1, false, undefined, undefined, '', true);
150+
151+
// When escapeHtml is applied to null, it becomes empty string
152+
expect(result.value).to.equal('');
153+
});
154+
});
155+
156+
describe('getOrgDetailsForReport', () => {
157+
it('should extract and return org details correctly', () => {
158+
const omnistudioOrgDetails: OmnistudioOrgDetails = {
159+
orgDetails: {
160+
Name: 'Test Org',
161+
Id: '00D123456789ABC',
162+
},
163+
packageDetails: {
164+
namespace: 'testns',
165+
},
166+
dataModel: 'Standard',
167+
} as OmnistudioOrgDetails;
168+
169+
const result = getOrgDetailsForReport(omnistudioOrgDetails);
170+
171+
expect(result).to.deep.equal({
172+
name: 'Test Org',
173+
id: '00D123456789ABC',
174+
namespace: 'testns',
175+
dataModel: 'Standard',
176+
});
177+
});
178+
179+
it('should handle empty namespace', () => {
180+
const omnistudioOrgDetails: OmnistudioOrgDetails = {
181+
orgDetails: {
182+
Name: 'Test Org',
183+
Id: '00D123456789ABC',
184+
},
185+
packageDetails: {
186+
namespace: '',
187+
},
188+
dataModel: 'Custom',
189+
} as OmnistudioOrgDetails;
190+
191+
const result = getOrgDetailsForReport(omnistudioOrgDetails);
192+
193+
expect(result.namespace).to.equal('');
194+
expect(result.dataModel).to.equal('Custom');
195+
});
196+
});
197+
198+
describe('createFilterGroupParam', () => {
199+
it('should create filter group with single filter', () => {
200+
const result = createFilterGroupParam('Status', 'status', ['Active']);
201+
202+
expect(result).to.deep.equal({
203+
label: 'Status',
204+
key: 'status',
205+
filters: [{ label: 'Active' }],
206+
});
207+
});
208+
209+
it('should create filter group with multiple filters', () => {
210+
const result = createFilterGroupParam('Type', 'type', ['DataRaptor', 'OmniScript', 'FlexCard']);
211+
212+
expect(result).to.deep.equal({
213+
label: 'Type',
214+
key: 'type',
215+
filters: [{ label: 'DataRaptor' }, { label: 'OmniScript' }, { label: 'FlexCard' }],
216+
});
217+
});
218+
219+
it('should handle empty filter array', () => {
220+
const result = createFilterGroupParam('Empty', 'empty', []);
221+
222+
expect(result).to.deep.equal({
223+
label: 'Empty',
224+
key: 'empty',
225+
filters: [],
226+
});
227+
});
228+
229+
it('should handle filter labels with special characters', () => {
230+
const result = createFilterGroupParam('Status', 'status', [
231+
'Ready <for> migration',
232+
'Needs "Manual" Intervention',
233+
]);
234+
235+
expect(result.filters).to.have.lengthOf(2);
236+
expect(result.filters[0].label).to.equal('Ready <for> migration');
237+
expect(result.filters[1].label).to.equal('Needs "Manual" Intervention');
238+
});
239+
});
240+
241+
describe('getAssessmentReportNameHeaders', () => {
242+
it('should return standard headers when in standard data model', () => {
243+
sandbox.stub(dataModelService, 'isStandardDataModel').returns(true);
244+
245+
const result = getAssessmentReportNameHeaders();
246+
247+
expect(result).to.deep.equal([{ name: 'Standard', colspan: 3, rowspan: 1 }]);
248+
});
249+
250+
it('should return managed package and standard headers when not in standard data model', () => {
251+
sandbox.stub(dataModelService, 'isStandardDataModel').returns(false);
252+
253+
const result = getAssessmentReportNameHeaders();
254+
255+
expect(result).to.deep.equal([
256+
{ name: 'Managed Package', colspan: 2, rowspan: 1 },
257+
{ name: 'Standard', colspan: 1, rowspan: 1 },
258+
]);
259+
});
260+
});
261+
});

0 commit comments

Comments
 (0)