hello! I'm back. Been working on the same pact for...
# pact-js
j
hello! I'm back. Been working on the same pact for a month or two. I don't have a good grasp of docker, environment variables, or jwt tokens and that's been the crux of all my issues 😞 I now have a pact that's failing verification with a 400 which is the closest I've gotten yet The expected body is { "data": { "createCustomTask": { .....some key value pairs } } The actual body has the operation name, query and variables passed in and does not have the data sent Here is my consumer test. If I fiddle with the response at all and run the pact test in consumer, the test fails
Copy code
import { mockCustomTaskCreateInput } from '@/__mocks__/generated/graphql';
import { CREATE_TASK } from '@/services/customTasks';
import { PactTestServerConfig } from '@/utils/pact-constants';
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client';
import { GraphQLInteraction, Pact } from '@pact-foundation/pact';
import fetch from 'cross-fetch';
import * as path from 'path';

const mockVariables = { input: mockCustomTaskCreateInput() };
const EXPECTED_RESPONSE = mockVariables.input;

let client: ApolloClient<unknown>;

// Create a 'pact' between the two applications in the integration we are testing
const provider = new Pact({
  log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
  dir: path.resolve(process.cwd(), './../pacts'),
  consumer: 'company-app',
  provider: 'custom-tasks',
  port: PactTestServerConfig.Port,
});

beforeAll(async () => {
  await provider.setup();
});

describe('custom task', () => {
  beforeAll(() => {
    client = new ApolloClient({
      cache: new InMemoryCache({ addTypename: false }),
      uri: `<http://127.0.0.1>:${PactTestServerConfig.Port}/graphql`,
      link: new HttpLink({
        uri: `<http://127.0.0.1>:${PactTestServerConfig.Port}/graphql`,
        fetch,
      }),
    });

    // Arrange: Setup our expected interactions
    const graphqlMutation = new GraphQLInteraction()
      .uponReceiving('a request to create a custom task')
      .withOperation('CreateCustomTask')
      //@ts-expect-error gql can be undefined
      .withMutation(CREATE_TASK.loc.source.body)
      .withRequest({
        method: 'POST',
        path: '/graphql',
        headers: {
          'Content-Type': 'application/json',
        },
      })
      .withVariables(mockVariables)
      .willRespondWith({
        status: 200,
        headers: { 'Content-Type': 'application/json' },
        body: {
          data: {
            createCustomTask: EXPECTED_RESPONSE,
          },
        },
      });

    return provider.addInteraction(graphqlMutation);
  });

  afterAll(async () => {
    await provider.verify();
    await provider.finalize();
  });

  it('should retrieve a created task', async () => {
    try {
      const results = await client.mutate({
        mutation: CREATE_TASK,
        variables: mockVariables,
      });
      expect(results.data.createCustomTask).toEqual(EXPECTED_RESPONSE);
      console.log('results', EXPECTED_RESPONSE);
    } catch (error) {
      console.log('error inside catch', error);
    }
  });
});
I'm also having a hell of time trying to get the env vars to point to test branches so i can play with the consumer side and see if the pact in the broker updates. Our docker commands are through make files and there's a long trail of following commands and short cuts to figure out what's going on, this is a huge monorepo.
m
Sorry to hear of the pain!
Are you able to share what’s in the output there?
Ideally, DEBUG level logs would help us see what your code is doing too. On this:
Copy code
.withMutation(CREATE_TASK.loc.source.body)
      .withRequest({
        method: 'POST',
        path: '/graphql',
        headers: {
          'Content-Type': 'application/json',
        },
      })
