Giter Site home page Giter Site logo

pact-mock_service's Introduction

Pact Mock and Stub Service

Build Status

This codebase provides the HTTP mock and stub service used by implementations of Pact. It is packaged as a gem, and as a standalone executable for Mac OSX and Linux and Windows.

The mock service provides the following endpoints:

  • DELETE /interactions - clear previously mocked interactions
  • POST /interactions - set up an expected interaction
  • PUT /interactions - clear and set up multiple expected interactions in one call
  • GET /interactions/verification - determine whether the expected interactions have taken place
  • POST /pact - write the pact file
  • GET / - the healthcheck endpoint

All requests to the "administration" endpoints listed above must contain the header X-Pact-Mock-Service: true to allow the mock service to know whether the request is an administration request or a request from the actual consumer code.

As the Pact mock service can be used as a standalone executable and administered via HTTP, it can be used for testing with any language. All that is required is a library in the native language to create the HTTP calls listed above. Check out docs.pact.io for a list of implemented languages. If you are interested in creating bindings in a new language, have a chat to one of us on the pact-dev Google group.

Installation

Without Ruby

Use the Pact standalone executables.

With Ruby

Use the pact gem if you would like the full Pact DSL, mock service and verification functionality in your ruby project.

Otherwise:

$ gem install pact-mock_service
$ pact-mock-service --consumer Foo --provider Bar --port 1234

Or add gem "pact-mock_service" to your Gemfile then run:

$ bundle install
$ bundle exec pact-mock-service --consumer Foo --provider Bar --port 1234

Run pact-mock-service help for command line options.

Mock Service Usage

Each mock service process is designed to mock only ONE provider for ONE consumer. To mock multiple providers, you will need to start a process for each provider. The lifecycle of a mock service instance during a test suite execution is as follows:

  • Before suite: start mock service
  • Before each test: clear interactions from previous test
  • During test: set up interactions, execute interactions
  • After each test: verify interactions
  • After suite: write pact file, stop mock service

Each mock service instance can only handle one test process/thread at a time. If you wish to run multiple test threads in parallel, you will need to start each mock service instance on a different port, and set the --pact-file-write-mode to merge (see usage notes below).

Usage:
  pact-mock-service service

Options:
      [--consumer=CONSUMER]                                      # Consumer name
      [--provider=PROVIDER]                                      # Provider name
  -p, [--port=PORT]                                              # Port on which to run the service
  -h, [--host=HOST]                                              # Host on which to bind the service
                                                                 # Default: localhost
  -d, [--pact-dir=PACT_DIR]                                      # Directory to which the pacts will be written
  -m, [--pact-file-write-mode=PACT_FILE_WRITE_MODE]              # `overwrite` or `merge`. Use `merge` when running multiple mock service instances in parallel for the same consumer/provider pair. Ensure the pact file is deleted before running tests when using this option so that interactions deleted from the code are not maintained in the file.
                                                                 # Default: overwrite
  -i, [--pact-specification-version=PACT_SPECIFICATION_VERSION]  # The pact specification version to use when writing the pact
                                                                 # Default: 2
  -l, [--log=LOG]                                                # File to which to log output
  -o, [--cors=CORS]                                              # Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses
      [--ssl], [--no-ssl]                                        # Use a self-signed SSL cert to run the service over HTTPS
      [--sslcert=SSLCERT]                                        # Specify the path to the SSL cert to use when running the service over HTTPS
      [--sslkey=SSLKEY]                                          # Specify the path to the SSL key to use when running the service over HTTPS

Start a mock service. If the consumer, provider and pact-dir options are provided, the pact will be written automatically on shutdown (INT).

See script/example.sh for an executable example.

You can find more documentation for the mock service in the repository wiki.

With SSL

If you need to use the mock service with HTTPS, you can use the built-in SSL mode which relies on and generates a self-signed certificate.

$ pact-mock-service --port 1234 --ssl

If you need to provide your own certificate and key, use the following syntax.

$ pact-mock-service --port 1234 --ssl --sslcert PATH_TO_CERT --sslkey PATH_TO_KEY

With CORS

Read the wiki page on CORS.

Stub Service Usage

The pact-stub-service allows you to reuse interactions that have been generated in previous tests. The typical situation would be to generate your pact file using unit tests, and then use the pact stub service for your higher level integration/ui tests. To help reduce the number of interactions that need verifying, you will want to use flexible matching on both requests and responses.

Unlike the mock service, which has a Ruby DSL for managing its lifecycle, the mock service can currently only be started from the command line, so you will need to start/background/kill the process yourself. If this is causing problems, please raise it in the pact-dev google group and we can discuss potential enhancements.

Usage:
  pact-stub-service PACT_URI ...

Options:
  -p, [--port=PORT]        # Port on which to run the service
  -h, [--host=HOST]        # Host on which to bind the service
                           # Default: localhost
  -l, [--log=LOG]          # File to which to log output
  -o, [--cors=CORS]        # Support browser security in tests by responding to OPTIONS requests and adding CORS headers to mocked responses
      [--ssl], [--no-ssl]  # Use a self-signed SSL cert to run the service over HTTPS
      [--sslcert=SSLCERT]  # Specify the path to the SSL cert to use when running the service over HTTPS
      [--sslkey=SSLKEY]    # Specify the path to the SSL key to use when running the service over HTTPS

Description:
  Start a stub service with the given pact file(s). Pact URIs may be local file paths or HTTP.
  Include any basic auth details in the URL using the format https://USERNAME:PASSWORD@URI.
  Where multiple matching interactions are found, the interactions will be sorted by
  response status, and the first one will be returned. This may lead to some non-deterministic
  behaviour. If you are having problems with this, please raise it on the pact-dev google group,
  and we can discuss some potential enhancements.
  Note that only versions 1 and 2 of the pact specification are currently fully supported.
  Pacts using the v3 format may be used, however, any matching features added in v4 will
  currently be ignored.

Contributing

See CONTRIBUTING.md

pact-mock_service's People

Contributors

