React Native – Testing (3)

How to fix “Received number of calls: 0” when testing a class method?

  • Main classes
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class API {
someMethod() {
...
}
}
export default API;
class API { someMethod() { ... } } export default API;
class API {
  someMethod() {
    ...
  }
}

export default API;
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import API from 'utils/API';
class Foo {
constructor() {
this.api = new API();
}
helloWorld() {
this.api.someMethod();
}
}
export default Foo;
import API from 'utils/API'; class Foo { constructor() { this.api = new API(); } helloWorld() { this.api.someMethod(); } } export default Foo;
import API from 'utils/API';

class Foo {
  constructor() {
    this.api = new API();
  }

  helloWorld() {
    this.api.someMethod();
  }
}

export default Foo;
  • Failed test
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
describe( 'Foo', () => {
it ( 'should call someMethod', () => {
const foo = new Foo();
const api = new API();
jest.spyOn( api, 'someMethod' );
foo.helloWorld();
expect(api.someMethod).toHaveBeenCalledTimes(1);
});
});
describe( 'Foo', () => { it ( 'should call someMethod', () => { const foo = new Foo(); const api = new API(); jest.spyOn( api, 'someMethod' ); foo.helloWorld(); expect(api.someMethod).toHaveBeenCalledTimes(1); }); });
describe( 'Foo', () => {
	it ( 'should call someMethod', () => {
		const foo = new Foo();
		const api = new API();

		jest.spyOn( api, 'someMethod' );

		foo.helloWorld();

		expect(api.someMethod).toHaveBeenCalledTimes(1);
	});
});
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
expect(jest.fn()).toHaveBeenCalledTimes(expected) Expected number of calls: 1 Received number of calls: 0
expect(jest.fn()).toHaveBeenCalledTimes(expected)

Expected number of calls: 1
Received number of calls: 0
  • Correct test file
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock
jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter
return jest.fn().mockImplementation(() => {
return {
someMethod: mockSomeMethod
};
});
});
describe( 'Foo', () => {
it ( 'should call greetWorld', () => {
const foo = new Foo();
const api = new API();
foo.helloWorld();
expect(api.greetWorld).toHaveBeenCalledTimes(1);
});
});
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter return jest.fn().mockImplementation(() => { return { someMethod: mockSomeMethod }; }); }); describe( 'Foo', () => { it ( 'should call greetWorld', () => { const foo = new Foo(); const api = new API(); foo.helloWorld(); expect(api.greetWorld).toHaveBeenCalledTimes(1); }); });
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock

jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter
	return jest.fn().mockImplementation(() => {
		return {
			someMethod: mockSomeMethod
		};
	});
});

describe( 'Foo', () => {
	it ( 'should call greetWorld', () => {
		const foo = new Foo();
		const api = new API();

		foo.helloWorld();

		expect(api.greetWorld).toHaveBeenCalledTimes(1);
	});
});

Ref: inner-functions-with-jest

How to mock a class to return a function instead of an object?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class API {
someMethod() {
...
}
}
export default API;
class API { someMethod() { ... } } export default API;
class API {
  someMethod() {
    ...
  }
}

export default API;
  • If a class is mistakenly mocked as an “object” as opposed to a function, an object cannot be instantiated with a “new” operator.
    This mock is incorrect because it returns an object:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns an object
return {
someMethod: mockSomeMethod
};
})
// This will throw the error
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { // Returns an object return { someMethod: mockSomeMethod }; }) // This will throw the error const api = new API();
import API from 'utils/API';

const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
  // Returns an object
  return {
    someMethod: mockSomeMethod
  };
})

// This will throw the error
const api = new API();
  • This mock is correct:
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns a function
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
})
// This will not throw an error anymore
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { // Returns a function return jest.fn().mockImplementation(() => ({ someMethod: mockSomeMethod })); }) // This will not throw an error anymore const api = new API();
import API from 'utils/API';

const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
  // Returns a function
  return jest.fn().mockImplementation(() => ({
    someMethod: mockSomeMethod
  }));
})

