Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation related to auto-mocking #8099

Merged
merged 14 commits into from
Mar 18, 2019
Merged
86 changes: 86 additions & 0 deletions docs/JestObjectAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,92 @@ test('implementation created by jest.genMockFromModule', () => {
});
```

This is how `genMockFromModule` will mock the follwing data types:
pedrottimark marked this conversation as resolved.
Show resolved Hide resolved

#### `Function`

A new function will be created. The new function will have no formal parameters and when called will return `undefined`. This functionality also applies to `async functions`.
SimenB marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should mocked async functions return Promise<undefined> instead?

Copy link
Contributor Author

@mackness mackness Mar 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested this and it seems like mocked async functions don't return Promise<undefined> instead they return undefined just like synchronous functions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, I meant that maybe we should change this. Good that the current behavior gets documented though!


#### `Class`

A new class will be created. The interface of the original class is maintained however all of the class member functions will be mocked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about class properties, if there's a property that is an array will it be mocked with the array strategy mentioned below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I can add this case to the example code / description.


#### `Object`

Objects are deeply cloned. Their interfaces are maintained and their values are mocked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Objects are deeply cloned. Their interfaces are maintained and their values are mocked.
Objects are deeply cloned. Their keys are maintained and their values are mocked.


#### `Array`

The original array is ignored and a new empty array is created.

#### `String`

A new copy of the original stirng is mocked.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A new copy of the original stirng is mocked.
A new copy of the original string is mocked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this!


#### `Number`

A new copy of the original number is mocked.

Example:

<!-- prettier-ignore -->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for some reason prettier is adding these unwanted parens after the closing class bracket

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remove js in the opening code block in the markdown file prettier does not insert the weird parenthesis. 🤔

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it's just adding the parense. new class Bar{} and new class Bar{}() behaves the same.

Should it be newed?

I opened up prettier/prettier#5964, not sure if it's a bug or not

Copy link
Contributor Author

@mackness mackness Mar 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I added another comment that may or may not be related to the same issue. For now I just removed the js attribute from the markdown code block and everything is formatted correctly and syntax hi-lighting seems to be working in the site preview

```js
// example.js
module.exports = {
function: function foo(a, b) {
return a + b;
},
asyncFunction: async function asyncFoo(a, b) {
const result = await a + b;
return result;
},
class: new class Bar {
foo() {}
},
object: {
baz: 'foo',
bar: {
fiz: 1,
buzz: [1, 2, 3],
},
},
array: [1, 2, 3],
number: 123,
string: 'baz',
};
```

```js
// __tests__/example.test.js
const example = jest.genMockFromModule('./example');

test('should run example code', () => {
SimenB marked this conversation as resolved.
Show resolved Hide resolved
// a new mocked function with no formal arguments.
expect(example.function.name).toEqual('foo');
expect(example.function.length).toEqual(0);
// async functions are treated just like standard synchronous functions.
expect(example.asyncFunction.name).toEqual('asyncFoo');
expect(example.asyncFunction.length).toEqual(0);
// a new mocked class that maintains the original interface and mocks member functions.
expect(example.class.constructor.name).toEqual('Bar');
expect(example.class.foo.name).toEqual('foo');
// a deeply cloned object that maintains the original interface and mocks it's values.
expect(example.object).toEqual({
baz: 'foo',
bar: {
fiz: 1,
buzz: [],
},
});
// the original array is ignored and a new emtpy array is mocked.
expect(example.array.length).toEqual(0);
// a new copy of the original number.
expect(example.number).toEqual(123);
// a new copy of the original string.
expect(example.string).toEqual('baz');
});
```

### `jest.mock(moduleName, factory, options)`

Mocks a module with an auto-mocked version when it is being required. `factory` and `options` are optional. For example:
Expand Down
46 changes: 46 additions & 0 deletions packages/jest-mock/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('moduleMocker', () => {
expect(moduleMocker.getMetadata('banana').value).toEqual('banana');
expect(moduleMocker.getMetadata(27).value).toEqual(27);
expect(moduleMocker.getMetadata(false).value).toEqual(false);
expect(moduleMocker.getMetadata(Infinity).value).toEqual(Infinity);
});

it('does not retrieve metadata for arrays', () => {
Expand All @@ -57,6 +58,51 @@ describe('moduleMocker', () => {
expect(metadata.members).toBeUndefined();
expect(metadata.type).toEqual('null');
});

it('retrieves metadata for ES6 classes', () => {
class ClassFooMock {
bar() {}
}
const fooInstance = new ClassFooMock();
const metadata = moduleMocker.getMetadata(fooInstance);
expect(metadata.type).toEqual('object');
expect(metadata.members.constructor.name).toEqual('ClassFooMock');
});

it('retrieves synchronous function metadata', () => {
function functionFooMock() {}
const metadata = moduleMocker.getMetadata(functionFooMock);
expect(metadata.type).toEqual('function');
expect(metadata.name).toEqual('functionFooMock');
});

it('retrieves asynchronous function metadata', () => {
async function asyncFunctionFooMock() {}
const metadata = moduleMocker.getMetadata(asyncFunctionFooMock);
expect(metadata.type).toEqual('function');
expect(metadata.name).toEqual('asyncFunctionFooMock');
});

it("retrieves metadata for object literals and it's members", () => {
const metadata = moduleMocker.getMetadata({
bar: 'two',
foo: 1,
});
expect(metadata.type).toEqual('object');
expect(metadata.members.bar.value).toEqual('two');
expect(metadata.members.bar.type).toEqual('constant');
expect(metadata.members.foo.value).toEqual(1);
expect(metadata.members.foo.type).toEqual('constant');
});

it('retrieves Date object metadata', () => {
const metadata = moduleMocker.getMetadata(Date);
expect(metadata.type).toEqual('function');
expect(metadata.name).toEqual('Date');
expect(metadata.members.now.name).toEqual('now');
expect(metadata.members.parse.name).toEqual('parse');
expect(metadata.members.UTC.name).toEqual('UTC');
});
});

describe('generateFromMetadata', () => {
Expand Down