It’s not clear what the contents of
withMutation
is here, so hard to say what it should be doing.
You mentioned you needed a dev to help with something - is this test written in the code base of the code you’re testing, or external to that? With respect, Pact is effectively a unit-testing tool, and therefore requires a developer-like skillset and good understanding of the code under test. You may have this, but just making this point.
side side note:
Copy code
client = new ApolloClient({
      cache: new InMemoryCache({ addTypename: false }),
      uri: `<http://127.0.0.1>:${PactTestServerConfig.Port}/graphql`,
      link: new HttpLink({
        uri: `<http://127.0.0.1>:${PactTestServerConfig.Port}/graphql`,
        fetch,
      }),
    });
Be careful with caches in these tests, they tend to cache things and then you get funny test results batting your head against them wondering why a single test always works, but not when you run multiple
j
hrm, ok so I just tried to change my .withMutation to this:
Copy code
.withMutation(
        `
      mutation CreateCustomTask($input: CustomTaskCreateInput!) {
        createCustomTask(input: $input) {
          entityId
          enabled
          description
          required
          name
          link
          title
          instructions
          requireUpload
          uploads {
            id
            filename
            mimetype
            encoding
            url
          }
        }
      }
    `
      )
Running that now
So same thing: What PACT is expecting is all those fields under input but for some reason what's being sent is all that PLUS the wrapper of operationName, query, variables/input ie. this is the ACTUAL response
Copy code
{
  "operationName": "CreateCustomTask",
  "query": "\n      mutation CreateCustomTask($input: CustomTaskCreateInput!) {\n        createCustomTask(input: $input) {\n          entityId\n          enabled\n          description\n          required\n          name\n          link\n          title\n          instructions\n          requireUpload\n          uploads {\n            id\n            filename\n            mimetype\n            encoding\n            url\n          }\n        }\n      }\n    ",
  "variables": {
    "input": {
      "description": "id",
      "enabled": false,
      "entityId": "9d29ce8e-d99f-4406-8d05-2bdc3d2bca3b",
      "instructions": "cupiditate",
      "link": "aliquid",
      "linkText": "assumenda",
      "name": "aliquid",
      "requireUpload": true,
      "required": true,
      "title": "quia",
      "uploads": [
        {
          "encoding": "eos",
          "filename": "molestias",
          "id": "voluptatem",
          "mimetype": "sed",
          "url": "quis"
        },
        {
          "encoding": "eos",
          "filename": "molestias",
          "id": "voluptatem",
          "mimetype": "sed",
          "url": "quis"
        }
      ]
    }
  }
}
The EXPECTED response is just this:
Copy code
{
  "description": "id",
  "enabled": false,
  "entityId": "9d29ce8e-d99f-4406-8d05-2bdc3d2bca3b",
  "instructions": "cupiditate",
  "link": "aliquid",
  "linkText": "assumenda",
  "name": "aliquid",
  "requireUpload": true,
  "required": true,
  "title": "quia",
  "uploads": [
    {
      "encoding": "eos",
      "filename": "molestias",
      "id": "voluptatem",
      "mimetype": "sed",
      "url": "quis"
    },
    {
      "encoding": "eos",
      "filename": "molestias",
      "id": "voluptatem",
      "mimetype": "sed",
      "url": "quis"
    }
  ]
}
Tests are written in the same repos as the code and I'm decent as a QA at writing unit tests but what I was having the most trouble with was env vars as this is often set up for me For ex, right now the env vars I'm trying to hard code in my zshrc so that i can test from one branch on a repo to another branch on a repo aren't working, because those variables aren't seen in the docker container that runs the tests. But the docker container is run through a series of make files (i think you have to follow at least 20 different make files just to see what the command is actually doing). And I don't understand enough about docker, make files, env vars, as well as I'm usually on the FE side of things and not the BE side of things. But like i said before, QAs are often expected to just do these kind of things (often flying blind without repo access). And I want to get a dev/devops skill set so it's good to do, it's just difficult. For now though, i'm just pushing my changes in CI, clicking on the CI link to the broker, and viewing what happens in the broker. I feel like there's literally gotta be something i'm writing wrong in my pact that's sending the request information instead of the response body
If I comment out the cache, the pact test fails but i think that's a separate issue