adbrowne avatar aerowiel avatar allavena avatar andreasf avatar barthez avatar benjaminpjacobs avatar bethesque avatar blackbaud-jonathanbell avatar dependabot[bot] avatar f1337 avatar georgepapas avatar heathd avatar inksprout avatar kpse avatar lextiz avatar mefellows avatar mhall58 avatar mtchavez avatar nagliyvred avatar neilcampbell avatar ojab avatar redbeard avatar robindaugherty avatar sergei-matheson avatar sk1talets avatar taiki45 avatar thatguysimon avatar timothyjones avatar vandemark avatar you54f avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pact-mock_service's Issues

Discussion - Optional fields in pact

Hi Beth,
I had so many discussions in my company about the same problem, that I'd like to expose it.
Just so we can talk about it, as I feel I'm missing some kind of capability.
We are "pact verifying" a lot of end points and there are always some properties on a JSON output that are not always there. Properties or even whole objects.

We kind of come to conclusion where we should either:

  • hard-code end point output in the interaction, use provide states, and not use matchers
  • remove optional fields from interaction

Here is a simple example of a list of categories for books:

{
	"_embedded": {
		"categories": [
			{
				"name": "Children",
				"_links": {
					"doc:books": {
						"href": "http://example.com/list-of-books?category=children"
					}
				}
			},
			{
				"name": "Factual",
				"_links": {}
			}
		]
        }
}

In this list of categories, the _links object may or may not contain a url that point to a list of books.

This is how my response interaction looks like:

{
    "_embedded": {
        "categories": Pact.Matchers.eachLike({
            "name": Pact.Matchers.somethingLike("Children"),
            "_links": {
                "doc:books": {
                    "href": Pact.Matchers.term({
                        matcher: "^(?=.*list-of-books)(?=.*category=)",
                        generate: "http://example.com/list-of-books?category=children"
                    })
                }
            }
        })
    }
}

When I come to verifying mocks, which may or may not have the links in each categories, the verification would fail as the pact interaction is expecting to always have a doc:books links.

What are my solutions?

  1. remove the optional part:
{
    "_embedded": {
        "categories": Pact.Matchers.eachLike({
            "name": Pact.Matchers.somethingLike("Children")
        })
    }
}

Problem: it doesn't represent the reality, url are not tested
Benefit: can verify any mock files

  1. use provider state, remove eachLike matcher, basically hard-code response
{
    "_embedded": {
        "categories": [
            {
                "name": "Children",
                "_links": {
                    "doc:books": {
                        "href": Pact.Matchers.term({
                            matcher: "^(?=.*list-of-books)(?=.*category=)",
                            generate: "http://example.com/list-of-books?category=children"
                        })
                    }
                }
            },
            {
                "name": "Factual",
                "_links": {}
            }
        ]
    }
}

Problem: it still doesn't represent the reality, can't verify mock files that are different from this response
Benefit: can test both case of having and not having the links

How I would like to write the interaction

I don't know if that's feasible, but if I had some kind of an "optional matcher", that would be applied or not applied depending of the existence of a node, it would help me write the interaction. I would also be able to verify any mock files and it would also represent the reality.

Something like (see the <Pact.Matchers.optional> in the node property):

{
    "_embedded": {
        "categories": Pact.Matchers.eachLike({
            "name": Pact.Matchers.somethingLike("Children"),
            "_links": {
                "<Pact.Matchers.optional>doc:books": {
                    "href": Pact.Matchers.term({
                        matcher: "^(?=.*list-of-books)(?=.*category=)",
                        generate: "http://example.com/list-of-books?category=children"
                    })
                }
            }
        })
    }
}

Any thought of how to approach this problem?

When adding request, the HTTP type MUST be lowercase, defying HTTP convention

This will work:

provider.given('initial state')
    .uponReceiving('a request for all the data')
    .withRequest('get', '/')
    .willRespondWith({
        status: 200,
        headers: { 'Content-Type': 'application/json' },
        body: 'weee'
    });

This will not:

provider.given('initial state')
    .uponReceiving('a request for all the data')
    .withRequest('GET', '/')
    .willRespondWith({
        status: 200,
        headers: { 'Content-Type': 'application/json' },
        body: 'weee'
    });

Spent a good hour trying to figure that tidbit out... Please fix.

Release page links broken

Hey,

The links on the release page incorrectly prefix the version with a 'v', which causes a 404.

curl -LO https://github.com/bethesque/pact-mock_service/releases/download/v0.7.1/pact-mock-service-0.7.1-1-osx.tar.gz

should be

curl -LO https://github.com/bethesque/pact-mock_service/releases/download/0.7.1/pact-mock-service-0.7.1-1-osx.tar.gz

Note, there is no v in download/0.7.1/...

gp

JSON dependency not downloading automatically when installing

After installing ruby and gems, we run a simple gem i pact-mock_service which seems to download just fine and it's able to use the command, but it crashes since it's missing the json dependency.

It doesn't seem to download it automatically or it simply fails silently since the json dependency needs the dev kit to be installed as well.

Trailing slash of path gets removed when query parameter is used

I have come across an issue when using a query parameter on the pact.with_request()

The issue is when your path has a trailing slash and you are including a query in your request

The resulting contract splits the path and query into separate keys under request but does not include the trailing slash as a part of the path.

I have included a link to a gist of an example test that generates a contract as well as the contract it generated in the comments

https://gist.github.com/nickshoust-wf/5850df10ec556632e8eee467f6819199

Arrays in query parameters not translated to have square brackets in the url

When setting a provider state like:

        some_service.given('some scenario')
          .upon_receiving('a request for questions')
          .with(method: :get, path: '/questions', query: { question_ids: [1,2] })

and sending in query params hash is like this:

query_params_hash = { question_ids: [1,2] }

I encounter the following error:

Missing requests:
            	GET /questions?question_ids=1&question_ids=2

            Unexpected requests:
            	GET /questions?question_ids[]=1&question_ids[]=2

The square brackets are missing from the expected request

Strange timezone adjustment issue

I'm running into a strange issue in my pact tests which I believe I have isolated to the pact-mock_service. My service is .NET (C#) and in one of my interactions I setup an interaction with a DateTimeOffset string in the body the timezone of that string is changed (and the time correctly adjusted) when the pact file is written. Because developer machines may run on a different timezone than build machines, this causes issues.