// This will not throw an error anymore
const api = new API();

How to mock a class which is exported as non-default?

The error you usually get for this case is “TypeError: _myClass.MyClass is not a constructor

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
export class API {
someMethod() {
...
}
}
export class API { someMethod() { ... } }
export class API {
  someMethod() {
    ...
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
return {
get API() {
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
}
}
})
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { return { get API() { return jest.fn().mockImplementation(() => ({ someMethod: mockSomeMethod })); } } }) const api = new API();
import API from 'utils/API';

const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
  return {
    get API() {
      return jest.fn().mockImplementation(() => ({
        someMethod: mockSomeMethod
      }));  
    }
  }
})

const api = new API();

How to test async/ await?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
export class API {
async fetchMethod() {
...
}
errroMethod() {
...
}
////////////////////////////////
////////////////////////////////
async someMethod() {
try {
await fetchMethod()
} catch(error) {
errorMethod()
}
}
}
export class API { async fetchMethod() { ... } errroMethod() { ... } //////////////////////////////// //////////////////////////////// async someMethod() { try { await fetchMethod() } catch(error) { errorMethod() } } }
export class API {
  async fetchMethod() {
    ...
  }

  errroMethod() {
    ...
  }

////////////////////////////////
////////////////////////////////

  async someMethod() {
    try {
      await fetchMethod()
    } catch(error) {
      errorMethod()
    }
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import API from 'utils/API';
const api = new API();
const mockErrorMethod = jest.spyOn(api, 'errorMethod');
describe('API fecth works', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve());
it('calls fetchMethod, errorMethod is not called', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(0);
});
})
describe('API fecth is down', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error));
it('calls fetchMethod, errorMethod', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(1);
});
})
import API from 'utils/API'; const api = new API(); const mockErrorMethod = jest.spyOn(api, 'errorMethod'); describe('API fecth works', () => { jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve()); it('calls fetchMethod, errorMethod is not called', async () => { await api.someMethod; expect(api.fetchMethod).toHaveBeenCalledTimes(1); expect(mockErrorMethod).toHaveBeenCalledTimes(0); }); }) describe('API fecth is down', () => { jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error)); it('calls fetchMethod, errorMethod', async () => { await api.someMethod; expect(api.fetchMethod).toHaveBeenCalledTimes(1); expect(mockErrorMethod).toHaveBeenCalledTimes(1); }); })
import API from 'utils/API';

const api = new API();
const mockErrorMethod = jest.spyOn(api, 'errorMethod');

describe('API fecth works', () => {
  jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve());

  it('calls fetchMethod, errorMethod is not called', async () => {
    await api.someMethod;
    expect(api.fetchMethod).toHaveBeenCalledTimes(1);
    expect(mockErrorMethod).toHaveBeenCalledTimes(0);
  });
})

describe('API fecth is down', () => {
  jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error));

  it('calls fetchMethod, errorMethod', async () => {
    await api.someMethod;
    expect(api.fetchMethod).toHaveBeenCalledTimes(1);
    expect(mockErrorMethod).toHaveBeenCalledTimes(1);
  });
})

How to test a component with a custom hook

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// click-a-button.tsx
import {useClickAButton} from "./hooks/index";
export const ClickAButton = () => {
const { handleClick, total } = useClickAButton();
return <button onClick={handleClick}>{total}</button>;
}
// click-a-button.tsx import {useClickAButton} from "./hooks/index"; export const ClickAButton = () => { const { handleClick, total } = useClickAButton(); return <button onClick={handleClick}>{total}</button>; }
// click-a-button.tsx
    
    import {useClickAButton} from "./hooks/index";
    
    export const ClickAButton = () => {
        const { handleClick, total } = useClickAButton();
        return <button onClick={handleClick}>{total}</button>;
    }
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// hooks/use-click-a-button.tsx
import React, {useCallback, useState} from 'react';
export const useClickAButton = () => {
const [total, setTotal] = useState<number>(0);
const handleClick = useCallback(() => {
setTotal(total => total + 1);
}, []);
return {
handleClick,
total,
};
}
// hooks/use-click-a-button.tsx import React, {useCallback, useState} from 'react'; export const useClickAButton = () => { const [total, setTotal] = useState<number>(0); const handleClick = useCallback(() => { setTotal(total => total + 1); }, []); return { handleClick, total, }; }
// hooks/use-click-a-button.tsx

