Skip to content

Commit a7950f3

Browse files
authored
fix: mock property support symbol (#62)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced mocking capabilities with support for Symbol and number properties. - Expanded test coverage for various asynchronous behaviors and error handling scenarios. - **Bug Fixes** - Improved error handling in tests for file reading functions and HTTP requests. - **Documentation** - Updated test descriptions to reflect new functionalities and broader scope. - **Refactor** - Updated type annotations for property parameters to improve type safety. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 13a540c commit a7950f3

4 files changed

Lines changed: 38 additions & 111 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"node": ">= 18.19.0"
2020
},
2121
"dependencies": {
22-
"@cnpmjs/muk-prop": "^1.0.0",
22+
"@cnpmjs/muk-prop": "^1.1.0",
2323
"is-type-of": "^2.2.0",
2424
"thenify": "^3.3.1"
2525
},

src/index.d.ts

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

src/index.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import is from 'is-type-of';
1010
// @ts-ignore
1111
import thenify from 'thenify';
1212

13-
function mock(target: any, property: string, value?: any) {
13+
function mock(target: any, property: PropertyKey, value?: any) {
1414
value = spyFunction(target, property, value);
1515
return muk(target, property, value);
1616
}
1717

18-
function spyFunction(target: any, property: string, fn: any) {
18+
function spyFunction(target: any, property: PropertyKey, fn: any) {
1919
if (!is.function(fn)) return fn;
2020
// support mock with jest.fn()
2121
if (fn._isMockFunction && fn.mock) return fn;
@@ -32,14 +32,14 @@ function spyFunction(target: any, property: string, fn: any) {
3232
fn.called++;
3333
const res = Reflect.apply(target, thisArg, args);
3434
if (isAsyncLike && !is.promise(res)) {
35-
throw new Error(`Can\'t mock async function to normal function for property "${property}"`);
35+
throw new Error(`Can\'t mock async function to normal function for property "${String(property)}"`);
3636
}
3737
return res;
3838
},
3939
});
4040
}
4141

