Most of the component in my react+meteor app use the React.createClass api.
When I try to use render any of them in the test file using render or mount, it throws the following error:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Constructor`.
at invariant (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:23890:15)
at ReactCompositeComponentWrapper.instantiateReactComponent [as _instantiateReactComponent] (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:14982:134)
at ReactCompositeComponentWrapper.performInitialMount (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15407:22)
at ReactCompositeComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15298:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at ReactCompositeComponentWrapper.performInitialMount (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15411:34)
at ReactCompositeComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15298:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at mountComponentIntoNode (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:20348:32)
at ReactReconcileTransaction.perform (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:9090:20)
Also, using shallow throws this error:
TypeError: Component is not a function
at packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15346:16
at measureLifeCyclePerf (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15115:12)
at ShallowComponentWrapper._constructComponentWithoutOwner (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15345:14)
at ShallowComponentWrapper.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:15228:21)
at Object.mountComponent (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:8128:35)
at ReactShallowRenderer._render (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21853:21)
at _batchedRender (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21834:12)
at Object.batchedUpdates (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:17599:7)
at Object.batchedUpdates (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:7770:20)
at ReactShallowRenderer.render (packages/modules.js?hash=70ab85ea6ef331c0dda6aaba437ed823158e87bb:21827:16)
But if I render a component create using the React.Component api, it works perfectly fine.
Now, my question is, does enzyme support the older React.createClass api?
Enzyme is fine with React.createClass. See the test case below taken from one of Enzyme tests.
https://github.com/airbnb/enzyme/blob/master/test/ShallowWrapper-spec.jsx#L13
it('can pass in context', () => {
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
const context = { name: 'foo' };
const wrapper = shallow(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
});
Related
I want to test the props of a Svelte component with Vitest.
Component:
<script>
export let foo
</script>
<div>{foo}</div>
Test:
const { component } = render(MyComponent, { foo: 'bar' })
expect(component.foo).toBe('bar')
When I run this test, I get the following error:
Props cannot be read directly from the component instance
unless compiling with 'accessors: true' or '<svelte:options accessors/>'
According to this post, I should pass accessors: true to the render() function:
const { component } = render(MyComponent, { accessors: true })
However, this doesn't work either and I keep getting the same error.
How can I test Svelte component props?
I have an epic with the following signature (note the dependency)
export const incrementalSearchEpic = (action$, store, { incrementalSearchService }) => {
// eslint-disable-next-line max-len
return action$.ofType('SEARCH_STORES').mergeMap((action) =>
incrementalSearchService.performIncrementalSearch(action)
);
};
Now I need to unit test this and this is my unit testing code
beforeEach(() => {
epicMiddleWare = createEpicMiddleware(incrementalSearchEpic,
{
dependencies: {
incrementalSearchService: IncrementalSearchServiceMock
}
});
const mockStore = configureMockStore([epicMiddleWare]);
const getState = {}; // initial state of the store
store = mockStore(getState);
});
// eslint-disable-next-line max-len
it('calls the incrementalSearchService->performIncrementalSearch with the parameters when called', () => {
//dispatch the incremental search action
const searchStore = {
type: 'SEARCH_STORES',
SearchText: 'Aldi'
};
store.dispatch(searchStore);
expect(store.getActions()).toEqual([
searchStore
]);
});
However when I run the code I get the following error
TypeError: Cannot read property 'performIncrementalSearch' of undefined
Seems like the dependency does not get passed in properly.
I just realized: if redux-observable wasn't injecting the provided dependencies object you'd actually get Cannot read property 'incrementalSearchService' of undefined not performIncrementalSearch because redux-observable does not inject an object by default--it's not erroring because it is indeed passing your object.
Instead, the likely problem is that your import or definition of IncrementalSearchServiceMock is actually undefined. Perhaps a wrong named import or similar.
If you can't immediately see why, pause your debugger at the beginning of beforeEach and confirm the value of IncrementalSearchServiceMock is not undefined.
I'm using Ember.Logger.error:
if (isInvalid) {
Ember.Logger.error('this is invalid');
}
I want to test it in qunit:
assert.throws(() => myFunction(), /this is invalid/, 'error was thrown');
But assert.throws doesn't catch the error. It does if I replace Ember.Logger.error with a simple throw statement, but surely there's a way to test for logged Ember errors. Anyone know the way?
UPDATE:
I made a little addon that adds this ability to QUnit. You can get it here.
Okay, so I've done a research how it's done in Ember and I've seen what's the practice to test it:
ember.js/packages/ember/tests/helpers/link_to_test.js
ember.js/packages/ember/tests/routing/basic_test.js
Here's example test function you could use to test calling Ember.Logger.error in helper unit test:
/* global Ember */
import { demo } from '../../../helpers/demo';
import { module, test } from 'qunit';
module('Unit | Helper | demo');
test('catching log', function(assert) {
assert.expect(1); // define how many assertions we expect
const oldError = Ember.Logger.error; // store original error function in variable
Ember.Logger.error = function(message) { // monkey patch with our custom function
assert.equal(message, 'this is invalid', 'error was thrown'); // our assertion
};
demo(); // actually call function
Ember.Logger.error = oldError; // restore original error function
});
I am trying to test this function with Jasmine:
myFunc: function () {
var name = document.getElementById("bob");
display.innerHTML = name;
return 100;
}
The test fails with ReferenceError: document is not defined. I understand that I'm not running the test in a browser so document isn't defined. But how come mocking it out isn't working? Is there a way to write this test with standalone Jasmine only?
How would one generally go about testing these kinds of functions (JavaScript mixed with DOM)? I'd prefer not to use another library/framework.
// Mock, stub dom object.
var document;
beforeEach(function () {
document = jasmine.createSpyObj('document', ['getElementById', 'createElement']);
});
describe("myFunc", function () {
it("return 100", function () {
console.log(document); // My mock document object successfully logs.
expect(myFunc()).toEqual(100); // but document isn't defined in here.
});
});
I'm using Meteor 1.0.
I have a Template.*name*.rendered function that makes a number of calculations. At the end of the calculations, I would like the output to make its way into a Template.*name*.helpers so I can use it in the corresponding html page.
Here's a simplified version of the code:
Template.myTemplate.rendered = function () {
var x = Math.random();
Template.otherTemplate.helpers({
randomNum: x
});
}
When I call {{randomNum}} in otherTemplate, nothing happens.
I have also tried putting the Template.*name*.helpers outside of Template.*name*.rendered, in which case, I get the error:
Uncaught ReferenceError: x is not defined
Thoughts?
This isn't really the right way of going about things as the way Meteor works is by compiling templates before the application starts, rather than at run-time. Whilst something along these lines may be possible (for example by using Template.registerHelper), it would be much better to set a reactive variable to a specific value in the rendered callback and have the helper set to return that instead:
Session.setDefault('randomNum', 0);
Template.myTemplate.rendered = function () {
Session.set('randomNum', Math.random());
}
Template.otherTemplate.helpers({
randomNum: Session.get('randomNum')
});
If you'd rather use a private variable for the randomNum, have a look at ReactiveVar. It could be any reactive data source and it would work.
You used to create helpers as an object of the template but since Meteor has deprecated that you now have to create the helpers within the helper function.
Now in order to call the helper via javascript you must use this function
Template.*TemplateName*.__helpers.get('*HelperName*')(*Params*);
Its a pretty simple way of doing this and it keeps the functions out of the global scope so its pretty clean.
Here is an example of how I am using this
~~~
Template.home.events({
'click .pair': function(event) {
var _this = $(event.currentTarget);
Template.home.__helpers.get('pairDevice')(_this);
}
});
Template.home.helpers({
'devices' : function() {
return Session.get('devices');
},
'pairDevice' : function(elm) {
elm.fadeOut();
$('.home-page').addClass('paired');
var deviceList = [
{
'name' : 'Patrick\'s Phone',
'UUID' : '234123,4n123k4nc1l2k3n4 l1k23n4l12k3nc4l12'
},
{
'name' : 'Mike\'s Phone',
'UUID' : '734k23k4l2k34l2k34l2k34l2k3m'
},
{
'name' : 'Edgar\'s Phone',
'UUID' : '567k56l7k4l56k7l5k46l74k56l74k5'
}
];
Session.set('devices', deviceList);
}
});
~~~