Skip to content

Commit

Permalink
chore: add more tests (#7)
Browse files Browse the repository at this point in the history
- validate history item
- more tests for matching
<!--- START AUTOGENERATED NOTES --->
# Contents ([#7](#7))

### Other
- validate history interface
- more tests for matching

<!--- END AUTOGENERATED NOTES --->
  • Loading branch information
vvscode committed Dec 4, 2023
1 parent 33c03ad commit 57e1c2c
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 2 deletions.
6 changes: 5 additions & 1 deletion src/create-spy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type History, isFunction, isObject } from './types';
import { type History, isFunction, isHistoryInstance, isObject } from './types';

// eslint-disable-next-line @typescript-eslint/ban-types -- it's require by Reflect.apply
const isValidSpyTarget = (value: unknown): value is object | Function =>
Expand All @@ -8,6 +8,10 @@ const shouldProxy = (value: unknown, key: string | symbol) =>
isValidSpyTarget(value) && !(isFunction(value) && (key === 'prototype' || key === 'constructor'));

export function createSpy<T>(obj: T, history: History): T {
if (!isHistoryInstance(history)) {
throw new TypeError('history should be an implementation of History');
}

const proxyCache = new Map<string, unknown>();

function createProxy(target: unknown, path: string[] = []): unknown {
Expand Down
6 changes: 6 additions & 0 deletions src/object-chronicler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,10 @@ describe('createSpy and BasicHistory Integration Tests', () => {
expect(history.has({ type: 'get', key: 'user.getAddress' })).toBe(true);
expect(history.has({ type: 'call', key: 'user.getAddress', args: [] })).toBe(true);
});

it('should throw type error if history is not an instance of History', () => {
expect(() => {
createSpy({}, undefined as unknown as BasicHistory);
}).toThrow('history should be an implementation of History');
});
});
14 changes: 14 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,18 @@ export type DeepPartial<T> = {

export const isObject = (value: unknown): value is object =>
typeof value === 'object' && value !== null;

export const isFunction = (value: unknown) => typeof value === 'function';

export const isHistoryInstance = (obj: unknown): obj is History => {
return (
!!obj &&
typeof obj === 'object' &&
'put' in obj &&
typeof obj.put === 'function' &&
'getAll' in obj &&
typeof obj.getAll === 'function' &&
'has' in obj &&
typeof obj.has === 'function'
);
};
24 changes: 23 additions & 1 deletion src/utils/deep-partially-match.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,34 @@ describe('deepPartiallyMatch with deepPartial', () => {
expect(deepPartiallyMatch(item1, item2)).toBe(true);
});

it('should return true for HistoryItems with partial match and nested objects', () => {
it('should return true for HistoryItems with partial match and partial match nested objects', () => {
const item1: HistoryItem = { type: 'call', key: 'b', args: [{ nested: 42, other: 'value' }] };
const item2: DeepPartial<HistoryItem> = { type: 'call', key: 'b', args: [{ nested: 42 }] };
expect(deepPartiallyMatch(item1, item2)).toBe(true);
});

it('should return true for HistoryItems with partial match and partial nesting (no objects in the list)', () => {
const item1: HistoryItem = { type: 'call', key: 'b', args: [{ nested: 42, other: 'value' }] };
const item2: DeepPartial<HistoryItem> = { type: 'call', key: 'b', args: [] };
expect(deepPartiallyMatch(item1, item2)).toBe(true);
});

it('should return false for HistoryItems with partial match and partial micmatch on nesting', () => {
const item1: HistoryItem = { type: 'call', key: 'b', args: [{ nested: 42, other: 'value' }] };
const item2: DeepPartial<HistoryItem> = {
type: 'call',
key: 'b',
args: [{ value: 42, other: 'other value' }],
};
expect(deepPartiallyMatch(item1, item2)).toBe(false);
});

it('should return true for HistoryItems with partial match and partial nesting (no list)', () => {
const item1: HistoryItem = { type: 'call', key: 'b', args: [{ nested: 42, other: 'value' }] };
const item2: DeepPartial<HistoryItem> = { type: 'call', key: 'b' };
expect(deepPartiallyMatch(item1, item2)).toBe(true);
});

it('should return false for non-matching HistoryItems with nested objects', () => {
const item1: HistoryItem = { type: 'get', key: 'a', args: [{ nested: 42 }] };
const item2: HistoryItem = { type: 'get', key: 'a', args: [{ nested: 43 }] };
Expand Down

0 comments on commit 57e1c2c

Please sign in to comment.