import React, {useCallback, useState} from 'react';

export const useClickAButton = () => {
    const [total, setTotal] = useState<number>(0);
    const handleClick = useCallback(() => {
        setTotal(total => total + 1);
    }, []);
    return {
        handleClick,
        total,
    };
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// click-a-button.test.tsx
import * as React from 'react';
import {act} from "react-dom/test-utils";
import {render} from "@testing-library/react";
import {useClickAButton} from './hooks/index'
import {ClickAButton} from "./index";
jest.mock('./hooks') // This is important
const hooks = { useClickAButton }
const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton');
const mockHandleClick = jest.fn();
mockUseClickAButton.mockReturnValue({
handleClick: mockHandleClick,
total: 5,
});
test('it runs with a mocked customHook',() => {
const component = render(<ClickAButton />);
expect(component.container).toHaveTextContent('5');
act(() => {
component.container.click();
});
expect(mockHandleClick).toHaveBeenCalled();
})
// click-a-button.test.tsx import * as React from 'react'; import {act} from "react-dom/test-utils"; import {render} from "@testing-library/react"; import {useClickAButton} from './hooks/index' import {ClickAButton} from "./index"; jest.mock('./hooks') // This is important const hooks = { useClickAButton } const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton'); const mockHandleClick = jest.fn(); mockUseClickAButton.mockReturnValue({ handleClick: mockHandleClick, total: 5, }); test('it runs with a mocked customHook',() => { const component = render(<ClickAButton />); expect(component.container).toHaveTextContent('5'); act(() => { component.container.click(); }); expect(mockHandleClick).toHaveBeenCalled(); })
// click-a-button.test.tsx

import * as React from 'react';
import {act} from "react-dom/test-utils";
import {render} from "@testing-library/react";
import {useClickAButton} from './hooks/index'
import {ClickAButton} from "./index";

jest.mock('./hooks') // This is important
const hooks = { useClickAButton }

const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton');
const mockHandleClick = jest.fn();
mockUseClickAButton.mockReturnValue({
    handleClick: mockHandleClick,
    total: 5,
});

test('it runs with a mocked customHook',() =>  {
    const component  = render(<ClickAButton />);
    expect(component.container).toHaveTextContent('5');
    act(() => {
        component.container.click();
    });
    expect(mockHandleClick).toHaveBeenCalled();
})

How to mock a hook?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// navigation.ts
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef();
...
// navigation.ts import { createNavigationContainerRef } from '@react-navigation/native'; export const navigationRef = createNavigationContainerRef(); ...
// navigation.ts

import { createNavigationContainerRef } from '@react-navigation/native';

export const navigationRef = createNavigationContainerRef();

...

Error when running the test file

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
TypeError: (0 , _native.createNavigationContainerRef) is not a function
TypeError: (0 , _native.createNavigationContainerRef) is not a function
TypeError: (0 , _native.createNavigationContainerRef) is not a function
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Test file
const mockNavigation = jest.fn();
jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
createNavigationContainerRef: () => {
return mockNavigation;
},
useNavigation: () => {
return mockNavigation;
}
}))
// Test file const mockNavigation = jest.fn(); jest.mock('@react-navigation/native', () => ({ ...jest.requireActual('@react-navigation/native'), createNavigationContainerRef: () => { return mockNavigation; }, useNavigation: () => { return mockNavigation; } }))
// Test file

const mockNavigation = jest.fn();
jest.mock('@react-navigation/native', () => ({
  ...jest.requireActual('@react-navigation/native'),
  createNavigationContainerRef: () => {
    return mockNavigation;
  },
  useNavigation: () => {
    return mockNavigation;
  }
}))