To reproduce this, and eliminate the I called the admin REST endpoints directly. I set the timezone on my machine to Pacific Time (UTC-08:00). After starting the mock service, I made two calls:

First:
POST /interactions

{
	provider_state: 'test',
	description: 'test',
	request: {
		method: 'get',
		path: '/test'
	},
	response: {
		status: 200,
		headers: {
			'Content-Type': 'application/json; charset=utf-8'
		},
		body: {
			datetimeoffset: '2012-12-12T01:11:11-05:00'
		}
	}
}

This returned:
200
Added interaction

Then:
POST /pact

{
	provider: {
		name: 'test-participant'
	},
	consumer: {
		name: 'test-consumer'
	}
}

This returned:
200

{
  "provider": {
    "name": "test-participant"
  },
  "consumer": {
    "name": "test-consumer"
  },
  "interactions": [
    {
      "description": "test",
      "provider_state": "test",
      "request": {
        "method": "get",
        "path": "/test"
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json; charset=utf-8"
        },
        "body": {
          "datetimeoffset": "2012-12-11T22:11:11-08:00"
        }
      }
    }
  ],
  "metadata": {
    "pactSpecificationVersion": "1.1.0"
  }
}

Note that the timezone has been adjusted, although it still refers to the same point in time.

With the mock server still running, I can set my timezone to Eastern Time (UCT-05:00) and call POST /pact again and get the same result (timezone adjusted). This suggests that something is happening to the date when the interaction is added.

I'm not familiar with Ruby so I wasn't able to debug into the server itself. Does this sound like an issue with the mock service, or am I just doing something wrong?

interactions with query parameters embedded directly in the URL are considered non-matching

Setting up an interaction using a withRequest component as in

myProvider.withRequest({
    method: "get",
    path: "/resource?query=param"
});

leads to a No matching interaction found for GET /resource?query=param error on the mock service end.

However, if I split out the query parameter into a dedicated query property as in

myProvider.withRequest({
    method: "get",
    path: "/resource",
    query: { query: "param" }
});

the interaction is matched successfully.

While it should probably be good practice to separate the path from the query parameter, I think that the mock service should still consider the interaction as matching in this case in order to avoid confusion on the user's end. This seems especially important when employing the more concise syntax

myProvider.withRequest("get", "/resource?query=param")

where a separate object is not required to specify the request.

If making the mock service more flexible in this regards is not an option, then I'd suggest to at least improve the error message because the current one makes it fairly hard to see what the problem is.

Pact mock server not returning proper CORS headers

My Pact mock server is listening in different port from my tests and my pact mock server is running with following configuration:

const provider = pact({
consumer: 'myconsumer',
provider: 'myprovider',
port: 8989,
cors: true,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'DEBUG',
spec: 1
});

I request the above mock server using 'axios' and the request is matched with one of the interaction i have configured on the provider (as per pact.log). But response always throws error with CORS.

My pact log has following information:
Received OPTIONS request for mock service administration endpoint POST /interactions. Returning CORS headers: {"Access-Control-Allow-Origin":"null","Access-Control-Allow-Headers":"x-pact-mock-service","Access-Control-Allow-Methods":"DELETE, POST, GET, HEAD, PUT, TRACE, CONNECT, PATCH"}.

why is Access-Control-Allow-Origin is null instead of '*'. ?

How can i disable CORS security completely with tests as the final resorts when i use webpack, npm and mocha based tests.?

Request matching with an array in the body

We have a request which has an array at the top level of the body which I am unable to perform a type match on.
For example:

        .withRequest({
            method: 'post',
            path: '/xxx/en',
            body: {
                  "json_class": "Pact::SomethingLike",
                    "contents": ["REVISION_HISTORY"]
               }
             })

This request only matches request with ["REVISION_HISTORY"] in the body and not all arrays.

Cannot stop log/pact.log from being created

I'm starting the pact mock service using this command:

pact-mock-service --port 1234 --log build-output/pact-mock-service-logs/pact.log --cors --pact-dir build-output/pact

Despite the fact I am passing a specific log file the file log/pact.log is created with the following contents:

# Logfile created on 2015-03-03 00:22:16 +1100 by logger.rb/31641

If I'm doing it wrong please let me know. Otherwise I think this is a bug.

I am using pact-mock_service 0.4.1, Ruby 1.9.3p551 and OS X 10.10.2.

CORS missing pre-flight requests

See pact-foundation/pact-js#58 (comment) for some background.

If you start the mock service as follows:

pact-mock-service --cors true --port 1234

And then cURL it, you can see, the Access-Control-Allow-Origin: * header is coming back, but nothing to do with methods it supports (e.g. Access-Control-Allow-Methods or the other headers) . Further more, a cURL with OPTIONS is returning a 500 which means pre-flight requests won't work.

GET and POST (and HEAD) requests don't require a pre-flight, which probably explains why they have worked to date, however PUT and others do.

Looks like we don't support the OPTIONS pre-flight check, and probably explicitly allow all methods to be used.

Should the client be able to control where the server writes pact files?

consumer_contract_params = default_options.merge(consumer_contract_details.merge(interactions: verified_interactions))

The configuration options and the post body are merged on that line to configure the ConsumerContractWriter. As I found when investigating a problem integrating pact-js with pack-mock_service, this means that the fields sent in the request depend on the launch configuration: a client may not know how the server was launched and therefore whether to supply pact_dir as part of the request body.

Further, the use of Hash#merge here means that the client can always override the configured pact_dir, controlling the output folder. That means the client can force the server to e.g. fill up a different volume than the intended pact_dir location, or write pacts to a folder not expected when the service was configured.

It seems that it should be an error not to provide a pact_dir on launch, or a reasonable default should be chosen, and that the mock service should not read it from the post request on writing a pact.

Misleading "No interaction" summary message in some situations

When an interaction described in the test suite differs from the interaction sent by the client, the summary message is something like:

  1) SomeProvider service View can add a new view :
     No interaction found for PATCH /view/

It's easy to read this as implying that the problem is with the POST or the /view/ not matching in the request, when it might be because the request fails to match for other reasons (such as a different body content or headers).

Further up, the detailed output says:

Pact verification failed!
Actual interactions do not match expected interactions for mock MockService.

Incorrect requests:
	PATCH /view/0 (request body did not match)

See /Users/tjones/office/jobsearch-malcolm-ui/logs/pact.log for details.
        2) "after each" hook for ""

I think the incorrect requests line there: PATCH /view/0 (request body did not match) would be a better summary than the No interaction found message.

If there's no easy way to pull a good summary for all the cases that cause No interaction, then an easy improvement would be:

No interaction found for PATCH /view/ (see detailed output above)

Happy to contribute PRs if it would be helpful.

Using pact-mock-server as mock data provider?

Can I use the pact-mock-service as data-provider for my integration and unit test?

If it possible to implement the following scenario:

  1. Define interactions (in the simplest variant with the same provider and consumer values for different tests)
  2. run those consumer contract definitions against pact-mock-server ( e.g. in current implementation run code that will populate the pact files).
  3. query pack-mock-server with XHR requests to get responses, from interactions ( from step 0. )

Thus populate the pack-mock-server with interactions and query it for responses from those interactions.

So we will use the interaction definitions as definition of mock data for our tests.

TCPServer Error: Cannot assign requested address - bind(2) for "::1" port

Hi,

I have followed the instructions mentioned here https://github.com/pact-foundation/pact-ruby-standalone/releases for the Linux x64 platform.

When I run the this command ./pact-mock-service start
I get the following message

INFO WEBrick 1.3.1
INFO ruby 2.2.2 (2015-04-13) [x86_64-linux]
WARN TCPServer Error: Cannot assign requested address - bind(2) for "::1" port 9222
INFO WEBrick::HTTPServer#start: pid=671 port=9222

I see this warning "TCPServer Error" only on the Linux Platform, I have tried Windows and OSX and both are working fine.
In the message it says it is a warning but in reality the server is not up or not accessible.

Steps to reproduce

docker run -it -p 9222:9222 microsoft/aspnetcore-build /bin/bash
curl -LO https://github.com/pact-foundation/pact-ruby-standalone/releases/download/v1.18.0/pact-1.18.0-linux-x86_64.tar.gz
tar xzf pact-1.18.0-linux-x86_64.tar.gz
cd pact/bin
./pact-mock-service start

Can you please shed some light on this issue.

Thanks

Mock service does not start on Windows because Windows does not implement fork

Adding this here to track the issue.

I'm working on a branch of the mock service here to implement pact-mock-service start using spawn instead of fork. I can get it to start up ok, but I can't work out how to kill the process gracefully (SIGTERM). It always needs to be killed with a SIGKILL, which means that the shutdown hook on the mock service won't execute.

Non-HTTP service

Are there any plans to add a possibility to use services that are not HTTP (ie. REST API) based?

I'm currently looking into adding messaging support to pact-js which ultimately uses pact-mock_service.

The most neat way for this would be to implement a service for message broker mocks here (RabbitMQ, NATS, Kafka...).

Same endpoint, different query strings

Hi there
recently a bug was opened on Pact JS relating to having two interactions with the same endpoint but with one of the interactions differing only by a query string on the request.

Here's the issue: pact-foundation/pact-js#12

I've tested locally and got the same results. Here's the test I created as part of the Pact JS suite: https://github.com/pact-foundation/pact-js/blob/test-query-string/test/dsl/integration.spec.js#L137

Edit:
I suspect the issue is on Pact Mock Server, hence the bug. Below is the output of my log file. The Pact file gets created with only one interaction:

