Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right way to unit test a component in EmberJS

I am trying to test a component in my Ember application unit tests, and until now all is good except that I am at a point where the assertions need its template to be rendered.

To do so normally one would call

var comp = App.SomeNamedComponent.create();
var comp.appendTo(App.rootElement);

But while this does create the base element of the component, it does not render its template. After a few research, I ended-up finding out that neither templateName nor template properties are set on the component. So I decided to set the templateName myself, but then it complains that A Component must have a parent view in order to yield..

I then decided to create another custom view in the test with a template using that component, but then I can't access the instance of the component...

I need to access the instance to make the assertions, and I need to have it's template rendered as some properties are calculated depending on the css of some elements in the template.

like image 757
Huafu Avatar asked Feb 27 '14 09:02

Huafu


People also ask

Is unit testing a component test?

Component Testing involves testing of each object or parts of the software separately. Unit Testing involves testing of individual programs or modules for program execution.

How do I run an ember integration test?

In order to integration test the Ember application, you need to run the app within your test framework. Set the root element of the application to an arbitrary element you know will exist. It is useful, as an aid to test-driven development, if the root element is visible while the tests run.


1 Answers

This is how I typically test a component when a container is not needed (specifically when the template and layout are provided to the component programmatically):

Ember.testing = true;

MyAwesomeComponent = Ember.Component.extend();

function createComponent(componentName, factory, options) {
  if (typeof options.template === 'string') {
    options.template = Ember.Handlebars.compile(options.template);
  }

  if (typeof options.layout === 'string') {
    options.layout = Ember.Handlebars.compile(options.layout);
  }

  if (options.template && !options.layout) {
    options.layout = options.template;
    delete options.template;
  }

  var component = factory.create(options);

  Ember.run(function(){
    component.appendTo('#qunit-fixture');
  });

  return component;
}

module('component testing sample');

test('a component with template', function(){
  var options = {layout: 'woot woot{{fullName}}'};

  var component = createComponent('my-awesome', MyAwesomeComponent, options);

  equal(component.$().text(), 'woot woot');
});

test('a component with custom options and a template', function(){
  var options = {
    fullName: 'Robert Jackson',
    layout: '{{fullName}}'
  };

  var component = createComponent('my-awesome', MyAwesomeComponent, options);

  equal(component.$().text(), 'Robert Jackson');
});

See an example JSBin.


If you need/want to be able to lookup the template you can use something like the following (which creates an isolated container):

Ember.testing = true;

MyAwesomeComponent = Ember.Component.extend();

function isolatedContainer() {
  var container = new Ember.Container();

  container.optionsForType('component', { singleton: false });
  container.optionsForType('view', { singleton: false });
  container.optionsForType('template', { instantiate: false });
  container.optionsForType('helper', { instantiate: false });

  return container;
}

function createComponent(componentName, factory, options) {
  var fullName = 'component:' + componentName,
      templateFullName = 'template:components/' + componentName;

  container.register(fullName, factory);

  if (container.has(templateFullName)) {
    container.injection(fullName, 'layout', templateFullName);
  }

  var Component = container.lookupFactory(fullName),
      component = Component.create(options);

  Ember.run(function(){
    component.appendTo('#qunit-fixture');
  });

  return component;
}

function registerTemplate(name, template){
  if (typeof template !== 'function') {
    template = Ember.Handlebars.compile(template);
  }

  container.register('template:' + name, template);
}

var container;

module('component testing sample', {
  setup: function(){
    container = isolatedContainer();
  },
  teardown: function(){
    Ember.run(container, 'destroy');
  }
});

test('a component with template', function(){
  registerTemplate('components/my-awesome', 'woot woot{{fullName}}');

  var component = createComponent('my-awesome', MyAwesomeComponent);

  equal(component.$().text(), 'woot woot');
});

test('a component with custom options and a template', function(){
  registerTemplate('components/my-awesome', '{{fullName}}');

  var component = createComponent('my-awesome', MyAwesomeComponent, {fullName: 'Robert Jackson'});

  equal(component.$().text(), 'Robert Jackson');
});

JSBin of the container version.

like image 95
Robert Jackson Avatar answered Nov 15 '22 10:11

Robert Jackson