diff --git a/project-manager/karma.conf.js b/project-manager/karma.conf.js index 9e88999..9f0e343 100644 --- a/project-manager/karma.conf.js +++ b/project-manager/karma.conf.js @@ -1,5 +1,5 @@ // Karma configuration -// Generated on Sat Mar 25 2017 06:31:51 GMT+0100 (CET) +// Generated on Thu Mar 09 2017 06:31:51 GMT+0100 (CET) module.exports = function(config) { config.set({ @@ -12,6 +12,9 @@ module.exports = function(config) { // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['jasmine', '@angular/cli'], + + // list of plugins to load. A plugin can be a string (in which case it will + // be required by Karma) or an inlined plugin - Object plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), diff --git a/project-manager/src/app/blog/blog-entry/blog-entry.component.html b/project-manager/src/app/blog/blog-entry/blog-entry.component.html index 22a4e2f..e7c99b9 100644 --- a/project-manager/src/app/blog/blog-entry/blog-entry.component.html +++ b/project-manager/src/app/blog/blog-entry/blog-entry.component.html @@ -4,9 +4,14 @@
{{entry.title}} -

{{entry.text}}

+

{{entry.text}}

+
+
+ created at: + {{entry.createdAt | date: 'yyyy-MM-dd'}} +
diff --git a/project-manager/src/app/blog/blog-entry/blog-entry.component.spec.ts b/project-manager/src/app/blog/blog-entry/blog-entry.component.spec.ts new file mode 100644 index 0000000..86a7a58 --- /dev/null +++ b/project-manager/src/app/blog/blog-entry/blog-entry.component.spec.ts @@ -0,0 +1,60 @@ +import {TestBed} from "@angular/core/testing"; +import {BlogEntryComponent} from "./blog-entry.component"; +import {BlogEntry} from "./blog-entry"; + +describe('Blog Entry Isolated Test', () => { + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [BlogEntryComponent], + }) + }); + + it('should render DOM correct according to Input', () => { + // Umgebung initialisieren + const fixture = TestBed.createComponent(BlogEntryComponent); + const blogEntryComponent : BlogEntryComponent = fixture.componentInstance; + const element = fixture.nativeElement; + const blogEntry : BlogEntry = new BlogEntry; + + // Testdaten + const testId = 101; + const testTitle = "test title"; + const testText = "test text"; + const testImage = "https://www.google.de/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"; + + // Input-Daten + blogEntry.id = testId; + blogEntry.title = testTitle; + blogEntry.text = testText; + blogEntry.image = testImage; + blogEntry.createdAt = new Date(); + ( blogEntryComponent).entry = blogEntry; + + // DOM update + fixture.detectChanges(); + + // DOM auslesen und Daten abgleichen + const imageSrc = element.querySelector('div /deep/ .blog-image > img').getAttribute("src"); + expect(imageSrc).toBe(testImage); + + // textContent statt innerHtml + // siehe http://stackoverflow.com/questions/40227533/angular-2-and-jasmine-unit-testing-cannot-get-the-innerhtml + const blogTitle = element.querySelector('div /deep/ .blog-summary > span'); + expect(blogTitle.textContent).toBe(testTitle); + + const blogText = element.querySelector('div /deep/ .blog-summary > p').textContent; + expect(blogText).toBe(testText); + + const blogTs = element.querySelector('div /deep/ .blog-timestamp > .timestamp').textContent; + expect(new Date(blogTs).getDate()).toBe(new Date().getDate()); + + const blogDelete = element.querySelector('div /deep/ .blog-delete > button').textContent; + expect(blogDelete).toBe("Entfernen") + + // keine Überprüfung der id, die lediglich im EventListener des Delete Button hinterlegt ist, möglich! + // nur durch click-Event auslösen, was jedoch BlogComponent vorraussetzt + + }); + +}); diff --git a/project-manager/src/app/blog/blog-entry/blog-entry.component.ts b/project-manager/src/app/blog/blog-entry/blog-entry.component.ts index e348332..933e4aa 100644 --- a/project-manager/src/app/blog/blog-entry/blog-entry.component.ts +++ b/project-manager/src/app/blog/blog-entry/blog-entry.component.ts @@ -1,4 +1,4 @@ -import {Component, Input } from '@angular/core'; +import {Component, Input} from '@angular/core'; import {BlogEntry} from './blog-entry'; import {BlogComponent} from "../blog.component"; diff --git a/project-manager/src/app/blog/blog-entry/blog-entry.ts b/project-manager/src/app/blog/blog-entry/blog-entry.ts index 087336f..e37f920 100644 --- a/project-manager/src/app/blog/blog-entry/blog-entry.ts +++ b/project-manager/src/app/blog/blog-entry/blog-entry.ts @@ -1,6 +1,7 @@ export class BlogEntry { - id :number; + id : number; title: string; text: string; image: string; + createdAt: Date; } diff --git a/project-manager/src/app/blog/blog.component.spec.ts b/project-manager/src/app/blog/blog.component.spec.ts index c562ebf..ab216bb 100644 --- a/project-manager/src/app/blog/blog.component.spec.ts +++ b/project-manager/src/app/blog/blog.component.spec.ts @@ -1,9 +1,48 @@ import {BlogComponent} from './blog.component' +import {Title} from "@angular/platform-browser"; -describe('', () => { +describe('Blog Component Isolated Test', () => { - it('', () => { + let blogComponent: BlogComponent; + beforeEach(() => { + blogComponent = new BlogComponent(null, null, new Title('Project Blog')); }); + it('should have initial entries', () => { + expect(blogComponent.entries.length).toBe(2); + blogComponent.entries.forEach((entry) => { + expect(entry.id).toBeLessThanOrEqual(blogComponent.id); + expect(entry.createdAt.getDate()).toBe(new Date().getDate()); + }) + }); + + it('should create new list entry and increment id', () => { + let preCreationId = blogComponent.id; + let entryTitle = "some fancy title"; + let entryImage = "https://avatars1.githubusercontent.com/u/3284117"; + let entryText = "some important text"; + blogComponent.createBlogEntry(entryTitle, entryImage, entryText); + + let newEntry = blogComponent.entries[blogComponent.entries.length - 1]; + expect(newEntry.id - 1).toBe(preCreationId) + expect(newEntry.image).toBe(entryImage); + expect(newEntry.text).toBe(entryText); + expect(newEntry.createdAt.getDate()).toBe(new Date().getDate()); + }); + + it('should delete entry by given id - and not change global max-id', () => { + let preDeletionId = blogComponent.id; + let latestId = blogComponent.entries[blogComponent.entries.length - 1].id; + blogComponent.deleteBlogEntry(latestId); + + expect(blogComponent.id).toBe(preDeletionId); + expect(() => { + if (blogComponent.entries.length > 0) { + return blogComponent.entries[blogComponent.entries.length - 1]; + } else { + return 0; + } + }).not.toBe(latestId); + }); }); diff --git a/project-manager/src/app/blog/blog.component.ts b/project-manager/src/app/blog/blog.component.ts index 920742a..acabd6f 100644 --- a/project-manager/src/app/blog/blog.component.ts +++ b/project-manager/src/app/blog/blog.component.ts @@ -18,9 +18,12 @@ export class BlogComponent { constructor(r: ActivatedRoute, private router: Router, private titleService: Title) { this.entries = initialEntries; - if (this.entries.length != 0) { - this.id = this.entries[this.entries.length-1].id; - } + this.entries.forEach((entry)=> { + entry.createdAt = new Date() + if (this.id < entry.id) { + this.id = entry.id; + } + }); } createBlogEntry(title:string, image:string, text:string) { @@ -31,6 +34,8 @@ export class BlogComponent { entry.title = title; entry.image = image; entry.text = text; + entry.createdAt = new Date(); + console.log(this.entries); this.entries.push(entry); } diff --git a/project-manager/src/app/blog/initialEntries.ts b/project-manager/src/app/blog/initialEntries.ts index 07dcb67..41700b9 100644 --- a/project-manager/src/app/blog/initialEntries.ts +++ b/project-manager/src/app/blog/initialEntries.ts @@ -3,12 +3,14 @@ export var initialEntries = [ id: 1, title: "Angular 2 erschienen", image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAADoCAMAAABVRrFMAAAAkFBMVEXzVz/////ySi3zVDvzUTfzUzryTDDzTzT70s76wLnzUDbySSzyTTHyRyn/+vn6vrb+7uzyRCT4qqD+8/L7zMb0aVX95+T94Nz1fm75sqn829f2joH3mo70ZVD1cV7zW0P3koX4pJn1dmT0YEn1e2v0blv81M/2iHr5r6X5uLD4oJX4p5z3j4L3mIv2g3TyPRge8FGCAAAP0klEQVR4nNVd63qqOBQlXCuI9W7rqdXWtra2et7/7SagQCDZIZcdT2fNn/lmKrAIrH3NxiM3w2h2u3NReLc60fq49Q53tzobuRWz5XSTp4EXZunpZuRuwGz29R4ngXdB6m+f1u7PSdwzGw3O8bCiVSJI8/0tyDllNro7+HHkcQjSzDu6JueQ2fppn4U8rZrc4nvl7uTumK2m20IzZAiSfD9dOjq/I2ZjVjNqIqLHMokXrsjhMxsNHrIhv1rB5o/w0aQr9/roghwys9H8nIg0w/Pir1UMPZbDePE1xr0QZGbr0zYT0iowI2/g/yvIvX3hel94zFbfQR6CmpG8UOI5yIwiGk7e7hFXDonZ+PHdT2TXnRcL8i4XSy+Kw7fBCOeKUJjNBm+5QDNYhH+KP5z7cmYlOf+MQ86aGawZLOKLUd70LFq1coe5PTlLZh87z++lRS/29fLn9/2LViL0oz/zf8hsdQxg96mF/OP6k73Kol3J+T93NitnzKxXMxgEi+pXj0NVZgW5bL/7kF2DA2az+9cJ5z7BiO+rH44gaw3ckjCLTIMCA2ZUM8J+zWhdYPPjqeo610j9/dEkKNBmpqgZLIbT5udjtRezBRqrbl60V06P2ero+fqXFrFu01OqT63wm33diEeD2fhzkWk/SxTpqXWUiQmzkly2+NQgp8psfP+uoxksJu3LEQcziuQmG+WIR4nZaP4Qxma06LP40D7YStFaA+SGybNaxKPA7G6X6GoGC79rks7mi3Yll78pkOtjtjbSDPY6nrlDSoMZJUTD4et9TzgnZTaeLvrSNL3IBtxhXy2egIZcnD5IgwKY2fhrYaoZDII9f+Q7qzetQRRPznNw5QBmo4GFZrAYfgmOrhTMKCHygwMQFAiZ3f3Eeu4TjFT0wMwznIOXCP3hjyic45mtnyw1g0VyFN5PvEUrEfre7qNLrsNs+W2vGSx8sTp/6bn8Cgiz7altXlhmVDNye81one9HSIwQI+dRjiD1Q7bGUzOjmpH2pGn0kUPhx6dOBKqONNvU4dyF2ejukGFpBoOIs9IVZtj3sAKNeLYvq4oZqmaw8OHS7dEkalBDkMSb7yXxlt8bVM1gT7EAiZExkrUGzpzkz16KqxksmvSHACcHIsJi7z07I+aFEmJk6XTRvODNO+ALxxVs+kOAg5NXu0L45L04eypSeZixsg9mJEgevS9XIpXupMQIeXD2tFAMB94c3dG5IutLWHy4XLRs7a0w/W4G0bmHGCELd+JFHVZv7GjNsv7Up0I5zRwz+o8TyKx0DeRghj39hnpXbg4vSH/wGDhbtOiVMnt1wYzeMxVsXS0aDZ88NxZz+KjE7NGVMCdTyuzowlT7atXKkYNTl4gHlBl+5A6mP3h8O/IT/A/KzIWpTlQ7VmaOmOVjysyBqQ4PisScRaB5EVPPTAtakuOqV1/HTlysIjPtEYKebKm6P5RgUU6TXMFbyQzdVPs6TSp25TQA4alkhh1NiIoUEtiW00Sg5qxgdkI+dCwqUsBAKKfxlzAomSHblMDT7ClCKae14a9LZve4EpLI0x88sMpp7DUsS2YfuEeeQOkPMC3iIAKdlczAzmUjtLs/WGKgLUAtpxUoNYwyG6M+5zFYpPgL2m/13kA1lAa1yOtvMQ/6AF5+Avpc98iua7i7MsN8znOoIXHuezGYzfJwFy15vDJDNNXBO3TxVNvBVxC7nFaYs5KZWfsafEwRSicqh4Ib5DRTmTcrmD2imepgC61KeffggBQ3mJmMr8wGaC8wmP4YXa48BRcNNZQKRldmazR7EkHW+OvyIiXf0KJhltMuuc6CGVr0Bz9tVaSUQT7lElH4L5anYDbCul+gQtSuIexUIiYHw1PNDCn2hNMf58quBFto0VZ4b1ryWTHDiiPAIgXTOxyDKVY8qxrPa2Y4uQg4/fHSaDpsFz7QdMxf18xw0sQZlP4Ysc4THHE/Yy1aPK6ZfWE4N3D6o2Uv4VoGWjDjk5oZSlQLL0ZboOD6E5Jnfn3gS2ZrBGaw6nUcAbhmiOQLFcnGihlGRbfYoipGV5/gdCTOi5Y+NcwIwprFkGPF3TY40sEpCyWPDDP72iPc/cHvywKj0xFKDfQaSV2Y2Vd0MzDJwV/t9UUQACX1eb2UC7OdramGL1YkC6CzMsIQ6Wvv8oXZp+29Ah8woecG34cnhEXbzhhmtmlifvNLBbGjCxbYxvbMKoG6MLM11T5ofcXlEDgqsH4v6rzghdnSMvaMoAudASbKhxJ0tldSRWcVM5N9pQyGnxAzaP/0ZY6BCNYR6NWcVV3tdvnnAN5QBB13CIXf1kmZeM4yI1bdxFd3RgDYfYezqrZhcGVSrszONocD0x+yw/rQOt9Zvmn5rMXMJikGC52svxvOc1l2o2ekxczGVMdgj6Y08wu+nHYNnXVke2Vm0aIEu+4jqczBgmrlF9dlriszC0UC0x99QYkP/c6qnJZWT/mVmbmBlPRo9gwUEm4BLdfaZtEqc1bvPzPOY4LX19u1DucXtOajdFCZs5qZ8V2KwSXr9SZAb9MmHV8HihUz09gTTn/0u+1wHu/FXKrDyrhWzEzTxGBFTCU+jiHxmRkvWvOIV8wM7xK4RVUpEQUn6Ham1JpDVswM08QTsF1AqRcftBjGu9OaTSsVMzNTDYf9ao4tHIsbvx2101YxM2ug5GZ/1FDsTs6gPa6mu9OaHHzFzCj2lGx++VE7HlyZkgx7lKERpYrZyKRFCU5/KKfXJpA7bdjB1+Q96z3wBhVduMqn3pQDb1Mzi0Dz2q/xLA4Ee+sa98mHEnSG5bT69/W/GaTDYrCtVuOq4LjVpJzGiG3NzGDgG5j+0Hr9c8gkmpTTmJyYZ34cuKlPq20FruIYJNQac9Yw09YiyeaX3WSojvgvdIcMymlMTFUz0449c3iL6kAL95CGjPRFjZlu0Uw+0WQGpz/woN/QyXQxNyqpaaq1Nr8YYqbNjJko0DDTS/MpblG1hHZDJ1M6aZjplQo0N78YQrecxjqyDTO9bmLhhC58KDrWFVi9bphpdRPDzaW4WOrl1NjLaphpxZ4x+jh8AHq709gUYcNMp0UJLuxhY61lrdlhTQ2zpYbEwt0f6NCKQVgftGGmkb6UpD/QoTUfhR2Qw8yVUz9AZj6NWx99nxtgEGwYxfYMDiGJpR1Ao5zWyqowzJRNNZz+cAL1+LwlbAwz1XauYH8bK11BPZhpFRkYZqppYkn6wwnUWzqG7MPEMFM11WBXgCsol9NaiV2GmWJaVpL+cATl0LGVUmGYzdRECE5/OIOqAkzYHzHM1NLEChO60KGamk/YH7ETYJUMmiT94Q5qjTjtBAbLTGXPjdbsDzSo7ZBrlylZZippYomV/riTY3DfYCD+EzA2UvIi2kEjy0whTSxxrMZ/fTliNsko/IsJmMJUKu8NW9NLWWYKaWJ4+xhKRzpsKlXelHadkmWmkiaGHSuMXQTwZkmV+SjtFl6WWX+aGO7+wBlZKBl0oxKBtlacZTbqTadM4PQHzmZGWKD671wnBdqa1d5X9ZJ0fxh/BqZzdXBOvTeY6RgkT+fHPmylsYb5wG2gvQ0mnbRTi1nPEyVJf1g2j4OXp3PfO/LTYtazkxXu0UQceZqDwt8XP3bmXLSYydPEstGnht0bAkjkt+eB9+FvIvSYasmAcsS5d5JcxFS+aJ2Cd4uZvJs4ICAwh4HBwj+TO495+69bzKSVc8mAcjT9KCCpzElbFbtWvsVMOjQG7tFEHlgFR4DSzw1046v2V1UkwipLf+DpRwFZ04JEvMNO90WbmaSiC/dook4tKQB8ZIb0bEfplPTazOAAD57QhT+gViL8knJad2xTmxlsquEeTfQ5XNcJQUJIGkK7rl+bGZhohttiHQy8g6dmyRzApPO6tJmBTpLEsULWjwISbwcup3X3RrWZQYstG326dDBRGN6eDco3l6FpM4MGaskGlFvshwAhSddCjxWXLux8JQy4SviVJsTJx1GGsI0BGjq75qzLTLzWsgHlbj7ZIBF+4OvdSbf21WEm3nIKm05n30bJ4DOKk2ScnnaYCTfjywaUY/sf9YXCIZO4nMYZ3A4zYZpYNqDchX4UkAi/uKGT2/rcYSYaOgF/n41Y7Mjrg6QzQ+jNRT1fUBQNCgP3rhCrPb09kDiqM8FJ+TXufhuSXzPpl18cflsJHEchdG/5G9FhJqguyno03cz9v0BiagSn5cxZl5mgmziFiTnTj8vFwu4BvzuNM2ccM85USweUYw9/bkHysPDlNH7LaJcZ9+LIvs/m9JNR0iZs7jL5xHyXWfflhOd4EBfxS/tq4dCJK6fxblKXWdfAg/txCFr9BYQsQ9Etp/HeWJdZx0BJv/ziVD8KSLJK3IvQy6yTJk6/7+bzebl9ZVrguDudTruHM8Xrs2NehZSv1uvVuAB34e00m6CZo8usayrSoimgRFIgDQtEBQKXulhRyyjyApMCxX8KFgXezu0wTSAHXWYG+4dujKAAvbGt/8ibM56Zuy/kuYQg28W9eY6V3BH+8rUAjtnB0VcwXSLNXjhiPDMyTV2LOTKifCfKZvDMyGw3dPqxXlwE/qs45Bcwo1HaQ/4/0ZHA30BxsZAZja2f/f8Dt+EWTgQBzAgZBOhffMNGmk0lGV6QGZWS6FdLSeTvpO31EmZk9uT/WikJ/IeeHnQZMyol58mvfN2CbNG7nUrOjPr+v1FK4r3CnqM+Zr9QShL/U2XLUT8zQj5/k5SE/pPavhwVZmR2yn6JlERZn3DoMSuk5Dd4JUH+rL4PU5EZlZL3fy4lSsKhz4xKydZZeUIFSfyotVdRgxmVkuCfSUkYHzU39Gkxo1KS/xMpifKz9q43PWallNw8nRDkrwZbw3SZ/QOvJN4bjY/RZ0alZH9DKUlCwxkrJsyolHg3kpIwOZpu3jZjRgOcyQ2kJJoczOeQGDIjZHxwLSVB9mYzrMOYmWspCQyFA4MZIXN3UjL0bIczWTEj5NGNV5KmL9ZTHyyZkdkRX0qiyQ/CACNbZoWUZKhSEuQPKFN+7JkVUpKhSYkk6asJDGZUSjZIUiJL+moChxkhXxi5kiT5xhsXg8WMzF5sA5xocsKcfIbGjErJH99CSoJMPwSTApFZISWmeSAqHNgztFCZUSlZGLViDbf4g6aQmVEp0Q9wkkQp6asJdGZk9BJrzbiM8pOTYUz4zKiU/KhLSX+1yBQumBGyelWTEpVqkSncMKNSopJS1kv6asIVM0LuvZ7qVJK6EI4a7piR0TSRbaXN3AhHDYfMqJTsoEJ35CN7HDycMqNS8iAqdAfZu/t5YI6ZEfLxzrWoxZtbjLZ0zoyQQdSSkiSRbK1ExA2YEfLZtN+FvnHSVxM3YUbGp7iUkig73GxG4m2YXdrvzKpFprgVMxq8LSyTvpq4HTNqum94LkL+A32x+QfAdXrsAAAAAElFTkSuQmCC", - text: "Endlich ist die finale Version von Angular 2 erschienen. Nach langer Beta-Phase ..." + text: "Endlich ist die finale Version von Angular 2 erschienen. Nach langer Beta-Phase ...", + createdAt: null }, { id: 2, title: "Neue Vorschläge für die kommende Module-Loader-Syntax", image: "https://cdn-images-1.medium.com/max/1000/1*RQFLsbQumE-iNrXzs_Oz8g.jpeg", - text: "Nachdem im ES2015-Standard bereits die Module-API verabschiedet wurde, hat das zuständige Konsortium nun neue Vorschläge für die Module-Loader-Syntax bekannt gegeben..." + text: "Nachdem im ES2015-Standard bereits die Module-API verabschiedet wurde, hat das zuständige Konsortium nun neue Vorschläge für die Module-Loader-Syntax bekannt gegeben...", + createdAt : null } -] \ No newline at end of file +];