Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mockServer does not start() #10

Closed
ghost opened this issue Aug 31, 2016 · 14 comments
Closed

mockServer does not start() #10

ghost opened this issue Aug 31, 2016 · 14 comments

Comments

@ghost
Copy link

ghost commented Aug 31, 2016

Hi,

I am trying to start doing CDD on my JS application. I am trying to create the most simple consumer pact, but when I call

mockServer.start().then(() => {
    provider = Pact({consumer: 'client', provider: 'service', port: 1234});
   done();
});

It never gets inside the then, so I am assuming the promise never gets resolved. I am using Jest that uses Jasmine behind the scene. I wonder if you have any clue of how could I debug this network issue ( if it is that ).

this is my test file

import Pact from 'pact';
import path from "path";
import chaiAsPromised from "chai-as-promised";
import pactWrapper from "@pact-foundation/pact-node";
import chai, {expect} from "chai";
import request  from 'superagent';

chai.use(chaiAsPromised);

describe("see all dog", () => {
    var provider, mockServer;

    beforeAll(() =>{
        mockServer = pactWrapper.createServer({
            port: 1234,
            host: "localhost",
            log: path.resolve(process.cwd(), 'logs', 'mockserver-integration.log'),
            dir: path.resolve(process.cwd(), 'pacts'),
            consumer: "client",
            provider: "service",
            spec: 2
        });
    });

    afterAll(() => {
        pactWrapper.removeAllServers();
    });

    beforeEach((done) => {
        mockServer.start().then(() => {
            provider = Pact({consumer: 'client', provider: 'service', port: 1234});
            done();
        });
    });

    afterEach((done) => {
        mockServer.delete().then(() => {
            done();
        });
    });

    describe("test", () => {
        describe("test", () => {
            beforeEach((done) => {
                provider.addInteraction({
                    state: 'I want to see my dogs',
                    uponReceiving: 'a request to get dogs',
                    withRequest: {
                        method: 'GET',
                        path: '/dogs',
                        headers: {'Accept': 'application/json'}
                    },
                    willRespondWith: {
                        status: 200,
                        headers: {'Content-Type': 'application/json'},
                        body: {}
                    }
                }).then(() => done());
            });

            afterEach((done) => {
                provider.finalize().then(() => done())
            });

            it('successfully verifies', (done) => {
                const verificationPromise = request
                    .get('http://localhost:1234/dogs')
                    .set({ 'Accept': 'application/json' })
                    .then(provider.verify);

                expect(verificationPromise).to.eventually.eql(JSON.stringify({})).notify(done)
            })
        });
    });
});

and when I run test I get

● see all dog › test › test › it successfully verifies
  - Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
        at Timeout.e [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:477:19)
        at tryOnTimeout (timers.js:232:11)
        at Timer.listOnTimeout (timers.js:202:5)
  - TypeError: Cannot read property 'addInteraction' of undefined
        at Object.<anonymous> (app/components/Dogs/__tests__/clientTest.js:47:25)
        at Timeout.e (node_modules/jsdom/lib/jsdom/browser/Window.js:477:19)
        at tryOnTimeout (timers.js:232:11)
        at Timer.listOnTimeout (timers.js:202:5)
  - TypeError: Cannot read property 'verify' of undefined
        at Object.<anonymous> (app/components/Dogs/__tests__/clientTest.js:71:30)
        at Timeout.e (node_modules/jsdom/lib/jsdom/browser/Window.js:477:19)
        at tryOnTimeout (timers.js:232:11)
        at Timer.listOnTimeout (timers.js:202:5)
  - TypeError: Cannot read property 'finalize' of undefined
        at Object.<anonymous> (app/components/Dogs/__tests__/clientTest.js:64:25)
        at Timeout.e (node_modules/jsdom/lib/jsdom/browser/Window.js:477:19)
        at tryOnTimeout (timers.js:232:11)
        at Timer.listOnTimeout (timers.js:202:5)
1 test failed, 0 tests passed (1 total in 1 test suite, run time 6.208s)
npm ERR! Test failed.  See above for more details.

There is a jasmine TIMEOUT.

@ghost
Copy link
Author

ghost commented Aug 31, 2016

This seem to be related with pact-foundation/pact-js-core#20

@tarciosaraiva
Copy link
Contributor

Will have a look at this today. Did you try installing a previous version of the library? The latest one went through a refactor last week and I wonder if it caused a side effect somewhere - or maybe it is really the pact-node issue you refer to.

Would you be able to tell 1) what environment are you on and 2) if you can try 1.0.0-rc.4 instead of the latest and how you go with it?

Thanks

@ghost
Copy link
Author

ghost commented Aug 31, 2016

The environment this is running is:

npm:  3.10.3
node: 6.4.0

And I just tried the rc.4 release, but that did not work.