I, [2016-09-24T16:03:37.783385 #9663]  INFO -- : Registered expected interaction GET /projects
D, [2016-09-24T16:03:37.783615 #9663] DEBUG -- : {
  "description": "a request for projects",
  "provider_state": "i have a list of projects",
  "request": {
    "method": "GET",
    "path": "/projects",
    "headers": {
      "Accept": "application/json"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": [
      {
        "id": 1,
        "name": "Project 1",
        "due": "2016-02-11T09:46:56.023Z",
        "tasks": [
          {
            "id": 1,
            "name": "Do the laundry",
            "done": true
          },
          {
            "id": 2,
            "name": "Do the dishes",
            "done": false
          },
          {
            "id": 3,
            "name": "Do the backyard",
            "done": false
          },
          {
            "id": 4,
            "name": "Do nothing",
            "done": false
          }
        ]
      }
    ]
  }
}
I, [2016-09-24T16:03:37.785313 #9663]  INFO -- : Registered expected interaction GET /projects?from=today
D, [2016-09-24T16:03:37.785473 #9663] DEBUG -- : {
  "description": "a request for projects starting today",
  "provider_state": "i have a list of projects starting today",
  "request": {
    "method": "GET",
    "path": "/projects",
    "query": {
      "from": [
        "today"
      ]
    },
    "headers": {
      "Accept": "application/json"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": [
      {
        "id": 1,
        "name": "Project 1",
        "due": "2016-02-11T09:46:56.023Z",
        "tasks": [
          {
            "id": 1,
            "name": "Do the laundry",
            "done": true
          },
          {
            "id": 2,
            "name": "Do the dishes",
            "done": false
          },
          {
            "id": 3,
            "name": "Do the backyard",
            "done": false
          },
          {
            "id": 4,
            "name": "Do nothing",
            "done": false
          }
        ]
      }
    ]
  }
}
I, [2016-09-24T16:03:37.794977 #9663]  INFO -- : Received request GET /projects
D, [2016-09-24T16:03:37.795086 #9663] DEBUG -- : {
  "path": "/projects",
  "query": "",
  "method": "get",
  "headers": {
    "Host": "localhost:1234",
    "Accept-Encoding": "gzip, deflate",
    "User-Agent": "node-superagent/2.3.0",
    "Accept": "application/json",
    "Connection": "close",
    "Version": "HTTP/1.1"
  }
}
I, [2016-09-24T16:03:37.795500 #9663]  INFO -- : Found matching response for GET /projects
D, [2016-09-24T16:03:37.795785 #9663] DEBUG -- : {
  "status": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": [
    {
      "id": 1,
      "name": "Project 1",
      "due": "2016-02-11T09:46:56.023Z",
      "tasks": [
        {
          "id": 1,
          "name": "Do the laundry",
          "done": true
        },
        {
          "id": 2,
          "name": "Do the dishes",
          "done": false
        },
        {
          "id": 3,
          "name": "Do the backyard",
          "done": false
        },
        {
          "id": 4,
          "name": "Do nothing",
          "done": false
        }
      ]
    }
  ]
}
I, [2016-09-24T16:03:37.801958 #9663]  INFO -- : Received request GET /projects?from=today
D, [2016-09-24T16:03:37.802037 #9663] DEBUG -- : {
  "path": "/projects",
  "query": "from=today",
  "method": "get",
  "headers": {
    "Host": "localhost:1234",
    "Accept-Encoding": "gzip, deflate",
    "User-Agent": "node-superagent/2.3.0",
    "Accept": "application/json",
    "Connection": "close",
    "Version": "HTTP/1.1"
  }
}
E, [2016-09-24T16:03:37.802210 #9663] ERROR -- : Multiple interactions found for GET /projects?from=today:
D, [2016-09-24T16:03:37.802344 #9663] DEBUG -- : {
  "description": "a request for projects",
  "provider_state": "i have a list of projects",
  "request": {
    "method": "GET",
    "path": "/projects",
    "headers": {
      "Accept": "application/json"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": [
      {
        "id": 1,
        "name": "Project 1",
        "due": "2016-02-11T09:46:56.023Z",
        "tasks": [
          {
            "id": 1,
            "name": "Do the laundry",
            "done": true
          },
          {
            "id": 2,
            "name": "Do the dishes",
            "done": false
          },
          {
            "id": 3,
            "name": "Do the backyard",
            "done": false
          },
          {
            "id": 4,
            "name": "Do nothing",
            "done": false
          }
        ]
      }
    ]
  }
}
D, [2016-09-24T16:03:37.802467 #9663] DEBUG -- : {
  "description": "a request for projects starting today",
  "provider_state": "i have a list of projects starting today",
  "request": {
    "method": "GET",
    "path": "/projects",
    "query": {
      "from": [
        "today"
      ]
    },
    "headers": {
      "Accept": "application/json"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": [
      {
        "id": 1,
        "name": "Project 1",
        "due": "2016-02-11T09:46:56.023Z",
        "tasks": [
          {
            "id": 1,
            "name": "Do the laundry",
            "done": true
          },
          {
            "id": 2,
            "name": "Do the dishes",
            "done": false
          },
          {
            "id": 3,
            "name": "Do the backyard",
            "done": false
          },
          {
            "id": 4,
            "name": "Do nothing",
            "done": false
          }
        ]
      }
    ]
  }
}
I, [2016-09-24T16:03:37.806536 #9663]  INFO -- : Writing pact with details {:consumer=>{:name=>"Consumer 1"}, :provider=>{:name=>"Provider 1"}}
I, [2016-09-24T16:03:37.806612 #9663]  INFO -- : Writing pact for Provider 1 to /home/tarcio/workspace/pact/pact-js/pacts/consumer_1-provider_1.json
I, [2016-09-24T16:03:37.808968 #9663]  INFO -- : Cleared interactions before example ""

stand-alone Pact Mock Service 0.5.1 not starting / installation instructions incorrect

I tried to run the latest Pact Mock Service (version 0.5.1) on my Mac as instructed on the release page, namely:

curl -LO https://github.com/bethesque/pact-mock_service/releases/download/v0.5.1/pact-mock-service-0.5.1-1-osx.tar.gz
tar xzf pact-mock-service-0.5.1-1-osx.tar.gz
cd pact-mock-service-0.5.1-1-osx
./pact-mock-service -p 1234

First of all, there's no pact-mock-service file in the root of the unpacked directory. There's a bin directory though, but when I try to start that one I get:

$ ./pact-mock-service -p 1234
Could not find awesome_print-1.6.1 in any of the sources
Run `bundle install` to install missing gems.

Here's the detailed output running with bash -x:

$ bash -x ./pact-mock-service 
+ set -e
++ dirname ./pact-mock-service
+ SELFDIR=.
++ cd .
++ cd ..
++ pwd
+ SELFDIR=/Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx
+ export BUNDLE_GEMFILE=/Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/vendor/Gemfile
+ BUNDLE_GEMFILE=/Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/vendor/Gemfile
+ unset BUNDLE_IGNORE_CONFIG
+ exec /Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/ruby/bin/ruby -rbundler/setup -I/Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/app/lib /Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/app/pact-mock-service.rb
Could not find awesome_print-1.6.1 in any of the sources
Run `bundle install` to install missing gems.

I realize that I am missing a dependency. However, my understanding of the stand-alone server was that I do not need to install Ruby or any Ruby dependencies. Am I missing something?

FWIW, when I execute the start command directly from the root directory without the bash wrapper, I get a bit further:

$ ls -1d *
bin
lib
$ ( export BUNDLE_GEMFILE=$(pwd)/lib/vendor/Gemfile && unset BUNDLE_IGNORE_CONFIG && lib/ruby/bin/ruby -rbundler/setup -I$(pwd)/lib/app/lib -I$(pwd)/lib/app/pact-mock-service.rb -p 1234 )
/Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/ruby/bin.real/ruby: No such file or directory -- 1234 (LoadError)

The error is a bit weird to me because the file does exist:

$ test -f /Users/treimann/Tasks/pact_mock_service/bin/pact-mock-service-0.5.1-1-osx/lib/ruby/bin.real/ruby && echo "ruby binary exists"
ruby binary exists

Side note: Version 0.5.1 seems to be fairly behind the latest code version (0.7.1). Would be great to see an update in this regards as well.

Accepting the entire pact file instead of interactions

Currently, I need the pact-mock_service to run as a service, and I am doing (in ruby)

system "pact-mock-service start -p #{PACT_PORT} -l pact/pact.log"
sleep 2
# `curl -XDELETE -H "X-Pact-Mock-Service: true" localhost:#{PACT_PORT}/interactions`

pact = JSON.parse(File.read('pactfile.json'))
pact['interactions'].each do |interaction|
  `curl -XPOST -H "X-Pact-Mock-Service: true" -H "Content-Type: application/json" http://localhost:#{PACT_PORT}/interactions -d '#{interaction.to_json}'`
end

Is there a way to avoid splitting the interactions, and just send the mock service the entire pactfile and let it parse the interactions from it? That way it won't require ruby to parse the interactions

Not able to create an interaction

Hi,

We have clients in different languages so I want to use pact-mock_service via HTTP directly. I tried to create an interaction via curl but does not seem to be working. Am I missing something here? I tried to trace what pact ruby client passes in and it seems to match what I am doing below.

here is my request -

curl -H "Content-Type: application/json" -X POST -d "{\"description\":\"a request for an account\",\"provider_state\":\"an account exists\",\"request\":{\"method\":\"get\",\"path\":\"/accounts/1\",\"query\":\"include_deleted=false&include_locked=false\"},\"response\":{\"status\":200,\"headers\":{\"Content-Type\":\"application/json\"},\"body\":{\"id\":1,\"is_active\":true,\"name\":\"Test account\",\"subdomain\":\"supercool\",\"time_zone\":\"UTC\",\"created_at\":null,\"owner_id\":null,\"host_mapping\":null,\"updated_at\":null,\"locale_id\":5,\"sandbox_master_id\":null,\"is_serviceable\":true,\"help_desk_size\":\"1\",\"shard_id\":1,\"lock_state\":0,\"route_id\":null,\"deleted_at\":null,\"account_group_id\":1,\"dnsttl\":null}}}" localhost:5000/interactions

and the response -

{"message":"No interaction found for POST /interactions","interaction_diffs":[]}

Cannot Use Flexible Matching for Headers

Found a use case that doesn't work for us. IE 8, by default, will send the header Content-Type with application/json; charset=utf-8; while Chrome will sent it as application/json; charset=UTF-8;. I'm certain that this is in fact browser specific.

The problem is that we need application/json to create the interaction needed on a put/post, but I can't specify it 'globally' because I need to specify the charset as well and there's no way to make it generic using Pact::Term. I've tried it, but it crashes. If I use it for all headers, it's giving me the error Error ocurred in mock service: NoMethodError - undefined method '[]' for #<Pact::Term:0x00000001c52e60>, if I put it specifically for the Content-Type header, it's giving me Error ocurred in mock service: TypeError - can't convert Pact::Term to String.

I imagine that there should be a way to say "Use this request as long as application/json is in the content-type" or any of the other headers, like accept.

fail-fast on missing --pact_dir parameter

If one does not pass the --pact_dir parameter the mock service, it only fails when the first interaction has succeeded, i.e., when the service wants to persist the generated Pact file.

IMHO, the service should already check whether the parameter has been passed on startup so that users receive an indication early enough. This is especially important in high-volume CI environments where extensive test suites should not even need to start if the mock service hasn't started successfully.

Pact-mock-server/Webrick server returns ECONNRESET

Hi!
I have 2 unit test written in js using ( pact-consumer-js-dsl ) that create interactions like in the README for that library e.g. alligators/Mary, alligators/Pete They are separated in two different files. In each file I set up the same logic:

describe("Client", function() {
  var client, helloProvider;

  beforeEach(function() {
    //ProviderClient is the class you have written to make the HTTP calls to the provider
    client = new ProviderClient('http://localhost:1234');
    helloProvider = Pact.mockService({
      consumer: 'Hello Consumer',
      provider: 'Hello Provider',
      port: 1234,
      done: function (error) {
        expect(error).toBe(null);
      }
    });
  });

  it("should say hello", function(done) {
    helloProvider
      .given("an alligator with the name Mary exists")
      .uponReceiving("a request for an alligator")
      .withRequest("get", "/alligators/Mary", {
        "Accept": "application/json"
      }).willRespondWith(200, {
        "Content-Type": "application/json"
      }, {
        "name": "Mary"
      });

    helloProvider.run(done, function(runComplete) {
      expect(client.getAlligatorByName("Mary")).toEqual(new Alligator("Mary"));
      runComplete();
    });
  });
});

When I trigger them the pact json files are generated. But after they are generated the pact-mock-server writes in logs that:

ERROR Errno:ECONNRESET: An existing connection was forcibly closed by the remote host. @ io-Fillbuf - fd:5

I don't know if this is the correct way of behavior so want to know if those errors that I get are
image`

After this error occurs, the server ( started on localhost:1234 ) as response to request localhost:1234/alligators/Mary (specified in the js code above) will response with:

image

Is this a BUG in pact-mock-server and how this can by solved?

P.S. These are errors of WebRick server, so in the internet people say that switching to thin server resolves this.

Ability to test the body schema

In our case, we need to be able to make sure that the json schema returned back by an API is current (right properties, right data types), but the data itself is not really important.

Path matcher does not generate correct pact file

Using a path matcher seems to work correctly from the consumer point of view, but the matcher details are missing from the outputted pact file.

The interaction sent to the mock server:

{
  "description": "a request for an alligator with path matcher",
  "provider_state": "an alligator exists",
  "request": {
    "method": "get",
    "path": {
      "json_class": "Pact::Term",
      "data": {
        "generate": "/alligators/1234",
        "matcher": {"json_class":"Regexp","o":0,"s":"^\\/alligators\\/[0-9]{4}"}
      }
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "type": "alligator",
      "name": "Mary"
    }
  }
}

And the resulting pact file:

{
      "description": "a request for an alligator with path matcher",
      "provider_state": "an alligator exists",
      "request": {
        "method": "get",
        "path": "/alligators/1234"
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json"
        },
        "body": {
          "type": "alligator",
          "name": "Mary"
        }
      }
    }

This is probably related to #11

Allow different content types

Hey there!

I am thinking of using pact-mock_service with a microservice that accepts Avro JSON and binary data. Looks like currently pact-mock_service only support JSON data. I am curious about your thoughts on extending it to support different content types?

Best!
Saroj

Raise/assume status code to be 200 if status code is not specified?

I'm not sure where to post it - I encountered it when used pact + pact-mock_service, so, I've decided to post it here.

When you accidentaly forget to specify status response option you can get strange result with Net::HTTP:

Net::HTTPBadResponse:
       wrong status line: "HTTP/1.1 0  "

I see such possible solutions:

  • raise an exception if status is not specified - it would be nice because error message can explicitly say "you forgot the status code" instead of assuming it as 0
  • or assume it to be 200 - it's the most common expected response code IMO;

Custom Header Key name reformat by mock service?

We have a custom header which has a key such as "APP_AUTH" and I'd like to keep this key in the pact contract. However, I believe pact-mock_serivce helps me reformat the custom header to be "App-Auth" and breaks the contract on the provider side.

After look around the source code with my bad ruby knowledge. I believe the source code is under pact-mock_service/lib/pact/consumer/mock_service/rack_request_helper.rb

line 47:

def standardise_header header
header.gsub(/^HTTP_/, '').split("_").collect{|word| word[0] + word[1..-1].downcase}.join("-")
end

Would you please tell me whether I can still keep the original contract format rather than to standardise it? I know "APP_AUTH" maybe is not a good name, however it's have been used by a lot of services which we can not easily modify.

Thanks for your help and looking forward to your reply. :)

Mock service only exits on SIGINT, but not SIGKILL

I just upgrade pact-node to the latest version of the pact-mock-service, where it was using 0.7.2 before. It seems that the exit signal has changed since I used a to a SIGKILL on the process to close it and it worked, but now it has to be SIGINT. Personally, I think both should be supported by pact-mock_service since one is a graceful exit and the other is ungraceful, which should still work.

Certain input causes mock service to hang

I'll investigate this further later, reporting so not to lose track of this bug.

When setting an expected interaction response with the following body payload, and posting to PACT, the server hangs until HTTP timeout.

Removing the regular expressions from the payload avoids the problem.

{
  "title":"Application Form",
  "questions":[
    {
      "label":"What is your name?",
      "fields":[
        {
          "type":"text",
          "placeholder":"Given name",
          "identifier":"given-name"
        },
        {
          "type":"text",
          "placeholder":"Family name",
          "identifier":"last-name"
        }
      ]
    },
    {
      "label":"What is your address?",
      "fields":[
        {
          "type":"address",
          "identifier":"address"
        }
      ]
    },
    {
      "label":"What is your tax file number?",
      "fields":[
        {
          "type":"text",
          "identifier":"tfn",
          "placeholder":"TFN",
          "validations":[
            {
              "type":"regexp",
              "expression":"([\\d]{3}[^\\d]*){3}",
              "message":"TFN requires 9 digits."
            }
          ],
          "processings":[
            {
              "type":"regexpReplace",
              "expression":"[^\\d]",
              "replace":""
            }
          ]
        }
      ]
    },
    {
      "label":"Employment history:",
      "fields":[
        {
          "type":"text",
          "placeholder":"Employer name",
          "identifier":"employer-name"
        },
        {
          "type":"city",
          "placeholder":"Employer city",
          "identifier":"employer-city"
        }
      ],
      "questions":[
        {
          "repeatable":{
            "min":1
          },
          "label":"Role in the company:",
          "fields":[
            {
              "type":"date",
              "placeholder":"Started",
              "identifier":"start-date"
            },
            {
              "type":"date",
              "placeholder":"Ended",
              "identifier":"end-date"
            },
            {
              "type":"text",
              "placeholder":"Title",
              "identifier":"role-title"
            },
            {
              "type":"text-area",
              "placeholder":"Description",
              "identifier":"role-desc"
            }
          ]
        }
      ]
    }
  ]
}

Duplicate interaction check needs to occur when the interaction is set up, not on replay

Otherwise the error does not bubble up to the client (eg the javascript client) in a helpful way, as the response may not be logged.

I, [2014-12-17T16:16:36.687916 #52188]  INFO -- : Received request POST /thing?lastName=Smith&firstName=Mary
D, [2014-12-17T16:16:36.688114 #52188] DEBUG -- : {
  "path": "/thing",
  "query": "lastName=Smith&firstName=Mary",
  "method": "post",
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "http://localhost:9876",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.9.8 Safari/534.34",
    "Referer": "http://localhost:9876/context.html",
    "Accept": "*/*",
    "Connection": "Keep-Alive",
    "Accept-Encoding": "gzip",
    "Accept-Language": "en-AU,*",
    "Host": "localhost:1234",
    "Version": "HTTP/1.1"
  }
}
E, [2014-12-17T16:16:36.688534 #52188] ERROR -- : Error ocurred in mock service:
E, [2014-12-17T16:16:36.688849 #52188] ERROR -- : #<RuntimeError: Interaction with same description (another request for hello) and provider state () already exists>
D, [2014-12-17T16:16:36.689348 #52188] DEBUG -- : [
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/interactions_filter.rb:39:in `<<'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/mock_service/interaction_replay.rb:36:in `add_verified_interaction'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/mock_service/interaction_replay.rb:63:in `handle_matched_interaction'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/mock_service/interaction_replay.rb:48:in `find_response'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/mock_service/interaction_replay.rb:30:in `respond'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/pact-mock_service-0.2.2/lib/pact/consumer/mock_service/app.rb:67:in `call'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rack-1.5.2/lib/rack/handler/webrick.rb:60:in `service'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/webrick-1.3.1/lib/webrick/httpserver.rb:138:in `service'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/webrick-1.3.1/lib/webrick/httpserver.rb:94:in `run'",
  "/usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/webrick-1.3.1/lib/webrick/server.rb:191:in `block in start_thread'"

Multiple Providers

The problem is about /pact DELETE. I have few tests within same consumer for multiple providers. When interactions for Provider A are finished I call DELETE on /pact and I would like to go with next Provider B. But when I do this I inherit Provider A interactions in pact file of Provider B, so for real they are not deleted.

Is there possibility to create pacts for multiple providers within one instance of pact-mock-service?

HTTP header names mangled even if conformant to RFC

I am (indirectly) using pact-mock_service to test against a REST service that I do not control that requires HTTP header names of the form /[a-z]+(_[a-z]+)/, e.g., 'my_header'. These tests fail, and I find that somewhere between the client sending the request and the pact mock receiving it, header names get rewritten to the form /[A_Z][a-z](-[A-Z][a-z])/, e.g., 'My-Header'.
While the latter form is most common in the wild, the former seems still to be according to the following definitions from RFC 7230 (https://tools.ietf.org/html/rfc7230#page-22):

3.2.  Header Fields

   Each header field consists of a case-insensitive field name followed
   by a colon (":"), optional leading whitespace, the field value, and
   optional trailing whitespace.

     header-field   = field-name ":" OWS field-value OWS

     field-name     = token

     ...

     token          = 1*tchar

     tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                    / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                    / DIGIT / ALPHA
                    ; any VCHAR, except delimiters

In https://github.com/pact-foundation/pact-mock_service/blob/7d4fd1f8ec6b6f6f118aae56fe6373ebc4f83972/lib/pact/consumer/mock_service/rack_request_helper.rb, I find:

   def standardise_header header
     header.gsub(/^HTTP_/, '').split("_").collect{|word| word[0] + word[1..-1].downcase}.join("-")
   end

All is well if I change the function to read,

      def standardise_header header
        header.gsub(/^HTTP_/, '').downcase
      end

I do not completely understand what is happening. What is the purpose of the original transformation? Can we do with my version?

Thank you!

Ability to specify interaction path to be a regex or support variables

Since we do not want to setup each restful path and then test every single one for the same interactions, the ability to specify a generic path that works for all the same paths would be the best way to move forward.

This and the ability to test data schema would solve 90% of our use cases: #10

Verifying before Received, resulting in missing request error.

My tests are working with chrome but failing with PhantomJs
It looks like the verification is done before the request with phantomjs.

The output I get from the pact-mock_service is:

I, [2016-05-16T15:41:49.828460 #79772]  INFO -- : Registered expected interaction POST /api/v1/campaigns
D, [2016-05-16T15:41:49.828915 #79772] DEBUG -- : {
  "description": "a campaign will be created",
  "provider_state": "we submit a new campaign",
  "request": {
    "method": "post",
    "path": "/api/v1/campaigns",
...
W, [2016-05-16T15:41:49.928726 #79772]  WARN -- : Verifying - actual interactions do not match expected interactions for example "".
Missing requests:
        POST /api/v1/campaigns


W, [2016-05-16T15:41:49.928768 #79772]  WARN -- : Missing requests:
        POST /api/v1/campaigns


I, [2016-05-16T15:41:49.930866 #79772]  INFO -- : Received request POST /api/v1/campaigns
D, [2016-05-16T15:41:49.931029 #79772] DEBUG -- : {

I, [2016-05-16T16:26:14.649965 #81885]  INFO -- : Found matching response for POST /api/v1/campaigns

on my test console:

✔ 0 tests completed
✖ 1 test failed

FAILED TESTS:
  PactCampaignCreate
    handleSubmit
      ✖ should send the correct request
        PhantomJS 2.1.1 (Mac OS X 0.0.0)
      AssertionError: expected [Error:
      pact-consumer-js-dsl: Pact verification failed
      Actual interactions do not match expected interactions for mock MockService.

      Missing requests:
        POST /api/v1/campaigns

      See standard out/err for details.
      ] to equal null (/Users/pierrecaserta/workspace/jupiter-admin/tests.webpack.js:24570 <- webpack:///~/chai/lib/chai/assertion.js:111:0)

Here is my test code:

  let pactMockService = null;
  let renderer = null;
  let form = null;

  beforeEach(() => {
    pactMockService = Pact.mockService({
      consumer: 'campaign create consumer',
      provider: 'campaign create provider',
      port: 1234,
      done: (error) => {
        expect(error).to.equal(null);
      }
    });
    // pactMockService.resetSession(done);
  });

  describe('handleSubmit', () => {
    beforeEach( () => {

      const spy = chai.spy((d) => {
        data = preprocessBeforeSend(d);
      });
      renderer = rendererValidation(createStore(browserHistory, client, mockStore), spy);
      form = ReactTestUtils.findRenderedDOMComponentWithClass(renderer, "form-horizontal");
    });

    afterEach( () => {
      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(renderer).parentNode);
    });

    it("should send the correct request", (done) => {

      const responseBody = {"id": Pact.Match.somethingLike(1097),
            "name":"492699",
            "start_date":"2016-06-04T00:00:00Z",
            "end_date":"2016-07-01T00:00:00Z",
            "internal_code": Pact.Match.somethingLike("8bbddbe518ed43368fc932a1092e0983"),
            "timezone":"Sydney",
            "cpc":0.5,
            "total_clicks":0,
            "max_clicks":186,
            "total_daily_clicks":0,
            "max_daily_clicks":76,
            "total_impressions":0,
            "budget":197.0,
            "advertiser_id":333555,
            "active":true,
            "priority_id":3,
            "frequency_capped":true,
            "freq_cap_time_unit":"day",
            "freq_cap_period":10,
            "freq_cap_count":5,
            "freq_cap_type":"impression",
            "created_at": Pact.Match.somethingLike("2016-05-09T04:36:33Z"),
            "updated_at":Pact.Match.somethingLike("2016-05-09T04:36:33Z"),
            "deleted_at":null,
            "disable_daily_cap":false,
            "target_platform":"both",
            "target_category_ids":[6263, 6076, 6317],
            "target_keywords":null,
            "target_sites":null,
            "target_location_ids":[6047981],
            "target_subcategory_ids":[]
      };

      pactMockService
      .given("we submit a new campaign")
      .uponReceiving("a campaign will be created")
      .withRequest({
        method: "post",
        path: "/api/v1/campaigns"
      }).willRespondWith({
        status: 201,
        headers: {"Content-Type": "application/json; charset=utf-8"},
        body: responseBody
      });
      pactMockService.run(done, (runComplete) => {
        ReactTestUtils.Simulate.submit(form);
        const headers = { "Accept": "*/*",
          "Accept-Encoding":"gzip, deflate",
          "Accept-Language":"en-US,en;q=0.8",
          "Connection":"keep-alive",
          "Content-Length":"491",
          "Content-Type":"application/json",
          "Host":"127.0.0.1:1234",
          "X-APIKEY": "49b4102ec4aad5a025fd906b4867bf11" };
        client.post('campaigns', {data: data, headers: headers}).then((r) => {
          // I do not care about the fake response
          expect(r.body.name).to.equal(responseBody.name);
        }).catch((e) => {
          console.log(e);
        });
        runComplete();
      });
    });

  });

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.