Skip to content

Commit

Permalink
feat(testing/utils): create public helper methods for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Hotell committed Jan 19, 2016
1 parent fc08560 commit e3559d1
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 4 deletions.
108 changes: 106 additions & 2 deletions docs/API.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
## API

Angular 1 container registration helper Methods:
Angular 1 boostraper:

`ng-metadata/platform`
- [bootstrap](#bootstrap)

Angular 1 container registration helper Methods:

`ng-metadata/core`
- [provide](#provide)
- [getInjectableName](#getinjectablename)

Decorators(core):
Testing helpers:

`ng-metadata/testing`
- [renderFactory](#renderfactory)
- [getInput](#getinput)

Decorators:

`ng-metadata/core`
- [@Component](#component)
- [@Directive](#directive)
- [@Input](#input)
Expand All @@ -25,6 +37,7 @@ Decorators(core):

Lifecycle hooks:

`ng-metadata/core`
- [OnInit](#oninit)
- [AfterContentInit](#aftercontentinit)
- [AfterViewInit](#afterviewtinit)
Expand Down Expand Up @@ -187,6 +200,97 @@ console.log(getInjectableName(MyService)); // 'myService48'
```
## renderFactory `ng-metadata/testing`
Helper for compiling Component/Directive classes within you unit test.
Use pattern shown in example:
- create local render variable with interface IRender to tell tsc what type it would be
- init it when you got $scope and $compile in beforeEach
- use it within the test
- if you want to override the inferred type from Directive argument use that via `<>` operator
*Example:*
```typescript
// my-component.ts
@Component({
selector:'my-component',
template:'hello {{ $ctrl.greeting }}'
})
class MyComponent{

greeting: string;

constructor(@Inject('ngModel') @Host() private ngModel){}

ngAfterViewInit(){
this.ngModel.$render = ()=>{
this.greeting = angular.copy(this.ngModel.$viewValue);
}
}
}

// my-component.spec.ts
import { MyModule } from './my';
import { MyComponent } from './my-component';
import { renderFactory, IRender } from 'ng-metadata/testing';

let $compile: ng.ICompileService;
let $rootScope: ng.IRootScopeService;
let $scope;
let render: IRender;

describe(`MyComponent`, ()=>{

beforeEach(() => {

angular.mock.module(MyModule);

});

beforeEach(angular.mock.inject((_$injector_: ng.auto.IInjectorService) => {

const $injector = _$injector_;

$compile = $injector.get<ng.ICompileService>('$compile');
$rootScope = $injector.get<ng.IRootScopeService>('$rootScope');
$scope = $rootScope.$new();

render = renderFactory($compile,$scope);

}));

it(`should create the DOM and compile`, ()=>{
const attrs = { 'ng-model':'model'};
$scope.model = 'Martin!';

// here we go!
// it returns instance and compiled DOM
const {compiledElement, ctrl} = render(MyComponent, {attrs});

expect(ctrl instanceOf MyComponent).to.equal(true);
expect(compiledElement[0]).to.equal('<my-component ng-model="model">hello Martin!</my-component>');
})

})

```
###### Parameters
| Parameter | Type | Description |
| ------------- | ------------------------------- |------------------------------------------ |
| **$compile** | `ng.ICompileService` | core angular 1 $compile service from ng.mock |
| **$scope** | `ng.IScope` | child scope for your component |
returns render `Function`
###### Behind the Scenes
it builds whole DOM for component/directive, so you don't need to bother with html strings in your test.
Within it calls angular 1 well known $compile with provided $scope and re runs $digest loop to reflect the changes.
## @Component
A decorator for adding component metadata to a class.
Expand Down
74 changes: 74 additions & 0 deletions src/testing/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,78 @@
import {isFunction} from '../facade/lang';
import {getInjectableName} from '../core/di/provider';
import {StringWrapper} from '../facade/primitives';

// public helpers


export interface IRender{
<T extends Type>(Directive: T, {jqHost, attrs, jqChildren}?: {
jqHost?: ng.IAugmentedJQuery,
attrs?: { [key: string]: any },
jqChildren?: ng.IAugmentedJQuery
}
):{
compiledElement: ng.IAugmentedJQuery,
ctrl: T
}
}
/**
* factory which will return function which will be used as your render method
*/
export function renderFactory( $compile: ng.ICompileService, $scope: any ) {

return _compileAndDigest;

function _compileAndDigest<T extends Type>(
Directive: T,
{jqHost, attrs, jqChildren}:{
jqHost?: ng.IAugmentedJQuery
attrs?: {[key:string]:any},
jqChildren?: ng.IAugmentedJQuery
} = {}
): { compiledElement: ng.IAugmentedJQuery, ctrl: T}{

const ctrlName = getInjectableName( Directive );
const selector = StringWrapper.kebabCase( ctrlName );

// is Directive
if ( jqHost ) {

jqHost.attr( selector, '' )

} else {
// is Component

const hostElement = `<${selector}></${selector}>`;
jqHost = angular.element( hostElement );

}

jqHost.attr(attrs);

if (jqChildren) {
jqHost.append(jqChildren);
}

// angular api
const compiledElement = $compile(jqHost)($scope);
const ctrl = compiledElement.controller(ctrlName) as T;
$scope.$apply();

return { compiledElement, ctrl };

}

}

export function getInput(element: ng.IAugmentedJQuery) {
return element.find('input');
}

// ============================
// _private helpers for testing
// ============================

/**
*
* @internal
Expand Down
3 changes: 1 addition & 2 deletions testing.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
// @TODO export public testing helpers
//import {} from './testing/utils';
export {renderFactory,getInput,IRender} from './src/testing/utils';

0 comments on commit e3559d1

Please sign in to comment.