Closed GantMan closed 8 years ago
I used https://github.com/mfncooper/mockery to solve the same issue. It allows you to globally mock require
, so you can do:
mockery.enable();
mockery.registerMock('../Images/Logo/some_image.png', 'nice image');
In your tests and this will affect all the files that require '../Images/Logo/some_image.png'. require('../Images/Logo/some_image.png')
then will return 'nice image'
.
Another similar tool is https://github.com/thlorenz/proxyquire
thanks!
This is a great question. Perhaps we could build a method where you can pass it a glob string for images and it will automatically register them as image objects in the require cache.
Open to hear anyone else's suggestions as well...
If I use mockery tests are working, but instead of a dir error I was getting the following:
Unexpected character '�' (1:0)
SyntaxError: test/images/reactNe.png: Unexpected character '�' (1:0)
> 1 | �PNG
| ^
2 |
3 |
4 | IHDR3�W�SgAMA��
�asRGB��� cHRMz&�����u0�`:�p��Q<bKGD������� pHYsHHF�k>n�IDATx���u�V�ڇ���A���������X����BQ��cwca�b���
at Parser.pp.raise (node_modules/babylon/index.js:1425:13)
@latusaki you cannot require an image in JS. React Native seems to have some kind of a wrapper around require
that catches all paths pointing to an image and processes them in a correct way. If you mock image requiring, you should just return a string that somehow relates to the required file (its name, for example), so you could test this string in a component and check that a correct file was required.
@Jeiwan How are you getting mockery to work? I am getting the same error as @latusaki .
In my module <Image source={require('./images/temp.png')}/>
In my test file I have:
var mockery = require('mockery');
mockery.enable();
mockery.registerMock('./images/temp.png', 'temp.png');
const Temp = require('../Temp.js');
mockery.disable();
describe('<Temp/>', () => {
...
});
I guess you have tried not disabling mockery?
@latusaki That worked, thanks!
If I remember correct the effect of mockery does not persist between test cases, so I have just added it like this:
before(() => {
mockery.enable();
mockery.registerMock('../../../images/logo-pink.png', 'logo-ping.png');
});
Hey Guys,
Thanks for your help I've been able to fix the require problem. However, none of your solutions worked for me because required propType for Image.source is either number or shape (?) So, my solution was this:
import mockery from "mockery";
mockery.enable();
mockery.registerMock('../img/myimage.png', 0)
@slamus The best way to mock an image objects source would be to pass it something it's expecting.
mockery.registerMock('../img/myimage.png', {{ uri: 'myimage.png' }});
The image doesnt have to exist or anything, but it's a better way of mocking it than just passing in a random value
I ran into the same issue today, and what i did was the following (im using jest): node_modules/babel-jest/src/index.js:
process(src, filename) {
if (babel.util.canCompile(filename)) {
return babel.transform(src, {
auxiliaryCommentBefore: ' istanbul ignore next ',
filename,
presets: [jestPreset],
retainLines: true,
}).code;
}
return src;
},
but it can't compile images, so it returns the source (which is the image itself). All my images are pngs, so i added the following check:
if (filename.match(/\.png$/)) {
const w = filename.match(/(.+\/)(.+png$)/)[2];
const source = `module.exports = '${w}';`;
return babel.transform(source, {
auxiliaryCommentBefore: ' istanbul ignore next ',
filename,
presets: [jestPreset],
retainLines: true,
}).code;
}
So i return a string for every image require i have, which is very convenient for testing: i shallow render the component, get a reference to the image and check the source prop string to be the right image name.
Hey, trying your solutions here, but not sure what I'm doing wrong.
test/Button.js
import React, { View, Text, StyleSheet } from 'react-native';
import mockery from "mockery";
import { shallow } from 'enzyme';
import { expect } from 'chai';
mockery.enable();
mockery.registerMock('../src/Theme/assets/closeWhite.png', { uri: 'myimage.png' }); //
import { CloseButton } from '../src';
describe('<CloseButton />', () => {
it('should render stuff', () => {
const wrapper = shallow(<CloseButton />);
expect(wrapper.length).to.equal(1);
});
});
/*
/node_modules/babel-core/lib/transformation/file/index.js:556
throw err;
^
/src/Theme/assets/closeWhite.png: Unexpected character '�' (1:0)
> 1 | �PNG
| ^
*/
@benjick Can you post the source of the CloseButton
component too? Remember the first arguement of mockery should be the exact string you try and require, not a relative path to the file
I didn't want to mock all image paths manually, so I made this hook:
var m = require('module');
var originalLoader = m._load;
m._load = function hookedLoader(request, parent, isMain) {
var file = m._resolveFilename(request, parent);
if (file.match(/.jpeg|.jpg|.png$/))
return {uri: file};
return originalLoader(request, parent, isMain);
}
@miracle2k oohh that's really nice! Could you submit that as a PR? Maybe putting it in mock.js
?
@miracle2k how can I use this hook with react-native-mock?
hey @slamus can u provide a repo with your solution?
@RealOrangeOne I think we should create a gitter room to discuss solutions for these issues
I was thinking about doing something like that, let me look into it further before I create something
for react-native-router-flux
to run I've used this commands with Mockery on testHelper.js
import mockery from 'mockery';
mockery.enable();
mockery.registerMock('./menu_burger.png', 'burguer');
mockery.registerMock('./back_chevron.png', 'chevron');
I'm running my tests with mocha and found mocha-image-compiler useful when testing components which require images. See my example repository for examples: react-native-unit-tests.
It comes with downside though: You will get a prop type warning when running the tests, but I'll rather take the warning than leave components untested.
@varmais Wow, that's really nice! Although yes the prop warning would get annoying. It's definately much easier than using mockery! We could fork that library and add it in, conditionally obviously.
Well, the solution of @miracle2k can not solve my problem directly because the image name they mock is just the same to the actual image name.
But as we all known, if you require an image without 2x
or 3x
postfix just like abc.png
instead of abc@2x.png
, react-native will also require the right one automatically depending on the active device. And that's why I confronted this problem and all above didn't solve it.
So inspired by the code of @miracle2k , I replaced the file
with request
directly because in my situation there is no abc.png
at all and the function _resolveFilename
will throw a can not find module
error.
At last, my code is below
const m = require('module');
const originalLoader = m._load;
m._load = function hookedLoader(request, parent, isMain) {
if (request.match(/.jpeg|.jpg|.png$/)) {
return { uri: request };
}
return originalLoader(request, parent, isMain);
};
I haven't tried the mockery solution because I use mocha and enzyme as my unit test library and I have a setup.js
file to handle all the mocks whatever the native modules or third-party modules. And the best solution for me is to write these code in the same file.
Funny that this discussion just arised.. I was working on the same mocking problem independently yesterday and came to a very similar (non-working) solution as @zhaotai ... this will save me many hours of debugging the node module system... it's also not as intrusive as mockery
.
I know mockery
and I used it for other products myself.. the thing is, before I would ever use it, I might as well just use jest
instead ... because jest
does practically the exact same thing more efficiently and with first level React-Native support...
Just tested the @zhaotai and @miracle2k solution. Works fantastic. Going to be moving this into our default AVA tests for the Ignite project. Now everyone who creates a new Ignite starter will have their work right away. I'll be sure to make more shout outs in the release notes. Thanks!
O and I"m closing this ticket :) cheers!
Hmm... I have added the hookLoader for images in my mocha setup file, I don't get the error about images anymore, but I do have the following error:
TypeError: Plugin 1 specified in "/node_modules/react-native-router-flux/node_modules/react-native-experimental-navigation/package.json" was expected to return a function but returned "undefined"
Anyone got this error?
I have a file where I require images, but I get the error:
any way we can mock this?