Does detox tests have access to code in my react-native app? - react-native

So inside my firstTest.e2e.js file I have stuff like:
describe('All tests', () => {
beforeEach(async () => {
//can add code here to do something before each it test
});
it('Take screenshot', async () => {
await device.takeScreenshot('home');
});
});
My question is if from this file do I have access to any of code in my actual app or is it working outside of my app? Can I call a helper class inside my app/src folder?

Related

How Test with Jest a function in the method "mounted" VueJS

I would to try call a function already mocked. I use vueJS for the frond and Jest as unit test. Below a example of my code. My purpose is to test the call of « anotherFunction". The first test is succeed , not the second.Thanks for help or suggestion
code vueJS:
mounted() {
this.myfunction();
}
methods: {
myfunction() {
this.anotherFunction();
}
}
Jest code:
describe('Home.vue', () => {
let wrapper = null;
const options = {
mocks: {
$t: () => 'some specific text',
},
methods: {
myFunction: jest.fn(),
},
};
it('Should renders Home Component', () => {
// Given
wrapper = shallowMount(Home, options);
// Then
expect(wrapper).toBeTruthy();
});
it('Should call anotherFunction', async (done) => {
// Given
wrapper.vm.anotherFunction = jest.fn().mockResolvedValue([]);
// When
await wrapper.vm.myFunction();
// THIS THE PROBLEM, myFunction is mocked and I can't call the function 'anotherFunction' inside...
// Then
// expect(wrapper.vm.anotherFunction).toHaveBeenCalled();
});
});
I was finding a good way to help you if this test case. So, I thought in something like the chuck code below:
import { mount } from '#vue/test-utils';
describe('Home', () => {
it('method calls test case', () => {
const anotherMethodMock = jest.fn();
wrapper = mount(Home, {
methods: {
anotherMethod: anotherMethodMock
}
});
expect(anotherMethodMock).toHaveBeenCalled();
});
});
But, the Jest threw the following exception:
[vue-test-utils]: overwriting methods via the methods property is deprecated and will be removed in the next major version. There is no clear migration path for themethods property - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex m ethod extract it from the component and test it in isolation. Otherwise, the suggestion is to rethink those tests.
I had the following insight, maybe, in this case, should be better to test the side effect of this anotherMethod calling. What does it change? Is something being shown to the user?
I believe that here we have started from the wrong concept.
I hope that this tip could be useful :)
As suggested by #Vinícius Alonso, We should avoid using methods and setMethods in our test cases because of it's deprecation. But you can still test the mounted lifecycle by mocking the functions that are being called during mount. So you can do something similar to below snippet.
describe('Mounted Lifecycle', () => {
const mockMethodOne = jest.spyOn(MyComponent.methods, 'methodOne');
const mockMethodTwo = jest.spyOn(MyComponent.methods, 'methodTwo');
it('Validate data and function call during mount', () => {
const wrapper = shallowMount(MyComponent);
expect(mockMethodOne).toHaveBeenCalled();
expect(mockMethodTwo).toHaveBeenCalled();
})
})
Do mount/shallowMount inside it only rather putting it outside of it as it was not working in my case. You can checkout more details on it if you want.

Jest Mocking Permissions of Expo TypeError: Cannot read property 'askAsync' of undefined

