Commit 6d10324a90f16eccd759ac21919c5390c803f85e
People block refactoring. Created component-test-helper
1 | import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder'; | 1 | import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder'; |
2 | import {Provider, Input, provide, Component} from 'ng-forward'; | 2 | import {Provider, Input, provide, Component} from 'ng-forward'; |
3 | - | ||
4 | import {MembersBlockComponent} from './members-block.component'; | 3 | import {MembersBlockComponent} from './members-block.component'; |
4 | +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper'; | ||
5 | 5 | ||
6 | const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>'; | 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,13 +10,9 @@ const tcb = new TestComponentBuilder(); | ||
10 | describe("Components", () => { | 10 | describe("Components", () => { |
11 | describe("Members Block Component", () => { | 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 | let providers = [ | 15 | let providers = [ |
17 | - new Provider('truncateFilter', { useValue: () => { } }), | ||
18 | - new Provider('stripTagsFilter', { useValue: () => { } }), | ||
19 | - new Provider('$state', { useValue: state }), | ||
20 | new Provider('ProfileService', { | 16 | new Provider('ProfileService', { |
21 | useValue: { | 17 | useValue: { |
22 | getProfileMembers: (profileId: number, filters: any): any => { | 18 | getProfileMembers: (profileId: number, filters: any): any => { |
@@ -25,28 +21,23 @@ describe("Components", () => { | @@ -25,28 +21,23 @@ describe("Components", () => { | ||
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(); | ||
41 | - }); | 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(htmlTemplate, [MembersBlockComponent], providers, properties); | ||
32 | + helper = new ComponentTestHelper(cls, done); | ||
33 | + }); | ||
34 | + | ||
35 | + it("get members of the block owner", () => { | ||
36 | + expect(helper.component.members[0].identifier).toEqual("person1"); | ||
42 | }); | 37 | }); |
43 | 38 | ||
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 | - }); | 39 | + it("render the profile image for each member", () => { |
40 | + expect(helper.all("noosfero-profile-image").length).toEqual(1); | ||
50 | }); | 41 | }); |
51 | 42 | ||
52 | }); | 43 | }); |
1 | import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder'; | 1 | import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder'; |
2 | -import {Provider, Input, provide, Component} from 'ng-forward'; | ||
3 | - | 2 | +import {Provider, provide} from 'ng-forward'; |
3 | +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper'; | ||
4 | +import {providers} from 'ng-forward/cjs/testing/providers'; | ||
1 |
|
||
4 | import {PeopleBlockComponent} from './people-block.component'; | 5 | import {PeopleBlockComponent} from './people-block.component'; |
5 | 6 | ||
6 | -const htmlTemplate: string = '<noosfero-people-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-people-block>'; | 7 | +import { INgForwardJQuery } from "ng-forward/cjs/util/jqlite-extensions"; |
7 | 8 | ||
8 | -const tcb = new TestComponentBuilder(); | 9 | +const htmlTemplate: string = '<noosfero-people-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-people-block>'; |
9 | 10 | ||
10 | describe("Components", () => { | 11 | describe("Components", () => { |
11 | - describe("People Block Component", () => { | ||
12 | 12 | ||
13 | - beforeEach(angular.mock.module("templates")); | ||
14 | - | ||
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: { | 13 | + describe("People Block Component", () => { |
14 | + let serviceMock = { | ||
2 |
|
||
22 | getEnvironmentPeople: (filters: any): any => { | 15 | getEnvironmentPeople: (filters: any): any => { |
23 | return Promise.resolve([{ identifier: "person1" }]); | 16 | return Promise.resolve([{ identifier: "person1" }]); |
24 | } | 17 | } |
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(); | ||
41 | - }); | 18 | + }; |
19 | + let providers = [new Provider('EnvironmentService', { useValue: serviceMock })]; | ||
20 | + | ||
21 | + let helper: ComponentTestHelper; | ||
22 | + | ||
23 | + beforeEach( angular.mock.module("templates") ); | ||
24 | + | ||
25 | + /** | ||
26 | + * The beforeEach procedure will initialize the helper and parse | ||
27 | + * the component according to the given providers. Unfortunetly, in | ||
28 | + * this mode, the providers and properties given to the construtor | ||
29 | + * can't be overriden. | ||
30 | + */ | ||
31 | + beforeEach( (done) => { | ||
32 | + // Create the component bed for the test. Optionally, this could be done | ||
33 | + // in each test if one needs customization of these parameters per test | ||
34 | + let cls = createClass(htmlTemplate, [PeopleBlockComponent], providers, {}); | ||
35 | + helper = new ComponentTestHelper(cls, done); | ||
36 | + }); | ||
37 | + | ||
38 | + /** | ||
39 | + * By default the helper will have the component, with all properties | ||
40 | + * ready to be used. Here the mock provider 'EnvironmentService' will | ||
41 | + * return the given array with one person. | ||
42 | + */ | ||
43 | + it("get block with one people", () => { | ||
44 | + expect(helper.component.people[0].identifier).toEqual("person1"); | ||
42 | }); | 45 | }); |
43 | 46 | ||
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 | - }); | 47 | + /** |
48 | + * There are helper functions to access the JQuery DOM like this. | ||
49 | + */ | ||
50 | + it("render the profile image for each person", () => { | ||
51 | + expect(helper.all("noosfero-profile-image").length).toEqual(1); | ||
50 | }); | 52 | }); |
51 | 53 | ||
54 | + /** | ||
55 | + * The main debugElement element is also available | ||
56 | + */ | ||
57 | + it("render the main noosfero people block", () => { | ||
58 | + expect(helper.debugElement.children().length).toEqual(1, "The people-block should have a div children"); | ||
59 | + }); | ||
60 | + | ||
61 | + /** | ||
62 | + * Just another example of a JQuery DOM helper function | ||
63 | + */ | ||
64 | + it("render the noosfero people block div", () => { | ||
65 | + let div = helper.findChildren("noosfero-people-block", "div"); | ||
66 | + expect(div.className).toBe('people-block', "The class should be people-block"); | ||
67 | + }); | ||
52 | }); | 68 | }); |
53 | }); | 69 | }); |
54 | \ No newline at end of file | 70 | \ No newline at end of file |
@@ -10,6 +10,7 @@ export class PeopleBlockComponent { | @@ -10,6 +10,7 @@ export class PeopleBlockComponent { | ||
10 | 10 | ||
11 | @Input() block: noosfero.Block; | 11 | @Input() block: noosfero.Block; |
12 | @Input() owner: noosfero.Environment; | 12 | @Input() owner: noosfero.Environment; |
13 | + private type: string = "people"; | ||
13 | 14 | ||
14 | people: noosfero.Person[] = []; | 15 | people: noosfero.Person[] = []; |
15 | 16 | ||
@@ -21,4 +22,5 @@ export class PeopleBlockComponent { | @@ -21,4 +22,5 @@ export class PeopleBlockComponent { | ||
21 | this.people = people; | 22 | this.people = people; |
22 | }); | 23 | }); |
23 | } | 24 | } |
25 | + | ||
24 | } | 26 | } |
1 | -<div class="peoples-block"> | 1 | +<div class="{{ctrl.type}}-block"> |
2 | <a ng-repeat="person in ctrl.people" ui-sref="main.profile.home({profile: person.identifier})" class="person"> | 2 | <a ng-repeat="person in ctrl.people" ui-sref="main.profile.home({profile: person.identifier})" class="person"> |
3 | <noosfero-profile-image [profile]="person"></noosfero-profile-image> | 3 | <noosfero-profile-image [profile]="person"></noosfero-profile-image> |
4 | </a> | 4 | </a> |
@@ -52,7 +52,7 @@ describe('Profile data component', () => { | @@ -52,7 +52,7 @@ describe('Profile data component', () => { | ||
52 | profileMock.additional_data = { | 52 | profileMock.additional_data = { |
53 | 'Address': 'Street A, Number 102' | 53 | 'Address': 'Street A, Number 102' |
54 | }; | 54 | }; |
55 | - | 55 | + |
56 | buildComponent().then((fixture: ComponentFixture) => { | 56 | buildComponent().then((fixture: ComponentFixture) => { |
57 | let profileData: ProfileDataComponent = fixture.debugElement.componentViewChildren[0].componentInstance; | 57 | let profileData: ProfileDataComponent = fixture.debugElement.componentViewChildren[0].componentInstance; |
58 | profileData.profile = profileMock; | 58 | profileData.profile = profileMock; |
@@ -0,0 +1,74 @@ | @@ -0,0 +1,74 @@ | ||
1 | +import { Component } from "ng-forward"; | ||
2 | +import { TestComponentBuilder } 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 | +export function createClass(template: any, directives: any, providers: any, properties: any): any { | ||
1 |
|
||
7 | + @Component({ selector: 'component-test-helper-container', template, directives, providers }) | ||
8 | + class Test { | ||
9 | + constructor() { | ||
10 | + Object.keys(properties).forEach((key: any) => { | ||
11 | + (<any>this)[key] = <any>properties[key]; | ||
12 | + }); | ||
13 | + } | ||
14 | + } | ||
15 | + return Test; | ||
16 | +} | ||
17 | + | ||
18 | +export function rebuild(factory: any, done: any): any { | ||
1 |
|
||
19 | + return new ComponentTestHelper(factory, done); | ||
20 | +} | ||
21 | + | ||
22 | +/** | ||
23 | + * Helper class for creating tests. It encapsulates the TestComponentBuilder initialization, | ||
24 | + * allowing the test to be DRY. To use, one must declare a beforeEach function in the | ||
25 | + * test, and inside construct this object like: | ||
26 | + * | ||
27 | + * let helper = let helper : ComponentTestHelper; | ||
1 |
|
||
28 | + * beforeEach( (done) => { | ||
29 | + * helper = new ComponentTestHelper(cls, tcb); | ||
30 | + * } | ||
31 | + */ | ||
32 | +export class ComponentTestHelper { | ||
33 | + | ||
34 | + mockComponent: any; | ||
35 | + tcb: TestComponentBuilder; | ||
36 | + component: any; | ||
2 |
|
||
37 | + debugElement: INgForwardJQuery; | ||
38 | + | ||
39 | + constructor(mockComponent: any, done: any) { | ||
1 |
|
||
40 | + this.mockComponent = mockComponent; | ||
41 | + this.tcb = new TestComponentBuilder(); | ||
42 | + this.init(done); | ||
43 | + } | ||
44 | + | ||
45 | + init(done: any): any { | ||
1 |
|
||
46 | + let promisse = this.tcb.createAsync(this.mockComponent) as any; | ||
1 |
|
||
47 | + return promisse.then((fixture: any) => { | ||
48 | + // Fire all angular events and parsing | ||
49 | + fixture.detectChanges(); | ||
50 | + // The main debug element | ||
51 | + this.debugElement = fixture.debugElement; | ||
52 | + this.component = this.debugElement.componentViewChildren[0].componentInstance; | ||
53 | + }).then(() => { | ||
54 | + // Force the resolution of components and sync | ||
55 | + done(); | ||
56 | + }); | ||
57 | + } | ||
58 | + | ||
59 | + /** | ||
60 | + * Return all elements matching the given selector | ||
61 | + */ | ||
62 | + all(selector: string): INgForwardJQuery[] { | ||
63 | + return this.debugElement.queryAll(selector); | ||
64 | + } | ||
65 | + | ||
66 | + find(selector: string): INgForwardJQuery { | ||
67 | + return this.all(selector)[0]; | ||
68 | + } | ||
69 | + | ||
70 | + findChildren(parentSelector: string, childSelector: string) { | ||
71 | + let parentComponent = this.find(parentSelector); | ||
2 |
|
||
72 | + return parentComponent.find(childSelector)[0]; | ||
73 | + } | ||
74 | +} | ||
0 | \ No newline at end of file | 75 | \ No newline at end of file |
@@ -72,6 +72,13 @@ export var mocks = { | @@ -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: {} | ||
1 |
|
||
79 | + }); | ||
80 | + } | ||
81 | + }, | ||
75 | profileService: { | 82 | profileService: { |
76 | getCurrentProfile: (profile: any) => { | 83 | getCurrentProfile: (profile: any) => { |
77 | return mocks.promiseResultTemplate({ | 84 | return mocks.promiseResultTemplate({ |