Skip to content

Commit

Permalink
refactor: Unify instance and createStub code
Browse files Browse the repository at this point in the history
The `isRecording` parameter is a function, instead of a simple constant,
so that in a future commit we can flip the value while we're inside a
`when` expectation.
  • Loading branch information
NiGhTTraX committed Jul 15, 2022
1 parent 054c1ea commit 2cda37c
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 256 deletions.
71 changes: 0 additions & 71 deletions src/instance/instance.spec.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,20 @@
import { printExpected } from 'jest-matcher-utils';
import { expectAnsilessEqual } from '../../tests/ansiless';
import { SM } from '../../tests/old';
import { ApplyProp } from '../expectation/expectation';
import { ExpectationRepository } from '../expectation/repository/expectation-repository';
import { instance } from '../index';
import { mock } from '../mock/mock';

describe('instance', () => {
const repo = SM.mock<ExpectationRepository>();

it('should get matching expectation for apply', () => {
SM.when(repo.get(ApplyProp)).thenReturn({ value: () => 42 });

const fn = mock<(x: number) => number>({ repository: SM.instance(repo) });

expect(instance(fn)(1)).toEqual(42);
});

it('should get matching expectation for method', () => {
SM.when(repo.get('bar')).thenReturn({ value: () => 42 });

const foo = mock<{ bar: (x: number) => number }>({
repository: SM.instance(repo),
});

expect(instance(foo).bar(1)).toEqual(42);
});

it('should get matching expectation for property', () => {
SM.when(repo.get('bar')).thenReturn({ value: 42 });

const foo = mock<{ bar: number }>({ repository: SM.instance(repo) });

expect(instance(foo).bar).toEqual(42);
});

it('should throw matching property error expectation', () => {
SM.when(repo.get('bar')).thenReturn({ value: 'foo', isError: true });

const foo = mock<{ bar: number }>({ repository: SM.instance(repo) });

expect(() => instance(foo).bar).toThrow('foo');
});

it('should resolve matching property promise expectation', async () => {
SM.when(repo.get('bar')).thenReturn({ value: 'foo', isPromise: true });

const foo = mock<{ bar: number }>({ repository: SM.instance(repo) });

await expect(instance(foo).bar).resolves.toEqual('foo');
});

it('should reject matching property error promise expectation', async () => {
SM.when(repo.get('bar')).thenReturn({
value: new Error('foo'),
isPromise: true,
isError: true,
});

const foo = mock<{ bar: number }>({ repository: SM.instance(repo) });

await expect(instance(foo).bar).rejects.toThrow('foo');
});

it('should pretty print', () => {
expectAnsilessEqual(
printExpected(instance(mock<any>())),
'[Function mock]'
);
});

it('should be spreadable', () => {
const baz = Symbol('baz');
const keys = ['foo', 'bar', baz];

SM.when(repo.getAllProperties()).thenReturn(keys).times(4);
SM.when(repo.get('foo')).thenReturn({ value: 1 });
SM.when(repo.get('bar')).thenReturn({ value: 2 });
SM.when(repo.get(baz)).thenReturn({ value: 3 });

const foo = mock<{ foo: number; bar: number; [baz]: number }>({
repository: SM.instance(repo),
});

expect({ ...instance(foo) }).toEqual({ foo: 1, bar: 2, [baz]: 3 });
});

it('should be referentially stable', () => {
const fn = mock<unknown>({ repository: SM.instance(repo) });

Expand Down
17 changes: 4 additions & 13 deletions src/instance/instance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ApplyProp, ReturnValue } from '../expectation/expectation';
import { ReturnValue } from '../expectation/expectation';
import { getMockState } from '../mock/map';
import { Mock } from '../mock/mock';
import { createProxy } from '../proxy';
import { createStub } from '../mock/stub';

// Keep a cache of all mock instances so that we can return a stable reference
// if `instance` is used multiple times.
Expand Down Expand Up @@ -42,18 +42,9 @@ export const instance = <T>(mock: Mock<T>): T => {
return cache.get(mock);
}

const { repository } = getMockState(mock);
const { repository, pendingExpectation } = getMockState(mock);

const proxy = createProxy<T>({
property: (property) => returnOrThrow(repository.get(property)),
apply: (args: any[]) => {
const fn = repository.get(ApplyProp);

// This is not using `returnOrThrow` because the repo will use it.
return fn.value(...args);
},
ownKeys: () => repository.getAllProperties(),
});
const proxy = createStub<T>(repository, pendingExpectation, () => false);

cache.set(mock, proxy);

Expand Down
Loading

0 comments on commit 2cda37c

Please sign in to comment.