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

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

Activity

  1. added this to the 1.5.x milestone on Apr 14, 2016
  2. gkalpak commented on Apr 14, 2016

    @gkalpak
    Member

    The current behavior is intended imo (see #14432 (comment)).
    We do need to fix the docs, though, so I'll keep this issue open for tracking that.

  3. added a commit that references this issue on Apr 26, 2016
    a2a907e
  4. added a commit that references this issue on Sep 28, 2024
    b9d76bf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions