Commit 7bab2b410b76a88463fc61b0218f685b054893ec

Authored by Michel Felipe
2 parents 556724ef 458f2ccd

Merge branch 'people-block' into 'master'

People block refactoring and component-test-helper

Refactored people-block and members-block to use the newly created component-test-helper

See merge request !5
src/app/layout/blocks/members-block/members-block.component.spec.ts
1 1 import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
2 2 import {Provider, Input, provide, Component} from 'ng-forward';
3   -
4 3 import {MembersBlockComponent} from './members-block.component';
  4 +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper';
5 5  
6 6 const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>';
7 7  
... ... @@ -10,13 +10,9 @@ const tcb = new TestComponentBuilder();
10 10 describe("Components", () => {
11 11 describe("Members Block Component", () => {
12 12  
13   - beforeEach(angular.mock.module("templates"));
  13 + let helper: ComponentTestHelper;
14 14  
15   - let state = jasmine.createSpyObj("state", ["go"]);
16 15 let providers = [
17   - new Provider('truncateFilter', { useValue: () => { } }),
18   - new Provider('stripTagsFilter', { useValue: () => { } }),
19   - new Provider('$state', { useValue: state }),
20 16 new Provider('ProfileService', {
21 17 useValue: {
22 18 getProfileMembers: (profileId: number, filters: any): any => {
... ... @@ -25,28 +21,28 @@ describe(&quot;Components&quot;, () =&gt; {
25 21 }
26 22 }),
27 23 ];
28   - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MembersBlockComponent], providers: providers })
29   - class BlockContainerComponent {
30   - block = { type: 'Block', settings: {} };
31   - owner = { name: 'profile-name' };
32   - constructor() {
33   - }
34   - }
35   -
36   - it("get members of the block owner", done => {
37   - tcb.createAsync(BlockContainerComponent).then(fixture => {
38   - let block: MembersBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
39   - expect(block.members).toEqual([{ identifier: "person1" }]);
40   - done();
  24 +
  25 + beforeEach(angular.mock.module("templates"));
  26 +
  27 + beforeEach( (done) => {
  28 + // Custom properties for the component
  29 + let properties = { owner: { id: 1 } };
  30 + // Create the component bed for the test.
  31 + let cls = createClass({
  32 + template: htmlTemplate,
  33 + directives: [MembersBlockComponent],
  34 + providers: providers,
  35 + properties: properties
41 36 });
  37 + helper = new ComponentTestHelper(cls, done);
42 38 });
43 39  
44   - it("render the profile image for each member", done => {
45   - tcb.createAsync(BlockContainerComponent).then(fixture => {
46   - fixture.debugElement.getLocal("$rootScope").$apply();
47   - expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);
48   - done();
49   - });
  40 + it("get members of the block owner", () => {
  41 + expect(helper.component.members[0].identifier).toEqual("person1");
  42 + });
  43 +
  44 + it("render the profile image for each member", () => {
  45 + expect(helper.all("noosfero-profile-image").length).toEqual(1);
50 46 });
51 47  
52 48 });
... ...
src/app/layout/blocks/people-block/people-block.component.spec.ts
1 1 import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
2   -import {Provider, Input, provide, Component} from 'ng-forward';
3   -
  2 +import {Provider} from 'ng-forward';
  3 +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper';
  4 +import {providers} from 'ng-forward/cjs/testing/providers';
4 5 import {PeopleBlockComponent} from './people-block.component';
5 6  
6 7 const htmlTemplate: string = '<noosfero-people-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-people-block>';
7 8  
8   -const tcb = new TestComponentBuilder();
9   -
10 9 describe("Components", () => {
11   - describe("People Block Component", () => {
12   -
13   - beforeEach(angular.mock.module("templates"));
14 10  
15   - let state = jasmine.createSpyObj("state", ["go"]);
16   - let providers = [
17   - new Provider('truncateFilter', { useValue: () => { } }),
18   - new Provider('stripTagsFilter', { useValue: () => { } }),
19   - new Provider('$state', { useValue: state }),
20   - new Provider('EnvironmentService', {
21   - useValue: {
  11 + describe("People Block Component", () => {
  12 + let serviceMock = {
22 13 getEnvironmentPeople: (filters: any): any => {
23 14 return Promise.resolve([{ identifier: "person1" }]);
24 15 }
25   - }
26   - }),
27   - ];
28   - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [PeopleBlockComponent], providers: providers })
29   - class BlockContainerComponent {
30   - block = { type: 'Block', settings: {} };
31   - owner = { name: 'profile-name' };
32   - constructor() {
33   - }
34   - }
35   -
36   - it("get people of the block owner", done => {
37   - tcb.createAsync(BlockContainerComponent).then(fixture => {
38   - let block: PeopleBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
39   - expect(block.people).toEqual([{ identifier: "person1" }]);
40   - done();
  16 + };
  17 + let providers = [new Provider('EnvironmentService', { useValue: serviceMock })];
  18 +
  19 + let helper: ComponentTestHelper;
  20 +
  21 + beforeEach( angular.mock.module("templates") );
  22 +
  23 + /**
  24 + * The beforeEach procedure will initialize the helper and parse
  25 + * the component according to the given providers. Unfortunetly, in
  26 + * this mode, the providers and properties given to the construtor
  27 + * can't be overriden.
  28 + */
  29 + beforeEach( (done) => {
  30 + // Create the component bed for the test. Optionally, this could be done
  31 + // in each test if one needs customization of these parameters per test
  32 + let cls = createClass({
  33 + template: htmlTemplate,
  34 + directives: [PeopleBlockComponent],
  35 + providers: providers,
  36 + properties: {}
41 37 });
  38 + helper = new ComponentTestHelper(cls, done);
42 39 });
43 40  
44   - it("render the profile image for each person", done => {
45   - tcb.createAsync(BlockContainerComponent).then(fixture => {
46   - fixture.debugElement.getLocal("$rootScope").$apply();
47   - expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);
48   - done();
49   - });
  41 + /**
  42 + * By default the helper will have the component, with all properties
  43 + * ready to be used. Here the mock provider 'EnvironmentService' will
  44 + * return the given array with one person.
  45 + */
  46 + it("get block with one people", () => {
  47 + expect(helper.component.people[0].identifier).toEqual("person1");
  48 + });
  49 +
  50 + /**
  51 + * There are helper functions to access the JQuery DOM like this.
  52 + */
  53 + it("render the profile image for each person", () => {
  54 + expect(helper.all("noosfero-profile-image").length).toEqual(1);
50 55 });
51 56  
  57 + /**
  58 + * The main debugElement element is also available
  59 + */
  60 + it("render the main noosfero people block", () => {
  61 + expect(helper.debugElement.children().length).toEqual(1, "The people-block should have a div children");
  62 + });
  63 +
  64 + /**
  65 + * Just another example of a JQuery DOM helper function
  66 + */
  67 + it("render the noosfero people block div", () => {
  68 + let div = helper.findChildren("noosfero-people-block", "div");
  69 + expect(div.className).toBe('people-block', "The class should be people-block");
  70 + });
52 71 });
53 72 });
54 73 \ No newline at end of file
... ...
src/app/layout/blocks/people-block/people-block.component.ts
... ... @@ -10,6 +10,7 @@ export class PeopleBlockComponent {
10 10  
11 11 @Input() block: noosfero.Block;
12 12 @Input() owner: noosfero.Environment;
  13 + private type: string = "people";
13 14  
14 15 people: noosfero.Person[] = [];
15 16  
... ... @@ -21,4 +22,5 @@ export class PeopleBlockComponent {
21 22 this.people = people;
22 23 });
23 24 }
  25 +
24 26 }
... ...
src/app/layout/blocks/people-block/people-block.html
1   -<div class="peoples-block">
  1 +<div class="{{ctrl.type}}-block">
2 2 <a ng-repeat="person in ctrl.people" ui-sref="main.profile.home({profile: person.identifier})" class="person">
3 3 <noosfero-profile-image [profile]="person"></noosfero-profile-image>
4 4 </a>
... ...
src/app/profile/data/profile-data.component.spec.ts
... ... @@ -52,11 +52,10 @@ describe(&#39;Profile data component&#39;, () =&gt; {
52 52 profileMock.additional_data = {
53 53 'Address': 'Street A, Number 102'
54 54 };
  55 +
55 56 buildComponent().then((fixture: ComponentFixture) => {
56 57 let profileData: ProfileDataComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
57 58 profileData.profile = profileMock;
58   -
59   - expect(profileData.hasCustomFields()).toBeTruthy();
60 59 expect(fixture.debugElement.query('div.profile-custom-fields').length).toEqual(1);
61 60 });
62 61 });
... ...
src/app/profile/data/profile-data.html
... ... @@ -22,7 +22,7 @@
22 22 </div>
23 23  
24 24 <!-- Custom Fields -->
25   -<div class="main-box clearfix profile-custom-fields" ng-if="ctrl.hasCustomFields()">
  25 +<div class="main-box clearfix profile-custom-fields" ng-if="!equals({},ctrl.profile.additional_data)">
26 26 <header class="main-box-header clearfix">
27 27 <h2>{{"profile.others_info" | translate}}</h2>
28 28 </header>
... ...
src/spec/component-test-helper.ts 0 → 100644
... ... @@ -0,0 +1,143 @@
  1 +import { Component } from "ng-forward";
  2 +import { TestComponentBuilder, ngClass } from 'ng-forward/cjs/testing/test-component-builder';
  3 +import { INgForwardJQuery } from "ng-forward/cjs/util/jqlite-extensions";
  4 +import { ComponentFixture } from 'ng-forward/cjs/testing/test-component-builder';
  5 +
  6 +/**
  7 + * @ngdoc object
  8 + * @name spec.ComponentTestHelper
  9 + * @description
  10 + *
  11 + * Helper class for creating tests. It encapsulates the TestComponentBuilder initialization,
  12 + * allowing the test to be DRY. To use, one must declare a beforeEach function in the
  13 + * test, and inside construct this object like:
  14 + *
  15 + * <pre>
  16 + * let helper = let helper : ComponentTestHelper;
  17 + * beforeEach( (done) => {
  18 + * helper = new ComponentTestHelper(cls, tcb);
  19 + * }
  20 + * </pre>
  21 + */
  22 +export class ComponentTestHelper {
  23 +
  24 + /**
  25 + * @ngdoc property
  26 + * @name mockComponent
  27 + * @propertyOf spec.ComponentTestHelper
  28 + * @description
  29 + * The component we are mocking.
  30 + */
  31 + mockComponent: ngClass;
  32 + /**
  33 + * @ngdoc property
  34 + * @name tcb
  35 + * @propertyOf spec.ComponentTestHelper
  36 + * @description
  37 + * The NgForward TestComponentBuilder
  38 + */
  39 + tcb: TestComponentBuilder;
  40 + /**
  41 + * @ngdoc property
  42 + * @name component
  43 + * @propertyOf spec.ComponentTestHelper
  44 + * @description
  45 + * The parsed component instance
  46 + */
  47 + component: any;
  48 + /**
  49 + * @ngdoc property
  50 + * @name debugElement
  51 + * @propertyOf spec.ComponentTestHelper
  52 + * @description
  53 + * The debugElement representing a JQuery element attached to the component
  54 + * on mock page.
  55 + */
  56 + debugElement: INgForwardJQuery;
  57 +
  58 + /**
  59 + * @ngdoc method
  60 + * @name constructor
  61 + * @methodOf spec.ComponentTestHelper
  62 + * @description
  63 + * The constructor for this component.
  64 + */
  65 + constructor(mockComponent: any, done: Function) {
  66 + this.mockComponent = mockComponent;
  67 + this.tcb = new TestComponentBuilder();
  68 + this.init(done);
  69 + }
  70 +
  71 + /**
  72 + * @ngdoc method
  73 + * @name init
  74 + * @methodOf spec.ComponentTestHelper
  75 + * @description
  76 + * The initializer function. It is called inside the constructor
  77 + */
  78 + init(done: Function): any {
  79 + let promisse = this.tcb.createAsync(this.mockComponent) as Promise<ComponentFixture>;
  80 + return promisse.then((fixture: any) => {
  81 + // Fire all angular events and parsing
  82 + fixture.detectChanges();
  83 + // The main debug element
  84 + this.debugElement = fixture.debugElement;
  85 + this.component = this.debugElement.componentViewChildren[0].componentInstance;
  86 + }).then(() => {
  87 + // Force the resolution of components and sync
  88 + done();
  89 + });
  90 + }
  91 +
  92 + /**
  93 + * @ngdoc method
  94 + * @name all
  95 + * @methodOf spec.ComponentTestHelper
  96 + * @description
  97 + * Return all elements matching the given selector
  98 + */
  99 + all(selector: string): INgForwardJQuery[] {
  100 + return this.debugElement.queryAll(selector);
  101 + }
  102 +
  103 + /**
  104 + * @ngdoc method
  105 + * @name find
  106 + * @methodOf spec.ComponentTestHelper
  107 + * @description
  108 + * Return the first element matching the given selector
  109 + */
  110 + find(selector: string): INgForwardJQuery {
  111 + return this.all(selector)[0];
  112 + }
  113 +
  114 + /**
  115 + * @ngdoc method
  116 + * @name findChildren
  117 + * @methodOf spec.ComponentTestHelper
  118 + * @description
  119 + * Return the first element of parent element that matches the given selector
  120 + */
  121 + findChildren(parentSelector: string, childSelector: string) {
  122 + let parentComponent = this.find(parentSelector);
  123 + return parentComponent.find(childSelector)[0];
  124 + }
  125 +}
  126 +
  127 +export function createClass({
  128 + template = '<div></div>',
  129 + directives = [],
  130 + providers = [],
  131 + properties = <any>{}
  132 +}): any {
  133 + @Component({ selector: 'component-test-helper-container', template, directives, providers })
  134 + class Test {
  135 + constructor() {
  136 + Object.keys(properties).forEach((key: any) => {
  137 + (<any>this)[key] = <any>properties[key];
  138 + });
  139 + }
  140 + }
  141 + return Test;
  142 +}
  143 +
... ...
src/spec/mocks.ts
... ... @@ -72,6 +72,13 @@ export var mocks = {
72 72 };
73 73 }
74 74 },
  75 + environmentService: {
  76 + getEnvironmentPeople: (params: any) => {
  77 + return mocks.promiseResultTemplate({
  78 + people: {}
  79 + });
  80 + }
  81 + },
75 82 profileService: {
76 83 getCurrentProfile: (profile: any) => {
77 84 return mocks.promiseResultTemplate({
... ...