├── .gitignore
├── README.md
├── package.json
├── protractor.conf.js
├── src
├── app
│ ├── app.component.ts
│ ├── bootstrap.ts
│ ├── characters
│ │ ├── character.service.ts
│ │ ├── character.ts
│ │ └── characters.component.ts
│ ├── dashboard
│ │ └── dashboard.component.ts
│ └── silly-calculator
│ │ └── calculator.component.ts
├── index.html
├── styles.css
└── system.config.ts
├── test
└── e2e
│ ├── calculator.spec.ts
│ ├── characters.spec.ts
│ ├── dashboard.spec.ts
│ └── pageObjects
│ ├── calculator.pageObject.ts
│ └── dashboard.pageObject.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # node & jspm
2 | node_modules
3 | jspm_packages
4 |
5 | # generated
6 | dev
7 | *.log
8 |
9 | # type definitions
10 | typings
11 |
12 | # IntelliJ
13 | .idea
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Angular 2 Go with Protractor !
2 |
3 | Simple starter example that gets you going with Angular 2 and Protractor in minutes, based on the
4 | [angular2-go seed](https://github.com/johnpapa/angular2-go) by John Papa.
5 |
6 | ## Quick note about dependencies
7 |
8 | This seed uses a Protractor version >= v3.0.0. Starting with v3.0.0 Protractor no longer supports node versions < v4.2
9 | (see [changelog](https://github.com/angular/protractor/blob/master/CHANGELOG.md#300)), so make sure you're using a
10 | compatible node version.
11 |
12 | ## Run the application
13 |
14 | 1. Run `npm install`
15 |
16 | 1. Run the TypeScript compiler and watch for changes `npm run dev`
17 |
18 | 1. Open 2nd terminal and launch the app in the browser `npm start`
19 |
20 | ## Run the e2e tests
21 |
22 | 1. Ensure the application is running (`npm start`)
23 |
24 | 1. Open a third terminal and run the tests `npm run e2e`
25 |
26 | The tests are run directly against Chrome, so no need to fire up a Selenium Standalone Server instance. Check
27 | protractor.conf.js for comments about ng2-specific configuration.
28 |
29 | Keep in mind that currently not all locator strategies are supported for ng2 apps. Things like by.model() or by.binding()
30 | are not working just yet. Check the Protractor [changelog](https://github.com/angular/protractor/blob/master/CHANGELOG.md)
31 | for new releases
32 |
33 | ##Notes
34 |
35 | This sample intentionally uses precise versions of Angular 2 and SystemJS so new versions do not break it. I will update these as Angular 2 moves out of Alpha.
36 |
37 | This uses the Path Routing Strategy (HTML5 Mode in Angular 1). This is ideal, however since this demo strives for a simple server using live-server, if you refresh the browser when on a deep link (a named route), you will get a 404. Simply go back to the root /.
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-go",
3 | "version": "0.0.1",
4 | "repository": "https://github.com/johnpapa/angular2-go",
5 | "scripts": {
6 | "copy": "cpy 'src/**/*.html' 'src/**/*.css' dev/src",
7 | "tsc": "tsc --outDir dev -w",
8 | "dev": "npm run copy && npm run tsc",
9 | "start": "live-server --open=dev/src/#/dashboard",
10 | "e2e": "./node_modules/protractor/bin/webdriver-manager update && protractor protractor.conf.js"
11 | },
12 | "engines": {
13 | "npm": ">=2.14.x",
14 | "node": ">=4.2.x"
15 | },
16 | "dependencies": {
17 | "angular2": "2.0.0-alpha.45",
18 | "systemjs": "0.19.5"
19 | },
20 | "devDependencies": {
21 | "cpy": "^3.4.1",
22 | "live-server": "^0.8.1",
23 | "protractor": "^3.0.0",
24 | "typescript": "^1.6.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/protractor.conf.js:
--------------------------------------------------------------------------------
1 | exports.config = {
2 | baseUrl: 'http://localhost:8080/dev/src/',
3 | specs: ['dev/test/e2e/**/*.spec.js'],
4 | directConnect: true,
5 | exclude: [],
6 | multiCapabilities: [{
7 | browserName: 'chrome'
8 | }],
9 | allScriptsTimeout: 110000,
10 | getPageTimeout: 100000,
11 | framework: 'jasmine2',
12 | jasmineNodeOpts: {
13 | isVerbose: false,
14 | showColors: true,
15 | includeStackTrace: false,
16 | defaultTimeoutInterval: 400000
17 | },
18 |
19 | /**
20 | * ng2 related configuration
21 | *
22 | * useAllAngular2AppRoots: tells Protractor to wait for any angular2 apps on the page instead of just the one matching
23 | * `rootEl`
24 | *
25 | */
26 | useAllAngular2AppRoots: true
27 | };
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import {Component} from 'angular2/angular2';
2 | import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
3 |
4 | import {DashboardComponent} from './dashboard/dashboard.component';
5 | import {CharactersComponent} from './characters/characters.component';
6 | import {CalculatorComponent} from './silly-calculator/calculator.component';
7 |
8 | @Component({
9 | selector: 'my-app',
10 | template: `
11 | Dashboard |
12 | Characters |
13 | Silly calculator
14 |
15 | `,
16 | directives: [ROUTER_DIRECTIVES]
17 | })
18 | @RouteConfig([
19 | { path: '/dashboard', as: 'Dashboard', component: DashboardComponent },
20 | { path: '/characters', as: 'Characters', component: CharactersComponent },
21 | { path: '/calculator', as: 'Calculator', component: CalculatorComponent }
22 | ])
23 | export class AppComponent { }
24 |
--------------------------------------------------------------------------------
/src/app/bootstrap.ts:
--------------------------------------------------------------------------------
1 | import {provide, bootstrap} from 'angular2/angular2';
2 | import {ROUTER_PROVIDERS, HashLocationStrategy, LocationStrategy} from 'angular2/router';
3 |
4 | import {AppComponent} from './app.component';
5 | import {CharacterService} from './characters/character.service';
6 |
7 | bootstrap(AppComponent, [
8 | ROUTER_PROVIDERS,
9 | CharacterService,
10 | provide(LocationStrategy, {useClass: HashLocationStrategy})
11 | ]);
12 |
--------------------------------------------------------------------------------
/src/app/characters/character.service.ts:
--------------------------------------------------------------------------------
1 | import {Character} from './character';
2 |
3 | export class CharacterService {
4 | getCharacters() { return Promise.resolve(CHARACTERS); }
5 |
6 | getCharacter(id: number) {
7 | return Promise.resolve(CHARACTERS)
8 | .then((characters) => { return characters.filter((c) => {
9 | return c.id === id;
10 | })[0]});
11 | }
12 | }
13 |
14 | var CHARACTERS : Character[] = [
15 | {
16 | "id": 11,
17 | "name": "Aragorn"
18 | },
19 | {
20 | "id": 12,
21 | "name": "Meriadoc Brandybuck"
22 | },
23 | {
24 | "id": 13,
25 | "name": "Pippin Took"
26 | },
27 | {
28 | "id": 14,
29 | "name": "Frodo Baggins"
30 | },
31 | {
32 | "id": 15,
33 | "name": "Samwise Gamgee"
34 | },
35 | {
36 | "id": 16,
37 | "name": "Gandalf"
38 | },
39 | {
40 | "id": 17,
41 | "name": "Boromir"
42 | },
43 | {
44 | "id": 18,
45 | "name": "Gimli"
46 | },
47 | {
48 | "id": 19,
49 | "name": "Legolas"
50 | },
51 | {
52 | "id": 20,
53 | "name": "Elrond"
54 | }
55 | ];
56 |
--------------------------------------------------------------------------------
/src/app/characters/character.ts:
--------------------------------------------------------------------------------
1 | export interface Character {
2 | id: number;
3 | name: string;
4 | }
5 |
--------------------------------------------------------------------------------
/src/app/characters/characters.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, NgFor, NgIf} from 'angular2/angular2';
2 | import {Router} from 'angular2/router';
3 |
4 | import {CharacterService} from './character.service';
5 | import {Character} from './character';
6 |
7 | @Component({
8 | selector: 'my-characters',
9 | template: `
10 |
Select a Character
11 |
12 | -
13 | {{character.id}} {{character.name}}
14 |
15 |
16 |
17 | {{currentCharacter.name | uppercase}} is my character
18 |
19 | `,
20 | directives: [NgFor, NgIf],
21 | styles: [`
22 | .characters {list-style-type: none; margin-left: 1em; padding: 0; width: 14em;}
23 | .characters li { cursor: pointer; }
24 | .characters li:hover {color: #369; background-color: #EEE; }
25 | `]
26 | })
27 | export class CharactersComponent {
28 | private _characters: Character[];
29 | public currentCharacter: Character;
30 |
31 | constructor(private _characterService: CharacterService) { }
32 |
33 | get characters() {
34 | return this._characters || this.getCharacters()
35 | }
36 |
37 | onSelect(character: Character) { this.currentCharacter = character; }
38 |
39 | /////////////////
40 |
41 | private getCharacters() {
42 | this._characters = [];
43 |
44 | this._characterService.getCharacters()
45 | .then(characters => this._characters = characters);
46 |
47 | return this._characters;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/app/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, FORM_DIRECTIVES} from 'angular2/angular2';
2 |
3 | @Component({
4 | selector: 'my-dashboard',
5 | template: `
6 | Dashboard
7 | Yo {{name}}
8 |
9 |
10 | {{message}}
11 | `,
12 | directives: [FORM_DIRECTIVES]
13 | })
14 | export class DashboardComponent {
15 | public name = 'John';
16 | public message = '';
17 |
18 | sayHello() {
19 | this.message = 'Yo ' + this.name + '!';
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/app/silly-calculator/calculator.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, FORM_DIRECTIVES} from 'angular2/angular2';
2 |
3 | @Component({
4 | selector: 'my-calculator',
5 | template: `
6 | The silly calculator
7 |
8 | +
9 |
10 | =
11 | {{add(firstOperand, secondOperand)}}
12 | `,
13 | directives: [FORM_DIRECTIVES]
14 | })
15 | export class CalculatorComponent {
16 |
17 | add(a: any, b: any) {
18 | if(a && b) {
19 | return (parseInt(a) + parseInt(b));
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Loading...
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | h2 { color: #444; font-weight: lighter; }
2 | body { margin: 2em; }
3 | body, input[text], button { color: #888; font-family: Cambria, Georgia; }
4 | button {padding: 0.2em; font-size: 14px}
--------------------------------------------------------------------------------
/src/system.config.ts:
--------------------------------------------------------------------------------
1 | System.config({
2 | packages: {'app': {defaultExtension: 'js'}}
3 | });
4 |
--------------------------------------------------------------------------------
/test/e2e/calculator.spec.ts:
--------------------------------------------------------------------------------
1 | import {CalculatorPageObject} from './pageObjects/calculator.pageObject';
2 |
3 | describe('Calculator Page', function() {
4 |
5 | var calculator = new CalculatorPageObject();
6 |
7 | beforeEach(function() {
8 | browser.get('#/calculator');
9 | });
10 |
11 | it('should add positive numbers', function() {
12 | calculator.add(1, 2);
13 | expect(calculator.result.getText()).toEqual('3');
14 |
15 | calculator.add(2, 2);
16 | expect(calculator.result.getText()).toEqual('4');
17 | });
18 |
19 | it('should add negative numbers', function() {
20 | calculator.add(-1, 4);
21 | expect(calculator.result.getText()).toEqual('3');
22 |
23 | calculator.add('2', '-2');
24 | expect(calculator.result.getText()).toEqual('0');
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/test/e2e/characters.spec.ts:
--------------------------------------------------------------------------------
1 | // TODO - go for it ;)
--------------------------------------------------------------------------------
/test/e2e/dashboard.spec.ts:
--------------------------------------------------------------------------------
1 | import {DashboardPageObject} from './pageObjects/dashboard.pageObject';
2 |
3 | describe('Dashboard page', function() {
4 |
5 | var dashboard: DashboardPageObject = new DashboardPageObject();
6 |
7 | beforeEach(function() {
8 | browser.get('#/dashboard');
9 | });
10 |
11 | it('should say hello', function() {
12 | dashboard.sayHi('yo');
13 | expect(dashboard.greeting.getText()).toEqual('Yo yo');
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/test/e2e/pageObjects/calculator.pageObject.ts:
--------------------------------------------------------------------------------
1 | export class CalculatorPageObject {
2 | public firstOperand = element.all(by.tagName('input')).get(0);
3 | public secondOperand = element.all(by.tagName('input')).get(1);
4 | public result = element(by.css('.result'));
5 |
6 | /////
7 |
8 | add(a: any, b: any) {
9 | // this doesn't work in ts
10 | // this.firstOperand.clear().sendKeys();
11 |
12 | this.firstOperand.clear();
13 | this.firstOperand.sendKeys(a);
14 |
15 | this.secondOperand.clear();
16 | this.secondOperand.sendKeys(b);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/test/e2e/pageObjects/dashboard.pageObject.ts:
--------------------------------------------------------------------------------
1 | export class DashboardPageObject {
2 | public name = element(by.tagName('input'));
3 | public hiButton = element(by.tagName('button'));
4 | public greeting = element(by.tagName('div'));
5 |
6 | /////
7 |
8 | sayHi(name: string) {
9 | this.name.clear();
10 | this.name.sendKeys(name);
11 | this.hiButton.click();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES5",
4 | "module": "commonjs",
5 | "sourceMap": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "removeComments": false,
9 | "noImplicitAny": true
10 | },
11 | "exclude": [
12 | "node_modules",
13 | "test/e2e/pageObjects"
14 | ]
15 | }
--------------------------------------------------------------------------------