Enzyme Mock ToastAndroid React Native Component - unit-testing

I am testing a react native component that uses ToastAndroid Component in a method, and while testing with enzyme I keep getting error TypeError: _reactNative.ToastAndroid.show is not a function
I am using react-native-mock-renderer for jest mock and my component has a method that gets called in with an onPress handler.
validateAndProceed = () => {
ToastAndroid.show(
'Show toast',
ToastAndroid.SHORT,
);
};
and my test to verify
it('should validate and process', () => {
const wrapper = shallow(<Component
/>);
const instance = wrapper.dive().instance();
jest.spyOn(instance, 'validateAndProceed');
instance.validateAndProceed();
expect(instance.validateAndProceed).toHaveBeenCalled();
});
I created a custom mock for the ToastAndroid
const ToastAndroid = {
SHORT: '',
LONG: '',
TOP: '',
BOTTOM: '',
CENTER: '',
show: jest.fn(),
showWithGravity: jest.fn(),
showWithGravityAndOffset: jest.fn(),
};
module.exports = ToastAndroid;
Still a not working

You don't need to mock the entire module. Mocking only relevant functions and constants did it for me.
Example:
ToastAndroid.showWithGravity = jest.fn();
ToastAndroid.show = jest.fn();

Related

NestJS: How can I mock ExecutionContext in canActivate

I am having trouble in mocking ExecutionContext in Guard middleware.
Here's my RoleGuard extends JwtGuard
#Injectable()
export class RoleGuard extends JwtAuthGuard {
...
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const params = request.params;
...
}
}
This is what I am trying on my unit test.
let context: ExecutionContext = jest.genMockFromModule('#nestjs/common');
context.switchToHttp = jest.fn().mockResolvedValue({
getRequest: () => ({
originalUrl: '/',
method: 'GET',
params: undefined,
query: undefined,
body: undefined,
}),
getResponse: () => ({
statusCode: 200,
}),
});
jest.spyOn(context.switchToHttp(), 'getRequest').mockImplementation(() => {
return Promise.resolve(null);
});
And I am getting this kind of error.
Cannot spy the getRequest property because it is not a function; undefined given instead
I would like you to suggest any other way to mock context. Thank you.
Please check this library https://www.npmjs.com/package/#golevelup/ts-jest
Then you could mock ExecutionContext as following.
import { createMock } from '#golevelup/ts-jest';
import { ExecutionContext } from '#nestjs/common';
describe('Mocked Execution Context', () => {
it('should have a fully mocked Execution Context', () => {
const mockExecutionContext = createMock<ExecutionContext>();
expect(mockExecutionContext.switchToHttp()).toBeDefined();
...
});
});
Hope it helps
When it comes to the ExecutionContext, depending on what I'm tetsting, I just supply a simple object instead, something like
const ctxMock = {
switchToHttp: () => ({
getRequest: () => ({
params: paramsToAdd,
url: 'some url path',
...
}),
}),
}
And use that as I need. If I need access to jest functions I save those to a variable before hand and assign the context's function to the variable, then I can use expect(variable).toHaveBeenCalledTimes(x) without a problem.
Another option is to use #golevelup/ts-jest to create type safe mock objects for you. I've made extensive use of this library as well for other libraries I've made.

How to test react component correctly?

