diff --git a/backend/docs/testing.md b/backend/docs/testing.md new file mode 100644 index 0000000..be9c7b2 --- /dev/null +++ b/backend/docs/testing.md @@ -0,0 +1,79 @@ +# Testing + +## Introduction + +Since backend and frontend use the same technology, the same testing framework can be used for both. [Mocha](https://github.com/mochajs/mocha) and [Jest](https://github.com/jestjs/jest) were considered as testing frameworks. Jest was chosen, because it is more commonly used and the team was more familiar with it. NestJS, which is used as the backend framework, also uses jest for testing by default. + +## Getting started + + + + +## Conventions + +Tests should be defined in a `test` folder in both the frontend and backend directories. Unit test files use the file ending `.spec.ts`. End to end tests use the `.e2e-spec.ts` file ending. + +For unit tests we use the assertions provided by Jest. For end to end tests we use [`supertest`](https://github.com/ladjs/supertest). + +## Example Unit Test + +```ts +import { CatsController } from './cats.controller'; +import { CatsService } from './cats.service'; + +describe('CatsController', () => { + let catsController: CatsController; + let catsService: CatsService; + + beforeEach(() => { + catsService = new CatsService(); + catsController = new CatsController(catsService); + }); + + describe('findAll', () => { + it('should return an array of cats', async () => { + const result = ['test']; + jest.spyOn(catsService, 'findAll').mockImplementation(() => result); + + expect(await catsController.findAll()).toBe(result); + }); + }); +}); +``` + +## Example End to End Test + +```ts +import * as request from 'supertest'; +import { Test } from '@nestjs/testing'; +import { CatsModule } from '../../src/cats/cats.module'; +import { CatsService } from '../../src/cats/cats.service'; +import { INestApplication } from '@nestjs/common'; + +describe('Cats', () => { + let app: INestApplication; + let catsService = { findAll: () => ['test'] }; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [CatsModule], + }) + .overrideProvider(CatsService) + .useValue(catsService) + .compile(); + + app = moduleRef.createNestApplication(); + await app.init(); + }); + + it(`/GET cats`, () => { + return request(app.getHttpServer()).get('/cats').expect(200).expect({ + data: catsService.findAll(), + }); + }); + + afterAll(async () => { + await app.close(); + }); +}); +``` diff --git a/docs/01-requirements/anforderungen.pdf b/docs/01-requirements/anforderungen.pdf deleted file mode 100644 index fd60b6e..0000000 Binary files a/docs/01-requirements/anforderungen.pdf and /dev/null differ diff --git a/docs/01-requirements/anforderungen.typ b/docs/01-requirements/anforderungen.typ deleted file mode 100644 index ee19fb5..0000000 --- a/docs/01-requirements/anforderungen.typ +++ /dev/null @@ -1,208 +0,0 @@ -#set heading(numbering: "1.") - -#align(center, text(24pt)[ - *DuoGradus* -]) - -#align(center, text(17pt)[ - Anforderungen -]) - -#pagebreak() -#set page( - numbering: "i" -) - -#show outline.entry.where( - level: 1 -): it => { - v(10pt) - text(size: 14pt, strong(it)) -} -#outline( - title: [Inhalt], - indent: auto, - depth: 3 -) - -#pagebreak() -#set page( - numbering: "1", -) - -= Präambel -== Projektbeschreibung -DuoGradus ist eine Anwendung, die Nutzer motivieren soll täglich Schritte zu sammeln. Dafür ist die App spielerisch aufgebaut und versucht die Nutzer durch Gamification zu mehr Schritten und weiteren Aktivitäten zu motivieren. -Das Konzept orientiert sich dabei an bereits etablierten Ideen, die sich bereits für das Erlernen von Sprachen etabliert haben und versucht diese auch auf sportliche Aktivitäten zu übertragen. -Durch die Anbindung von externen APIs wird es Nutzern möglich sein ihre bestehenden Gadgets, wie z.B. Fitnesstracker mit dem System zu verbinden. - -== Beteiligte Personen -#table( - columns: (1fr, 1fr), - inset: 10pt, - align: horizon, - [*Person*], [*Rolle*], - [Dr. Roland Schätzle], [formaler Auftraggeber], - [Benedict Weis], [Projektmanagement, DevOps], - [Henry Brink], [Entwicklung Backend], - [Ingo Neuse], [Entwicklung Backend], - [Luis Bernhardt], [Entwicklung Frontend], - [Justin Hubert], [Entwicklung Frontend] -) - -#pagebreak() - -= Projektumfang -Das Projekt umfasst die Entwicklung einer Anwendung, bei der eine Minimal-Infrastruktur durch den Auftraggeber vorgegeben ist. Die Gestaltung der Software ist frei, deswegen werden in diesem Lastenheft die vom Team definierten Anforderungen an die Anwendung festgehalten. - -== Anforderungen des Auftraggebers -Durch den Auftraggeber wird die folgende Struktur für die Anwendung vorgegeben: -#figure( - image("images/01_minimal_project_structure.png", width: 50%) -) -Der Auftraggeber stellt zudem weiter Anforderungen an das Projekt: - -- Nutzung eines zentralen GitHub-Repositories für das Code-Hosting -- Dokumentation des Projektes innerhalb des Repositories oder über eine weiter Wiki-Plattform -- Statusreports über GitHub-Discussions -- Zeiterfassung - -#pagebreak() -== Anforderungen an das Produkt -=== Integration mit Drittanbietern zur Datenerhebung [PM-1] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [10], - [*Komponenten*], [Backend], -) -Das Produkt soll Schritt- und eventuell Aktivitätsdaten von externen Anbietern erfassen. Diese Anforderung ergibt sich aus der Grundfunktionalität der Anwendung, sowie der Anforderung des Auftraggebers. -Folgende Anbieter werden für die Implementierung herangezogen: - -+ Fitbit -+ Google Health -+ Samsung Fit - -Mindestens erforderlich ist die Integration eines einzigen Anbieters, aufgrund der vergleichsweise simplen Schnittstelle wird Fitbit für eine erste Implementierung empfohlen. - -==== Technische Betrachtung -Für die Integration mit Drittanbietern ist es notwendig, dass diese eine Schnittstelle anbieten, auf die wir zugreifen können. Wir möchten für diese Anwendung nur offizielle Schnittstellen verwenden. Da wir keine Anwendung auf den Endgeräten planen müssen wir uns auf Web-APIs beschränken. - -FitBit bietet eine Rest-API an, die sich für diesen Zweck eignen könnte. Für die Nutzung dieser ist lediglich ein FitBit-Account notwendig. - -Die Daten müssen durch das Backend von der API abgerufen werden, dafür ist bei den meisten APIs eine Zustimmung des Nutzers über das OAuth2-Verfahren notwendig. Der Nutzer muss die Anwendung einmalig berechtigen und kann dabei auch Berechtigungen festlegenen. -=== Aufgaben, Ziele und Abzeichen [PM-2] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [9], - [*Komponenten*], [Backend, Frontend], -) -Kernfunktionalität der Anwendung sind "Ziele", die der Benutzer durch seine Aktivitäten erreichen kann. Die Art der Ziele ist dabei abhängig von den implementierten Integrationen. Mindestens verfügbar sein sollen Schrittziele, bei denen folgende Parameter erforderlich sind: - -+ Anzahl von Schritten -+ Startzeit -+ Endzeit -+ Punkte -+ Dauer (beispielsweise: "100 Schritte innerhalb von 4 Minuten erreichen.") - -Zudem sollen Ziele sinnvolle Namen erhalten. - -Weitere optionale Felder sind: -+ Wetter - -Falls möglich, sollen neben Schrittzielen zusätzlich Aktivitätsziele definiert werden. - -Für bestimmte Aktivitäten soll ein Nutzer zudem Abzeichen / Erfolge sammeln können. Denkbar wäre hier beispielsweise ein Abzeichen "Nicht aus Zucker" für eine Aktivität im Regen. - -=== Tageszielpunkte [PM-3] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [8], - [*Komponenten*], [Backend, Frontend], -) -Damit der Nutzer die App regelmäßig verwendet soll der Nutzer für jeden Tag an dem er die App verwendet einen Punkt erhalten. Nutzt er die App an einem Tag nicht (bzw. erfüllt seine Mindest-Anzahl an Schritten nicht) werden die Punkte auf 0 zurückgesetzt. - -Gegen Abend soll der Nutzer eine Benachrichtigung erhalten, falls er bisher noch keinen Punkt erreicht hat. Diese soll den Nutzer passiv-aggressiv an seine Schritte erinnern (siehe [PM-5]) - -Optional: Nachrichten mithilfe generativer AI erstellen. - -Benachrichtiungen z.B. über E-Mail - -=== Rangliste [PM-4] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [7], - [*Komponenten*], [Backend, Frontend], -) -Die Anwendung bietet Nutzern die Möglichkeit sich in einer Rangliste zu vergleichen. Dabei gibt es eine globale Rangliste und eine private Rangliste, in der sich Nutzer mit Freunden vergleichen können. - -Für die private Rangliste müssen Nutzer Freundschaftsanfragen an Nutzer senden können und ihre Freundesliste verwalten können. - -=== Erinnerungen [PM-5] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [7], - [*Komponenten*], [Backend], -) -Die Anwendung soll dem Nutzer automatisiert Benachrichtungen senden, falls er bis zu einer bestimmten Tageszeit seine Ziele noch nicht erreicht hat. - -=== Schnittstelle für Wetter-Daten [PM-6] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [5], - [*Komponenten*], [Backend, Frontend], -) -Die Anwendung soll es Nutzern ermöglichen ihren (Haupt-)Standort festzulegen und sich dann mit den Wetter-Daten des jeweiligen Standorts verknüpfen lassen. -Die Wetter-Daten sollen für personalisierte Aufgaben verwendet werden (z.B. "Mache 2.000 Schritte im Regen") oder dem Nutzer ein Bonus-Abzeichen geben. - -=== Integration eines Shops [PM-7] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [2], - [*Komponenten*], [Backend, Frontend], -) -Die Anwendung soll dem Nutzer die Möglichkeit bieten in Aktivitäten gesammelte Punkte für virtuelle Gegenstände auszugeben. Denkbar wäre z.B. ein spezielles Design der Anwendung oder eine Wiederherstellung verlorengeganer Tagespunkte. - -=== Kalorienverbrauch [PM-8] -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [4], - [*Komponenten*], [Backend, Frontend], -) -Die Anwendung soll, falls durch die Drittanbieter [PM-1] bereitgestellt, dem Nutzer seine aktuell verbrannten Kalorien anzeigen. - -Diese Daten können zudem für Aufgaben oder Erfolge verwendet werden. - -=== Unterstützung für verschiedene Anmeldeverfahren -#table( - columns: (1fr, 2fr), - align: horizon, - inset: 7pt, - stroke: 1pt, - [*Priorität*], [2], - [*Komponenten*], [Backend, Frontend], -) -Das System ermöglicht es dem Nutzer sich über verschiedene Verfahren und Dienstanbieter (z.B. Google, Apple) anzumelden. Für die Integration kann optional ein Drittsystem verantwortlich sein. \ No newline at end of file diff --git a/docs/01-requirements/images/01_minimal_project_structure.png b/docs/01-requirements/images/01_minimal_project_structure.png deleted file mode 100644 index 53b7e62..0000000 Binary files a/docs/01-requirements/images/01_minimal_project_structure.png and /dev/null differ diff --git a/docs/03-development/testing.md b/docs/03-development/testing.md deleted file mode 100644 index c33fca3..0000000 --- a/docs/03-development/testing.md +++ /dev/null @@ -1,154 +0,0 @@ -# Testing - -## Backend - -### Introduction - -Since backend and frontend use the same technology, the same testing framework can be used for both. [Mocha](https://github.com/mochajs/mocha) and [Jest](https://github.com/jestjs/jest) were considered as testing frameworks. Jest was chosen, because it is more commonly used and the team was more familiar with it. NestJS, which is used as the backend framework, also uses jest for testing by default. - -### Getting started - - - - -### Conventions - -Tests should be defined in a `test` folder in both the frontend and backend directories. Unit test files use the file ending `.spec.ts`. End to end tests use the `.e2e-spec.ts` file ending. - -For unit tests we use the assertions provided by Jest. For end to end tests we use [`supertest`](https://github.com/ladjs/supertest). - -### Example Unit Test - -```ts -import { CatsController } from './cats.controller'; -import { CatsService } from './cats.service'; - -describe('CatsController', () => { - let catsController: CatsController; - let catsService: CatsService; - - beforeEach(() => { - catsService = new CatsService(); - catsController = new CatsController(catsService); - }); - - describe('findAll', () => { - it('should return an array of cats', async () => { - const result = ['test']; - jest.spyOn(catsService, 'findAll').mockImplementation(() => result); - - expect(await catsController.findAll()).toBe(result); - }); - }); -}); -``` - -#### Example End to End Test - -```ts -import * as request from 'supertest'; -import { Test } from '@nestjs/testing'; -import { CatsModule } from '../../src/cats/cats.module'; -import { CatsService } from '../../src/cats/cats.service'; -import { INestApplication } from '@nestjs/common'; - -describe('Cats', () => { - let app: INestApplication; - let catsService = { findAll: () => ['test'] }; - - beforeAll(async () => { - const moduleRef = await Test.createTestingModule({ - imports: [CatsModule], - }) - .overrideProvider(CatsService) - .useValue(catsService) - .compile(); - - app = moduleRef.createNestApplication(); - await app.init(); - }); - - it(`/GET cats`, () => { - return request(app.getHttpServer()).get('/cats').expect(200).expect({ - data: catsService.findAll(), - }); - }); - - afterAll(async () => { - await app.close(); - }); -}); -``` - -## Frontend - -### Introduction - -For testing the frontend, two frameworks are used: Jasmine and Protractor. Jasmine is utilized for unit testing individual components, while Protractor is specifically designed for end-to-end (E2E) testing of Angular applications. This combination provides comprehensive coverage of the various types of testing in Angular projects. - -Jasmine is already part of the initialization of an Angular project with the Angular CLI. It is a popular testing framework for JavaScript applications and offers a clear syntax for writing unit and integration tests. - -On the other hand, Protractor is tailored to the needs of Angular applications and enables the writing of E2E tests. - -### Getting Started - -Jasmin: https://jasmine.github.io/ -Potractor: https://www.protractortest.org/#/ - -### Conventions - -The unit tests are placed directly within the same folder as the file being tested and have the extension `.spec.ts`. End-to-end tests are located in a `test` folder and have the extension `.e2e-spec.ts`. - -### Example Unit Test - -```ts -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { GreetingComponent } from './greeting.component'; - -describe('GreetingComponent', () => { - let component: GreetingComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GreetingComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GreetingComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); - - it('should display the correct greeting message', () => { - const element: HTMLElement = fixture.nativeElement; - expect(element.textContent).toContain('Hello, World!'); - }); -}); -``` - -### Example E2E-Test - ---- - -```ts -// Beispiel-E2E-Test: app.e2e-spec.ts - -import { browser, by, element } from 'protractor'; - -describe('Greeting App', () => { - beforeEach(() => { - browser.get('/'); - }); - - it('should display the correct greeting message', () => { - const greetingMessage = element(by.tagName('h1')); - expect(greetingMessage.getText()).toEqual('Hello, World!'); - }); -}); -``` diff --git a/docs/mockups/Account.pdf b/docs/03-mockups/Account.pdf similarity index 100% rename from docs/mockups/Account.pdf rename to docs/03-mockups/Account.pdf diff --git a/docs/mockups/Friendlist.pdf b/docs/03-mockups/Friendlist.pdf similarity index 100% rename from docs/mockups/Friendlist.pdf rename to docs/03-mockups/Friendlist.pdf diff --git a/docs/mockups/Homepage.pdf b/docs/03-mockups/Homepage.pdf similarity index 100% rename from docs/mockups/Homepage.pdf rename to docs/03-mockups/Homepage.pdf diff --git a/docs/mockups/Ranking.pdf b/docs/03-mockups/Ranking.pdf similarity index 100% rename from docs/mockups/Ranking.pdf rename to docs/03-mockups/Ranking.pdf diff --git a/docs/mockups/Settings.pdf b/docs/03-mockups/Settings.pdf similarity index 100% rename from docs/mockups/Settings.pdf rename to docs/03-mockups/Settings.pdf diff --git a/docs/architecture.drawio.png b/docs/architecture.drawio.png deleted file mode 100644 index 319a7b6..0000000 Binary files a/docs/architecture.drawio.png and /dev/null differ diff --git a/docs/basearchitecture.drawio.png b/docs/basearchitecture.drawio.png deleted file mode 100644 index 42ab5f4..0000000 Binary files a/docs/basearchitecture.drawio.png and /dev/null differ diff --git a/frontend/docs/testing.md b/frontend/docs/testing.md new file mode 100644 index 0000000..7c42dc0 --- /dev/null +++ b/frontend/docs/testing.md @@ -0,0 +1,72 @@ +# Frontend + +## Introduction + +For testing the frontend, two frameworks are used: Jasmine and Protractor. Jasmine is utilized for unit testing individual components, while Protractor is specifically designed for end-to-end (E2E) testing of Angular applications. This combination provides comprehensive coverage of the various types of testing in Angular projects. + +Jasmine is already part of the initialization of an Angular project with the Angular CLI. It is a popular testing framework for JavaScript applications and offers a clear syntax for writing unit and integration tests. + +On the other hand, Protractor is tailored to the needs of Angular applications and enables the writing of E2E tests. + +## Getting Started + +Jasmin: +Potractor: + +## Conventions + +The unit tests are placed directly within the same folder as the file being tested and have the extension `.spec.ts`. End-to-end tests are located in a `test` folder and have the extension `.e2e-spec.ts`. + +## Example Unit Test + +```ts +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { GreetingComponent } from './greeting.component'; + +describe('GreetingComponent', () => { + let component: GreetingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [GreetingComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(GreetingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should display the correct greeting message', () => { + const element: HTMLElement = fixture.nativeElement; + expect(element.textContent).toContain('Hello, World!'); + }); +}); +``` + +## Example E2E-Test + +--- + +```ts +// Beispiel-E2E-Test: app.e2e-spec.ts + +import { browser, by, element } from 'protractor'; + +describe('Greeting App', () => { + beforeEach(() => { + browser.get('/'); + }); + + it('should display the correct greeting message', () => { + const greetingMessage = element(by.tagName('h1')); + expect(greetingMessage.getText()).toEqual('Hello, World!'); + }); +}); +```