# Mocks

Mocks are the simplest way to customize scalar types (such as String or Int) and type fields (such as Book.title).

# Scalar types

To customize scalar types, specify a function for each type:

const mocks = {
  String: () => 'my custom string',
  Int: () => faker.datatype.number({min: -500, max: 500}),
}

Poser already mocks a few scalar types:

import { faker } from '@faker-js/faker';

import type { Mocks } from '../types';

const defaultMocks: Mocks = {
  DateTime: () => faker.date.past().toISOString(),
  Int: () => faker.datatype.number(),
  JSON: () => faker.datatype.json(),
  String: () => faker.random.words(4),
};
export default defaultMocks;

You can overwrite these defaults by specifying your own, but they will only have effect in the service they live in.

# Type fields

Every field of every type (including Query and Mutation) can have a specific mock to return something else than the scalar type mock.

To customize type fields, specify a function for each field:

const mocks = {
  Book: {
    id: () => faker.datatype.uuid(),
    title: () => 'A fixed title for all books',
  }
}

This can also be done for Query fields, mostly to modify the default list length of 2:

import { utils } from '@datacamp/poser';

const mocks = {
  Query: {
    books: () => utils.mockList(20)
  }
}

# Constructor

In some cases, some fields depend on others, so mocking them one by one in isolation won't produce a result realistic enough.

For example, let's assume a type Task with the following fields:

type Task {
  progress: Float # Progress from 0 (not started) to 1 (completed)
  completedAt: Date
}

If these 2 fields must be coherent, we can't have a date in completedAt unless progress is set to 1.

This can be solved by using the __constructor function:

const mocks = {
  Task: {
    __constructor: (values: any = {}) => {
      // 20% chance a Task is completed
      const isCompleted = faker.datatype.number(100) < 20; 

      return {
        progress: isCompleted ? 1 : faker.datatype.float({min:0.1, max:0.9}),
        completedAt: isCompleted ? faker.date.recent() : null,
        ...values
      }
    },
    otherField: () => 'can still be mocked'
  }
}

The __constructor function will be called everytime a new instance is created, including store.insert(). When calling store.insert(), the second parameter contains values and is passed as the first parameter of __constructor. These values should be included in the return value of __constructor as shown above.