1

I keep getting this error when testing my TodoList component:

debug.html:38
Invariant Violation:
Element type is invalid:
expected a string (for built-in components) or a class/function (for composite components) but got: object.

I'm not sure what's causing it. Could anyone lead me into the right direction?

TodoList.js:

import React from 'react';

import Todo from 'Todo';

class TodoList extends React.Component {
    renderTodos(todos) {
        return todos.map(todo => {
            return <Todo key={todo.id} {...todo} />;
        });
    }
    render() {
        const { todos } = this.props;
        return (
            <div>
                {this.renderTodos(todos)}
            </div>
        );
    }
}

export default TodoList;

TodoList.test.js:

const React = require('react');
const ReactDOM = require('react-dom');
const TestUtils = require('react-addons-test-utils');
const expect = require('expect');
const $ = require('jQuery');

const TodoList = require('TodoList');
const Todo = require('Todo');

describe('TodoList', () => {
    it('should exist', () => {
        expect(TodoList).toExist();
    });

    it('should render one Todo component for each todo item', () => {
        const todos = [{
            id: 1,
            text: "Do something"
        }, {
            id: 2,
            text: "Check mail"
        }];
        const todoList = TestUtils.renderIntoDocument(<TodoList todos={todos} />);
        const todoComponents = TestUtils.scryRenderedComponentsWithType(todoList, Todo);

        expect(todoComponents.length).toBe(todos.length);
    });
});

Link to source code: link to source code

zx485
  • 28,498
  • 28
  • 50
  • 59
Funk Soul Ninja
  • 2,113
  • 3
  • 17
  • 27

3 Answers3

2

In your TodoList.Test.js, remove

const TodoList = require('TodoList');
const Todo = require('Todo');

and replace it with

import TodoList from 'TodoList'
import Todo from 'Todo

That is because you are exporting your components in the ES6 way and importing it the nodejs way.

If you still want to use require in your test then you will have to replace the

export default TodoList

with

module.exports = TodoList;

Hope it helps :)

Swapnil
  • 2,573
  • 19
  • 30
1

alternatively:

const TodoList = require('TodoList').default;
const Todo = require('Todo').default;
yadhu
  • 15,423
  • 7
  • 32
  • 49
0

By default in Node, if you use this syntax:

require('Todo')

It will look for the node module Todo, as in it will look in your node_modules directory for a directory named Todo. Node doesn't know how to use custom Webpack resolves. You have this setting:

    modulesDirectories: [
        'node_modules',
        './app/components'
    ],

Meaning any time Webpack sees a require('Todo') or import from 'Todo' it will check both in node_moudles for a file or folder named Todo, and it will check app/components for a folder.

If you want to use the same resolve trick in your tests, you have to build a test bundle with Webpack and run that bundle, the same way you build a browser bundle.

Otherwise you have to use the default Node way to require files not in node_modules, which is with relative paths:

const TodoList = require('../../components/TodoList');
const Todo = require('../../components/Todo');
Andy Ray
  • 30,372
  • 14
  • 101
  • 138