DiUS / pact-consumer-js-dsl

*DEPRECATED* A Javascript DSL for creating pacts, superceded by Pact JS
https://github.com/pact-foundation/pact-js
Other
56 stars 26 forks source link

Allow the consumer DSL to be used from code running in a node context (rather than browser) #17

Closed redbeard closed 9 years ago

redbeard commented 9 years ago

This required a couple of changes:

bethesque commented 9 years ago

I'm not a JS expert in any way, so my apologies if this sounds stupid. We've just pulled out all the "require" stuff so that it can be used in a framework independent way. Would it not be better to do the require line if (!XMLHttpRequest) { var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; } in the calling code, and keep the dsl code completely framework agnostic?

bethesque commented 9 years ago

Which XMLHttpRequest is being required here? I didn't think Node had one?

I'm not actually sure if we want to make this change or not. @BenSayers is working modifying the code to work with Node in an async way. See https://github.com/DiUS/pact-consumer-js-dsl/issues/15

BenSayers commented 9 years ago

@bethesque Christmas and New Years slowed me down a bit but I'm back working on it in my spare time now. Should be finished soon. If you are interested in the progress you can see it on my branch.

bethesque commented 9 years ago

No worries. One thing to note is that the xhr.status is a string within a browser, but is an integer in Node. The code in master now does parseInt(xhr.status, 10) !== 200 to cover both bases.

bethesque commented 9 years ago

Hey Ben, if the mock service doesn't start up because you're a numpty and you've forgotten to bundle install before you run the tests, the run-tests just finishes with a success status code. Do you know if there's a way to fail the tests if waitForServerToStart fails?

bethesque commented 9 years ago

Something funny is up with the ordering of the requests. This is running the tests in the example directory.

I had to change the files in example/karma.conf.js to

    files: [
      'client.js',
      'client-spec.js',
      '../src/bootstrap.js',
      '../src/**/*.js'
    ],

Then I ran script/setup.sh and script/test.sh. As you can see from the logs, the interactions get cleared all at once at the start, then the registration and the executions are all mixed up. It looks like the tests are running in parallel, which won't work with the current implementation of the mock server.