Recently I am learning to test React with jest and enzyme, It seems hard to understand what a unit test is it, my code
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
value: ""
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const value = e.target.value;
this.setState({
value
});
}
render() {
return <Nest value={this.state.value} handleChange={this.handleChange} />;
}
}
export const Nest = props => {
return <input value={props.value} onChange={props.handleChange} />;
};
export default App;
and my test
import React from "react";
import App, { Nest } from "./nest";
import { shallow, mount } from "enzyme";
it("should be goood", () => {
const handleChange = jest.fn();
const wrapper = mount(<App />);
wrapper.find("input").simulate("change", { target: { value: "test" } });
expect(handleChange).toHaveBeenCalledTimes(1);
});
IMO, the mocked handleClick will intercept the handleClick on App,
if this is totally wrong, what's the right way to use mock fn and test the handleClick be called.
Another: I search a lot, read the similar situations, seem like this iscontra-Unit Test,
Probably I should test the two component separately, I can test both components,
test the
<Nest value={value} handleChange={handleChange} />
by pass the props manually, and then handleChangeinvoked by simulate change
it passed test.
but how can I test the connection between the two?
I read
some work is React Team's Work
...
I don't know which parts I have to test in this case, and Which parts react already tested and don't need me to test. That's confusing.
You should take the path of testing the Nest component in isolation first, passing your mocked handleChange as a prop, to verify that input changes are being propagated.
If you want to test the state part, then you can get the instance of your App class from enzyme and call that method directly:
it("should update the Nest value prop when change is received", () => {
const wrapper = mount(<App />);
const instance = wrapper.instance()
instance.handleChange( { target: { value: "test" } })
const nestComponent = wrapper.find("Nest").first()
expect(nestComponent).prop('value').toEqual('test');
});
This a very very basic, almost not needed to test piece of code, but it will get your test coverage up if that's what you're after.
Doc for instance: http://airbnb.io/enzyme/docs/api/ReactWrapper/instance.html
If you want to test for the connection. From what I see, the nest component is a child component inside the App component. You could test that <App /> contains `.
describe('<App />', () => {
it('should contain a nest component', () => {
const wrapper = mount(<App />);
expect(wrapper.find(<Nest />)).toHaveLength(1);
});
});
Secondly, since the onChange event on the nest component updates the state in the App component, you can also test for state changes since its a behavior you expect.
it('should update state', () => {
//find input and simulate change with say {value: 'new value'} and then
expect(wrapper.state().value).toBe('newValue');
});
I hope this helps.

How to "mock" navigator.geolocation in a React Jest Test

I'm trying to write tests for a react component I've built that utilizes navigator.geolocation.getCurrentPosition() within a method like so (rough example of my component):
class App extends Component {
constructor() {
...
}
method() {
navigator.geolocation.getCurrentPosition((position) => {
...code...
}
}
render() {
return(...)
}
}
I'm using create-react-app, which includes a test:
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
This test fails, printing out this in the console:
TypeError: Cannot read property 'getCurrentPosition' of undefined
I'm new to React, but have quite a bit of experience with angular 1.x. In angular it is common to mock out (within the tests in a beforeEach) functions, "services", and global object methods like navigator.geolocation.etc. I spent time researching this issue and this bit of code is the closest I could get to a mock:
global.navigator = {
geolocation: {
getCurrentPosition: jest.fn()
}
}
I put this in my test file for App, but it had no effect.
How can I "mock" out this navigator method and get the test to pass?
EDIT: I looked into using a library called geolocation which supposedly wraps navigator.getCurrentPosition for use in a node environment. If I understand correctly, jest runs tests in a node environment and uses JSDOM to mock out things like window. I haven't been able to find much information on JSDOM's support of navigator. The above mentioned library did not work in my react app. Using the specific method getCurrentPosition would only return undefined even though the library itself was imported correctly and available within the context of the App class.
It appears that there is already a global.navigator object and, like you, I wasn't able to reassign it.
I found that mocking the geolocation part and adding it to the existing global.navigator worked for me.
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn()
};
global.navigator.geolocation = mockGeolocation;
I added this to a src/setupTests.js file as described here - https://create-react-app.dev/docs/running-tests#initializing-test-environment
I know this issue might have been solved, but seems that all the solutions above are all wrong, at least for me.
When you do this mock: getCurrentPosition: jest.fn()
it returns undefined, if you want to return something, this is the correct implementation:
const mockGeolocation = {
getCurrentPosition: jest.fn()
.mockImplementationOnce((success) => Promise.resolve(success({
coords: {
latitude: 51.1,
longitude: 45.3
}
})))
};
global.navigator.geolocation = mockGeolocation;
I am using create-react-app
A TypeScript version for anyone that was getting
Cannot assign to 'geolocation' because it is a read-only property.
In the mockNavigatorGeolocation.ts file (this can live in a test-utils folder or similar)
export const mockNavigatorGeolocation = () => {
const clearWatchMock = jest.fn();
const getCurrentPositionMock = jest.fn();
const watchPositionMock = jest.fn();
const geolocation = {
clearWatch: clearWatchMock,
getCurrentPosition: getCurrentPositionMock,
watchPosition: watchPositionMock,
};
Object.defineProperty(global.navigator, 'geolocation', {
value: geolocation,
});
return { clearWatchMock, getCurrentPositionMock, watchPositionMock };
};
I then import this in my test at the top of the file:
import { mockNavigatorGeolocation } from '../../test-utils';
And then use the function like so:
const { getCurrentPositionMock } = mockNavigatorGeolocation();
getCurrentPositionMock.mockImplementation((success, rejected) =>
rejected({
code: '',
message: '',
PERMISSION_DENIED: '',
POSITION_UNAVAILABLE: '',
TIMEOUT: '',
})
);
Mocking with setupFiles
// __mocks__/setup.js
jest.mock('Geolocation', () => {
return {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
});
and then in your package.json
"jest": {
"preset": "react-native",
"setupFiles": [
"./__mocks__/setup.js"
]
}
I followed #madeo's comment above to mock global.navigator.geolocation. It worked!
Additionally I did the following to mock global.navigator.permissions:
global.navigator.permissions = {
query: jest
.fn()
.mockImplementationOnce(() => Promise.resolve({ state: 'granted' })),
};
Set state to any of granted, denied, prompt as per requirement.
For whatever reason, I did not have the global.navigator object defined, so I had to specify it in my setupTests.js file
const mockGeolocation = {
getCurrentPosition: jest.fn(),
watchPosition: jest.fn(),
}
global.navigator = { geolocation: mockGeolocation }
Added to the above answers, if you want to update navigator.permissions, this will work.The key here is to mark writable as true before mocking
Object.defineProperty(global.navigator, "permissions", {
writable: true,
value: {
query : jest.fn()
.mockImplementation(() => Promise.resolve({ state: 'granted' }))
},
});

How to unit test the checkbox in Angular2

I have a sample code for checkbox written with Angular2.
<div class="col-sm-7 align-left" *ngIf="Some-Condtion">
    <input type="checkbox" id="mob_Q1" value="Q1" />
    <label for="mob_Q1">Express</label>
</div>
I want to unit test the above checkbox. Like I want to recognize the checkbox and test whether it is check-able. How do I unit test this with Karma Jasmine?
Component, e.g. CheckboxComponent, contains input element. Unit test should looks like:
import {ComponentFixture, TestBed} from '#angular/core/testing';
import {By} from '#angular/platform-browser';
import {CheckboxComponent} from './checkbox.component';
describe('Checkbox test.', () => {
let comp: CheckboxComponent;
let fixture: ComponentFixture<CheckboxComponent>;
let input: Element;
beforeEach(() => {
TestBed.configureTestingModule(
{
declarations: [CheckboxComponent],
},
);
fixture = TestBed.createComponent(CheckboxComponent);
comp = fixture.componentInstance;
input = fixture.debugElement.query(By.css('#mob_Q1')).nativeElement;
});
it('should click change value', () => {
expect(input.checked).toBeFalsy(); // default state
input.click();
fixture.detectChanges();
expect(input.checked).toBeTruthy(); // state after click
});
});
IS there a need to write fixture.detectChanges()?
I went through the same test without this and it ends with success.
Button 1 is 'checked' by default
const button1 = debugElement.nativeElement.querySelector(selectorBtn1);
const button2 = debugElement.nativeElement.querySelector(selectorBtn2);
...
expect(button1.checked).toBeTruthy();
expect(button2.checked).toBeFalsy();
button2.click();
expect(button1.checked).toBeFalsy();
expect(button2.checked).toBeTruthy();
...
ngModel directive is async one and requires to use asynchronous capabilities of Angular unit testing. Adding async and whenStable functions.
it('checkbox is checked if value is true', async(() => {
component.model = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
const inEl = fixture.debugElement.query(By.css('#mob_Q1'));
expect(inEl.nativeElement.checked).toBe(true);
});
}));
Source LinkLink

Angular2 testing with fakeAsync

I'm trying to use fakeAsync to test an Angular 2 component, but the fixture variable is not being set. In fact, the promise callback is not being called. Here is the code:
#Component({
template: '',
directives: [GroupBox, GroupBoxHeader]
})
class TestComponent {
expandedCallback() { this.expandedCalled = true; }
}
it('testing...', inject([TestComponentBuilder], fakeAsync((tcb) => {
var fixture;
tcb.createAsync(TestComponent).then((rootFixture) => {
fixture = rootFixture
});
tick();
fixture.detectChanges();
})));
When I run this code, I get:
Failed: Cannot read property 'detectChanges' of undefined
TypeError: Cannot read property 'detectChanges' of undefined
I can't figure out why the callback isn't fired. In this repository, it works fine: https://github.com/juliemr/ng2-test-seed/blob/master/src/test/greeting-component_test.ts
Any clue?
Note: I'm using ES6, Traceur, Angular 2 beta, Karma and Jasmine.
------ UPDATE ------
It follows a repository with the failing test:
https://github.com/cangosta/ng2_testing_fakeasync
TestComonentBuilder doesn't work with templateUrl https://github.com/angular/angular/issues/5662
Try this way
https://github.com/antonybudianto/angular2-starter/blob/master/app/simplebind/child.component.spec.ts#L15
The point is you create a test dummy component (TestComponent for example) and register the component you want to test in directives: [...] and use template: <my-cmp></my-cmp>, then pass the TestComponent to tsb.createAsync(TestComponent)..., and use injectAsync.
I prefer this way since I can easily mock the data from parent, and pass any input and handle output to/from the component.
import {
it,
injectAsync,
describe,
expect,
TestComponentBuilder,
ComponentFixture
} from 'angular2/testing';
import { Component } from 'angular2/core';
import { ChildComponent } from './child.component';
#Component({
selector: 'test',
template: `
<child text="Hello test" [(fromParent)]="testName"></child>
`,
directives: [ChildComponent]
})
class TestComponent {
testName: string;
constructor() {
this.testName = 'From parent';
}
}
let testFixture: ComponentFixture;
let childCompiled;
let childCmp: ChildComponent;
describe('ChildComponent', () => {
it('should print inputs correctly', injectAsync([TestComponentBuilder],
(tsb: TestComponentBuilder) => {
return tsb.createAsync(TestComponent).then((fixture) => {
testFixture = fixture;
testFixture.detectChanges();
childCompiled = testFixture.nativeElement;
childCmp = testFixture.debugElement.children[0].componentInstance;
expect(childCompiled).toBeDefined();
expect(childCmp).toBeDefined();
expect(childCompiled.querySelector('h6'))
.toHaveText('From parent');
expect(childCompiled.querySelector('h5'))
.toHaveText('Hello test');
});
}));
it('should trigger changeMe event correctly', () => {
childCmp.changeMe();
testFixture.detectChanges();
expect(childCmp.num).toEqual(1);
expect(childCompiled.querySelector('h6'))
.toHaveText('Changed from child. Count: ' + childCmp.num);
});
});