-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathctx.test.js
More file actions
237 lines (235 loc) · 8.67 KB
/
ctx.test.js
File metadata and controls
237 lines (235 loc) · 8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import Ctx from '../src/ctx';
import React from 'react';
import * as Babel from '@babel/standalone';
beforeEach(() => {});
afterEach(() => {});
describe('constructor :', () => {
test('it should work correctly without errors', () => {
new Ctx(React, Babel);
expect(1).toBe(1);
});
test('it should throw an error when Babel value is not passed in to it', () => {
expect.assertions(1);
try {
new Ctx(React, undefined);
} catch (er) {
expect(er.message).toBe(
`Package "string-to-react-component" has a missing peer dependency of "@babel/standalone" ( requires ">=7.15.8" )`,
);
}
});
test('check _getReact property', () => {
const ins = new Ctx(React, Babel);
expect(ins._getReact()).toEqual(React);
});
test('check _getBabel property', () => {
const ins = new Ctx(React, Babel);
expect(ins._getBabel()).toEqual(Babel);
});
test('it should set _rerender property', () => {
const rerender = () => {};
const ins = new Ctx(React, Babel, rerender);
expect(ins._rerender).toEqual(rerender);
});
test('the initial value of _com prop should be a function which returns null', () => {
const ins = new Ctx(React, Babel);
expect(typeof ins._com).toBe('function');
expect(ins._com()).toBe(null);
});
});
describe('methods : ', () => {
test('_validateTemplate method ', () => {
expect.assertions(3);
const ins = new Ctx(React, Babel);
try {
ins._validateTemplate({});
} catch (er) {
expect(er.message).toBe('passed child into string-to-react-component element should b a string');
}
try {
ins._validateTemplate();
} catch (er) {
expect(er.message).toBe('passed child into string-to-react-component element should b a string');
}
try {
ins._validateTemplate('');
} catch (er) {
expect(er.message).toBe('passed string into string-to-react-component element can not be empty');
}
});
test('_validateCodeInsideTheTemp method', () => {
expect.assertions(3);
const ins = new Ctx(React, Babel);
{
ins._validateCodeInsideTheTemp(() => {});
expect(1).toBe(1);
}
{
class c {
constructor() {}
}
ins._validateCodeInsideTheTemp(c);
expect(1).toBe(1);
}
try {
ins._validateCodeInsideTheTemp({});
} catch (er) {
expect(er.message).toBe('code inside the passed string into string-to-react-component, should be a function');
}
});
test('_getBlob method', () => {
const ins = new Ctx(React, Babel);
const blob = ins._getBlob('()=>{}');
expect(!!blob.size).toBe(true);
expect(blob.type).toBe('application/javascript');
});
test('update method should call _update', () => {
const ins = new Ctx(React, Babel);
ins._update = jest.fn(() => {});
const str = '()=>{}';
const babelOptions = {};
ins.update(str, babelOptions);
expect(ins._update.mock.calls.length).toBe(1);
expect(ins._update.mock.calls[0][0]).toBe(str);
expect(ins._update.mock.calls[0][1]).toBe(babelOptions);
});
test('_update method', () => {
const ins = new Ctx(React, Babel);
ins._updateTemplate = jest.fn((template, babelOptions) => 'transpiled string code');
ins._updateComponent = jest.fn((temp, babelOp) => {});
const str = '()=>{}';
const babelOptions = {};
ins._update(str, babelOptions);
expect(ins._updateTemplate.mock.calls.length).toBe(1);
expect(ins._updateTemplate.mock.calls[0][0]).toBe(str);
expect(ins._updateTemplate.mock.calls[0][1]).toBe(babelOptions);
expect(ins._updateComponent.mock.calls.length).toBe(1);
expect(ins._updateComponent.mock.calls[0][0]).toBe('transpiled string code');
});
test('_checkBabelOptions method should set react preset and inline sourceMaps and throw an error with invalid parameter', () => {
expect.assertions(6);
const ins = new Ctx(React, Babel);
try {
ins._checkBabelOptions([]);
} catch (e) {
expect(e.message).toBe(`babelOptions prop of string-to-react-component element should be an object.`);
}
try {
ins._checkBabelOptions({presets: {}});
} catch (e) {
expect(e.message).toBe(
`string-to-react-component Error : presets property of babelOptions prop should be an array`,
);
}
let babelOp = {};
ins._checkBabelOptions(babelOp);
expect(babelOp.presets.indexOf('react') >= 0).toBe(true);
expect(babelOp.sourceMaps).toBe('inline');
babelOp = {presets: []};
ins._checkBabelOptions(babelOp);
expect(babelOp.presets.indexOf('react') >= 0).toBe(true);
expect(babelOp.sourceMaps).toBe('inline');
});
test('_transpile method should override _temp to "null" when _temp is an empty string', () => {
const ins = new Ctx(React, Babel);
ins._temp = '';
ins._transpile({sourceMaps: false});
expect(ins._temp).toBe('null');
});
test('_transpile method should override _temp to the transpiled code', () => {
const ins = new Ctx(React, Babel);
ins._temp = `()=><div>2</div>`;
const code = ins._transpile({sourceMaps: false});
expect(
[
'() => React.createElement("div", null, "2");',
`() => /*#__PURE__*/React.createElement("div", null, "2");`,
].indexOf(ins._temp) >= 0,
).toBe(true);
});
test('_import method', async () => {
expect.assertions(1);
const ins = new Ctx(React, Babel);
await ins._import('../__test__/mock-module.js').then((res) => {
expect(res.default || res).toBe('mock-module');
});
});
test('_updateComponent method', async () => {
const ins = new Ctx(React, Babel);
const blob = new Blob();
const com = () => 3;
ins._getBlob = jest.fn(() => blob);
ins._getModule = jest.fn(() => Promise.resolve(com));
ins._rerender = jest.fn(() => {});
const str = '()=>{}';
await ins._updateComponent(str);
expect(ins._getBlob.mock.calls.length).toBe(1);
expect(ins._getBlob.mock.calls[0][0]).toBe(str);
expect(ins._com()).toBe(com());
expect(ins._rerender.mock.calls.length).toBe(1);
expect(ins._rerender.mock.calls[0][0]).toEqual({});
});
});
describe('_getModule method', () => {
beforeEach(() => {
global.URL.createObjectURL = jest.fn(() => 'mocked-url');
global.URL.revokeObjectURL = jest.fn(() => {});
});
it('should successfully load a module and return the expected component', async () => {
const instance = new Ctx(React, Babel);
const mockReactComponent = jest.fn((React) => {});
instance._import = jest.fn(() => {
return Promise.resolve({default: mockReactComponent});
});
const mockBlob = new Blob();
const result = await instance._getModule(mockBlob);
expect(instance._import).toHaveBeenCalled();
expect(result).toBe(mockReactComponent(instance._getReact()));
});
it('should handle errors during module loading', async () => {
expect.assertions(4);
const instance = new Ctx(React, Babel);
const mockReactComponent = jest.fn((React) => {});
const mockError = new Error('Module loading failed');
instance._import = jest.fn(() => {
return Promise.reject(mockError);
});
const mockBlob = new Blob(); // Create a mock Blob
expect(global.URL.revokeObjectURL.mock.calls.length).toBe(0);
// Ensure that the error is logged to the console
const consoleErrorSpy = jest.spyOn(console, 'error');
await instance._getModule(mockBlob).catch((er) => {
expect(er.message).toBe('string-to-react-component loading module is failed:');
expect(global.URL.revokeObjectURL.mock.calls.length).toBe(1);
expect(consoleErrorSpy).toHaveBeenCalledWith('string-to-react-component loading module is failed:', mockError);
consoleErrorSpy.mockRestore(); // Restore original console.error
});
});
});
describe('_updateTemplate method : ', () => {
let ins;
beforeEach(() => {
ins = new Ctx(React, Babel);
});
test('_updateTemplate should call _validateTemplate method', () => {
ins._validateTemplate = jest.fn(() => {});
ins._updateTemplate('()=>{}', {});
expect(ins._validateTemplate.mock.calls.length).toBe(1);
expect(ins._validateTemplate.mock.calls[0][0]).toBe('()=>{}');
});
test('_updateTemplate method should call _prependCode, _transpile and _postpendCode methods', () => {
ins._prependCode = jest.fn(() => {
ins._transpile = jest.fn(() => {
ins._postpendCode = jest.fn(() => ins._temp);
return ins;
});
return ins;
});
ins._updateTemplate('()=>{}', {});
expect(ins._prependCode.mock.calls.length).toBe(1);
expect(ins._prependCode.mock.calls[0][0]).toBe('()=>{}');
expect(ins._transpile.mock.calls.length).toBe(1);
expect(ins._transpile.mock.calls[0][0]).toEqual({});
expect(ins._postpendCode.mock.calls.length).toBe(1);
});
});