how to mock variables inside a function in jest
Asked Answered
E

3

12

I want to test the 'canViewPage method in jest. How do mock the const userPages which is the values from the func getUserPage

   canViewPage(page){
     const userPages = getUsersPages();
    if(userPages.includes(page)){
      return true;
    }
    return false;
   }


  getUsersPages(){
    // here i hardcode a list of pages, for simplicity purposes
    const pages = ['home','about','contact'];
    return pages

  }



here is what i tried

test('test canViewPage', () => {
    const spy = jest.spyOn(canViewPage, 'userPages');
    spy.mockReturnValue(['home','about','contact']);

    expect(canViewPage('premiumPage')).toBe(false); 

    spy.mockRestore();
  });

I also tried this

test('test canViewPage', () => {
    const spy = jest.spyOn(canViewPage, 'getUsersPage');
    spy.mockReturnValue(['home','about','contact']);

    expect(canViewPage('premiumPage')).toBe(false); 

    spy.mockRestore();
  });
Eucken answered 21/6, 2019 at 15:45 Comment(4)
You are right to mock getUsersPage(), but you setting up the mock/spy incorrectly. getUsersPages() is not defined/exported from within canViewPage(). Instead try targeting getUsersPage() directly to create a mock/spy. With the spy working, then you can assert canViewPage('premiumPage') accordingly.Diazonium
and how do i do that, thats what i've struggling withEucken
You may need to share more information regarding the file where getUsersPage(), is it can exported function? What have you tried from jestjs.io/docs/en/mock-functions other than what you shared in your question?Diazonium
this question is about mocking return values from a function, not mocking variablesColumella
F
12

To mock the value of userPages you have to mock getUserPage. To achieve this, it depends on where and how getUserPage and canViewPage are defined. I'm going to assuming these two functions are defined in class MyAwesomeClass

// MyAwesomeClass.js
export default class MyAwesomeClass {
  canViewPage(page) {
    const userPages = this.getUsersPages();
    if (userPages.includes(page)) {
      return true;
    }
    return false;
  }


  getUsersPages() {
    // here i hardcode a list of pages, for simplicity purposes
    const pages = ['home', 'about', 'contact'];
    return pages;
  }
}

// test.js
import MyAwesomeClass from '<path to MyAwesomeClass.js>'
test('test canViewPage', () => {
  const instance = new MyAwesomeClass()
  const spy = jest.spyOn(instance, 'getUsersPages');
  spy.mockReturnValue(['mockItem1','mockItem2','mockItem3']);

  expect(instance.canViewPage('premiumPage')).toBe(false);
  expect(instance.canViewPage('mockItem1')).toBe(true);

  spy.mockRestore();
});

if canViewPage and getUsersPages are static methods within the class, you mock differently

test('test canViewPage', () => {
  const spy = jest.spyOn(MyAwesomeClass, 'getUsersPages');
  spy.mockReturnValue(['mockItem1','mockItem2','mockItem3']);

  expect(MyAwesomeClass.canViewPage('premiumPage')).toBe(false);
  expect(MyAwesomeClass.canViewPage('mockItem3')).toBe(true);

  spy.mockRestore();
});
Frenchman answered 21/6, 2019 at 17:0 Comment(3)
thats did it for me, the only difference was my case, my functions were stand alone with no class, so imported them like this. "import * as MyAwesomeClass from './utils.js' "Eucken
What if there is no class and 'getUsersPages' is just method in that file ?Burck
@Burck -- have you tried doing import * as MyAwesomeClass from '<filepath>'Frenchman
W
0

This is not Jest but sinon, in case if you can not see the instance of the target class, you can also set mock values as below. Once specified, mocked values will be returned until sinon.restore() called

const sinon = require('sinon');
const test = await sinon
    .stub(MyAwesomeClass.prototype, 'getUsersPages')
    .returns(['mockItem1','mockItem2','mockItem3']);

const instance = new MyAwesomeClass()
console.log(instance.getUserPages()) // <- this return ['mockItem1','mockItem2','mockItem3']

It assume that this is target source code.

// MyAwesomeClass.js
export default class MyAwesomeClass {
  canViewPage(page) {
    const userPages = this.getUsersPages();
    if (userPages.includes(page)) {
      return true;
    }
    return false;
  }
    
  getUsersPages() {
    // here i hardcode a list of pages, for simplicity purposes
    const pages = ['home', 'about', 'contact'];
    return pages;
  }
}

// test.js
import MyAwesomeClass from '<path to MyAwesomeClass.js>'
test('test canViewPage', () => {
  const instance = new MyAwesomeClass()
  const spy = jest.spyOn(instance, 'getUsersPages');
  spy.mockReturnValue(['mockItem1','mockItem2','mockItem3']);

  expect(instance.canViewPage('premiumPage')).toBe(false);
  expect(instance.canViewPage('mockItem1')).toBe(true);

  spy.mockRestore();
});
Wrongly answered 31/7, 2022 at 3:22 Comment(0)
L
-1

Spy and stub is a recommended approach, however in case if you want to access the outside scope object, hack window variable and assign it with desired value

for ex:

var a = 10;
const myfun = () => {
 return a + 20;
}

test('myfun', () => {
  window.a = 20
  expect(myfun).toBe(40)
 }
Limnology answered 9/10, 2020 at 4:54 Comment(3)
This is not working as expected with angularjs.Tether
Not sure what you mean angularJS, do you mean Karma/Jasmine? or JESTLimnology
I think you should avoid using this way making global variablesPillory

© 2022 - 2024 — McMap. All rights reserved.