Skip to main content

Defining an interaction

In ContractCase, a contract is a series of interactions, defined by example. In English, an interaction might be "a getUser request looks like $X, and a success response looks like $Y":

Instead of making examples dependent on each other (and the corresponding explosion of complexity and potentially brittle tests), each interaction runs independently during contract definition.

This is achieved with state definitions, which you can define any preconditions that your interaction needs (for example "a user with ID 'foo' must exist").

A complete interaction looks like:

  • States:
    • When the server has a user named `` with ID 123
  • a getUser request looks like $X, and
  • the success response looks like $Y

For example:

import {
willSendHttpRequest,
inState,
stateVariable,
stringPrefix,
anyString,
HttpRequestConfig,
} from '@contract-case/contract-case-jest';
import { YourApi } from './YourApi.js';


it('behaves as expected', async () => {
await contract.runInteraction({
states: [
inState('Server is up'),
inState('A user with id "foo" exists'),
],
definition: willSendHttpRequest({
request: {
method: 'GET',
path: '/users/foo',
},
response: {
status: 200,
body: {
userId: 'foo',
name: 'john smith',
},
},
}),
});
});
How are these states handled later?

After your contract is written, the provider verification will use state handlers to fill in the implementation details.

Overriding configuration

You can override the configuration for individual tests by providing an optional ContractCaseConfig object as the final argument. See the configuration options reference for full details. For example, here's how you could set the log level to debug for an individual test:

        await contract.runInteraction(
{
states: [
/* as above */
],
definition:
/* as above */
},
{ logLevel: 'debug' },
);

Setting the log level to debug is a useful way to see what is happening during the test, which can help you understand why an interaction might be failing.

Do I describe the whole API payload?

You only need to describe the parts of the API payload that your consumer relies on.

This is advantageous because it's not a breaking change to rename or remove a field/endpoint that no-one is using.

Next steps

Next, set up your state state definitions.