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

Mocking with supertest in Node, not working? #68

Closed
embpdaniel opened this issue Jan 25, 2019 · 6 comments
Closed

Mocking with supertest in Node, not working? #68

embpdaniel opened this issue Jan 25, 2019 · 6 comments

Comments

@embpdaniel
Copy link

Hey there, brand new to your library. I am using supertest to test my Express routes, and one of my route files uses the firebase admin sdk.

I want to mock the firebase admin sdk, so as a first test to confirm that rewiremock is working, I have assigned an empty object as the dependency for firebase. I proxy the module that handles my routes '../api/controlelrs/auth', and this is the module that directly imports the 'firebase-admin' module from the firebase sdk:

it('Verifies token and returns 200', done => {
      const rewiremock = require('rewiremock/node').default
      const mock = rewiremock.proxy('../api/controllers/auth', {
        'firebase-admin': new function (location) {
          return {}
        }()
      }).default

     request(app)
              .post(API_URL)
              .send({ phone: PHONE, token })
              .end((err, res) => {
                if (err) return done(err)
                expect(res.statusCode).to.be.equal(200)
                done()
              })
    })

What happens here is that verifyIdtoken from the REAL firebase admin sdk is called within my route. I verified by adding a console.log inside of the real firebase-admin library.

What I expected to happen was for my test console.log to not be called, as I'm hoping that the rewiremock library will replace the real firebase SDK with a mock (in the case of this example, an empty object).

Like I said, I'm new to using your library, maybe I am not setting up something correctly. Can you help? Thank you!

Danny

@theKashey
Copy link
Owner

theKashey commented Jan 25, 2019

A few questions:

  • what is request
  • how controllers/auth got called
  • when do you setup your application?

What rewiremock.proxy does:

  • requires module with overridden dependencies
  • returns it
  • clears everything

Override does not exists before and after rewiremock.proxy.

What you probably shall do(these are all different variants):

  1. Use returned mock object somehow.
  2. Recreate your express server, to include the override
  3. Dont disable rewiremock.

So simplest way is 3

rewiremock('firebase-admin').with(new function (location) { return {} });
rewiremock.enable();
// rewiremock is active and will override any require to `firebase-admin`
// just do that require (probably re-create server)
     request(app)
              .post(API_URL)
              .send({ phone: PHONE, token })
              .end((err, res) => {
              // disable it
               rewiremock.disable();
                if (err) return done(err)
                expect(res.statusCode).to.be.equal(200)
                done()
              })

@embpdaniel
Copy link
Author

hi @theKashey thanks for your suggestions. I tried option 3, but I get this error:
TypeError: rewiremock.mock is not a function

Maybe it has something to do with the way I required rewiremock? (const rewiremock = require('rewiremock/node').default)

To answer your other questions:

What is request

Request comes from supertest, basically all I do is const request = require('supertest') at the top, then I pass app which is basically, the top-level Mocha index.js file. That file requires my 'server' file (not currently mocked), and the server file requires 'firebase-admin' to initialize firebase. Just making a note of that in case it matters.

How controllers/auth got called

The server module I initialized in the Mocha index.js is what connects the express server and the routes. When I use supertest to route (request(app).post(/some/endpoint/)), it will find the appropriate route. So there is no need for me to import the actual module into my tests as it is invoked via supertest.

when do you setup your application?

To explain a bit more on the order:

  1. mocha command targeting tests folder is ran
  2. tests/index.js runs, uses real server module
  3. server module initializes express and routes, and requires 'firebase-admin' to initialize it
  4. test runs for auth route
  5. rewiremock attempts to mock any request to 'firebase-admin' within it function
  6. test invokes a route to 'controllers/auth', passing token
  7. auth route requires 'firebase-admin' to attempt to verify token
  8. real 'firebase-admin' library is used, instead of the mock

Hope this helps, let me know if any more info, thanks again!
Danny

@theKashey
Copy link
Owner

rewiremock.mock is not a function

// just
rewiremock('firebase-admin').with(new function (location) { return {} });

Regarding the rest - after you have created server - you can't change it. It's already created.
You have to recreate server with some parts mocked(by the time of creation), and that's the only way to do the job. That's not how mocking works, but how javascript works.

@embpdaniel
Copy link
Author

embpdaniel commented Jan 26, 2019

Oh, I see. So my problem is, I am trying to mock after I have already required 'firebase-admin' by my server module. So I need to mock 'firebase-admin' before requiring the server. And then to have the most control possible, ideally I would need to create a mocked server before each test runs, so that I have full control of my environment in the test. Am I understanding the flow of things?

@theKashey
Copy link
Owner

Yep. You shall first setup your environment, next create subject under test, then test it.

Things like Jest, which runs tests in isolation might help here, especially if you will use jest-like mocking (https://github.com/theKashey/rewiremock#hoisted-mocking)

@embpdaniel
Copy link
Author

Thank you @theKashey . I have now been able to set it up 👍

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

2 participants