How to test a button press and fire an event?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// MyComponent.tsx
...
return
<MyButton
// Setup testID
testID={constants.testId.myButton}
// onPress action
onPress={() => navigateToSomewhere(link)}
/>
...
// MyComponent.tsx ... return <MyButton // Setup testID testID={constants.testId.myButton} // onPress action onPress={() => navigateToSomewhere(link)} /> ...
// MyComponent.tsx

...

return 
  <MyButton
    // Setup testID
    testID={constants.testId.myButton}

    // onPress action
    onPress={() => navigateToSomewhere(link)}
  />

...
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// Test file
// Mock action
const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation();
// Get button view by id
const { getByTestId } = render(<MyComponent />);
const button = getByTestId(constants.testId.myButton);
await waitFor(() => expect(button).toBeTruthy());
// Perform press action
fireEvent.press(button);
// Test result
expect(mockAction).toBeCalled();
// Test file // Mock action const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation(); // Get button view by id const { getByTestId } = render(<MyComponent />); const button = getByTestId(constants.testId.myButton); await waitFor(() => expect(button).toBeTruthy()); // Perform press action fireEvent.press(button); // Test result expect(mockAction).toBeCalled();
// Test file

// Mock action
const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation();

// Get button view by id
const { getByTestId } = render(<MyComponent />);
const button = getByTestId(constants.testId.myButton);
await waitFor(() => expect(button).toBeTruthy());

// Perform press action
fireEvent.press(button);

// Test result
expect(mockAction).toBeCalled();

How to test an API request using Axios?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// index.tsx
export const getUserProfile = async () => {
try {
const response = await axios.get(userProfileUrl)
return response.data;
} catch (error) {
throw error;
}
}
// index.tsx export const getUserProfile = async () => { try { const response = await axios.get(userProfileUrl) return response.data; } catch (error) { throw error; } }
// index.tsx

export const getUserProfile = async () => {
  try {

    const response = await axios.get(userProfileUrl)
    return response.data;

  } catch (error) {
    throw error;
  }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import axios from 'axios';
// Mock axios
jest.mock('axios');
const mockAxios = axios as jest.Mocked<typeof axios>;
describe('fetch user profile sucessfully', () => {
it('should return user profile', async () => {
// Mock return value
mockAxios.get.mockResolvedValue(mockData);
// Perform axios request
await getUserProfile();
// Result
expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`)
})
})
import axios from 'axios'; // Mock axios jest.mock('axios'); const mockAxios = axios as jest.Mocked<typeof axios>; describe('fetch user profile sucessfully', () => { it('should return user profile', async () => { // Mock return value mockAxios.get.mockResolvedValue(mockData); // Perform axios request await getUserProfile(); // Result expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`) }) })
import axios from 'axios';

// Mock axios
jest.mock('axios');
const mockAxios = axios as jest.Mocked<typeof axios>;

describe('fetch user profile sucessfully', () => {
  it('should return user profile', async () => {
    // Mock return value
    mockAxios.get.mockResolvedValue(mockData);

    // Perform axios request
    await getUserProfile();

    // Result
    expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`)
  })
}) 

How to test if an element is displayed?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const { getByTestId, toJSON } = render(<MyComponent />);
// Snapshot
expect(toJSON()).toMatchSnapshot();
// Get element by Id
const button = getByTestId(testId.button.login);
expect(button).toBeTruthy();
const { getByTestId, toJSON } = render(<MyComponent />); // Snapshot expect(toJSON()).toMatchSnapshot(); // Get element by Id const button = getByTestId(testId.button.login); expect(button).toBeTruthy();
const { getByTestId, toJSON } = render(<MyComponent />);

// Snapshot
expect(toJSON()).toMatchSnapshot();

// Get element by Id
const button = getByTestId(testId.button.login);
expect(button).toBeTruthy();

Be the first to comment

Leave a Reply

Your email address will not be published.


*