I'm mocking expo and the Permissions module, but when calling Permissions.AskAsync Permissions is undefined.
Problem looks like this question. Using Jest to mock named imports
Used the provided answer, but did not work.
I have mocked the axios, which works. Doing the same for the expo module does not work.
The function I want to test:
checkPermission = async () => {
const {statusCamera} = await Permissions.askAsync(Permissions.CAMERA);
// console.log(statusCamera);
this.setState({cameraPermission: statusCamera});
const {statusCameraRoll} = await Permissions.askAsync(Permissions.CAMERA_ROLL);
this.setState({cameraRollPermission: statusCameraRoll});
};
The test:
describe("Test the Permission function", () => {
it('should return rejected permission.', async function () {
const wrapper = shallow(<Photo2/>);
const instance = wrapper.instance();
await instance.checkPermission();
expect(instance.state("cameraPermission")).toBeFalsy();
});
});
The mock I use for expo:
jest.mock('expo', ()=>({
Permissions: {
askAsync: jest.fn()
}
}))
and tried
(In file mocks/expo.js)
export default {
Permissions: {
askAsync: jest.fn(() => {
return "SOMETHING"
})
}
}
and tried
(In file mocks/expo.js)
jest.mock('expo', ()=>({
Permissions: {
askAsync: jest.fn()
}
}));
Error: "TypeError: Cannot read property 'askAsync' of undefined"
This error occures on line where Permissions.askAsyc is called. So Permissions is undefined. (Also checked it with console.log(Permissions)
I expected the instance.state("cameraPermission") to be falsy, but it crashes before it comes to that line.
Since expo change the packages to be import * as Permissions from 'expo-permissions';
You just need to create "mocks/expo-permissions.js" and have it has:
export const getAsync = jest.fn(permissions => Promise.resolve());
export const askAsync = jest.fn(permissions => Promise.resolve());
teerryn's answer is correct and is a good start. To add some more details:
Unless you've configured different roots for Jest, you should place your mock file in __mocks__/expo-permissions.js where __mocks__ is a directory at the same level as your node_modules folder. See Jest docs on mocking node modules.
The permissions argument being passed in will be undefined due to the way we're mocking the module, so you'll need to mock the permission types you want to use. Just need something simple like export const CAMERA_ROLL = 'camera_roll';
If you want to respond differently based on the permission type passed in (for example, allow Permissions.CAMERA but deny Permissions.CAMERA_ROLL and all other types), you can mock the implementation of the askAsync function. For example, your __mocks__/expo-permissions.js file would look like this:
export const CAMERA = 'camera';
export const CAMERA_ROLL = 'camera_roll';
export const askAsync = jest.fn().mockImplementation((permissionType) => {
const responseData = permissionType === CAMERA ? { status: 'granted' } : { status: 'undetermined' }; // you could also pass `denied` instead of `undetermined`
return Promise.resolve(responseData);
});
The problem is that you are handling async tests incorrectly (your checkPermission() function is async). There are several ways you can tell jest that you want to test an async function. Here are a few ways.
Here is a quick solution to your problem:
...
import { Permissions } from 'expo';
...
jest.mock('expo', () => ({
Permissions: {
askAsync: jest.fn(),
}
}));
...
describe("Test the Permission function", () => {
it('should return rejected permission.', () => {
Permissions.askAsync.mockImplementation( permission => { return {status: 'granted'}; } ); // if you want to add some sort of custom functionality
const wrapper = shallow(<Photo2/>);
const instance = wrapper.instance();
return instance.checkPermission().then(data => {
expect(instance.state("cameraPermission")).toBeFalsy();
});
});
});

Detox: "Cannot find UI element." when trying to scroll FlatList

This is the code for the tests:
//navigates to the new screen:
it("should show myFlatListScreen after tap", async () => {
await element(by.id("navigationButton")).tap();
await waitFor(element(by.id("myFlatListScreen"))).toBeVisible();
});
//Passes without issue:
it("FlatList should be visible", async () => {
await waitFor(element(by.id("myFlatList"))).toBeVisible();
});
//Fails with: "Cannot find UI element." error
it("FlatList should scroll", async () => {
await element(by.id('myFlatList')).scroll(100, 'down');
});
How is it that the element can pass the toBeVisible() test and then not exist for scrolling?
EDIT: I figured it out. there is some code before these that looks like this:
beforeEach(async () => {
await device.reloadReactNative();
});
The app is reloading from the start each time which is why that element is no longer available. It looks like I have to write all my tests so they run start to finish for each.
There is some code before these that looks like this:
beforeEach(async () => {
await device.reloadReactNative();
});
The app is reloading from the start each time which is why that element is no longer available. It looks like I have to write all my tests so they run start to finish for each.

Testing a function called on an object with Jest in React Native

EDIT
Current example,
it('CALLED THE canOpenURL FUNCTION', () => {
const wrapper = mount(<ResourceCardComponent {...mockProps} />);
const canOpenURLSpy = jest.spyOn(Linking, 'canOpenURL');
wrapper.find('TouchableOpacity').simulate('click');
expect(canOpenURLSpy).toHaveBeenCalled();
canOpenURLSpy.mockReset();
canOpenURLSpy.mockRestore();
});
Error
expect(jest.fn()).toHaveBeenCalled() Expected mock function to have
been called.
Problem
I am using Jest & Enzyme to test a class made with React Native. This class has a function inside of it that when fired off uses the Linking library to call canOpenUrl and openUrl. I can simulate the click event on the mounted component but I am having trouble knowing how much of this I can actually test.
My goal is to check if Linking.canOpenUrl ever fires off.
Exmaple
The function inside the component looks like this,
onPressLink() {
console.log('HEY THIS FUNCTION FIRED WOOT WOOT');
Linking.canOpenURL(this.props.url).then((supported) => {
if (supported) {
Linking.openURL(this.props.url);
}
});
}
I can simulate this firing off like this,
describe('onPressLink has been called!', () => {
it('It clicks the mock function onPressLink!', (done) => {
const wrapper = mount(<MyComponent {...mockProps} />);
const onPressLink = jest.fn();
const a = new onPressLink();
wrapper.find('TouchableOpacity').first().simulate('click');
expect(onPressLink).toHaveBeenCalled();
done();
});
});
Now that does work, but my goal is to use something like this,
expect(Linking.canOpenUrl).toHaveBeenCalled();
But I keep getting this error,
TypeError: Cannot read property '_isMockFunction' of undefined
Current code that is trying to check if this function is ever fired off. Which is inside the parent function that is clicked with the simulate method,
it('calls canOpenURL', () => {
const wrapper = mount(<MyComponent {...mockProps} />);
const canOpenURL = jest.spyOn(wrapper.instance, 'onPressLink');
wrapper.find('TouchableOpacity').simulate('click');
expect('Linking.canOpenUrl').toHaveBeenCalled();
});
Question
What is the proper way to check to see if Linking.canOpenURL is fired when its parent function is executed?
(Since Jest 19.0.0+)
You can spy on the Linking module methods using jest.spyOn().
(1) Tell jest to spy on the module method:
const spy = jest.spyOn(Linking, 'canOpenURL');
(2) After doing everything you need to test it, check the spy:
expect(spy).toHaveBeenCalled();
(3) Clean up and stop spying on the module method
spy.mockReset();
spy.mockRestore();
If you don't want the tests to use the actual implementation of the methods, you can fake them like this:
jest.spyOn(Linking, 'canOpenURL').mockImplementation(() => Promise.resolve());
Where the function passed to mockImplementation will be whatever you want the method to do when called.
Ref https://facebook.github.io/jest/docs/en/jest-object.html#jestspyonobject-methodname
When using the actual implementation of your module method, which is asynchronous, the promise might not have been resolved by the time you tested it. You need to make sure any promise is resolved in your method implementation before making any assertions on it.
One way to deal with this is using async/await, like so:
it('...', async () => {
// Wait for promise to resolve before moving on
await wrapper.instance().onPressLink();
// make your assertions
expect(...);
});
Another option is using expect().resolves, available since Jest 20.0.0, where you wait for some promise in the argument to expect() to resolve with a value before making an assertion on that value.
expect(somePromiseThatEventuallyResolvesWithValue).resolves.toBe(Value);
I've done in simplest way:
Steps to spy:
Make spy object for original function using jest
Call original function with / without argument(s)
Assert the function which should be called with valid argument(s)
Reset mock
Restore mock
Here is the sample example
DefaultBrowser.ts which is actual class.
import { Linking } from 'react-native';
export const openDefaultBrowser = async url => {
if (await Linking.canOpenURL(url)) {
Linking.openURL(url);
}
};
DefaultBrowser.test.ts which is test case class.
import { openDefaultBrowser } from '../DefaultBrowser';
import { Linking } from 'react-native';
describe('openDefaultBrowser with validate and open url', () => {
it('validate url', async () => {
const spy = jest.spyOn(Linking, 'canOpenURL');
openDefaultBrowser('https://www.google.com');
expect(spy).toBeCalledWith('https://www.google.com');
spy.mockReset();
spy.mockRestore();
});
it('open url', async () => {
const spy = jest.spyOn(Linking, 'openURL');
openDefaultBrowser('https://www.google.com');
expect(spy).toBeCalledWith('https://www.google.com');
spy.mockReset();
spy.mockRestore();
});
});
Hope this helps you.
it('open url', async () => {
jest.spyOn(Linking, 'canOpenURL')
const spy = jest.spyOn(Linking, 'openURL')
openURL(sitePath)
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(sitePath)
})
spy.mockReset()
spy.mockRestore()
})

