Im tring to get a headless backbone.router test to work with jsdom but having a bit of a problem solving this cryptic error:
Route
MinRouter
1) "before each" hook
0 passing (167ms)
1 failing
1) Route "before each" hook:
Uncaught TypeError: Cannot call method 'toLowerCase' of undefined
at _.extend.start (/home/user/min/vendor/backbone.js:1398:68)
at /home/user/min/__test__/uroute/testrouter.js:14:30
at Object.jsdom.env.done (/home/user/min/__test__/helpers/clientenv.js:30:13)
at /home/user/min/node_modules/jsdom/lib/jsdom.js:249:18
at process._tickCallback (node.js:419:13)
and here is how is setup jsdom env:
jsdom.env({
html: html,
done: function(errs, window) {
global.window = window;
...
global.BP.Router = {};
global.navigator = { browser: 'foo' };
callback();
}
});
turns out this is required in jsdom
jsdom.env({
html: html,
done: function(errs, window) {
global.window = window;
...
global.BP.Router = {};
global.navigator = { userAgent: 'node-js' };
callback();
}
});
Related
I have an application that raise an odd error when I run tests. The error is the following :
TypeError: undefined is not a constructor (evaluating 'allKeys[i].match(/^[0-9]+$/)') in node_modules/jasmine-core/lib/jasmine-core/jasmine.js (line 2988)
test/spec/core/http/response-spec.js:92:63
loaded#http://localhost:8080/context.js:151:17
Most of those tests passes, but a very few break. Here is one of the test that breaks:
(function () {
'use strict';
describe('MyAccount.core.http.response', function () {
var ResponseInterceptor = {},
$httpProvider = {},
$window = {},
env = {},
MessageQueue = {};
beforeEach(module('MyAccount.core.environment'));
beforeEach(module('MyAccount.core.http', function (_$httpProvider_, $provide) {
$httpProvider = _$httpProvider_;
MessageQueue = {
dispatch: jasmine.createSpy('dispatch')
};
$window = {
location: {
href: jasmine.createSpy()
}
};
$provide.value('$window', $window);
$provide.value('MessageQueue', MessageQueue);
}));
beforeEach(inject(function (_$window_, _ResponseInterceptor_, _env_) {
$window = _$window_;
ResponseInterceptor = _ResponseInterceptor_;
env = _env_;
}));
describe('response status', function () {
// Asserting that 404 and 403 errors are intercepted.
angular.forEach([404, 403], function (error) {
describe('is ' + error, function () {
beforeEach(function () {
ResponseInterceptor.responseError({
status: error,
data: {
message: 'error ' + error
}
});
});
it('calls MessageQueue.dispatch with the error message', function () {
expect(MessageQueue.dispatch).toHaveBeenCalledWith('error ' + error, {
on: 'global.errors'
});
});
});
});
});
});
})();
I've been stuck on that for few hours now and can't seems to find a solution. Here are the dependencies I'm using and their versions:
karma: ^1.2.0
jasmine-core: ^2.5.0
karma-jasmine: ^1.0.2
karma-phantomjs-launcher: ^1.0.2
phantomjs: ^2.1.7
NOTE: This is a brand new yeoman application using the angular generator.
I had the same problem, but got it solved moments ago.
To repeat what I said in the comments: The error happens when you have two arrays that are equal, believe it or not. If they are unequal, you get the standard error with the differences shown.
jasmine-core 2.5.0. was published two days ago, as of this moment. I downgraded to 2.4.1., and it works.
It seems that 2.5.0. is the culprit.
Downgrade to 2.4.1., until the publisher gets it solved.
My setup: maven/frontend-maven-plugin/karma(*)/phantomJS
(*) could probably have said 'Jasmine' here as well.
While trying to setup a test environment I ran into the following problem. When I run the tests (using mocha ./src/test/.setup.js ./src/test/**.test.js), I get a Element is not defined error:
app\node_modules\onsenui\js\onsenui.js:603
var originalCreateShadowRoot = Element.prototype.createShadowRoot;
^
ReferenceError: Element is not defined
at app\node_modules\onsenui\js\onsenui.js:603:34
at app\node_modules\onsenui\js\onsenui.js:359:7
at Array.forEach (native)
at initializeModules (app\node_modules\onsenui\js\onsenui.js:358:13)
at app\node_modules\onsenui\js\onsenui.js:908:5
(...)
How is this possible, isn't Element a basic DOM element?
The following versions are used:
enzyme#2.4.1
mocha#3.0.2
onsenui#2.0.0-rc.17
react#15.3.1
react-onsenui#0.7.5
The following .setup.js file is used:
require('babel-register')({
presets: ["react","airbnb","es2015"]
});
var jsdom = require('jsdom').jsdom;
var exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
documentRef = document;
And the test file is as follows:
import React from 'react';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
import * as Ons from 'react-onsenui';
import MainPage from '../react/MainPage/MainPage.jsx';
describe("Component MainPage", function() {
it("should have a Ons.Page component", function() {
const wrapper = mount(<MainPage />);
expect(wrapper.find(Ons.Page)).to.equal(true);
});
});
onsenui seems to be written for a browser enviroment, whilst you're executing it in a nodejs enviroment.
Element is a DOM api. nodejs has no DOM.
You could research using jsDom which is a node module that mimics the browser DOM for nodejs.
Edit:
I think this package could solve your problems: https://github.com/rstacruz/jsdom-global I checked, it should place a 'Element' property in the global.
I am using requireJS to load React components but I was getting the error "Uncaught SyntaxError: Unexpected token <" because the script type for the file is "text/javascript" instead of "text/babel". To solve this I have tried to set the scriptType as explained by requireJS docs and explained in this question, but I'm unable to get it working or find a good example of how to make this work.
requireConfig.js:
requirejs.config({
baseUrl: 'scripts/',
paths:
{
jquery: 'jquery-1.9.0',
react: 'libs/build/react',
reactdom: 'libs/build/react-dom',
browser: '//cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min',
inputWindow: 'inputWindow/inputWindow'
},
scriptType: {
'inputWindow': "text/babel"
}
});
define(function (require) {
var InputWindow = require('inputWindow');
InputWindow.initialize();
});
inputWindow.js:
define(function(require){
var React = require('react');
var ReactDOM = require('reactdom');
var InputWindow = React.createClass({
render: function(){
return(<div>
{this.props.message}
</div>)
}
});
function initialize(){
ReactDOM.render(<InputWindow message="Hello World!"/>, document.getElementById('inputWindowDiv'))
}
return {
initialize: initialize,
}
})
When I configure requireConfig.js with the section
scriptType:{
'inputWindow':'text/babel'
}
then the file inputWindow.js is loaded into index.html with the tag
type="[Object Object]"
until requireJS times out.
screen capture of inputWindow.js loaded with type=[Object Object]
Instead of
scriptType: {
'inputWindow': "text/babel"
}
try
scriptType: 'text/babel'
It should work. Right now you're trying to stringify an object so no wonder it doesn't work. ;)
React Tests Fails after set State causes second render
Up until now testing has been going well with JSDOM and Mocha. So far have not had to test any components that change their state. I found my first issue testing a component that changes it's state.
The Error
1) Reduced Test Case - #current Tests that Fail when Component changes state and renders "before each" hook:
Error: Invariant Violation: dangerouslyRenderMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use React.renderToString for server rendering.
at Context.<anonymous> (test/react-reflux/parts/Reduced-spec.js:47:32)
The Component : Reduced.js
var React = require('react');
var Reduced = React.createClass({
getInitialState() {
console.log("start off with editing as false");
return {editing: false};
},
edit() {
console.log("Setting State to Edit");
this.setState({editing: true});
},
render() {
console.log("Rendering");
return (
<span onClick={this.edit}>
{(this.state.editing) ? "Editing" : "Click To Edit"}
</span>
);
}
});
module.exports = Reduced;
The Tests : 1-pass, 1-fail
var React, TestUtils, jsdom, Reduced, expect;
describe('Reduced Test Case', function () {
before(function () {
jsdom = require('jsdom');
global.document = jsdom.jsdom('<!doctype html><html><body></body></html>');
global.window = global.document.parentWindow;
React = require('react/addons');
TestUtils = React.addons.TestUtils;
Reduced = require('./Reduced');
expect = require('chai').expect;
this.component = TestUtils.renderIntoDocument(
<Reduced />
);
var root = TestUtils.findRenderedDOMComponentWithTag(this.component, 'span');
this.el = root.getDOMNode();
});
describe("Tests Pass without simulate", function () {
it("Root Element Reads 'Click To Edit'", function () {
expect(this.el.innerHTML).to.equal('Click To Edit');
});
});
describe("Tests that Fail when Component changes state and renders", function () {
beforeEach(function () {
//
// Simulate invokes edit, invokes set state, invokes render, then error occures
//
TestUtils.Simulate.click(this.el);
});
it("Root Element Reads 'Editing'", function () {
expect(this.el.innerHTML).to.equal('Editing');
});
});
});
The Results
> mocha --compilers js:babel/register
Reduced Test Case - #current
start off with editing as false
Rendering
Tests Pass without simulate
✓ Root Element Reads 'Click To Edit'
Tests that Fail when Component changes state and renders
Setting State to Edit
Rendering
1) "before each" hook
1 passing (379ms)
1 failing
1) Reduced Test Case Tests that Fail when Component changes state and renders "before each" hook:
Error: Invariant Violation: dangerouslyRenderMarkup(...): Cannot render markup in a worker thread. Make sure `window` and `document` are available globally before requiring React when unit testing or use React.renderToString for server rendering.
at Context.<anonymous> (test/Reduced-spec.js:47:32)
I've been going crazy
Everything is loaded after global.window and global.document
The Simulate Event invokes edit(), then render() before error
All React Mocha JSDOM tests have been working well until this state change issue
Please help ???
The setup JSDOM setup was missing global.navigator.
global.navigator = {
userAgent: 'node.js'
};
Insert your global object modifying(passing window and document objects to global) before React is required.
Because React creates its ExecutionEnvironment object while required and don't modify it while works.
I'm trying to test a component that has a value from a state object displayed in it's render().
I've simplified the component in question in to this simple Test component for reproduction. I'm using React 0.12.2.
I am populating my "report" in getIntitialState's call to getStateFromStores(). In testing though this value is empty and is what I think is leading to the error.
Certainly a conditional checking to see if this.state.report is defined would work, but it seems a bit much to have to put conditionals on all variables printed in a render() that are populated via state.
Test Component
var React = require('react');
var AppStore = require('../stores/AppStore');
function getStateFromStores() {
return {
report: AppStore.getCurrentReport(),
};
}
var Test = React.createClass({
getInitialState: function() {
return getStateFromStores();
},
render: function(){
return (
<div>
// This call to the report.id on state seems to be the issue
{this.state.report.id}
</div>
);
}
});
module.exports = Test;
The Test
jest.dontMock('../Test');
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
var Test = require('../Test');
describe("Test", function() {
it("should render Test", function() {
var test = TestUtils.renderIntoDocument(<Test />);
expect(test).toBeDefined();
});
});
Ideally, I'd like to pre-populate the state of the component before renderIntoDocument() is called in the test as that is where it is failing.
I receive this failure:
● Test › it should render Test
- TypeError: Cannot read property 'id' of undefined
at React.createClass.render (/Users/kevinold/_development/app/assets/javascripts/_app/components/Test.jsx:20:26)
at ReactCompositeComponentMixin._renderValidatedComponent (/Users/kevinold/_development/node_modules/react/lib/ReactCompositeComponent.js:1260:34)
at wrapper [as _renderValidatedComponent] (/Users/kevinold/_development/node_modules/react/lib/ReactPerf.js:50:21)
at ReactCompositeComponentMixin.mountComponent (/Users/kevinold/_development/node_modules/react/lib/ReactCompositeComponent.js:802:14)
at wrapper [as mountComponent] (/Users/kevinold/_development/node_modules/react/lib/ReactPerf.js:50:21)
at ReactComponent.Mixin._mountComponentIntoNode (/Users/kevinold/_development/node_modules/react/lib/ReactComponent.js:405:25)
at ReactReconcileTransaction.Mixin.perform (/Users/kevinold/_development/node_modules/react/lib/Transaction.js:134:20)
at ReactComponent.Mixin.mountComponentIntoNode (/Users/kevinold/_development/node_modules/react/lib/ReactComponent.js:381:19)
at Object.ReactMount._renderNewRootComponent (/Users/kevinold/_development/node_modules/react/lib/ReactMount.js:312:25)
at Object.wrapper [as _renderNewRootComponent] (/Users/kevinold/_development/node_modules/react/lib/ReactPerf.js:50:21)
at Object.ReactMount.render (/Users/kevinold/_development/node_modules/react/lib/ReactMount.js:381:32)
at Object.wrapper [as render] (/Users/kevinold/_development/node_modules/react/lib/ReactPerf.js:50:21)
at Object.ReactTestUtils.renderIntoDocument (/Users/kevinold/_development/node_modules/react/lib/ReactTestUtils.js:48:18)
at Spec.<anonymous> (/Users/kevinold/_development/app/assets/javascripts/_app/components/__tests__/Test-test.js:9:26)
at jasmine.Block.execute (/Users/kevinold/_development/node_modules/jest-cli/vendor/jasmine/jasmine-1.3.0.js:1065:17)
at jasmine.Queue.next_ (/Users/kevinold/_development/node_modules/jest-cli/vendor/jasmine/jasmine-1.3.0.js:2098:31)
at null._onTimeout (/Users/kevinold/_development/node_modules/jest-cli/vendor/jasmine/jasmine-1.3.0.js:2088:18)
I am not sure how to preload state for this component, which should solve the issue, prior to the renderIntoDocument() call in my test.
I've also considered trying to mock getIntitialState() for this component, but there has to be a better way.
Any ideas on how to test this?
I ended up solving this by mocking out the AppStore.getCurrentReport() method like so:
jest.dontMock('../Test');
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
var Test = require('../Test');
var AppStore = require('../stores/AppStore');
describe("Test", function() {
it("should render Test", function() {
// Mock the return value from the method in the store that populates the value in getInitialState()
AppStore.getCurrentReport.mockReturnValue({id: 1, title: 'Test Rpt'});
var test = TestUtils.renderIntoDocument(<Test />);
expect(test).toBeDefined();
});
});