I am contributing to a project which is built with React (with webpack) running in Electron. When executing unit tests with Jest, it fails with the error TypeError: Cannot read property 'on' of undefined (and works fine when not testing, eg. run with Electron).
The code:
import React, { Component } from 'react';
import { ipcRenderer } from 'electron';
// some more imports
class Setup extends Component {
constructor(props) {
super(props);
this.state = {
// some state
};
ipcRenderer.on('open-file-reply', this.someMethod); // << fails on this line
}
// more class stuff
}
It took me a few days but finally, I found this answer in this great blog post. Quote:
Jest is called from Node and doesn't run test code through Webpack.
Instead, we have to use Jest's mocking functions to replace the import
with a stub file.
Jest has a helper method called moduleNameMapper [object<string, string>] . From jest documentation:
A map from regular expressions to module names that allow to stub out
resources, like images or styles with a single module.
It should be added in your package.json root object like this:
{
"name": "My awesome app",
"jest": {
"moduleNameMapper": {
"electron": "<rootDir>/src/components/tests/mock/electron.js"
}
}
}
and the mock file itself (/src/components/tests/mock/electron.js):
export const ipcRenderer = {
on: jest.fn()
};
This way you can stub other electron modules and methods (like remote which is shown in the blog above).
Another way is creating an electron.js file in __mocks__ in your root folder.
The electron.js should look something like
export const ipcRenderer = {
on: jest.fn(),
};
You can read more at https://jestjs.io/docs/en/manual-mocks#mocking-node-modules
Related
We are using the aurelia component testing as defined here (with jest): https://aurelia.io/docs/testing/components#testing-a-custom-element
The component we are testing has a transient dependency. We are creating a mock for this dependency but when we run the tests using au jest, the real one always gets injected by the DI container and never the mock.
Here is the Transient service:
import { transient } from "aurelia-framework";
#transient()
export class ItemService {
constructor() {
}
getItems(): void {
console.log('real item service');
}
}
Here is the 'Mock' service (we have also tried using jest mocks but we get the same result):
import { transient } from "aurelia-dependency-injection";
#transient()
export class MockItemService{
getItems():void {
console.log('mock item service');
}
}
Here is the component under test:
import {ItemService} from "../services/item-service";
import { autoinject } from "aurelia-dependency-injection";
#autoinject()
export class TestElement {
constructor(private _itemService: ItemService) {
}
attached(): void {
this._itemService.getItems();
}
}
Here is the spec file:
import {TestElement} from "../../src/resources/elements/test-element";
import {ComponentTester, StageComponent} from "aurelia-testing";
import {ItemService} from "../../src/resources/services/item-service";
import {MockItemService} from "./mock-item-service";
import {bootstrap} from "aurelia-bootstrapper";
describe('test element', () => {
let testElement;
const path: string = '../../src/resources/elements/test-element';
beforeEach(() => {
testElement = StageComponent.withResources(path).inView(`<test-element></test-element>`);
testElement.bootstrap(aurelia => {
aurelia.use.standardConfiguration();
aurelia.container.registerTransient(ItemService, MockItemService);
});
});
afterEach(() => {
testElement.dispose();
});
it('should call mock item service', async() => {
await testElement.create(bootstrap);
expect(testElement).toBeTruthy();
})
});
But every-time the test is run, the console logs out the real service and not the mock. I have traced this to the aurelia-dependency-injection.js in the Container.prototype.get function. The issue seems to be around this section of code:
var registration = aureliaMetadata.metadata.get(aureliaMetadata.metadata.registration, key);
if (registration === undefined) {
return this.parent._get(key);
}
The registration object seems to be a bit odd, if it was undefined, the code would work as the correct dependency is registered on the parent and it would get the mock dependency. However, it is not undefined therefore it registers the real service in the DI container on this line:
return registration.registerResolver(this, key, key).get(this, key);
The registration object looks like this:
registration = TransientRegistration {_key = undefined}
Is this a bug in aurelia or is there something wrong with what I am doing?
Many Thanks
p.s. GitHub repo here to replicate the issue: https://github.com/Magrangs/aurelia-transient-dependency-issue
p.p.s Forked the DI container repo and added a quick fix which would fix my particular issue but not sure what the knock on effects would be. If a member of the aurelia team could check, that would be good:
https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596
After talking to Rob Eisenberg on the issue there is a workaround for this problem. Firstly remove the #transient decorator on the class and then in your app start (usually main.ts) register the class there as a transient.
See the thread here:
https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596
I have also updated the repo posted above: https://github.com/Magrangs/aurelia-transient-dependency-issue
to include the fix.
Hopefully this will help any other devs facing the same issue.
I'm playing with mount() from vue-test-utils, have a component that imports services that should be mocked in the unit test.
I see that mount() has a mocks option, but trying to extrapolate the example given at guides, common-tips, mocking injections to the scenario of an injected service is eluding me.
mount(Component, {
mocks: {
...?
}
})
The component simply imports the service, which is plain JS
import DataService from '../services/data.service'
I can get it working using the inject-loader which is detailed here Testing With Mocks
The code that does work
const MyComponentInjector = require('!!vue-loader?inject!./MyComponent.vue')
const mockedServices = {
'../services/data.service': {
checkAll: () => { return Promise.resolve() }
},
}
const MyComponentWithMocks = MyComponentInjector(mockedServices)
const wrapper = mount(MyComponentWithMocks, { store: mockStore, router })
What is the syntax for mount(MyComponent, { mocks: ... })?
Since mount() has a mocks option, should it not be possible to pass mockedServices to it in some form?
mocks refers to the Vue instance. You're trying to mock a file dependency, which is a different problem. As you said, one solution is inject-loader. Another is the babel-plugin-rewire.
Let me clear up what the mocks option does.
mocks adds properties to the Vue instance.
If you have an app that injects $route, you might have a component that tries to access it: this.$route.path:
...
methods: {
logPath() {
console.log(this.$route.path)
}
}
...
If you try to mount this component without installing Vue router, it will throw an error. To solve this, you can use the mocks mount option to inject a mock $route object to the Vue instance:
const $route = { path: 'some/mock/value' }
mount(Component, {
mocks: {
$route
}
})
Little exhausted here, may be that is why my title is not so accurate.
I am writing a unit test for my DummyService:
import {Injectable} from '#angular/core';
#Injectable()
export class DummyService {
getAllDataSources():Promise<Array<DummyData>> {
return new Promise<DummyData[]>(resolve =>
setTimeout(()=>resolve([]), 1000) // 1 seconds
);
}
}
Please assume am returning a list of DummyData objects from getAllDataSources.
Now, I have a structure/interface for the dummy data in the same service file:
export interface DummyData{
Name:string;
IsActive:boolean;
}
I tried to write unit test for this service:
import {DummyService, DummyData} from './dummy.service';
import {
beforeEachProviders
} from '#angular/core/testing';
import {provide} from '#angular/core';
export function main() {
describe('dummy.service', () => {
let dsService:DummyService;
it('should fetch data', ()=> {
dummyData: DummyData = new DummyData(); // >>>> culprit...
expect(1).toEqual(1);
});
});
}
This unit test seem little funny, as I am really not calling DummyServices function to get the list of DummyData.
I am doing this because I was getting some issue, due to which I was not able to see my test. I did some research, spent a whole day and finally found that this structure DummyData is the CULPRIT. I proved this to myself when I tried creating an object of it in my unit test (in the code above) and I got the following error:
FAILED TESTS:
dummy.service
✖ should fetch data
PhantomJS 2.1.1 (Linux 0.0.0)
Chrome 50.0.2661 (Linux 0.0.0)
ReferenceError: **DummyData is not defined**
at eval (/home/aodev/WebstormProjects/Data Federation App/data-mapping-app/dist/dev/app/shared/datasource.service.spec.js:8:28)
at Object.eval (/home/aodev/WebstormProjects/Data Federation App/data-mapping-app/node_modules/#angular/core/testing/testing.js:80:25)
So, can someone tell me please, what am I doing wrong?
Why I cannot create the object of DummyData inside my unit test?
Please help!
TypeScript interfaces exist only during compile time, runtime knows nothing about interfaces.
This is how you create instance that implements interface:
interface itest
{
success:boolean;
}
let a:itest = {success: true}; //compiler checks that object matches interface itest
I am new to Jest and trying to write some unit tests for my existing React App. I have a global variable window.CONFIG which stores some configurations which are used at different places in app. This variable is initialised in a script tag of landing HTML page
Now I am trying to write a test of an helper function which depends on this window.CONFIG and it is always undefined when accesses
Here is the code:
config.js
export default window.CONFIG;
app/helper.js
import config from "../config";
export default {
getCompanyURL(company) {
return config.baseUrl + "/companies/" + company.id;
},
}
_ tests _/helpers-test.js
jest.dontMock('../app/helpers.js');
var helper = require('../app/helpers.js').default;
describe('Get company URL', function() {
it('returns company url with company id appended', function() {
expect(companies.getCompanyURL({id: 1})).toBe('test_base_url/companies/1');
});
});
config for Get Company Url is always undefined. As the browser landing page is not loaded window.CONFIG is not initialised. How can I mock this config module in my unit test in Jest?
Thanks in advance!!
I'm not sure if this helps you or not but you can put global variables directly into your package.json
"jest":{
"globals": {
"config": {"foo":"bar"}
}
}
In a recent project (using create-react-app, jest, react testing library and TypeScript), I was using the variable globalThis._env_.
All my attempts to override it in the files containing the tests failed, but adding it to setupTests.ts worked in the end:
// in setuTests.ts
globalThis._env_ = {
UPLOAD_FILE_SIZE_LIMIT_MB: '5'
};
(I think setupTests.js / setupTests.ts is a react testing library thing - https://create-react-app.dev/docs/running-tests/#react-testing-library )
I solved this by creating a manual mock of config.js in __mocks__ directory as follows:
let configMock = jest.genMockFromModule('../config');
let __mockConfig = {};
__mockConfig.baseUrl = "test_base_url/";
configMock = __mockConfig;
export default configMock;
I'm new to Mocha and I am trying to use it to test a simple React component. The test would pass if the react component doesn't have any CSS styling but throws a syntax error if the tag within the React component contains any className:
Testing.react.js
import React from 'react';
export default class Testing extends React.Component {
render() {
return (
<section>
<form>
<input type="text" />
</form>
</section>
);
}
}
testing.jsx
import {
React,
sinon,
assert,
expect,
TestUtils
} from '../../test_helper';
import TestingSample from '../../../app/components/Testing.react.js';
describe('TestingSample component', function(){
before('render and locate element', function(){
var renderedComponent = TestUtils.renderIntoDocument(
<TestingSample />
);
var inputComponent = TestUtils.findRenderedDOMComponentWithTag(
renderedComponent, 'input'
);
this.inputElement = inputComponent.getDOMNode();
});
it('<input> should be of type "text"', function () {
assert(this.inputElement.getAttribute('type') === 'text');
});
})
The test would pass:
> mocha --opts ./test/javascripts/mocha.opts --compilers js:babel/register --recursive test/javascripts/**/*.jsx
TestSample component
✓ <input> should be of type "text"
1 passing (44ms)
after I added the className inside of the input tag an error shows up:
import React from 'react';
import testingStyle from '../../scss/components/landing/testing.scss';
export default class Testing extends React.Component {
render() {
return (
<section>
<form>
<input type="text" className="testingStyle.color" placeholder="Where would you like to dine" />
</form>
</section>
);
}
}
Test result:
SyntaxError: /Users/../../../Documents/project/app/scss/components/landing/testing.scss: Unexpected token (1:0)
> 1 | .color {
| ^
2 | color: red;
3 | }
I've searched online but no luck so far. Am I missing something? Please help me out or point me to the right direction would be greatly appreciated.
I'm currently using:
Node Express Server
React
React-router
Webpack
Babel
Mocha
Chai
Sinon
Sinon-Chai
There is a babel/register style hook to ignore style imports:
https://www.npmjs.com/package/ignore-styles
Install it:
npm install --save-dev ignore-styles
Run tests without styles:
mocha --require ignore-styles
you can use a css compilers run mocha, the compiler js as follow:
css-dnt-compiler.js
function donothing() {
return null;
}
require.extensions['.css'] = donothing;
require.extensions['.less'] = donothing;
require.extensions['.scss'] = donothing;
// ..etc
and run the mocha command like this:
mocha --compilers js:babel-core/register,css:css-dnt-compiler.js --recursive
My same answer as here, this is what I used to get working on Babel 6
package.json
"scripts": {
"test": "mocha --compilers js:babel-core/register
--require ./tools/testHelper.js 'src/**/*-spec.#(js|jsx)'",
tools/testHelper.js
// Prevent mocha from interpreting CSS #import files
function noop() {
return null;
}
require.extensions['.css'] = noop;
This enables you to have your tests inside your src folder alongside your components. You can add as many extensions as you would like with require.extensions.
Since you're using webpack, use null-loader to load null when webpack encounters a required CSS/LESS/SASS/etc file in your components. Install via npm and then update your webpack config to include the loader:
{
test: /(\.css|\.less|.\scss)$/,
loader: 'null-loader'
}
Obviously this will prevent you from loading CSS in your actual application, so you'll want to have a separate webpack config for your test bundle that uses this loader.
For those looking how to handle this in jest - you just add a handler for style files:
// package.json
{
"jest": {
"moduleNameMapper": {
"\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/styleMock.js"
}
}
}
// __mocks__/styleMock.js
module.exports = {};
More here.
None of these solutions worked for me, as I'm using mocha-webpack, and it doesn't accept the "--compilers" switch. I implemented the ignore-styles package, as described in the most popular answer, but it seemed inert, with no difference in my Istanbul coverage report (.less files still being tested).
The problem is the .less loader that I was using in my webpack.config.test.js file. Simply swapping less-loader for null-loader fixed my problem.
module: {
rules: [
{
test: /\.less$/,
use: ['null-loader']
}
]
}
For me, this is by far the simplest solution, and targets my testing configuration directly, rather than having to alter/add to the package.json scripts, or worse, add new .js files.
One simple way is to import 'ignore-styles'; in your test classes..
The code below works without any dependencies. Just add it to the top of the tests.
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function () {
if (arguments[0] && arguments[0].endsWith(".css"))
return;
return originalRequire.apply(this, arguments);
};
Although very old, this question is still relevant, so let me throw in another solution.
Use pirates, a package to add hooks to require() - if you use Babel, you already have it.
Example code:
// .test-init.js
const { addHook } = require('pirates');
const IGNORE_EXTENSIONS = ['.scss', '.svg', '.css'];
addHook((code, filename) => '', { exts: IGNORE_EXTENSIONS });
This way you can call mocha like so: mocha --require .test-init.js [whatever other parameters you use]
This is straightforward, elegant and unlike ignore-styles it doesn't imply you are ignoring styles only. Also, this is easily extendable if you need to apply some more trickery to your tests like mocking entire modules.