Hi :wave:, We're just getting started using <pact....
# pact-ruby
r
Hi 👋, We're just getting started using pact.io for api contracts between our frontend platform and ruby monolith. I'm having trouble as the provider state
set_up
method is not being called prior to the interaction being verified. Can anyone help? Here are some code snippets:
Copy code
from the contract:
  "interactions": [
    {
      "description": "a request to GET cards",
      "providerState": "user has cards", ...

from the provider states files:

Pact.provider_states_for "bloomandwild-frontend" do
  provider_state "user has cards" do
    # code reaches here
    set_up do
          # code doesn't reach here
apart from that, the verification is working - ie I can successful verify an interaction that requires no set up. Any help or advice appreciated TIA
b
@Rachel Bingham what is the output of the test?
r
The test fails as the expected user has not been set up in the database
Copy code
1) Verifying a pact between bloomandwild-frontend and v1-cards Given user has cards a request to GET cards with GET /api/v1/cards?locale=en&shipping_country_id=1 returns a response which has status code 200
     Failure/Error: expect(response_status).to eql expected_response_status
     
       expected: 200
            got: 302
Basically, the auth fails as user doesn't exist so response is a redirect.
b
have you put a debug point in to see that it's not being executed?
is there any output to say that the provider state definition wasn't found?
r
No. See my comments in the code. It finds the provider state but never seems to execute the set_up method
b
there's nothing obviously wrong in the snippet you've shared 🤔
Can you share a code example that shows the issue for me to debug?
r
Here are all the files (user data is made up)
Copy code
# pack_helper.rb
require "pact/provider/rspec"
require "pry"
require "rails_helper"

require_relative "provider_states_for_bloomandwild_frontend.rb"

Pact.service_provider "v1-cards" do
  honours_pact_with "bloomandwild-frontend" do
    pact_uri "spec/pacts/bloomandwild-frontend-v1-cards.json"
  end
end

# provider_states_for_bloomandwild_frontend.rb
Pact.provider_states_for "bloomandwild-frontend" do
  provider_state "user has cards" do
    set_up do
      user = User.create!(id: 6390154, email: "<mailto:markus123456@bloomandwild.com|markus123456@bloomandwild.com>")
      user.credit_cards.create!(
        "brand": "Visa",
        "created_at": "2022-03-21T09:59:57.543+00:00",
        "exp_month": 2,
        "exp_year": 2024,
        "id": 10121358,
        "kind": "card",
        "last4": "4242",
        "temporary": false,
        "token": "card_1Kfi1oKoz4lNOAHNvfFpz1ec",
        "updated_at": "2022-03-21T09:59:57.581+00:00",
      )
      UserToken.create!(user: user, kind: :login, token: "BYsijJUFrmzU-pTzhaZM")
    end

    tear_down do
      no_op
      # clean up objects
    end
  end
end

# the contract

{
  "consumer": {
    "name": "bloomandwild-frontend"
  },
  "provider": {
    "name": "v1-cards"
  },
  "interactions": [
    {
      "description": "a request to GET cards",
      "providerState": "user has cards",
      "request": {
        "method": "GET",
        "path": "/api/v1/cards",
        "query": "locale=en&shipping_country_id=1",
        "headers": {
          "Accept": "application/json, text/plain, */*",
          "x-angular-version": "6",
          "x-fingerprint": "eaa08c06-ada8-4717-831d-e480d2dd12f3",
          "x-fingerprint-old": "",
          "x-user-email": "<mailto:markus123456@bloomandwild.com|markus123456@bloomandwild.com>",
          "x-user-token": "BYsijJUFrmzU-pTzhaZM"
        },
        "matchingRules": {
          "$.headers.x-fingerprint": {
            "match": "type"
          },
          "$.headers.x-user-email": {
            "match": "type"
          },
          "$.headers.x-user-token": {
            "match": "type"
          }
        }
      },
      "response": {
        "status": 200,
        "headers": {
        },
        "body": {
          "cards": [
            {
              "brand": "Visa",
              "created_at": "2022-03-21T09:59:57.543+00:00",
              "exp_month": 2,
              "exp_year": 2024,
              "id": 10121358,
              "kind": "card",
              "last4": "4242",
              "name": "Visa ending 4242 (exp. 2/24)",
              "temporary": false,
              "token": "card_1Kfi1oKoz4lNOAHNvfFpz1ec",
              "updated_at": "2022-03-21T09:59:57.581+00:00",
              "user_id": 6390154
            }
          ]
        },
        "matchingRules": {
          "$.body.cards": {
            "min": 1
          },
          "$.body.cards[*].*": {
            "match": "type"
          },
          "$.body.cards[*]": {
            "match": "type"
          }
        }
      }
    }
  ],
  "metadata": {
    "pactSpecification": {
      "version": "3.0.0"
    }
  }
}
Sry hit return too soon!
b
it looks fine to me.
are you comfortable using pry-byebug?
r
Yeah, that is how I found out no data is being created and that it never seems to execute set_up
But, as I said above, for an interaction which requires no set up, I can verify it. So everything seems to be working except for the set up.
b
can you run
bundle open pact
to get the source code open?
r
I can view the gem source code (is that what you mean)?
b
put a break point in
lib/pact/provider/test_methods.rb:45
👀 1
I can view the gem source code
yes, on your local machine
r
Hmm, it is showing no provider_states
Copy code
pry > provider_states
[]
b
make double sure all the names match up
r
Yup, I have double checked but I guess something, somewhere is awry. I just can't see what 🤷
But now I know which part of the the gem to look in, I can carry on debugging. Thanks for helping.
b
Have a look in
lib/pact/provider/state/provider_state.rb
as well.
r
The state is missing from the
interaction
interaction { :description => "a request to GET cards", :provider_states => [], :request => { :method => "GET",
Hmm why multiple provider states? In the contract, there is only one but here in the gem it has an array.
Is there some other syntax? I tried changing the contract to
Copy code
"providerStates": ["user has cards"],
and now the interaction has this
Copy code
:description => "a request to GET cards",
    :provider_states => [
        [0] {
              "name" => nil,
            "params" => nil
        }
    ],
so I wondering how to add my one state in an array format?
b
what version of pact are you using?
that' says it's a v3 pact specification pact, but the provider state format is in v2 format.
in v3, it's an array of hashes
in v2, it's just a string.
r
My FE team used v3 to create the contract, my gem version is 1.62.0
b
what language wrote the contract?
r
Copy code
Angular (I think!)
I'm thinking gem version is not the same a pact version, right?
1.62.0 seems very recent (2022-02-21)
b
gem version is different to the pact specification version.
I think the problem is, there are two parsers, and it uses the parser based on the pact specification number.
your pact says it's v3, so the v3 parser is looking for an array at
providerStates
provider_states = parse_provider_states(hash['providerStates'])
r
Oo, I just changed to contract to say pact v2 and I have a provider state.
b
but it's actually v2
I think the angular code needs to specify v 2.0
if it's the implementation backed by the ruby shared codebase, then it does not support v3.
it's unfortunate that it lets you specify 3.0
feel free to raise an issue in the pact-ruby-standalone project
r
Okay. FE dev did ask me which version to use and I said latest ie v3 is fine. I think I have lots more to go on now. Hopefully we can get it sorted. Thanks so much for your help @Beth (pactflow.io/Pact Broker/pact-ruby) 🙏
b
no worries, glad we got it sorted
r
yep. bedtime for me now. tyvm
🛏️ 1
s
Hello! A little late here, but the solution was to change the contract version from 2 to 3? Like
Copy code
"metadata": {
    "pactSpecification": {
      "version": "3.0.0"
    }
  }
I'm having the same issue
Fixed it by upgrading the JS client to beta, but still not getting it to call
set_up
b
You can't just change the number. You have to change the format.