I, [2015-01-09T10:38:18.155785 #93131]  INFO -- : Cleared interactions before example ""
I, [2015-01-09T10:38:18.197403 #93131]  INFO -- : Cleared interactions before example ""
I, [2015-01-09T10:38:18.201621 #93131]  INFO -- : Cleared interactions before example ""
I, [2015-01-09T10:38:18.207031 #93131]  INFO -- : Registered expected interaction GET /sayHello
D, [2015-01-09T10:38:18.207309 #93131] DEBUG -- : {
  "providerState": null,
  "description": "a request for hello",
  "request": {
    "method": "get",
    "path": "/sayHello"
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "reply": "Hello"
    }
  }
}
I, [2015-01-09T10:38:18.213704 #93131]  INFO -- : Registered expected interaction GET /friends?age=30&children=Mary Jane&children=James
D, [2015-01-09T10:38:18.213955 #93131] DEBUG -- : {
  "providerState": null,
  "description": "a request friends",
  "request": {
    "method": "get",
    "path": "/friends",
    "query": {
      "age": "30",
      "children": [
        "Mary Jane",
        "James"
      ]
    },
    "headers": {
      "Accept": "application/json"
    }
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "friends": [
        {
          "name": "Sue"
        }
      ]
    }
  }
}
I, [2015-01-09T10:38:18.219044 #93131]  INFO -- : Registered expected interaction PUT /unfriendMe
D, [2015-01-09T10:38:18.219178 #93131] DEBUG -- : {
  "providerState": null,
  "description": "a request to unfriend",
  "request": {
    "method": "put",
    "path": "/unfriendMe"
  },
  "response": {
    "status": 200,
    "headers": {
      "Content-Type": "application/json"
    },
    "body": {
      "reply": "Bye"
    }
  },
  "provider_state": "I am friends with Fred"
}
I, [2015-01-09T10:38:18.223505 #93131]  INFO -- : Received request GET /sayHello
D, [2015-01-09T10:38:18.223690 #93131] DEBUG -- : {
  "path": "/sayHello",
  "query": "",
  "method": "get",
  "headers": {
    "Host": "localhost:1234",
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
    "Accept": "*/*",
    "Referer": "http://localhost:9876/context.html",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Version": "HTTP/1.1"
  }
}
I, [2015-01-09T10:38:18.223971 #93131]  INFO -- : Found matching response for GET /sayHello
D, [2015-01-09T10:38:18.224082 #93131] DEBUG -- : {
  "status": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": {
    "reply": "Hello"
  }
}
W, [2015-01-09T10:38:18.231852 #93131]  WARN -- : Verifying - actual interactions do not match expected interactions for example "". 
Missing requests:
    GET /friends?age=30&children=Mary Jane&children=James
    PUT /unfriendMe

W, [2015-01-09T10:38:18.231949 #93131]  WARN -- : Missing requests:
    GET /friends?age=30&children=Mary Jane&children=James
    PUT /unfriendMe

I, [2015-01-09T10:38:18.235510 #93131]  INFO -- : Received request GET /friends?age=30&children=Mary%20Jane&children=James
D, [2015-01-09T10:38:18.235664 #93131] DEBUG -- : {
  "path": "/friends",
  "query": "age=30&children=Mary%20Jane&children=James",
  "method": "get",
  "headers": {
    "Host": "localhost:1234",
    "Connection": "keep-alive",
    "Accept": "application/json",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
    "Referer": "http://localhost:9876/context.html",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Version": "HTTP/1.1"
  }
}
I, [2015-01-09T10:38:18.236125 #93131]  INFO -- : Found matching response for GET /friends?age=30&children=Mary Jane&children=James
D, [2015-01-09T10:38:18.236222 #93131] DEBUG -- : {
  "status": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": {
    "friends": [
      {
        "name": "Sue"
      }
    ]
  }
}
W, [2015-01-09T10:38:18.243576 #93131]  WARN -- : Verifying - actual interactions do not match expected interactions for example "". 
Missing requests:
    PUT /unfriendMe

W, [2015-01-09T10:38:18.243665 #93131]  WARN -- : Missing requests:
    PUT /unfriendMe

I, [2015-01-09T10:38:18.248980 #93131]  INFO -- : Received request PUT /unfriendMe
D, [2015-01-09T10:38:18.249325 #93131] DEBUG -- : {
  "path": "/unfriendMe",
  "query": "",
  "method": "put",
  "headers": {
    "Host": "localhost:1234",
    "Connection": "keep-alive",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
    "Origin": "http://localhost:9876",
    "Accept": "*/*",
    "Referer": "http://localhost:9876/context.html",
    "Accept-Encoding": "gzip, deflate, sdch",
    "Accept-Language": "en-US,en;q=0.8",
    "Version": "HTTP/1.1"
  }
}
I, [2015-01-09T10:38:18.249669 #93131]  INFO -- : Found matching response for PUT /unfriendMe
D, [2015-01-09T10:38:18.249830 #93131] DEBUG -- : {
  "status": 200,
  "headers": {
    "Content-Type": "application/json"
  },
  "body": {
    "reply": "Bye"
  }
}
I, [2015-01-09T10:38:18.257649 #93131]  INFO -- : Verifying - interactions matched for example ""
bethesque commented 9 years ago

Ok, worked it out, I needed to make the tests do the 'done' callback. They can't be synchronous any more.

bethesque commented 9 years ago

I'm thinking, it's quite tedius to do a DELETE and a POST for each interaction. It would be much simpler to do a a PUT /interactions and do the whole thing in one go. I'll look into that if I have the time.

bethesque commented 9 years ago

When verification fails, is there a way to fail the test in an asynchronous world? In the example, if I take out the code that verifies that the response returned by the mock service is right, but make a wrong call to the mock service, the test should still fail, but it doesn't.

describe("when there are no friends", function () {
        it("returns an error message", function (jasmineDone) {
          //Add interaction
          helloProvider
            .given("I have no friends")
            .uponReceiving("a request to unfriend")
            .withRequest("put", "/unfriendMe2")
            .willRespondWith(404);

          //Run the tests
          helloProvider.run(function(pactDone) {

            function success(message) {
              //The success callback should *not* be invoked!
              // expect(true).toEqual(false);
              pactDone(jasmineDone);
            }

            function error(message) {
              //The error callback *should* be invoked
              // expect(message).toEqual("No friends :(")
              pactDone(jasmineDone);
            }

            client.unfriendMe(success, error);

          });
        });
      });
BenSayers commented 9 years ago

@bethesque are these comments intended for my nodejs pull request?

bethesque commented 9 years ago

Ha, yes. I just realised I put them on the wrong one. Will repost. I'm going to close this PR, seeing as yours supersedes it.