Skip to content

Commit d80c3e2

Browse files
complete tests
1 parent 02c0e2d commit d80c3e2

File tree

5 files changed

+152
-62
lines changed

5 files changed

+152
-62
lines changed

src/__snapshots__/stringToReact.test.js.snap

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/ctx.test.js

Lines changed: 142 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,18 @@ describe('constructor :', () => {
1818
);
1919
}
2020
});
21-
test('check _parentTemp property', () => {
21+
test('check _getReact property', () => {
2222
const ins = new Ctx(React, Babel);
23-
expect(ins._parentTemp).toBe(`"use strict";\nreturn @temp;`);
23+
expect(ins._getReact()).toEqual(React);
2424
});
25-
test('it should set React global variable if it is not existed', () => {
26-
window.React = undefined;
27-
new Ctx(React, Babel);
28-
expect(window.React).toEqual(React);
29-
window.React = undefined;
30-
const _React = {};
31-
new Ctx(_React, Babel);
32-
expect(window.React).toEqual(_React);
33-
new Ctx(React, Babel);
34-
expect(window.React).toEqual(_React);
35-
window.React = undefined;
25+
test('check _getBabel property', () => {
26+
const ins = new Ctx(React, Babel);
27+
expect(ins._getBabel()).toEqual(Babel);
28+
});
29+
test('it should set _rerender property', () => {
30+
const rerender = () => {};
31+
const ins = new Ctx(React, Babel, rerender);
32+
expect(ins._rerender).toEqual(rerender);
3633
});
3734
test('the initial value of _com prop should be a function which returns null', () => {
3835
const ins = new Ctx(React, Babel);
@@ -64,48 +61,54 @@ describe('methods : ', () => {
6461
expect.assertions(3);
6562
const ins = new Ctx(React, Babel);
6663
{
67-
ins._com = () => {};
68-
ins._validateCodeInsideTheTemp();
64+
ins._validateCodeInsideTheTemp(() => {});
6965
expect(1).toBe(1);
7066
}
7167
{
7268
class c {
7369
constructor() {}
7470
}
75-
ins._com = c;
76-
ins._validateCodeInsideTheTemp();
71+
ins._validateCodeInsideTheTemp(c);
7772
expect(1).toBe(1);
7873
}
7974
try {
80-
ins._com = '';
81-
ins._validateCodeInsideTheTemp();
75+
ins._validateCodeInsideTheTemp({});
8276
} catch (er) {
8377
expect(er.message).toBe('code inside the passed string into string-to-react-component, should be a function');
8478
}
8579
});
86-
test('_generateCom method', () => {
80+
test('_getBlob method', () => {
8781
const ins = new Ctx(React, Babel);
88-
ins._transpile = () => '() => {}';
89-
ins._validateCodeInsideTheTemp = jest.fn(() => {});
90-
ins._generateCom();
91-
expect(ins._validateCodeInsideTheTemp.mock.calls.length).toBe(1);
82+
const blob = ins._getBlob('()=>{}');
83+
expect(!!blob.size).toBe(true);
84+
expect(blob.type).toBe('application/javascript');
9285
});
93-
test('updateTemplate method', () => {
86+
test('update method should call _update', () => {
9487
const ins = new Ctx(React, Babel);
95-
ins._validateTemplate = jest.fn();
96-
ins._generateCom = jest.fn();
97-
let temp = '()=>3';
98-
ins._temp = '()=>3';
99-
ins.updateTemplate(temp);
100-
expect(ins._validateTemplate.mock.calls.length).toBe(1);
101-
expect(ins._validateTemplate.mock.calls[0][0]).toBe(temp);
102-
expect(ins._generateCom.mock.calls.length).toBe(0);
103-
ins._temp = '';
104-
ins.updateTemplate(temp);
105-
expect(ins._generateCom.mock.calls.length).toBe(1);
88+
ins._update = jest.fn(() => {});
89+
const str = '()=>{}';
90+
const babelOptions = {};
91+
ins.update(str, babelOptions);
92+
expect(ins._update.mock.calls.length).toBe(1);
93+
expect(ins._update.mock.calls[0][0]).toBe(str);
94+
expect(ins._update.mock.calls[0][1]).toBe(babelOptions);
10695
});
107-
test('_checkBabelOptions method should set react preset and throw an error with invalid parameter', () => {
108-
expect.assertions(4);
96+
test('_update method', () => {
97+
const ins = new Ctx(React, Babel);
98+
ins._updateTemplate = jest.fn((template, babelOptions) => 'transpiled string code');
99+
ins._updateComponent = jest.fn((temp, babelOp) => {});
100+
const str = '()=>{}';
101+
const babelOptions = {};
102+
ins._update(str, babelOptions);
103+
expect(ins._updateTemplate.mock.calls.length).toBe(1);
104+
expect(ins._updateTemplate.mock.calls[0][0]).toBe(str);
105+
expect(ins._updateTemplate.mock.calls[0][1]).toBe(babelOptions);
106+
expect(ins._updateComponent.mock.calls.length).toBe(1);
107+
expect(ins._updateComponent.mock.calls[0][0]).toBe('transpiled string code');
108+
expect(ins._updateComponent.mock.calls[0][1]).toBe(babelOptions);
109+
});
110+
test('_checkBabelOptions method should set react preset and inline sourceMaps and throw an error with invalid parameter', () => {
111+
expect.assertions(6);
109112
const ins = new Ctx(React, Babel);
110113
try {
111114
ins._checkBabelOptions([]);
@@ -122,18 +125,114 @@ describe('methods : ', () => {
122125
let babelOp = {};
123126
ins._checkBabelOptions(babelOp);
124127
expect(babelOp.presets.indexOf('react') >= 0).toBe(true);
128+
expect(babelOp.sourceMaps).toBe('inline');
125129
babelOp = {presets: []};
126130
ins._checkBabelOptions(babelOp);
127131
expect(babelOp.presets.indexOf('react') >= 0).toBe(true);
132+
expect(babelOp.sourceMaps).toBe('inline');
128133
});
129-
test('_transpile method should return "null" when _temp is an empty string', () => {
134+
test('_transpile method should override _temp to "null" when _temp is an empty string', () => {
130135
const ins = new Ctx(React, Babel);
131-
expect(ins._transpile({})).toBe('null');
136+
ins._temp = '';
137+
ins._transpile({sourceMaps: false});
138+
expect(ins._temp).toBe('null');
132139
});
133-
test('_transpile method should return the transpiled code', () => {
140+
test('_transpile method should override _temp to the transpiled code', () => {
134141
const ins = new Ctx(React, Babel);
135142
ins._temp = `()=><div>2</div>`;
136-
const code = ins._transpile({filename: 'counter.ts'});
137-
expect(code).toBe('() => React.createElement("div", null, "2");\n//# sourceURL=counter.ts');
143+
const code = ins._transpile({sourceMaps: false});
144+
expect(
145+
[
146+
'() => React.createElement("div", null, "2");',
147+
`() => /*#__PURE__*/React.createElement("div", null, "2");`,
148+
].indexOf(ins._temp) >= 0,
149+
).toBe(true);
150+
});
151+
test('_import method', async () => {
152+
expect.assertions(1);
153+
const ins = new Ctx(React, Babel);
154+
await ins._import('./mock-module.js').then((res) => {
155+
expect(res.default || res).toBe('mock-module');
156+
});
157+
});
158+
test('_updateComponent method', async () => {
159+
const ins = new Ctx(React, Babel);
160+
const blob = new Blob();
161+
const com = () => 3;
162+
ins._getBlob = jest.fn(() => blob);
163+
ins._getModule = jest.fn(() => Promise.resolve(com));
164+
ins._rerender = jest.fn(() => {});
165+
const str = '()=>{}';
166+
await ins._updateComponent(str);
167+
expect(ins._getBlob.mock.calls.length).toBe(1);
168+
expect(ins._getBlob.mock.calls[0][0]).toBe(str);
169+
expect(ins._com()).toBe(com());
170+
expect(ins._rerender.mock.calls.length).toBe(1);
171+
expect(ins._rerender.mock.calls[0][0]).toEqual({});
172+
});
173+
});
174+
describe('_getModule method', () => {
175+
beforeEach(() => {
176+
global.URL.createObjectURL = jest.fn(() => 'mocked-url');
177+
global.URL.revokeObjectURL = jest.fn(() => {});
178+
});
179+
180+
it('should successfully load a module and return the expected component', async () => {
181+
const instance = new Ctx(React, Babel);
182+
const mockReactComponent = jest.fn((React) => {});
183+
instance._import = jest.fn(() => {
184+
return Promise.resolve({default: mockReactComponent});
185+
});
186+
const mockBlob = new Blob();
187+
const result = await instance._getModule(mockBlob);
188+
expect(instance._import).toHaveBeenCalled();
189+
expect(result).toBe(mockReactComponent(instance._getReact()));
190+
});
191+
192+
it('should handle errors during module loading', async () => {
193+
expect.assertions(4);
194+
const instance = new Ctx(React, Babel);
195+
const mockReactComponent = jest.fn((React) => {});
196+
const mockError = new Error('Module loading failed');
197+
instance._import = jest.fn(() => {
198+
return Promise.reject(mockError);
199+
});
200+
const mockBlob = new Blob(); // Create a mock Blob
201+
expect(global.URL.revokeObjectURL.mock.calls.length).toBe(0);
202+
// Ensure that the error is logged to the console
203+
const consoleErrorSpy = jest.spyOn(console, 'error');
204+
await instance._getModule(mockBlob).catch((er) => {
205+
expect(er.message).toBe('string-to-react-component loading module is failed:');
206+
expect(global.URL.revokeObjectURL.mock.calls.length).toBe(1);
207+
expect(consoleErrorSpy).toHaveBeenCalledWith('string-to-react-component loading module is failed:', mockError);
208+
consoleErrorSpy.mockRestore(); // Restore original console.error
209+
});
210+
});
211+
});
212+
describe('_updateTemplate method : ', () => {
213+
let ins;
214+
beforeEach(() => {
215+
ins = new Ctx(React, Babel);
216+
});
217+
test('_updateTemplate should call _validateTemplate method', () => {
218+
ins._validateTemplate = jest.fn(() => {});
219+
ins._updateTemplate('()=>{}', {});
220+
expect(ins._validateTemplate.mock.calls.length).toBe(1);
221+
expect(ins._validateTemplate.mock.calls[0][0]).toBe('()=>{}');
222+
});
223+
test('_updateTemplate method should call _prependCode, _transpile and _postpendCode methods', () => {
224+
ins._prependCode = jest.fn(() => {
225+
ins._transpile = jest.fn(() => {
226+
ins._postpendCode = jest.fn(() => ins._temp);
227+
return ins;
228+
});
229+
return ins;
230+
});
231+
ins._updateTemplate('()=>{}', {});
232+
expect(ins._prependCode.mock.calls.length).toBe(1);
233+
expect(ins._prependCode.mock.calls[0][0]).toBe('()=>{}');
234+
expect(ins._transpile.mock.calls.length).toBe(1);
235+
expect(ins._transpile.mock.calls[0][0]).toEqual({});
236+
expect(ins._postpendCode.mock.calls.length).toBe(1);
138237
});
139238
});

src/ctx.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ class Ctx implements IStringToReactApi {
5151
_getBlob(temp: string): Blob {
5252
return new Blob([temp], {type: 'application/javascript'});
5353
}
54+
_import(url: string): Promise<any> {
55+
return import(/* webpackIgnore: true */ url);
56+
}
5457
_getModule(blob: Blob): Promise<FC> {
5558
const moduleUrl = URL.createObjectURL(blob);
56-
return import(/* webpackIgnore: true */ moduleUrl)
59+
return this._import(moduleUrl)
5760
.then((module) => {
5861
URL.revokeObjectURL(moduleUrl);
5962
return Promise.resolve((module?.default || module)(this._getReact()));
@@ -90,22 +93,19 @@ class Ctx implements IStringToReactApi {
9093
}
9194
/** update transpiled code */
9295
_updateTemplate(template: string, babelOptions: TransformOptions): string {
93-
if (template !== this._temp) {
94-
this._validateTemplate(template);
95-
return this._prependCode(template)._transpile(babelOptions)._postpendCode();
96-
}
97-
return this._temp;
96+
this._validateTemplate(template);
97+
return this._prependCode(template)._transpile(babelOptions)._postpendCode();
9898
}
9999
update(template: string, babelOptions: TransformOptions): void {
100100
this._update(template, babelOptions);
101101
}
102102
_update(template: string, babelOptions: TransformOptions): void {
103-
this._updateComponent(this._updateTemplate(template, babelOptions), babelOptions);
103+
this._updateComponent(this._updateTemplate(template, babelOptions));
104104
}
105105
_onChangeComponent(): void {
106106
this._rerender({});
107107
}
108-
_updateComponent(template: string, babelOptions: TransformOptions): void {
108+
_updateComponent(template: string): void {
109109
this._getModule(this._getBlob(template)).then((com: FC) => {
110110
this._validateCodeInsideTheTemp(com);
111111
this._com = com;

src/mock-module.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 'mock-module';

src/stringToReact.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('calling update method : ', () => {
5858
return _ctx2;
5959
};
6060
const babelOp = {};
61-
renderApp(str, babelOp, {getCtx, react, Babel}, true, str);
61+
renderApp(str, babelOp, {getCtx, react, Babel}, true, str, babelOp);
6262
expect(_ctx.update.mock.calls.length).toBe(1);
6363
expect(_ctx.update.mock.calls[0][0]).toBe(str);
6464
expect(_ctx.update.mock.calls[0][1]).toEqual(babelOp);

0 commit comments

Comments
 (0)