import 'zone.js/dist/zone';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/sync-test';
import {setBaseTestProviders} from '@angular/core/testing';
import {
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
} from '@angular/platform-browser-dynamic/testing';
setBaseTestProviders(
TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS
);
import 'app/calculator.spec';
import 'app/hello.component.spec';
import 'app/user-store.spec';
import {
it,
expect,
describe
} from '@angular/core/testing';
import {Calculator} from './calculator';
describe('Calculator', () => {
it('should say 4 when asked 2 * 2', () => {
let calculator = new Calculator();
expect(calculator.calculate('2 * 2')).toEqual(4);
});
});
export class Calculator {
calculate(formula: string) {
let [value1, value2] = formula.split('*');
return parseFloat(value1) * parseFloat(value2);
}
}
import {Injectable} from '@angular/core';
import {HTTP_PROVIDERS, Http} from '@angular/http';
import {Observable} from 'rxjs/Rx';
import {User} from './user';
@Injectable()
export class UserStore {
private _userListObservable: Observable<User[]> = null;
private _userListObserver = null;
private _userList = null;
static PROVIDERS = [
HTTP_PROVIDERS,
UserStore
];
constructor(private _http: Http) {
this._userListObservable = new Observable<User[]>(observer => {
let httpSubscription = null;
this._userListObserver = observer;
if (this._userList === null) {
httpSubscription = this._http.get('/api/v1/users/')
.map(response => response.json().objects)
.subscribe(userList => {
this._userList = userList;
observer.next(userList);
});
}
else {
observer.next(this._userList);
}
return () => {
if (httpSubscription !== null) {
httpSubscription.unsubscribe();
}
};
});
}
addUser({user}: {user: User}): Promise<User> {
return this._http.post('/api/v1/users/', JSON.stringify(user))
.map(response => response.json())
.do(user => {
this._userList.push(user);
this._userListObserver.next(this._userList);
})
.toPromise();
}
userList(): Observable<User[]> {
return this._userListObservable;
}
}
/**
*
* (c) 2013-2016 Wishtack
*
* $Id: $
*/
import {provide} from '@angular/core';
import {Http, Response, ResponseOptions, RequestOptions, RequestMethod} from '@angular/http';
import {beforeEach, beforeEachProviders, describe, expect, fakeAsync, inject, it, tick} from '@angular/core/testing';
import {MockBackend, MockConnection} from '@angular/http/testing';
import {UserStore} from './user-store';
import {User} from './user';
describe('UserStore', () => {
let spyConnection = null;
beforeEachProviders(() => [
MockBackend,
UserStore.PROVIDERS,
provide(Http, {
deps: [MockBackend, RequestOptions],
useFactory: (mockBackend, requestOptions) => {
return new Http(mockBackend, requestOptions);
}
})
]);
beforeEach(inject([MockBackend], (mockBackend:MockBackend) => {
spyConnection = jasmine.createSpy('connection');
mockBackend.connections.subscribe((connection:MockConnection) => {
connection.mockRespond(new Response(new ResponseOptions(spyConnection({
body: connection.request.text(),
method: connection.request.method,
url: connection.request.url
}))));
});
}));
it('should get user list from server', inject(
[UserStore],
(userStore:UserStore) => {
let userList = null;
spyConnection.and.returnValue({
body: {
meta: {totalCount: 3},
objects: [
{
id: '1',
firstName: 'Foo',
lastName: 'BAR'
},
{
id: '2',
firstName: 'Mads',
lastName: 'MIKKELSEN'
}
]
}
});
userStore.userList()
.subscribe(_userList_ => userList = _userList_)
.unsubscribe();
expect(userList).toEqual([
{
id: '1',
firstName: 'Foo',
lastName: 'BAR'
},
{
id: '2',
firstName: 'Mads',
lastName: 'MIKKELSEN'
}
]);
expect(spyConnection.calls.count()).toEqual(1);
expect(spyConnection).toHaveBeenCalledWith({
body: '',
method: RequestMethod.Get,
url: '/api/v1/users/'
});
spyConnection.calls.reset();
/* Second call should reuse cached result. */
userStore.userList()
.subscribe(result => userList = result)
.unsubscribe();
expect(userList).toEqual([
{
id: '1',
firstName: 'Foo',
lastName: 'BAR'
},
{
id: '2',
firstName: 'Mads',
lastName: 'MIKKELSEN'
}
]);
expect(spyConnection.calls.count()).toEqual(0);
})
);
it('should send user to server and invalidate observable cache', fakeAsync(inject(
[UserStore],
(userStore) => {
let serverUser = null;
let subscription = null;
let userList = null;
spyConnection.and.returnValue({
body: {
meta: {totalCount: 3},
objects: [
{
id: '1',
firstName: 'Foo',
lastName: 'BAR'
},
{
id: '2',
firstName: 'Mads',
lastName: 'MIKKELSEN'
}
]
}
});
userStore.userList()
.subscribe(data => userList = data)
.unsubscribe();
spyConnection.calls.reset();
/* Add user */
spyConnection.and.returnValue({
body: {
id: '3',
firstName: 'Jack',
lastName: 'WILD'
}
});
/* Subscribe should be called after user is added as user list has been updated. */
subscription = userStore.userList()
.subscribe(data => userList = data);
userList = null;
userStore.addUser({user: new User({firstName: 'Jack', lastName: 'WILD'})})
.then(data => serverUser = data);
tick();
expect(serverUser.id).toEqual('3');
expect(spyConnection).toHaveBeenCalledWith({
body: JSON.stringify({firstName: 'Jack', lastName: 'WILD'}),
method: RequestMethod.Post,
url: '/api/v1/users/'
});
expect(userList.length).toEqual(3);
expect(userList[2].id).toEqual('3');
expect(userList[2].firstName).toEqual('Jack');
expect(userList[2].lastName).toEqual('WILD');
subscription.unsubscribe();
})
));
});
export class User {
id: string;
firstName: string;
lastName: string;
constructor({id, firstName, lastName}: {id?: string, firstName: string, lastName: string}) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
}
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 QuickStart</title>
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="https://npmcdn.com/core-js/client/shim.min.js"></script>
<script src="https://npmcdn.com/zone.js@0.6.12?main=browser"></script>
<script src="https://npmcdn.com/reflect-metadata@0.1.3"></script>
<script src="https://npmcdn.com/systemjs@0.19.27/dist/system.src.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.2/jasmine.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.2/jasmine-html.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.2/boot.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app/bootstrap').catch(function(err){ console.error(err); });
</script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: { emitDecoratorMetadata: true },
packages: {'app': {defaultExtension: 'ts'}}
});
System.import('app/bootstrap')
.then(window.onload, console.error.bind(console));
</script>
</head>
<!-- 3. Display the application -->
<body>
</body>
</html>
(function(global) {
var ngVer = '@2.0.0-rc.1';
var routerVer = '@3.0.0-alpha.3';
//map tells the System loader where to look for things
var map = {
'app': 'app',
'@angular': 'https://npmcdn.com/@angular',
'@angular/router': 'https://npmcdn.com/@angular/router' + routerVer,
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6',
'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js',
'typescript': 'https://npmcdn.com/typescript@1.9.0-dev.20160409/lib/typescript.js',
'zone.js': 'https://npmcdn.com/zone.js@0.6.12'
};
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'rxjs': { defaultExtension: 'js' },
'zone.js': { defaultExtension: 'js' }
};
var ngPackageNames = [
'common',
'compiler',
'core',
'http',
'platform-browser',
'platform-browser-dynamic',
'router-deprecated',
'upgrade',
];
// Add map entries for each angular package
// only because we're pinning the version with `ngVer`.
ngPackageNames.forEach(function(pkgName) {
map['@angular/'+pkgName] = 'https://npmcdn.com/@angular/' + pkgName + ngVer;
});
// Add package entries for angular packages
ngPackageNames.forEach(function(pkgName) {
// Bundled (~40 requests):
// packages['@angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
// Individual files (~300 requests):
packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
// No umd for router yet
packages['@angular/router'] = { main: 'index.js', defaultExtension: 'js' };
var config = {
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
tsconfig: true
},
meta: {
'typescript': {
"exports": "ts"
}
},
map: map,
packages: packages
}
System.config(config);
})(this);
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}
import {Component} from '@angular/core';
import {TestComponentBuilder} from '@angular/compiler/testing';
import {beforeEachProviders, describe, fakeAsync, inject, it} from '@angular/core/testing';
import {HelloComponent} from './hello.component';
describe('Hello component', () => {
beforeEachProviders(() => [
TestComponentBuilder
]);
it('should say hi', fakeAsync(inject([TestComponentBuilder], (testComponentBuilder) => {
let fixture = testComponentBuilder.createFakeAsync(HelloComponent);
let element = fixture.nativeElement;
fixture.componentInstance.name = 'John';
fixture.detectChanges();
expect(element.innerText).toEqual('Hello John');
})));
it('should say hi with wrapping test component', fakeAsync(inject([TestComponentBuilder], (testComponentBuilder) => {
@Component({
directives: [HelloComponent],
selector: 'wt-test',
template: `<wt-hello [name]="'John'"></wt-hello>`
})
class TestComponent {}
let fixture = testComponentBuilder.createFakeAsync(TestComponent);
let element = fixture.nativeElement;
fixture.detectChanges();
expect(element.innerText).toEqual('Hello John');
})));
});
import {Component, Input} from '@angular/core';
@Component({
selector: 'wt-hello',
template: `
<div>
<span>Hello </span><span [innerText]="name"></span>
</div>
`
})
export class HelloComponent {
static PROVIDERS = [HelloComponent];
@Input() name: string;
}