Hi guys, good morning :wave:, I want to learn how ...
# pact-js
s
Hi guys, good morning πŸ‘‹, I want to learn how to use dynamic ids, for this create a dummy example to implement; I want to change a path param in the URL for a specific test case using a GET method; I see that it works fine on the consumer side but not on the provider side , below more details (I'm using version 10.0.0-beta.59)
this is my code for the consumer side:
Copy code
"use strict"

const { getRequest } = require("../../../helpers/sendRequest")
const identity_data = require("../../data/identity/get.identity.data")
const { PactV3, MatchersV3 } = require('@pact-foundation/pact/v3');
const { string, integer, url2, regex, datetime, fromProviderState, like } =
    MatchersV3;
const { createOptsConsumer } = require("../../../helpers/createOpts")

const provider = new PactV3(createOptsConsumer(identity_data));

describe("Validate pact of identity", () => {

    describe("Validate pact get identity", () => {

        test("Validate successful get of an identity without QR associated", async () => {

            provider
                .given('A message with a 200 OK without QR associated', { id: '45' })
                .uponReceiving('I want to get a new identity without QR')
                .withRequest({
                    method: 'GET',
                    path: fromProviderState('/public/v2/posts/${id}/comments', '/public/v2/posts/100/comments'),
                    headers: {
                        "Content-Type": "application/json",
                        "authorization": `Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730`
                    }
                })
                .willRespondWith({
                    status: 200,
                    body: [
                        {
                            "id": 107,
                            "post_id": 100,
                            "name": "Rakesh Nair",
                            "email": "<mailto:nair_rakesh@schoen.io|nair_rakesh@schoen.io>",
                            "body": "Sed vel ad. Ea similique tempora. In a iusto."
                        }
                    ]
                });

            return provider.executeTest(async (mockserver) => {
                const response = await getRequest(mockserver.url, identity_data.successfulDataWithoutQR.interaction.withRequest);
                expect(response.status).toEqual(identity_data.successfulDataWithoutQR.interaction.willRespondWith.status)
            });
        })

        test("Validate successful get of an identity with QR associated", async () => {
            provider
                .given('A message with a 200 OK with QR associated', { id: '50' })
                .uponReceiving('I want to get a new identity with QR')
                .withRequest({
                    method: 'GET',
                    path: fromProviderState('/public/v2/posts/${id}/comments', '/public/v2/posts/101/comments'),
                    headers: {
                        "Content-Type": "application/json",
                        "authorization": `Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730`
                    }
                })
                .willRespondWith({
                    status: 200,
                    body: []
                });

            return provider.executeTest(async (mockserver) => {
                const response = await getRequest(mockserver.url, identity_data.successfulDataWithQR.interaction.withRequest);
                expect(response.status).toEqual(identity_data.successfulDataWithQR.interaction.willRespondWith.status)
            });
        })

    })
})
this is the generated pact
Copy code
{
  "consumer": {
    "name": "getidentityConsumer"
  },
  "interactions": [
    {
      "description": "I want to get a new identity with QR",
      "providerState": "A message with a 200 OK with QR associated",
      "request": {
        "generators": null,
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "$.path": {
            "match": "type"
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/101/comments"
      },
      "response": {
        "body": [],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    },
    {
      "description": "I want to get a new identity without QR",
      "providerState": "A message with a 200 OK without QR associated",
      "request": {
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "$.path": {
            "match": "type"
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/100/comments"
      },
      "response": {
        "body": [
          {
            "body": "Sed vel ad. Ea similique tempora. In a iusto.",
            "email": "<mailto:nair_rakesh@schoen.io|nair_rakesh@schoen.io>",
            "id": 107,
            "name": "Rakesh Nair",
            "post_id": 100
          }
        ],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    }
  ],
  "metadata": {
    "pact-js": {
      "version": "10.0.0-beta.59"
    },
    "pactRust": {
      "ffi": "0.2.4",
      "models": "0.3.1"
    },
    "pactSpecification": {
      "version": "1.1.0"
    }
  },
  "provider": {
    "name": "getidentityProvider"
  }
}
this is my code for the provider side
Copy code
"use strict"

const { VerifierV3 } = require('@pact-foundation/pact/v3');
const identity_data = require("../../data/identity/get.identity.data")
const { createOptsProvider } = require('../../../helpers/createOpts');


describe("Validate pact of identity", () => {

    it("validate the pact of an identity get", () => {

        let opts = {
            consumerVersionTags: ['QA'],
            providerVersionTags: ['QA'],
            providerVersion: '1.0.0',
            providerBaseUrl: '<https://gorest.co.in>',
            changeOrigin: true,
            logLevel: 'TRACE',
            provider: 'getidentityProvider',
            pactUrls: [
                'C:\\pact\\transfers-be-automation-test-pact\\__tests__\\contract\\pacts\\getidentityConsumer-getidentityProvider.json'
            ],
            stateHandlers: {
                'A message with a 200 OK without QR associated': {
                    setup: (params) => {
                        console.log("Entering to the state");
                        console.log(params);
                        Promise.resolve({ id: 102 });
                    }
                }
            },
        }

        return new VerifierV3(opts).verifyProvider()
            .then((res) => {
                console.log('Pact Verification Complete!: Get identity ', res);
            }).catch((res) => {
                throw new Error('Pact Verification FAIL!: Get identity ', res);
            });
    })

})
the problem is that i want to change (in this dummy example) the url https://gorest.co.in/public/v2/posts/100/comments to https://gorest.co.in/public/v2/posts/102/comments but it doesn't work, maybe you know what i'm doing wrong? πŸ€”
the complete log:
y
Not sure if this is the same in v3, but in v2 you had the ability to set a value in the state handlers, and feed in via request filters https://github.com/pact-foundation/pact-js#modify-requests-prior-to-verification-request-filters see here for some context around when I was trying to access the body https://github.com/pact-foundation/pact-js/issues/304
This is the section in the docs about it, in v3
s
thanks @Yousaf Nabi (pactflow.io) 😁 for the comment, yep actually I'm following the instructions of the post that you mentioned (https://github.com/pact-foundation/pact-js#request-filters), also I'm implementing something like this https://github.com/pact-foundation/pact-js/tree/feat/v3.0.0/examples/v3/provider-state-injected, but I don't know what is happening jejeje, the id doesn't change
πŸ˜… 1
πŸ‘€ 1
y
I will have to test out that example as I haven't tried it out, or really kicked the tyres on v3, been caught up with 101 things!
s
@Yousaf Nabi (pactflow.io) Thank you very much for your help 😎, I created a repository with the complete implementation of the example, it could be clearer 😁 https://github.com/athan3350/pactjs-implementation
y
Hey @Sebastian Suarez, I haven't sorry, I did take a cursory look and I loved your readme chefkiss . Promise to get it on the radar as soon as possible
s
oh jeje thank you πŸ₯³πŸ‘Œ
y
@Sebastian Suarez remove this line https://github.com/athan3350/pactjs-implementation/blob/019d3dcd5358676fd66960d3bb[…]0f25fab4b6e948/__tests__/contract/consumer/get.consumer.spec.js
spec:2
as it in not generating the correct contracts, this is after removing that the provider side is amending the URL correctly. Btw there are some other things that will cause you issue in your test setup 1. Your consumer tests pass, even if you an an expectation that fails, such as expecting the body to some something or that the expected result. You can see the pact-verifier throwing an error,. 2. Your have fixed responses on your consumer side and you are testing against a live service, both of which are less than ideal.
Copy code
{
  "consumer": {
    "name": "getidentityConsumer"
  },
  "interactions": [
    {
      "description": "I want to get a new identity with QR",
      "providerStates": [
        {
          "name": "A message with a 200 OK with QR associated",
          "params": {
            "id": "50"
          }
        }
      ],
      "request": {
        "generators": {
          "path": {
            "expression": "/public/v2/posts/${id}/comments",
            "type": "ProviderState"
          }
        },
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "header": {},
          "path": {
            "combine": "AND",
            "matchers": [
              {
                "match": "type"
              }
            ]
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/101/comments"
      },
      "response": {
        "body": [],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    },
    {
      "description": "I want to get a new identity without QR",
      "providerStates": [
        {
          "name": "A message with a 200 OK without QR associated",
          "params": {
            "id": "45"
          }
        }
      ],
      "request": {
        "generators": {
          "path": {
            "expression": "/public/v2/posts/${id}/comments",
            "type": "ProviderState"
          }
        },
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "header": {},
          "path": {
            "combine": "AND",
            "matchers": [
              {
                "match": "type"
              }
            ]
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/100/comments"
      },
      "response": {
        "body": [
          {
            "body": "Sed vel ad. Ea similique tempora. In a iusto.",
            "email": "<mailto:nair_rakesh@schoen.io|nair_rakesh@schoen.io>",
            "id": 107,
            "name": "Rakesh Nair",
            "post_id": 100
          }
        ],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    }
  ],
  "metadata": {
    "pact-js": {
      "version": "10.0.0-beta.59"
    },
    "pactRust": {
      "ffi": "0.2.4",
      "models": "0.3.1"
    },
    "pactSpecification": {
      "version": "3.0.0"
    }
  },
  "provider": {
    "name": "getidentityProvider"
  }
}
@Matt (pactflow.io / pact-js / pact-go) if we set
spec: 2
in the provider v2 options, we get a
v1.1.0
spec generated. Looking at the types, neither of those are supported (allowing options are 3 and 4).
Copy code
{
  "consumer": {
    "name": "getidentityConsumer"
  },
  "interactions": [
    {
      "description": "I want to get a new identity with QR",
      "providerState": "A message with a 200 OK with QR associated",
      "request": {
        "generators": null,
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "$.path": {
            "match": "type"
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/101/comments"
      },
      "response": {
        "body": [],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    },
    {
      "description": "I want to get a new identity without QR",
      "providerState": "A message with a 200 OK without QR associated",
      "request": {
        "headers": {
          "Content-Type": "application/json",
          "authorization": "Bearer c71a5d82d1d52eb305b9302363ff68502737cca35426d880cc9a5c934f0c1730"
        },
        "matchingRules": {
          "$.path": {
            "match": "type"
          }
        },
        "method": "GET",
        "path": "/public/v2/posts/100/comments"
      },
      "response": {
        "body": [
          {
            "body": "Sed vel ad. Ea similique tempora. In a iusto.",
            "email": "<mailto:nair_rakesh@schoen.io|nair_rakesh@schoen.io>",
            "id": 107,
            "name": "Rakesh Nair",
            "post_id": 100
          }
        ],
        "headers": {
          "Content-Type": "application/json"
        },
        "status": 200
      }
    }
  ],
  "metadata": {
    "pact-js": {
      "version": "10.0.0-beta.59"
    },
    "pactRust": {
      "ffi": "0.2.4",
      "models": "0.3.1"
    },
    "pactSpecification": {
      "version": "1.1.0"
    }
  },
  "provider": {
    "name": "getidentityProvider"
  }
}
m
Interesting. That might be a mapping issue Yousaf. I'll fix tonight, good pickup
OK just taken a look now. This interface actually accepts a
SpecificationVersion
enum, which correctly maps to the right spec. But because JS, you can shove any number in there. Because this maps to an underlying enum, it actually maps to 1.1 (hence the problem). It might need a guard added to the method to ensure only valid specs can be specified. I’ll have a think about a nice way of doing it
y
Hmmm, I wonder if β€’ we could spit out a warning when using that
v1
spec was used but no longer supported, β€’ if someone provides a spec version, but uses matchers/generators that aren't supported, when we throw an error. I think the 2nd point leads into the discussion around the pact specs and generators, trying to find the thread
This was the blurb, and link to the discussion. Got my thinking cap on
The feature support issue is still also a big challenge. The specification only governs the contract format and matching rules, but is silent on other behaviour (see also https://github.com/pact-foundation/pact-net/pull/380).
So, to avoid incompatibility issues you have to know:
1. What version of the client library you are on (what features it supports)
2. What specification it supports (contract file compatibility)
3. What are the versions of each of the providers you have (to determine feature support)
4. What specification it supports (to determine if the contract file is compatible)
That information isn’t accessible anywhere, and, it could be argued, is a lot to expect of a user
s
Hi @Yousaf Nabi (pactflow.io) πŸ‘‹ thanks for your help, you rock πŸ˜ŽπŸ‘Œ, you are absolutely right with the change, I already see that the contract is generated with the id variable, but I see that when I run the provider the id variable does not change, (I try to change it to 100 so that the call at api returns an empty array), it is still making the call with the id variable set to 101, I already updated the repo https://github.com/athan3350/pactjs-implementation it could be clearer 😁
y
You are calling a real end point and there is data there, not an empty array as you expect
You should be running your provider in isolation, so off the back of your injected data in your state handler, and you can control your providers response based on the value in the state handler
If you put Id of 999 you get some random data in that pre seeded api, and go to the browser for that Id you’ll see the same response
s
@Yousaf Nabi (pactflow.io) yep, that is a dummy example, in my real project. I'm not pointing to a real API else to a code made in react, what I'm trying to do with this example is learn how to change parameters in my URL from the provider side.
but I see that the variable $id does not change on the provider side, it always stays at 101, maybe I'm doing something wrong πŸ˜•
y
that is calling this URL https://gorest.co.in/public/v2/posts/999/comments and the errors are correct, you are trying to match a random response, against a fixed response encoded in your consumer test
Copy code
[2022-04-21T16:25:29Z DEBUG pact_matching::json] JSON -> JSON: Comparing '100' to '999' using Equality -> Err(Expected '100' to be equal to '999')
[2022-04-21T16:25:29Z DEBUG pact_matching::json] compare_values: Comparing 'Number(100)' to 'Number(999)' at path '$[0].post_id' -> Err(["Expected '100' to be equal to '999'"])
post ID 107 has an empty array https://gorest.co.in/public/v2/posts/100/comments
Copy code
2) Verifying a pact between getidentityConsumer and getidentityProvider Given A message with a 200 OK without QR associated - I want to get a new identity without QR
    2.1) has a matching body
           $ -> Expected {"body":"Sed vel ad. Ea similique tempora. In a iusto.","email":"<mailto:nair_rakesh@schoen.io|nair_rakesh@schoen.io>","id":107,"name":"Rakesh Nair","post_id":100} but was missing
           $ -> Expected a List with 1 elements but received 0 elements
☝️ 1
❀️ 1
s
Hi @Yousaf Nabi (pactflow.io), Sorry I hadn't seen your message, you're right ❀️, I was looking at the logs wrong, thank you very much for your help (as always jejej), this helps me a lot πŸ˜ŽπŸ‘Œ
πŸ‘ 1

https://media.giphy.com/media/DGWAx8d3IkICs/giphy.gifβ–Ύ