42-
function isAsyncLikeFunction(target: any, property: string) {
42+
function isAsyncLikeFunction(target: any, property: PropertyKey) {
4343
// don't call getter
4444
// Object.getOwnPropertyDescriptor can't find getter in prototypes
4545
if (typeof target.__lookupGetter__ === 'function' && target.__lookupGetter__(property)) return false;
@@ -90,7 +90,7 @@ function _createError(error?: MockError, props?: Record<string, any>): Error {
9090
return error;
9191
}
9292

93-
function _mockError(mod: any, method: string, error?: MockError, props?: Record<string, any> | number,
93+
function _mockError(mod: any, method: string | symbol, error?: MockError, props?: Record<string, any> | number,
9494
timeout?: number | string, once?: boolean) {
9595
if (typeof props === 'number') {
9696
timeout = props;
@@ -140,7 +140,7 @@ function _mockError(mod: any, method: string, error?: MockError, props?: Record<
140140
* @param {Object} props, error properties
141141
* @param {Number} timeout, mock async callback timeout, default is 0.
142142
*/
143-
function mockError(mod: any, method: string, error?: MockError,
143+
function mockError(mod: any, method: string | symbol, error?: MockError,
144144
props?: Record<string, any> | number,
145145
timeout?: number) {
146146
return _mockError(mod, method, error, props, timeout);
@@ -154,7 +154,7 @@ function mockError(mod: any, method: string, error?: MockError,
154154
* @param {Object} props, error properties
155155
* @param {Number} timeout, mock async callback timeout, default is 0.
156156
*/
157-
function errorOnce(mod: any, method: string, error?: MockError,
157+
function errorOnce(mod: any, method: string | symbol, error?: MockError,
158158
props?: Record<string, any> | number,
159159
timeout?: number) {
160160
return _mockError(mod, method, error, props, timeout, true);
@@ -168,7 +168,7 @@ function errorOnce(mod: any, method: string, error?: MockError,
168168
* @param {Array} datas, return datas array.
169169
* @param {Number} timeout, mock async callback timeout, default is 10.
170170
*/
171-
function mockDatas(mod: any, method: string, datas: any[] | any, timeout?: number) {
171+
function mockDatas(mod: any, method: string | symbol, datas: any[] | any, timeout?: number) {
172172
if (timeout) {
173173
timeout = parseInt(String(timeout), 10);
174174
}
@@ -208,7 +208,7 @@ function mockDatas(mod: any, method: string, datas: any[] | any, timeout?: numbe
208208
* @param {Object} data, return data.
209209
* @param {Number} timeout, mock async callback timeout, default is 0.
210210
*/
211-
function mockData(mod: any, method: string, data: any, timeout?: number) {
211+
function mockData(mod: any, method: string | symbol, data: any, timeout?: number) {
212212
const isGeneratorFunction = is.generatorFunction(mod[method]);
213213
const isAsyncFunction = is.asyncFunction(mod[method]);
214214
if (isGeneratorFunction || isAsyncFunction) {
@@ -217,7 +217,7 @@ function mockData(mod: any, method: string, data: any, timeout?: number) {
217217
return mockDatas(mod, method, [ data ], timeout);
218218
}
219219

220-
function dataWithAsyncDispose(mod: any, method: string, data: any, timeout?: number) {
220+
function dataWithAsyncDispose(mod: any, method: string | symbol, data: any, timeout?: number) {
221221
data = {
222222
...data,
223223
async [Symbol.asyncDispose]() {
@@ -234,7 +234,7 @@ function dataWithAsyncDispose(mod: any, method: string, data: any, timeout?: num
234234
* @param {String} method, mock module object method name.
235235
* @param {Number} [timeout], mock async callback timeout, default is 0.
236236
*/
237-
function mockEmpty(mod: any, method: string, timeout?: number) {
237+
function mockEmpty(mod: any, method: string | symbol, timeout?: number) {
238238
return mockDatas(mod, method, [ null ], timeout);
239239
}
240240

@@ -243,9 +243,9 @@ function mockEmpty(mod: any, method: string, timeout?: number) {
243243
* @param {Object} mod, module object
244244
* @param {String} method, mock module object method name.
245245
*/
246-
function spy(mod: any, method: string) {
246+
function spy(mod: any, method: string | symbol) {
247247
if (typeof mod[method] !== 'function') {
248-
throw new Error(`spy target ${method} is not a function`);
248+
throw new Error(`spy target ${String(method)} is not a function`);
249249
}
250250
const originalFn = mod[method];
251251
const wrap = function proxy(this: any, ...args: any[]) {
@@ -262,7 +262,7 @@ function spy(mod: any, method: string) {
262262
* @param {String|Error} error, error string message or error instance.
263263
* @param {Object} [props], error properties
264264
*/
265-
function syncError(mod: any, method: string, error?: MockError, props?: Record<string, any>) {
265+
function syncError(mod: any, method: string | symbol, error?: MockError, props?: Record<string, any>) {
266266
error = _createError(error, props);
267267
mock(mod, method, () => {
268268
throw error;
@@ -276,7 +276,7 @@ function syncError(mod: any, method: string, error?: MockError, props?: Record<s
276276
* @param {String} method, mock module object method name.
277277
* @param {Object} data, return data.
278278
*/
279-
function syncData(mod: any, method: string, data?: any) {
279+
function syncData(mod: any, method: string | symbol, data?: any) {
280280
mock(mod, method, () => {
281281
return data;
282282
});
@@ -288,7 +288,7 @@ function syncData(mod: any, method: string, data?: any) {
288288
* @param {Object} mod, module object
289289
* @param {String} method, mock module object method name.
290290
*/
291-
function syncEmpty(mod: any, method: string) {
291+
function syncEmpty(mod: any, method: string | symbol) {
292292
return syncData(mod, method);
293293
}
294294

@@ -581,7 +581,7 @@ function omit(obj: Record<string, any>, key: string) {
581581
/**
582582
* mock class method from instance
583583
*/
584-
function classMethod(instance: any, property: string, value?: any) {
584+
function classMethod(instance: any, property: PropertyKey, value?: any) {
585585
mock(instance.constructor.prototype, property, value);
586586
}
587587

test/mm.test.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -763,23 +763,37 @@ describe('test/mm.test.js', () => {
763763
});
764764
});
765765

766-
describe('mm()', function() {
767-
766+
describe('mm(), mock()', function() {
768767
it('should mock process.env.KEY work', function() {
769-
const orginalEnv = process.env.NODE_ENV;
768+
const originalEnv = process.env.NODE_ENV;
770769
mm(process.env, 'NODE_ENV', 'test2');
771770
process.env.NODE_ENV!.should.equal('test2');
772771
mm.restore();
773772

774-
assert(process.env.NODE_ENV === orginalEnv);
773+
assert(process.env.NODE_ENV === originalEnv);
775774

776775
mm(process.env, 'NODE_ENV', 'test2');
777776
process.env.NODE_ENV!.should.equal('test2');
778777
mm(process.env, 'NODE_ENV', 'production');
779778
process.env.NODE_ENV!.should.equal('production');
780779
mm.restore();
781780

782-
assert(process.env.NODE_ENV === orginalEnv);
781+
assert(process.env.NODE_ENV === originalEnv);
782+
});
783+
784+
it('should mock Symbol property work', () => {
785+
const foo = Symbol('foo');
786+
const data = { [foo]: 'bar' };
787+
assert.equal(data[foo], 'bar');
788+
mm(data, foo, 'bar1');
789+
assert.equal(data[foo], 'bar1');
790+
});
791+
792+
it('should mock number property work', () => {
793+
const data = { 1: 'bar' };
794+
assert.equal(data[1], 'bar');
795+
mm(data, 1, 'bar1');
796+
assert.equal(data[1], 'bar1');
783797
});
784798

785799
it('should mm() just like muk()', function(done) {
@@ -830,7 +844,7 @@ describe('test/mm.test.js', () => {
830844
});
831845
});
832846

833-
it('shoud mock function with property', () => {
847+
it('should mock function with property', () => {
834848
const NativeDate = Date;
835849
const mockNow = function(date: any) {
836850
const NewDate = function(...args: any[]) {

0 commit comments

Comments
 (0)