Skip to content

Commit efac655

Browse files
committed
Created utils.test.js
Created unit test cases for each of the four functions mentioned in the github issue.
1 parent 20c4215 commit efac655

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// @flow
2+
import { Utils } from './index';
3+
import axios from 'axios';
4+
import React from 'react';
5+
import { renderToStaticMarkup } from 'react-dom/server';
6+
7+
describe('Utils', () => {
8+
describe('randomString', () => {
9+
it('should return a string with only lowercase alphanumeric characters', () => {
10+
const str = Utils.randomString();
11+
expect(str).toMatch(/^[a-z0-9]+$/);
12+
});
13+
14+
it('should produce strings with a minimum length of 26 characters', () => {
15+
const str = Utils.randomString();
16+
expect(str.length).toBeGreaterThanOrEqual(26);
17+
});
18+
19+
it('should produce different outputs over multiple invocations', () => {
20+
const outputs = new Set();
21+
for (let i = 0; i < 10; i++) {
22+
outputs.add(Utils.randomString());
23+
}
24+
expect(outputs.size).toBe(10);
25+
});
26+
});
27+
28+
describe('setCsrfToken', () => {
29+
beforeEach(() => {
30+
document.head.innerHTML = '';
31+
axios.defaults.headers.common['X-CSRF-Token'] = undefined;
32+
});
33+
34+
it('should not set anything if meta tag is missing', () => {
35+
Utils.setCsrfToken();
36+
expect(axios.defaults.headers.common['X-CSRF-Token']).toBeUndefined();
37+
});
38+
39+
it('should set token if meta tag is present', () => {
40+
const meta = document.createElement('meta');
41+
meta.name = 'csrf-token';
42+
meta.setAttribute('content', 'secure-token');
43+
document.head.appendChild(meta);
44+
45+
Utils.setCsrfToken();
46+
expect(axios.defaults.headers.common['X-CSRF-Token']).toBe('secure-token');
47+
});
48+
49+
it('should overwrite an existing CSRF token if re-run', () => {
50+
const meta = document.createElement('meta');
51+
meta.name = 'csrf-token';
52+
meta.setAttribute('content', 'first-token');
53+
document.head.appendChild(meta);
54+
55+
Utils.setCsrfToken();
56+
expect(axios.defaults.headers.common['X-CSRF-Token']).toBe('first-token');
57+
58+
meta.setAttribute('content', 'updated-token');
59+
Utils.setCsrfToken();
60+
expect(axios.defaults.headers.common['X-CSRF-Token']).toBe('updated-token');
61+
});
62+
});
63+
64+
describe('getPusher', () => {
65+
beforeEach(() => {
66+
document.head.innerHTML = '';
67+
});
68+
69+
it('should return null if window.Pusher is undefined', () => {
70+
delete window.Pusher;
71+
expect(Utils.getPusher()).toBeNull();
72+
});
73+
74+
it('should return null if required meta tags are missing', () => {
75+
window.Pusher = jest.fn();
76+
expect(Utils.getPusher()).toBeNull();
77+
});
78+
79+
it('should return a configured Pusher instance with meta tag values', () => {
80+
window.Pusher = jest.fn((key, options) => ({ key, ...options }));
81+
82+
const metaKey = document.createElement('meta');
83+
metaKey.setAttribute('name', 'pusher-key');
84+
metaKey.setAttribute('content', 'abc123');
85+
document.head.appendChild(metaKey);
86+
87+
const metaCluster = document.createElement('meta');
88+
metaCluster.setAttribute('name', 'pusher-cluster');
89+
metaCluster.setAttribute('content', 'mt1');
90+
document.head.appendChild(metaCluster);
91+
92+
const pusher = Utils.getPusher();
93+
expect(pusher.key).toBe('abc123');
94+
expect(pusher.cluster).toBe('mt1');
95+
});
96+
});
97+
98+
describe('renderContent', () => {
99+
it('should sanitize malicious HTML and preserve safe HTML', () => {
100+
const malicious = `<img src=x onerror=alert(1) /><p>Hello</p>`;
101+
const result = Utils.renderContent(malicious);
102+
const html = renderToStaticMarkup(result);
103+
expect(html).not.toContain('onerror');
104+
expect(html).toContain('<p>Hello</p>');
105+
expect(html).not.toContain('<img'); // sanitized away
106+
});
107+
108+
it('should return cloned React element with merged props', () => {
109+
const element = <button className="primary">Click</button>;
110+
const result = Utils.renderContent(element, { id: 'submitBtn', disabled: true });
111+
112+
expect(React.isValidElement(result)).toBe(true);
113+
expect(result.type).toBe('button');
114+
expect(result.props.className).toBe('primary');
115+
expect(result.props.id).toBe('submitBtn');
116+
expect(result.props.disabled).toBe(true);
117+
});
118+
119+
it('should override props when duplicate keys exist', () => {
120+
const element = <input type="text" value="default" />;
121+
const result = Utils.renderContent(element, { value: 'override' });
122+
expect(result.props.value).toBe('override');
123+
});
124+
125+
it('should return non-string non-React values unchanged', () => {
126+
const obj = { foo: 'bar' };
127+
expect(Utils.renderContent(obj)).toEqual(obj);
128+
});
129+
130+
it('should return null safely', () => {
131+
expect(Utils.renderContent(null)).toBeNull();
132+
});
133+
134+
it('should handle undefined input gracefully', () => {
135+
expect(Utils.renderContent(undefined)).toBeUndefined();
136+
});
137+
138+
it('should preserve fragments', () => {
139+
const fragment = <>{['One', 'Two'].map((txt, i) => <span key={i}>{txt}</span>)}</>;
140+
const result = Utils.renderContent(fragment, { 'data-test': 'fragment' });
141+
142+
// Fragments can't be cloned with props directly, but test still returns the same JSX
143+
expect(React.isValidElement(result)).toBe(true);
144+
});
145+
});
146+
});

0 commit comments

Comments
 (0)