If I move the initialization of the variable provider outside the callback from the server start(). The pact interaction gets registered on the pact file. The test fails at the end, and during the execution I see this too:

 [SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()
 Unhandled promise rejection ProgressEvent { isTrusted: [Getter] } ( 6x)

@tarciosaraiva
Copy link
Contributor

Moving the variable outside you can't be sure if the server really started.

I just noticed this line: Cannot read property 'finalize' of undefined

And also paying to attention to Jest, the async behaviour is different from Jasmine based on what I seen on the documentation and it doesn't look like it contains beforeAll and afterAll hooks like the latest versions of Jasmine do based on this part of the docs.

Maybe you have to adapt your code?

@ghost
Copy link
Author

ghost commented Aug 31, 2016

Yes, that is what I am assuming. The undefined is because of that. provider is undefined until the server starts. It never starts it timeout and then run those lines for the afterEach and afterAll. Sure I will try that! thanks and I will update

@tarciosaraiva
Copy link
Contributor

No worries @dolfo-pivotal - BTW first time I've seen someone using Jest with Pact. Would be great to have your contribution on a test case / doco 👍

@tarciosaraiva
Copy link
Contributor

How did you go @dolfo-pivotal ?

@dolfolife
Copy link

dolfolife commented Sep 5, 2016

@tarciosaraiva this is my personal account. XD I could not allocated more work on the client, but I created a example using jest. https://github.com/rodolfo2488/pact-test-example/blob/master/client/__tests__/mainTest.js that works, but:

I have to tell jest to use the "node" testEnvironment

I get weird errors/warnings on the jsdom mode with jest like

crypto not usable, falling back to insecure Math.random()
ProgressEvent is untrusted

Note: this is because something is rejecting the request when it is by a script.

I could not use the pact.verify call

I need to read more the implementation of that method to see where I can fit that in the test. So far I am not using it.

I had to use cors true or it won't work

I have no clue why is this.

But I will continue working on that when I have time. A friend of mine started a project for spring boot verifier on the provider side that as well I am using it on the server side of that example. check that out.

Feel free to corrent my mainTest.js or suggest changes on it.

@tarciosaraiva
Copy link
Contributor

hi @rodolfo2488 I think I identified the issue. Jest loads up JSDOM by default, even though the Jest configuration states that a browser environment is off by default.

This is causing Pact to instantiate a XMLHttpRequest object that is basically invalid:

    XMLHttpRequest {
      onabort: null,
      onerror: null,
      onload: null,
      onloadend: null,
      onloadstart: null,
      onprogress: null,
      ontimeout: null,
      upload: 
       XMLHttpRequestUpload {
         onabort: null,
         onerror: null,
         onload: null,
         onloadend: null,
         onloadstart: null,
         onprogress: null,
         ontimeout: null,
         _ownerDocument: Document { location: [Getter/Setter] } },
      onreadystatechange: null }

I'm digging further to see how we can fix this. Will keep you posted.

@tarciosaraiva
Copy link
Contributor

tarciosaraiva commented Sep 24, 2016

OK @rodolfo2488 @dolfo-pivotal I understand what's going on now.

TL;DR: Jest uses JSDOM by default and brings along A LOT of polyfills to mimic a real browser environment (RBE) which passes the supporting libraries checks for RBE's thus using polyfills of questionable implementation.

JSDOM, as you know, is highly used by Facebook, Airbnb, etc to simulate a RBE in Node especially for React testing.

Most libraries that deal with HTTP/S requests that try to be universal usually check fora RBE like this:

    typeof window !== 'undefined' &&
    typeof document !== 'undefined' &&
    typeof document.createElement === 'function'

The code above is actually from axios and the full method is like this

function isStandardBrowserEnv() {
  return (
    typeof window !== 'undefined' &&
    typeof document !== 'undefined' &&
    typeof document.createElement === 'function'
  );
}

Pact JS does a similar check. I don't think JSDOM was meant to be used so heavily like this with real XHR objects being instantiated and requests making their way through - which actually work as you seen the log being populated - but the response somehow is not mapped correctly on the polyfill causing the request to fail and always be rejected by the Promise.

The guys from Jest thought about that and provided a configuration option named testEnvironment. If you set it to node then everything works.

I will be pushing an examples folder that contain a sample with Jest for Node. For the browser though, I strongly recommend you use something like Karma if you can.

Hope that helps and thanks for the issue. At least now I know that JSDOM might be something to look out for and potentially bring more support for React testing with Pact.

@tarciosaraiva
Copy link
Contributor

hi @rodolfo2488 here's the example code based on your sample: https://github.com/pact-foundation/pact-js/tree/master/examples/jest

@mefellows
Copy link
Member

Nice work @tarciosaraiva, is it worth noting this in the README more explicitly for future reference?

@tarciosaraiva
Copy link
Contributor

you're right @mefellows might update that now

@mefellows
Copy link
Member

I've updated the README with a reference to the details of this issue, closing.

mefellows pushed a commit that referenced this issue Feb 25, 2018
chore(request): make Request class work across both Node and Browser using Popsicle

Includes a number of changes and tidying ups:

* Add 'exit' flag to mocha to exit properly after tests are done
* Update superagent dependency
* Update dependencies for karma-pact to fix issue with peer dependencies
* Update standard version, make sure the ignore glob is correct
* Fix Mocha registering ts-node twice
* Update nock to 9.1.x and fix tests
* Update lock file for e2e tests
* Adding union type for http methods to gradually change to the enum

See #134 and #10 for background.
mefellows pushed a commit that referenced this issue Feb 25, 2018
…using Popsicle

Includes a number of changes and tidying ups:

* Add 'exit' flag to mocha to exit properly after tests are done
* Update superagent dependency
* Update dependencies for karma-pact to fix issue with peer dependencies
* Update standard version, make sure the ignore glob is correct
* Fix Mocha registering ts-node twice
* Update nock to 9.1.x and fix tests
* Update lock file for e2e tests
* Adding union type for http methods to gradually change to the enum

See #134 and #10 for background.
blackbaud-joshlandi pushed a commit to blackbaud-joshlandi/pact-js that referenced this issue Mar 2, 2018
…using Popsicle

Includes a number of changes and tidying ups:

* Add 'exit' flag to mocha to exit properly after tests are done
* Update superagent dependency
* Update dependencies for karma-pact to fix issue with peer dependencies
* Update standard version, make sure the ignore glob is correct
* Fix Mocha registering ts-node twice
* Update nock to 9.1.x and fix tests
* Update lock file for e2e tests
* Adding union type for http methods to gradually change to the enum

See pact-foundation#134 and pact-foundation#10 for background.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants