Skip to content

Commit

Permalink
fix(utils): [define] invalid property descriptor
Browse files Browse the repository at this point in the history
- cannot both specify accessors and a value or writable attribute
- https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Aug 8, 2023
1 parent 94e502a commit 6693824
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 31 deletions.
111 changes: 90 additions & 21 deletions src/utils/__tests__/define.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@

import VEHICLE from '#fixtures/vehicle'
import type { PropertyDescriptor } from '#src/interfaces'
import type { Assign, EmptyArray, Fn } from '#src/types'
import clone from '../clone'
import constant from '../constant'
import testSubject from '../define'
import description from '../descriptor'
import omit from '../omit'

describe('unit:utils/define', () => {
describe('add property', () => {
Expand All @@ -18,16 +22,48 @@ describe('unit:utils/define', () => {
vrm = faker.vehicle.vrm()
})

it('should return obj with new property', () => {
// Act
const result = testSubject(VEHICLE, property, { value: vrm })
describe('accessor descriptor', () => {
let vehicle: typeof VEHICLE

// Expect
expect(result).to.have.descriptor(property, {
configurable: true,
enumerable: true,
value: vrm,
writable: true
beforeAll(() => {
vehicle = clone(VEHICLE)
})

it('should return obj with new accessor descriptor', () => {
// Arrange
const get: Fn<EmptyArray, typeof vrm> = constant(vrm)

// Act
const result = testSubject(vehicle, property, { get })

// Expect
expect(result).to.have.descriptor(property, {
configurable: true,
enumerable: true,
get,
set: undefined
})
})
})

describe('data descriptor', () => {
let vehicle: typeof VEHICLE

beforeAll(() => {
vehicle = clone(VEHICLE)
})

it('should return obj with new data descriptor', () => {
// Act
const result = testSubject(vehicle, property, { value: vrm })

// Expect
expect(result).to.have.descriptor(property, {
configurable: true,
enumerable: true,
value: vrm,
writable: true
})
})
})
})
Expand All @@ -41,20 +77,53 @@ describe('unit:utils/define', () => {
vin = faker.vehicle.vin()
})

it('should return obj with modified property', () => {
// Arrange
const descriptor: PropertyDescriptor<typeof vin> = {
enumerable: false,
value: vin
}
describe('accessor descriptor', () => {
let vehicle: Assign<typeof VEHICLE, { vin?: string }>

beforeAll(() => {
vehicle = Object.defineProperty(omit(clone(VEHICLE), ['vin']), 'vin', {
configurable: true,
get: constant(VEHICLE.vin)
})
})

it('should return obj with modified accessor descriptor', () => {
// Arrange
const get: Fn<EmptyArray, typeof vin> = constant(vin)

// Act
const result = testSubject(vehicle, property, { get })

// Expect
expect(result).to.have.descriptor(property, {
...description(vehicle, property),
get
})
})
})

describe('data descriptor', () => {
let vehicle: typeof VEHICLE

beforeAll(() => {
vehicle = clone(VEHICLE)
})

it('should return obj with modified data descriptor', () => {
// Arrange
const descriptor: PropertyDescriptor<typeof vin> = {
enumerable: false,
value: vin
}

// Act
const result = testSubject(VEHICLE, property, descriptor)
// Act
const result = testSubject(vehicle, property, descriptor)

// Expect
expect(result).to.have.descriptor(property, {
...description(VEHICLE, property),
...descriptor
// Expect
expect(result).to.have.descriptor(property, {
...description(vehicle, property),
...descriptor
})
})
})
})
Expand Down
15 changes: 5 additions & 10 deletions src/utils/define.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,12 @@ const define = <T extends object, V = any, U = T>(
property: PropertyKey,
descriptor: PropertyDescriptor<V> = {}
): U => {
/**
* Default attributes.
*
* @const {PropertyDescriptor<V>} defaults
*/
const defaults: PropertyDescriptor<V> = hasOwn(obj, property)
? description(obj, property)
: { configurable: true, enumerable: true, writable: true }

return Object.defineProperty(cast(obj), property, {
...defaults,
...(hasOwn(obj, property)
? description(obj, property)
: hasOwn(descriptor, 'get') || hasOwn(descriptor, 'set')
? { configurable: true, enumerable: true }
: { configurable: true, enumerable: true, writable: true }),
...descriptor
})
}
Expand Down

0 comments on commit 6693824

Please sign in to comment.