Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Unexpected behavior in unit-tests using $componentController and &-bindings to pass data #14426

Closed
@mjwwit

Description

@mjwwit

Do you want to request a feature or report a bug?
Bug with using $componentController, &-bindings, and passing arguments.

What is the current behavior?
Using $componentController to instantiate the controller of a component that has an &-binding used to pass data back to its user results in unexpected argument data being passed to the function.

_Example_
Given:

  angular.module('heroApp', [])
    .component('heroDetail', {
      template: '<div></div>',
      bindings: {
        hero: '<',
        onDelete: '&'
      }
    });

The current behavior using $componentController is:

    it('should call the onDelete binding when a hero is deleted', function() {
      var deleteSpy = jasmine.createSpy('deleteSpy');
      component = $componentController('heroDetail',
        {$scope: scope},
        {
          hero: {name: 'Wolverine'},
          onDelete: deleteSpy
        }
      );

      component.onDelete({hero: component.hero});
      // Spy is called with object map, instead of just the "hero" value
      expect(deleteSpy).toHaveBeenCalledWith({hero: component.hero});
    });

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).
Here is a minimal demo, comparing $componentController and $compile to unit-test the onDelete binding: Demo

What is the expected behavior?
Given the same "heroDetail" component as above, one would expect the following test to succeed:

    it('should call the onDelete binding when a hero is deleted', function() {
      var deleteSpy = jasmine.createSpy('deleteSpy');
      component = $componentController('heroDetail',
        {$scope: scope},
        {
          hero: {name: 'Wolverine'},
          onDelete: deleteSpy
        }
      );

      component.onDelete({hero: component.hero});
      // Spy is called with the object map, instead of just the "hero" value
      expect(deleteSpy).toHaveBeenCalledWith(component.hero);
    });

This would make $componentController's behavior consistent with $compile's behavior (and the real world).

What is the motivation / use case for changing the behavior?
Using components is the recommended design-pattern from AngularJS 1.5.0. Using $componentController in unit-tests to instantiate component controllers greatly simplifies testing code. One would expect behavior to be consistent with the real world (and the former unit test implementation technique using $compile).

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
AngularJS >=1.5.0 using Chrome 49 and Safari 9.0.3

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions