5
votes

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.

1

1 Answers

20
votes

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.