feat(object): add toHaveOwnProperty method and improve property-path matching in object assertions
This commit is contained in:
		| @@ -1,5 +1,13 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## 2025-04-30 - 2.4.0 - feat(object) | ||||
| add toHaveOwnProperty method and improve property-path matching in object assertions | ||||
|  | ||||
| - Added 'toHaveOwnProperty' as a direct method on Assertion to check for own properties | ||||
| - Enhanced property path evaluation in 'toHaveProperty' to handle nested keys more robustly | ||||
| - Renamed test file to maintain consistent naming for expect.any tests | ||||
| - Introduced scratch.js for manual testing and debugging of property matchers | ||||
|  | ||||
| ## 2025-04-30 - 2.3.3 - fix(tests) | ||||
| Fix test file naming inconsistencies | ||||
|  | ||||
|   | ||||
							
								
								
									
										16
									
								
								scratch.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scratch.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import * as smartexpect from './dist_ts/index.js'; | ||||
| class Foo { constructor(){ this.foo='bar'; } } | ||||
| console.log('foo in instance:', 'foo' in new Foo()); | ||||
| console.log('hasOwn foo:', Object.prototype.hasOwnProperty.call(new Foo(), 'foo')); | ||||
| try { | ||||
|   smartexpect.expect(new Foo()).object.toHaveProperty('foo'); | ||||
|   console.log('toHaveProperty passed'); | ||||
| } catch (err) { | ||||
|   console.error('toHaveProperty failed:', err.message); | ||||
| } | ||||
| try { | ||||
|   smartexpect.expect(new Foo()).object.toHaveOwnProperty('foo'); | ||||
|   console.log('toHaveOwnProperty passed'); | ||||
| } catch (err) { | ||||
|   console.error('toHaveOwnProperty failed:', err.message); | ||||
| } | ||||
| @@ -2,7 +2,9 @@ import { tap, expect as tExpect } from '@push.rocks/tapbundle'; | ||||
| import * as smartexpect from '../dist_ts/index.js'; | ||||
|  | ||||
| tap.test('toHaveProperty nested path via dot notation', async () => { | ||||
|   const testObject = { level1: { level2: { level3: 'value' } } }; | ||||
|   const testObject = { level1: { level2: { level3: 'value' }},  publicTest: 'hi' }; | ||||
|  | ||||
|   smartexpect.expect(testObject).object.toHaveProperty('publicTest'); | ||||
|   // Existence check | ||||
|   smartexpect.expect(testObject).object.toHaveProperty('level1.level2.level3'); | ||||
|   // Value check | ||||
| @@ -11,4 +13,4 @@ tap.test('toHaveProperty nested path via dot notation', async () => { | ||||
|   smartexpect.expect(testObject).not.object.toHaveProperty('level1.level2.missing'); | ||||
| }); | ||||
|  | ||||
| export default tap.start(); | ||||
| export default tap.start(); | ||||
|   | ||||
| @@ -3,6 +3,6 @@ | ||||
|  */ | ||||
| export const commitinfo = { | ||||
|   name: '@push.rocks/smartexpect', | ||||
|   version: '2.3.3', | ||||
|   version: '2.4.0', | ||||
|   description: 'A testing library to manage expectations in code, offering both synchronous and asynchronous assertion methods.' | ||||
| } | ||||
|   | ||||
| @@ -62,13 +62,21 @@ export class ObjectMatchers<T extends object, M extends TExecutionType> { | ||||
|     return this.assertion.customAssertion( | ||||
|       (v) => { | ||||
|         const obj = v as any; | ||||
|         // first check for a literal property (including inherited) | ||||
|         if (property in obj) { | ||||
|           if (arguments.length === 2) { | ||||
|             return plugins.fastDeepEqual(obj[property], value); | ||||
|           } | ||||
|           return true; | ||||
|         } | ||||
|         // no direct key, try nested path via dot notation | ||||
|         const path = property.split('.'); | ||||
|         let current = obj; | ||||
|         for (const key of path) { | ||||
|           if (current == null || !(key in current)) { | ||||
|             return false; | ||||
|           } | ||||
|           current = current[key]; | ||||
|           current = (current as any)[key]; | ||||
|         } | ||||
|         if (arguments.length === 2) { | ||||
|           return plugins.fastDeepEqual(current, value); | ||||
|   | ||||
| @@ -356,6 +356,7 @@ export class Assertion<T = unknown, M extends TExecutionType = 'sync'> { | ||||
|   public toMatch(regex: RegExp) { return this.string.toMatch(regex); } | ||||
|   public toBeOneOf(values: any[]) { return this.string.toBeOneOf(values as string[]); } | ||||
|   public toHaveProperty(property: string, value?: any) { return this.object.toHaveProperty(property, value); } | ||||
|   public toHaveOwnProperty(property: string, value?: any) { return this.object.toHaveOwnProperty(property, value); } | ||||
|   public toMatchObject(expected: object) { return this.object.toMatchObject(expected); } | ||||
|   public toBeInstanceOf(constructor: any) { return this.object.toBeInstanceOf(constructor); } | ||||
|   public toHaveDeepProperty(path: string[]) { return this.object.toHaveDeepProperty(path); } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user