diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 6eb0477..e12dcbe 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -5,24 +5,25 @@ import { getDefaultTplWrapper, getWrapperId, getXPathForElement, + isPropertyReadonly, nextTask, sleep, validateExportLifecycle, } from '../utils'; -test('should wrap the id [1]', () => { +it('should wrap the id [1]', () => { const id = 'REACT16'; expect(getWrapperId(id)).toBe(`__qiankun_microapp_wrapper_for_${'react_16'}__`); }); -test('should wrap the id [2]', () => { +it('should wrap the id [2]', () => { const id = 'react16'; expect(getWrapperId(id)).toBe('__qiankun_microapp_wrapper_for_react_16__'); }); -test('should wrap string with div', () => { +it('should wrap string with div', () => { const tpl = 'qiankun'; const factory = getDefaultTplWrapper('react16'); @@ -34,7 +35,7 @@ test('should wrap string with div', () => { ); }); -test('should be able to validate lifecycle', () => { +it('should be able to validate lifecycle', () => { const noop = () => undefined; const export1 = { @@ -71,7 +72,7 @@ test.skip('should be able to suspend', async () => { expect(diff >= 10).toBeTruthy(); }); -test('Deferred should worked [1]', async () => { +it('Deferred should worked [1]', async () => { const inst = new Deferred(); setTimeout(() => { @@ -82,7 +83,7 @@ test('Deferred should worked [1]', async () => { expect(ret).toBe(1); }); -test('Deferred should worked [2]', async () => { +it('Deferred should worked [2]', async () => { const inst = new Deferred(); setTimeout(() => { @@ -100,7 +101,7 @@ test('Deferred should worked [2]', async () => { expect(err).toBeInstanceOf(Error); }); -test('should getXPathForElement work well', () => { +it('should getXPathForElement work well', () => { const article = document.createElement('article'); article.innerHTML = `
@@ -140,7 +141,7 @@ it('should nextTick just executed once in one task context', async () => { expect(counter).toBe(3); }); -it('should genAppInstanceIdByName works well', () => { +it('should genAppInstanceIdByName work well', () => { const instanceId1 = genAppInstanceIdByName('hello'); expect(instanceId1).toBe('hello'); @@ -150,3 +151,34 @@ it('should genAppInstanceIdByName works well', () => { const instanceId3 = genAppInstanceIdByName('hello'); expect(instanceId3).toBe('hello_2'); }); + +it('should isPropertyReadonly work well', () => { + const a = { + get name() { + return 'read only'; + }, + }; + expect(isPropertyReadonly(a, 'name')).toBeTruthy(); + + const b = { + get name() { + return 'read only'; + }, + set name(_) {}, + }; + expect(isPropertyReadonly(b, 'name')).toBeFalsy(); + + const c = {}; + Object.defineProperty(c, 'name', { writable: false }); + expect(isPropertyReadonly(c, 'name')).toBeTruthy(); + + const d = {}; + Object.defineProperty(d, 'name', { configurable: true }); + expect(isPropertyReadonly(d, 'name')).toBeTruthy(); + + const e = {}; + Object.defineProperty(e, 'name', { writable: true }); + expect(isPropertyReadonly(e, 'name')).toBeFalsy(); + + expect(isPropertyReadonly(undefined, 'name')).toBeFalsy(); +}); diff --git a/src/utils.ts b/src/utils.ts index 2af3f85..213c557 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -96,27 +96,26 @@ export const isCallable = (fn: any) => { */ const propertyReadonlyCacheMap = new WeakMap>(); export function isPropertyReadonly(target: any, p?: PropertyKey): boolean { - // 异常返回 if (!target || !p) { return false; } - // 取缓存 const targetPropertiesFromCache = propertyReadonlyCacheMap.get(target) || {}; - if (typeof targetPropertiesFromCache[p] === 'boolean') { + if (targetPropertiesFromCache[p]) { return targetPropertiesFromCache[p]; } - // 计算 const propertyDescriptor = Object.getOwnPropertyDescriptor(target, p); - const result = propertyDescriptor?.configurable === false && propertyDescriptor?.writable === false; + const readonly = Boolean( + propertyDescriptor && + (propertyDescriptor.writable === false || (propertyDescriptor.get && !propertyDescriptor.set)), + ); - // 写缓存 - targetPropertiesFromCache[p] = result; + targetPropertiesFromCache[p] = readonly; propertyReadonlyCacheMap.set(target, targetPropertiesFromCache); - return result; + return readonly; } const boundedMap = new WeakMap();