Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stub a node module in Cypress?

Tags:

jestjs

cypress

I am able to mock modules using jest easily like:

import * as PubNub from 'pubnub';

jest.mock('pubnub', () =>
  jest.fn().mockImplementation(() => {
    mockPubnubInstance = {
      addListener(options) {
        mockPubnubListener(options);
      },
      publish() {
        return Promise.resolve({});
      },
      subscribe: jest.fn(),
      history(params, callback) {
        return mockHistory(params, callback);
      },
    };

    return mockPubnubInstance;
  }),
);

How do I do it in Cypress?

cy.stub('pubnub', 'publish').returns(Promise.resolve({}))

I tried looking at Cypress stub but it does not seem to work.

like image 641
Yogesh Avatar asked Dec 04 '19 06:12

Yogesh


2 Answers

Add a visitWithStubs command in cypress/support/commands.js:

Cypress.Commands.add('visitWithStubs', (url, stubs) => {
  if (!stubs) return cy.visit(url);
  cy.visit(url, {
    onBeforeLoad(win) {
      Object.entries(stubs).forEach(([name, stubCallback]) => {
        let target = undefined;
        Object.defineProperty(win, name, {
          // on set, stub the object
          set: (object) => {
            target = object;
            stubCallback(target);
          },
          // on get, return the stubbed object
          get: () => target,
        });
      });
    },
  });
});

Now if you expose the imported object on window

import PubNub from 'pubnub';
window.PubNub = PubNub
    
PubNub.subscribe();

You can stub it like this:

// pubnub.spec.js
    
describe('visitWithStubs', () => {
  it('lets you stub stuff', () => {
    cy.visitWithStubs('/pubnub-page', {
      PubNub: (PubNub) => {
        cy.stub(PubNub, 'addListener', mockPubnubListener);
        cy.stub(PubNub, 'publish').resolves({});
        cy.stub(PubNub, 'subscribe').as('subscribe');
        cy.stub(PubNub, 'history', mockHistory);
      },
    });
    cy.get('@subscribe').should('have.been.called');
  });
});
like image 50
skot Avatar answered Oct 16 '22 03:10

skot


Cypress use sinon internally as its stub and spy library. Here is the unit test solution:

index.ts:

import PubNub from 'pubnub';

export const pubnub = new PubNub({
  publishKey: 'demo',
  subscribeKey: 'demo'
});

export function publish() {
  function publishSampleMessage() {
    console.log("Since we're publishing on subscribe connectEvent, we're sure we'll receive the following publish.");
    var publishConfig = {
      channel: 'hello_world',
      message: {
        title: 'greeting',
        description: 'hello world!'
      }
    };
    pubnub.publish(publishConfig, function(status, response) {
      console.log(status, response);
    });
  }
  pubnub.addListener({
    status: function(statusEvent) {
      if (statusEvent.category === 'PNConnectedCategory') {
        publishSampleMessage();
      }
    },
    message: function(msg) {
      console.log(msg.message.title);
      console.log(msg.message.description);
    },
    presence: function(presenceEvent) {
      // handle presence
    }
  });
  console.log('Subscribing..');
  pubnub.subscribe({
    channels: ['hello_world']
  });
}

index.spec.ts:

/// <reference types="Cypress" />

import { publish, pubnub } from './';

describe('59170422', () => {
  it('should pass', () => {
    const logSpy = cy.spy(console, 'log');
    const addListenerStub = cy.stub(pubnub, 'addListener');
    const publishStub = cy.stub(pubnub, 'publish').resolves({});
    const subscribeStub = cy.stub(pubnub, 'subscribe');
    publish();
    addListenerStub.yieldTo('status', { category: 'PNConnectedCategory' });
    expect(addListenerStub).to.have.been.calledOnce;
    expect(publishStub).to.have.been.calledOnce;
    expect(subscribeStub).to.have.been.calledOnce;
    publishStub.yield(200, 'haha');
    expect(logSpy).to.have.been.calledWith(200, 'haha');
    addListenerStub.yieldTo('message', { message: { title: 'I am title', description: 'I am description' } });
    expect(logSpy).to.have.been.calledWith('I am title');
    expect(logSpy).to.have.been.calledWith('I am description');
  });
});

Unit test result:

====================================================================================================

  (Run Starting)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:    3.8.0                                                                              │
  │ Browser:    Electron 78 (headless)                                                             │
  │ Specs:      1 found (stackoverflow/59170422/index.spec.ts)                                     │
  │ Searched:   cypress/integration/stackoverflow/59170422/index.spec.ts                           │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


────────────────────────────────────────────────────────────────────────────────────────────────────

  Running:  stackoverflow/59170422/index.spec.ts                                            (1 of 1)


  59170422
    ✓ should pass (66ms)


  1 passing (202ms)


  (Results)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Tests:        1                                                                                │
  │ Passing:      1                                                                                │
  │ Failing:      0                                                                                │
  │ Pending:      0                                                                                │
  │ Skipped:      0                                                                                │
  │ Screenshots:  0                                                                                │
  │ Video:        true                                                                             │
  │ Duration:     0 seconds                                                                        │
  │ Spec Ran:     stackoverflow/59170422/index.spec.ts                                             │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


  (Video)

  -  Started processing:  Compressing to 32 CRF                                                     
  -  Finished processing: /Users/ldu020/workspace/github.com/mrdulin/cypress-codebase     (1 second)
                          /cypress/videos/stackoverflow/59170422/index.spec.ts.mp4                  


====================================================================================================

  (Run Finished)


       Spec                                              Tests  Passing  Failing  Pending  Skipped  
  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ ✔  stackoverflow/59170422/index.spec.t      184ms        1        1        -        -        - │
  │    s                                                                                           │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘
    ✔  All specs passed!                        184ms        1        1        -        -        -  

Source code: https://github.com/mrdulin/cypress-codebase/tree/master/cypress/integration/stackoverflow/59170422

like image 3
slideshowp2 Avatar answered Oct 16 '22 04:10

slideshowp2