After I update react-onsenui from 0.7.3 to 1.0.0 . I use mocha to test my webapp. error occured like this:
Error: Invalid state
at /Users/*****/node_modules/onsenui/js/onsenui.js:581:11
onsenui.js' code is like this:
throw new Error('Invalid state');
How are you running your Mocha tests? I saw this error using Mocha with JSDOM. It's just one of the many errors that occur because OnsenUI expects a real browser environment, and JSDOM is not one.
My approach has been to stub everything that OnsenUI needs in the browser.js file where I define my DOM.
The code called at line 581 is looking for the key 'transitionDuration' in the results of window.getComputedStyle(document.documentElement, '')
, and errors when it doesn't find it. I added this to my browser.js file:
//** Polyfill for values missing from JSDOM
window.getComputedStyle = function(el1, el2) {
return [
"transitionDuration"
]
}
This resolved this specific error, but there were a lot more.
The JSDOM window
element's properties weren't available to as global variables for OnsenUI, so I saw a lot of errors like Element is not defined
, Node is not defined
and so on. I solved these by either matching them to the window property if it existed, or stubbing empty functions, like this:
// browser.js
global['Element'] = window.Element;
global['HTMLElement'] = window.HTMLElement;
global['WebComponents'] = function() {};
global['Node'] = window.Node;
global['Window'] = window;
global['Viewport'] = function() { return { setup: function() {} } }
This was still not enough to get it running. To resolve errors relating to web components and custom elements, I installed document-register-element
, and imported it at the top of my tests. I also needed to import the MutationObserver from https://github.com/megawac/MutationObserver.js, like this:
//shims.js
import './shims/mutationobserver';
global['MutationObserver'] = window.MutationObserver;
In the end my test files look like this:
import 'babel-polyfill'
import React from 'react';
import { mount, shallow } from 'enzyme';
import {expect} from 'chai';
import document from './helpers/browser';
import './helpers/shims';
import 'document-register-element';
import Frame from '../react-app/components/frame';
describe('<Frame />', function () {
it('renders without problems', function () {
var wrapper = shallow(<Frame />);
expect(wrapper.find('iframe')).to.have.length(1);
});
});
Here's the full text of browser.js
:
import { jsdom } from 'jsdom';
//** Create a fake DOM to add the tests to
const document = jsdom('<!doctype html><html><body></body></html>');
const window = document.defaultView;
//** Push the window object properties to the Mocha global object- no idea why it doesn't work for all of the properties
Object.keys(window).forEach((key) => {
if (!(key in global)) {
global[key] = window[key];
}
});
//** These ones need to be done manually
global['Element'] = window.Element;
global['HTMLElement'] = window.HTMLElement;
global['WebComponents'] = function() {};
global['Node'] = window.Node;
global['Window'] = window;
global['Viewport'] = function() { return { setup: function() {} } }
//** Polyfill for values missing from JSDOM
window.getComputedStyle = function(el1, el2) {
return [
"transitionDuration"
]
}
global.document = document;
global.window = window;