Testing ExpressJS endpoint with Jest

I'm trying to test an endpoint from my express application using Jest. I'm migrating from Mocha to try out Jest to improve the speed. However, my Jest test does not close? I'm at a loss...
process.env.NODE_ENV = 'test';
const app = require('../../../index');
const request = require('supertest')(app);
it('should serve the apple-app-site-association file /assetlinks.json GET', async () => {
const response = await request.get('/apple-app-site-association')
expect(response.statusCode).toBe(200);
});
So the only thing I could think for this failing is that you might be missing the package babel-preset-env.
In any case there are two other ways to use supertest:
it('should serve the apple-app-site-association file /assetlinks.json GET', () => {
return request.get('/apple-app-site-association').expect(200)
})
or
it('should serve the apple-app-site-association file /assetlinks.json GET', () => {
request.get('/apple-app-site-association').then(() => {
expect(response.statusCode).toBe(200);
done()
})
})
async is the fancy solution, but is also the one that has more requirements. If you manage to find what was the issue let me know :).
(Reference for my answer: http://www.albertgao.xyz/2017/05/24/how-to-test-expressjs-with-jest-and-supertest/)
it("should serve the apple-app-site-association file /assetlinks.json GET", async () => {
await request
.get("/apple-app-site-association")
.send()
.expect(200);
});
if your configuration setup is correct this code should work.