Final repo #1

Merged
hardi merged 1 commits from unit-test into master 2017-05-17 22:05:17 +02:00
15 changed files with 201 additions and 54 deletions

View File

@ -2,6 +2,12 @@ import {browser, element, by} from 'protractor';
import {AbstractHeaderPage} from "../page-object/abstract-header.po"; import {AbstractHeaderPage} from "../page-object/abstract-header.po";
import {TaskOverviewPage} from "../page-object/task/task-overview.po"; import {TaskOverviewPage} from "../page-object/task/task-overview.po";
/**
* E2E-Test für grundsätzlichen Seitenzugriff und die Seitennavigation
* bezüglich AbstractPageHeader Implementierung
*
* @author FHartwich
*/
describe('Access Projectmanager Homepage', function () { describe('Access Projectmanager Homepage', function () {
beforeEach(() => { beforeEach(() => {

View File

@ -2,19 +2,57 @@ import {AbstractHeaderPage} from "../abstract-header.po";
import {by, element} from "protractor"; import {by, element} from "protractor";
import {TaskOverviewPage} from "./task-overview.po"; import {TaskOverviewPage} from "./task-overview.po";
/**
* PageObject Klasse, repräsentiert die Formularseite zum
* editieren und Erstellen von Aufgaben
*
* @author FHartwich
*/
export class TaskEditPage extends AbstractHeaderPage { export class TaskEditPage extends AbstractHeaderPage {
/**
* Array mit möglichen Fehleranzeigen
* @type {{title: string; email: string}}
*/
errorMessages = {title: 'Titel muss mindestens 5 Zeichen enthalten', errorMessages = {title: 'Titel muss mindestens 5 Zeichen enthalten',
email : 'Bitte geben Sie eine gültige E-Mail Adresse an'}; email : 'Bitte geben Sie eine gültige E-Mail Adresse an'};
/**
* Eingabefeld - Titel
* @type {ElementFinder}
*/
titleInput = element(by.id('title')); titleInput = element(by.id('title'));
/**
* Eingabefeld - Beschreibung
* @type {ElementFinder}
*/
descriptionInput = element(by.id('description')); descriptionInput = element(by.id('description'));
statusDropdown = element(by.id('state'));
assigneeName = element(by.id('assignee_name')); /**
* Eingabefeld - Verantwortlicher, eMail
* @type {ElementFinder}
*/
assigneeEmail = element(by.id('assignee_email')); assigneeEmail = element(by.id('assignee_email'));
/**
* Speichern - Button
* @type {ElementFinder}
*/
saveButton = element(by.id('save')); saveButton = element(by.id('save'));
/**
* Abbrechen - Button
* @type {ElementFinder}
*/
cancelButton = element(by.id('cancel')); cancelButton = element(by.id('cancel'));
/**
* Konstruktor
* @param newTask - true, wenn die Seite für einen neuen Tasks geöffnet wird
* false, wenn ein Task editiert wird
*/
constructor(newTask: boolean) { constructor(newTask: boolean) {
super(); super();
let headline; let headline;
@ -26,47 +64,65 @@ export class TaskEditPage extends AbstractHeaderPage {
super.validatePageHeadline(headline) super.validatePageHeadline(headline)
} }
/**
* Löscht alten Titel und gibt neuen ein
* @param title - neuer Titel
*/
clearEnterTitle(title: string) { clearEnterTitle(title: string) {
this.titleInput.clear(); this.titleInput.clear();
this.titleInput.sendKeys(title); this.titleInput.sendKeys(title);
} }
/**
* Löscht alte Beschreibung und gibt neue ein
* @param description - neue Beschreibung
*/
clearEnterDescription(description: string) { clearEnterDescription(description: string) {
this.descriptionInput.clear(); this.descriptionInput.clear();
this.descriptionInput.sendKeys(description); this.descriptionInput.sendKeys(description);
} }
setStatus(state: string) { /**
this.statusDropdown.element(by.css('[value="${state}"]')) * Löscht alte Assignee eMail und trägt neue ein
.click()// -> Höller, Christoph - Angular, S. 562 - Listing 14.12 * @param email - neue eMail Adresse
} */
clearInsertName(name: string) {
this.assigneeName.clear();
this.assigneeName.sendKeys(name);
}
clearInsertEmail(email: string) { clearInsertEmail(email: string) {
this.assigneeEmail.clear(); this.assigneeEmail.clear();
this.assigneeEmail.sendKeys(email); this.assigneeEmail.sendKeys(email);
} }
/**
* Klick auf den Button zum absenden des Formulars
* @returns {TaskOverviewPage}
*/
submitTaskForm() { submitTaskForm() {
this.saveButton.click(); this.saveButton.click();
return new TaskOverviewPage; return new TaskOverviewPage;
} }
/**
* Klick auf den Button zum Abbrechen der Formulareingabe
* @returns {TaskOverviewPage}
*/
cancelSubmitTask() : TaskOverviewPage { cancelSubmitTask() : TaskOverviewPage {
this.cancelButton.click(); this.cancelButton.click();
return new TaskOverviewPage(); return new TaskOverviewPage();
} }
/**
* überprüft den Feldwert des über die ID beschriebenen Elements
* @param elementId - CSS ID des Testfeldes
* @param value - erwarteter Wert
*/
static validateInput(elementId: string, value: string) { static validateInput(elementId: string, value: string) {
const input = element(by.id(elementId)); const input = element(by.id(elementId));
expect(input.getAttribute('value')).toBe(value); expect(input.getAttribute('value')).toBe(value);
} }
/**
* prüft ob ein Error existiert der diesen Wert hat
* @param input - erwartete Fehlermeldung
*/
validateError(input: string) { validateError(input: string) {
expect(element(by.className('alert')).getText()) expect(element(by.className('alert')).getText())
.toBe(this.errorMessages[input]); .toBe(this.errorMessages[input]);

View File

@ -2,11 +2,26 @@ import {AbstractHeaderPage} from "../abstract-header.po";
import {browser, by, element, ElementArrayFinder, ElementFinder, ExpectedConditions} from "protractor"; import {browser, by, element, ElementArrayFinder, ElementFinder, ExpectedConditions} from "protractor";
import {TaskEditPage} from "./task-edit.po"; import {TaskEditPage} from "./task-edit.po";
/**
* PageObject Klasse als Repräösentation der Aufgabenübersichts-Seite
*
* @author FHartwich
*/
export class TaskOverviewPage extends AbstractHeaderPage { export class TaskOverviewPage extends AbstractHeaderPage {
/**
* Button zum Anlegen einer neuen Aufgabe
*/
neueAufgabeBtn: ElementFinder; neueAufgabeBtn: ElementFinder;
/**
* Liste aller Einträge
*/
taskEntries: ElementArrayFinder; taskEntries: ElementArrayFinder;
/**
* Konstruktor
*/
constructor() { constructor() {
super(); super();
super.validatePageHeadline('Aufgaben durchsuchen'); super.validatePageHeadline('Aufgaben durchsuchen');
@ -14,21 +29,39 @@ export class TaskOverviewPage extends AbstractHeaderPage {
this.taskEntries = element.all(by.className('task-list-entry')); this.taskEntries = element.all(by.className('task-list-entry'));
} }
/**
* Prüft den Wert im Suchfeld
* @param value - erwarteter Wert
*/
validateSearchFieldValue(value: string) { validateSearchFieldValue(value: string) {
const inputField = element(by.id('search-tasks')); const inputField = element(by.id('search-tasks'));
expect(inputField.getAttribute('value')).toEqual(value); expect(inputField.getAttribute('value')).toEqual(value);
} }
/**
* Klick auf den Button zum Erstellen einer neuen Aufgabe
* @returns {TaskEditPage}
*/
clickNeueAufgabe(): TaskEditPage { clickNeueAufgabe(): TaskEditPage {
this.neueAufgabeBtn.click(); this.neueAufgabeBtn.click();
return new TaskEditPage(true); return new TaskEditPage(true);
} }
/**
* validiert dass ein Task mit gegebenen Titel in der Liste
* vorhanden ist
* @param title - erwarteter Titel
*/
verifyNewTask(title: string) { verifyNewTask(title: string) {
const newEntry = element(by.linkText(title)); const newEntry = element(by.linkText(title));
browser.wait(ExpectedConditions.presenceOf(newEntry)); browser.wait(ExpectedConditions.presenceOf(newEntry));
} }
/**
* Klick auf den Link einer Aufgabe mit gegebenen Titel
* @param title - Titel der Aufgabe
* @returns {TaskEditPage}
*/
clickTask(title: string) { clickTask(title: string) {
const entry = element(by.linkText(title)); const entry = element(by.linkText(title));
entry.click(); entry.click();

View File

@ -3,7 +3,7 @@ import {TaskOverviewPage} from "../page-object/task/task-overview.po";
import {TaskEditPage} from "../page-object/task/task-edit.po"; import {TaskEditPage} from "../page-object/task/task-edit.po";
/** /**
* E2E Testsuite für seitenübergreifende * E2E Test für seitenübergreifende
* Interaktionen beim Erstellen einer neuen Aufagbe * Interaktionen beim Erstellen einer neuen Aufagbe
* *
* @author FHartwich * @author FHartwich

View File

@ -2,7 +2,7 @@
"tasks": [ "tasks": [
{ {
"id": 3, "id": 3,
"title": "Ersten Prototyp mit Angular 4.0 entwickelt", "title": "Ersten Prototyp mit Angular 2.0 entwickeln",
"description": "Der Prototyp soll zeigen, wie Routing und HTTP-Anbindung umgesetzt werden können.", "description": "Der Prototyp soll zeigen, wie Routing und HTTP-Anbindung umgesetzt werden können.",
"tags": [], "tags": [],
"state": "IN_PROGRESS", "state": "IN_PROGRESS",
@ -57,15 +57,6 @@
"state": "IN_PROGRESS", "state": "IN_PROGRESS",
"title": "New Task", "title": "New Task",
"id": 9 "id": 9
},
{
"assignee": {
"email": "testuser@test.com"
},
"tags": [],
"state": "BACKLOG",
"title": "valid title",
"id": 10
} }
] ]
} }

View File

@ -5,6 +5,12 @@ import {BlogComponent} from "../blog.component";
import {RouterTestingModule} from "@angular/router/testing"; import {RouterTestingModule} from "@angular/router/testing";
import {MockBlogComponent} from "../../mocks/mock-blog.component"; import {MockBlogComponent} from "../../mocks/mock-blog.component";
/**
* Test für die Klasse BlogEntryComponent
* isoliert und in Abhängigkeit zu BlogComponent
*
* @author FHartwich
*/
describe('Blog Entry Isolated Test', () => { describe('Blog Entry Isolated Test', () => {
describe('Isolated Test', () => { describe('Isolated Test', () => {

View File

@ -1,11 +1,17 @@
import {BlogComponent} from './blog.component' import {BlogComponent} from "./blog.component";
import {async, inject, TestBed} from "@angular/core/testing"; import {async, TestBed} from "@angular/core/testing";
import {RouterTestingModule} from "@angular/router/testing"; import {RouterTestingModule} from "@angular/router/testing";
import {Component, CUSTOM_ELEMENTS_SCHEMA} from "@angular/core"; import {CUSTOM_ELEMENTS_SCHEMA} from "@angular/core";
import {By} from "@angular/platform-browser"; import {By} from "@angular/platform-browser";
import {BlogEntryComponent} from "./blog-entry/blog-entry.component";; import {BlogEntryComponent} from "./blog-entry/blog-entry.component";
import {Router} from "@angular/router/router"; ;
/**
* Test für die BlogComponent Klasse, z.T.mit
* sich wiederholenden Tesfällen, verschiedenen Kontextumfangs
*
* @author FHartwich
*/
describe('Blog Component', () => { describe('Blog Component', () => {
describe('Isolated Component Test', () => { describe('Isolated Component Test', () => {

View File

@ -6,7 +6,12 @@ import {FormsModule} from "@angular/forms";
import {MockLoginService} from "../mocks/mock-login-service"; import {MockLoginService} from "../mocks/mock-login-service";
import Spy = jasmine.Spy; import Spy = jasmine.Spy;
/**
* Test für die LoginComponent Klasse
* für Formulareingabe und Service Interaktion
*
* @author FHartwich
*/
describe('Login Component UI Driven Form Test with Spy', () => { describe('Login Component UI Driven Form Test with Spy', () => {
beforeEach(() => { beforeEach(() => {

View File

@ -1,5 +1,12 @@
import {Component} from "@angular/core"; import {Component} from "@angular/core";
/**
* Gemockte Klasse basierend auf BlogComponent,
* die lediglich die Directive und zwei minimal-Einträge
* des BlogEntry zur Interaktion bereitstellt
*
* @author FHartwich
*/
@Component({ @Component({
selector: 'blog', selector: 'blog',
template: '<blog-entry *ngFor="let entry of entries" [entry]="entry" [blogComponent]="this"></blog-entry>' template: '<blog-entry *ngFor="let entry of entries" [entry]="entry" [blogComponent]="this"></blog-entry>'

View File

@ -1,5 +1,12 @@
/**
* Klasse mit einzelner, leerer Methode
* als Mock zum Testen der Service-Interaktion
*
* @author FHartwich
*/
export class MockLoginService { export class MockLoginService {
login(name, password) {}; login(name, password) {
};
} }

View File

@ -1,5 +1,11 @@
import {Component} from "@angular/core"; import {Component} from "@angular/core";
/**
* Mock für die TaskItemComponent
* zur Nutzung als leere Klasse ohne Interaktion
*
* @author FHartwich
*/
@Component({ @Component({
selector: 'pjm-task-item', selector: 'pjm-task-item',
template: '', template: '',

View File

@ -1,11 +1,18 @@
import {FormGroup, ReactiveFormsModule} from '@angular/forms'; import {FormGroup, ReactiveFormsModule} from "@angular/forms";
import {TestBed} from '@angular/core/testing'; import {TestBed} from "@angular/core/testing";
import {ModelDrivenFormComponent} from './model-driven-form.component'; import {ModelDrivenFormComponent} from "./model-driven-form.component";
import {UserService} from '../services/user-service/user.service'; import {UserService} from "../services/user-service/user.service";
import {TaskServiceModelForm} from "../services/task-service/task-model-form.service"; import {TaskServiceModelForm} from "../services/task-service/task-model-form.service";
import {ShowErrorComponentModelDriven} from "../show-error/show-error-model-driven.component"; import {ShowErrorComponentModelDriven} from "../show-error/show-error-model-driven.component";
import {generateRandomString} from "../test/test.helper"; import {generateRandomString} from "../test/test.helper";
/**
* Test für die ModelDrivenFormComponent mit Interaktion
* auf Grundlage des Modell-Getriebenen-Formulars (FormGroup)
*
* @author FHartwich
*/
describe('Model Driven Form', () => { describe('Model Driven Form', () => {
// ModelDrivenFormComponent Fixture // ModelDrivenFormComponent Fixture

View File

@ -7,8 +7,11 @@ import {LoginService} from "./login-service";
import {UserStore} from "../stores/user.store"; import {UserStore} from "../stores/user.store";
/** /**
* Test für die LoginService Klasse
* Initialisierung und Durchführung nach Vorlage aus dem * Initialisierung und Durchführung nach Vorlage aus dem
* TaskService Tests (../task-service/task.service.spec.ts) von Christoph Höller * TaskService Tests (../task-service/task.service.spec.ts) von Christoph Höller
*
* @author FHartwich
*/ */
describe('Login-Service', () => { describe('Login-Service', () => {
beforeEach(() => { beforeEach(() => {

View File

@ -1,14 +1,22 @@
import {TaskService} from '../../services/task-service/task.service'; import {TaskService} from "../../services/task-service/task.service";
import {RouterTestingModule} from '@angular/router/testing'; import {RouterTestingModule} from "@angular/router/testing";
import {TestBed} from '@angular/core/testing'; import {TestBed} from "@angular/core/testing";
import {EditTaskComponent} from './edit-task.component'; import {EditTaskComponent} from "./edit-task.component";
import {ShowErrorComponent} from '../../show-error/show-error.component'; import {ShowErrorComponent} from "../../show-error/show-error.component";
import {APPLICATION_VALIDATORS} from '../../models/app-validators'; import {APPLICATION_VALIDATORS} from "../../models/app-validators";
import {Title} from '@angular/platform-browser'; import {Title} from "@angular/platform-browser";
import {FormsModule} from '@angular/forms'; import {FormsModule} from "@angular/forms";
import {MockTaskService} from '../../mocks/mock-task-service'; import {MockTaskService} from "../../mocks/mock-task-service";
import {generateRandomString} from "../../test/test.helper"; import {generateRandomString} from "../../test/test.helper";
/**
* Test für die Klasse EditTaskComponent
* zur Prüfung von Formularinteraktion auf Grundlage
* eines Template-Getriebenen-Formulars
*
* @author FHartwich
*/
describe('EditTask Component', () => { describe('EditTask Component', () => {
describe('Template Driven Form API-based Test', () => { describe('Template Driven Form API-based Test', () => {

View File

@ -1,14 +1,20 @@
import {async, TestBed} from "@angular/core/testing"; import {async, inject, TestBed} from "@angular/core/testing";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {ReactiveFormsModule} from "@angular/forms"; import {ReactiveFormsModule} from "@angular/forms";
import {inject} from "@angular/core/testing";
import {TaskListComponent} from "./task-list.component"; import {TaskListComponent} from "./task-list.component";
import {RouterTestingModule} from "@angular/router/testing"; import {RouterTestingModule} from "@angular/router/testing";
import {MockTaskService} from "../../mocks/mock-task-service"; import {MockTaskService} from "../../mocks/mock-task-service";
import {TaskService} from "../../services/task-service/task.service"; import {TaskService} from "../../services/task-service/task.service";
import {MockTaskItemComponent} from '../../mocks/mock-task-item.component' import {MockTaskItemComponent} from "../../mocks/mock-task-item.component";
describe('Task Overview Component Routing', () => {
/**
* Test der TaskListComponent
* im Hinblick auf die Router-Iteraktion
*
* @author FHartwich
*/
describe('Task List Component Routing', () => {
let component: TaskListComponent; let component: TaskListComponent;
let fixture; let fixture;