diff --git a/TODO.md b/TODO.md
index bd2b916..c6f1464 100644
--- a/TODO.md
+++ b/TODO.md
@@ -8,4 +8,3 @@
- create weight graph
- create weight endpoints which retuns weight in last day, week, month, year
- fix pgexporter logs about missing role
-- fix test for notification, notifications + service
diff --git a/client/src/app/common-components/badge/badge.component.spec.ts b/client/src/app/common-components/badge/badge.component.spec.ts
new file mode 100644
index 0000000..17ba4af
--- /dev/null
+++ b/client/src/app/common-components/badge/badge.component.spec.ts
@@ -0,0 +1,37 @@
+import { TestBed } from '@angular/core/testing';
+
+import { Component } from '@angular/core';
+import { BadgeComponent } from './badge.component';
+
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
+
+ await TestBed.configureTestingModule({
+ declarations: [BadgeComponent, TestComponent],
+ }).compileComponents();
+
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
+
+ return {
+ fixture,
+ nativeElement: debugElement.nativeElement as HTMLElement,
+ };
+}
+
+describe('BadgeComponent', () => {
+ it('renders content', async () => {
+ const { nativeElement } = await setup({
+ template: 'test text',
+ });
+ expect(nativeElement.textContent).toBe('test text');
+ });
+});
diff --git a/client/src/app/common-components/header/header.component.spec.ts b/client/src/app/common-components/header/header.component.spec.ts
index 10f7744..1a60f70 100644
--- a/client/src/app/common-components/header/header.component.spec.ts
+++ b/client/src/app/common-components/header/header.component.spec.ts
@@ -2,27 +2,45 @@ import { TestBed } from '@angular/core/testing';
import { HeadingComponent } from '../heading/heading.component';
import { HeaderComponent } from './header.component';
+import { Component } from '@angular/core';
+
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
-async function setup() {
await TestBed.configureTestingModule({
- declarations: [HeaderComponent, HeadingComponent],
+ declarations: [HeaderComponent, TestComponent, HeadingComponent],
}).compileComponents();
- const fixture = TestBed.createComponent(HeaderComponent);
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
return {
fixture,
- component: fixture.componentInstance,
- element: fixture.nativeElement as HTMLElement,
+ nativeElement: debugElement.nativeElement as HTMLElement,
};
}
describe('HeaderComponent', () => {
+ it('render content', async () => {
+ const { nativeElement } = await setup({
+ template: 'test text',
+ });
+ expect(nativeElement.textContent).toBe('test text');
+ });
+
it('render title', async () => {
- const { fixture, component, element } = await setup();
- component.title = 'test title';
- fixture.detectChanges();
- expect(element.querySelector('app-heading')?.textContent).toBe(
+ const { nativeElement } = await setup({
+ template: '',
+ });
+ expect(nativeElement.querySelector('app-heading')?.textContent).toBe(
'test title'
);
});
diff --git a/client/src/app/common-components/heading/heading.component.spec.ts b/client/src/app/common-components/heading/heading.component.spec.ts
index e612f6b..8b8f6d0 100644
--- a/client/src/app/common-components/heading/heading.component.spec.ts
+++ b/client/src/app/common-components/heading/heading.component.spec.ts
@@ -1,34 +1,46 @@
import { TestBed } from '@angular/core/testing';
-
+import { Component } from '@angular/core';
import { HeadingComponent } from './heading.component';
-async function setup() {
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
+
await TestBed.configureTestingModule({
- declarations: [HeadingComponent],
+ declarations: [TestComponent, HeadingComponent],
}).compileComponents();
- const fixture = TestBed.createComponent(HeadingComponent);
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
return {
fixture,
- component: fixture.componentInstance,
- element: fixture.nativeElement as HTMLElement,
+ nativeElement: debugElement.nativeElement as HTMLElement,
};
}
describe('HeadingComponent', () => {
+ it('renders content', async () => {
+ const { nativeElement } = await setup({ template: 'test text'});
+ expect(nativeElement.textContent).toContain('test text');
+ });
+
it('defaults to level 1', async () => {
- const { element, fixture } = await setup();
- fixture.detectChanges();
- expect(element.className).toContain('level1');
+ const { nativeElement } = await setup({ template: ''});
+ expect(nativeElement.className).toContain('level1');
});
[1, 2, 3, 4, 5, 6].forEach((level) => {
it(`renderes level ${level}`, async () => {
- const { component, element, fixture } = await setup();
- component.level = level;
- fixture.detectChanges();
- expect(element.className).toContain(`level${level}`);
+ const { nativeElement } = await setup({ template: ``});
+ expect(nativeElement.className).toContain(`level${level}`);
});
});
});
diff --git a/client/src/app/common-components/main/main.component.spec.ts b/client/src/app/common-components/main/main.component.spec.ts
new file mode 100644
index 0000000..91477e3
--- /dev/null
+++ b/client/src/app/common-components/main/main.component.spec.ts
@@ -0,0 +1,37 @@
+import { TestBed } from '@angular/core/testing';
+
+import { Component } from '@angular/core';
+import { MainComponent } from './main.component';
+
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
+
+ await TestBed.configureTestingModule({
+ declarations: [MainComponent, TestComponent],
+ }).compileComponents();
+
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
+
+ return {
+ fixture,
+ nativeElement: debugElement.nativeElement as HTMLElement,
+ };
+}
+
+describe('MainComponent', () => {
+ it('renders content', async () => {
+ const { nativeElement } = await setup({
+ template: 'test text',
+ });
+ expect(nativeElement.textContent).toBe('test text');
+ });
+});
diff --git a/client/src/app/common-components/notification.service.spec.ts b/client/src/app/common-components/notification.service.spec.ts
index c4f2cd6..04d79ee 100644
--- a/client/src/app/common-components/notification.service.spec.ts
+++ b/client/src/app/common-components/notification.service.spec.ts
@@ -1,16 +1,55 @@
import { TestBed } from '@angular/core/testing';
-import { NotificationService } from './notification.service';
+import { Notification, NotificationService } from './notification.service';
-describe('NotificationService', () => {
- let service: NotificationService;
+function setup() {
+ TestBed.configureTestingModule({});
+
+ const service = TestBed.inject(NotificationService);
+ return { service };
+}
- beforeEach(() => {
- TestBed.configureTestingModule({});
- service = TestBed.inject(NotificationService);
+describe('NotificationService', () => {
+ it('stores notifications', () => {
+ const notifications: Notification[] = [];
+ const { service } = setup();
+ service.$notifications.subscribe((notification) =>
+ notifications.push(notification)
+ );
+ service.showNotification('test notification');
+ expect(notifications).toHaveSize(1);
+ expect(notifications[0]).toEqual({
+ type: 'success',
+ message: 'test notification',
+ });
});
- it('should be created', () => {
- expect(service).toBeTruthy();
+ it('stores multiple notifications', () => {
+ const notifications: Notification[] = [];
+ const { service } = setup();
+ service.$notifications.subscribe((notification) =>
+ notifications.push(notification)
+ );
+ service.showNotification('test notification 1');
+ service.showNotification('test notification 2', 'error');
+ service.showNotification('test notification 3', 'success');
+ service.showNotification('test notification 4', 'error');
+ expect(notifications).toHaveSize(4);
+ expect(notifications[0]).toEqual({
+ type: 'success',
+ message: 'test notification 1',
+ });
+ expect(notifications[1]).toEqual({
+ type: 'error',
+ message: 'test notification 2',
+ });
+ expect(notifications[2]).toEqual({
+ type: 'success',
+ message: 'test notification 3',
+ });
+ expect(notifications[3]).toEqual({
+ type: 'error',
+ message: 'test notification 4',
+ });
});
});
diff --git a/client/src/app/common-components/notification/notification.component.spec.ts b/client/src/app/common-components/notification/notification.component.spec.ts
index e6109ce..de8b5af 100644
--- a/client/src/app/common-components/notification/notification.component.spec.ts
+++ b/client/src/app/common-components/notification/notification.component.spec.ts
@@ -1,25 +1,63 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { TestBed } from '@angular/core/testing';
-import { NotificationComponent } from './notification.component';
+import { Component } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { NotificationComponent } from './notification.component';
+
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
+
+ await TestBed.configureTestingModule({
+ declarations: [NotificationComponent, TestComponent],
+ imports: [NoopAnimationsModule],
+ }).compileComponents();
+
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
+
+ return {
+ fixture,
+ nativeElement: debugElement.nativeElement as HTMLElement,
+ };
+}
describe('NotificationComponent', () => {
- let component: NotificationComponent;
- let fixture: ComponentFixture;
-
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ NotificationComponent ],
- imports: [NoopAnimationsModule]
- })
- .compileComponents();
-
- fixture = TestBed.createComponent(NotificationComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
+ it('renders content', async () => {
+ const { nativeElement } = await setup({
+ template: 'Test notification',
+ });
+ expect(nativeElement.textContent).toBe('Test notification');
});
- it('should create', () => {
- expect(component).toBeTruthy();
+ it('defaults to success type', async () => {
+ const { nativeElement } = await setup({
+ template: '',
+ });
+
+ expect(nativeElement.classList.contains('success')).toBe(true);
+ });
+
+ it('renders success type', async () => {
+ const { nativeElement } = await setup({
+ template: '',
+ });
+
+ expect(nativeElement.classList.contains('success')).toBe(true);
+ });
+
+ it('renders error type', async () => {
+ const { nativeElement } = await setup({
+ template: '',
+ });
+
+ expect(nativeElement.classList.contains('error')).toBe(true);
});
});
diff --git a/client/src/app/common-components/notifications/notifications.component.spec.ts b/client/src/app/common-components/notifications/notifications.component.spec.ts
index 07f2f87..aa25d9a 100644
--- a/client/src/app/common-components/notifications/notifications.component.spec.ts
+++ b/client/src/app/common-components/notifications/notifications.component.spec.ts
@@ -1,23 +1,78 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NotificationsComponent } from './notifications.component';
+import { Component } from '@angular/core';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { NotificationService } from '../notification.service';
+import { NotificationComponent } from '../notification/notification.component';
-describe('NotificationsComponent', () => {
- let component: NotificationsComponent;
- let fixture: ComponentFixture;
+async function setup({
+ template,
+}: {
+ template?: string;
+} = {}) {
+ @Component({
+ template,
+ })
+ class TestComponent {}
+
+ await TestBed.configureTestingModule({
+ declarations: [
+ NotificationsComponent,
+ TestComponent,
+ NotificationComponent,
+ ],
+ imports: [NoopAnimationsModule],
+ providers: [NotificationService],
+ }).compileComponents();
+
+ const fixture = TestBed.createComponent(TestComponent);
+ const debugElement = fixture.debugElement.children[0];
+ fixture.detectChanges();
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ NotificationsComponent ]
- })
- .compileComponents();
+ const notificationService = TestBed.inject(NotificationService);
- fixture = TestBed.createComponent(NotificationsComponent);
- component = fixture.componentInstance;
+ return {
+ fixture,
+ nativeElement: debugElement.nativeElement as HTMLElement,
+ notificationService,
+ };
+}
+
+describe('NotificationsComponent', () => {
+ it('should render notifications added by notification service', async () => {
+ const { nativeElement, fixture, notificationService } = await setup({
+ template: '',
+ });
+ notificationService.showNotification('test notification');
fixture.detectChanges();
+ const notifications = Array.from(
+ nativeElement.querySelectorAll('app-notification')
+ );
+ expect(notifications).toHaveSize(1);
+ expect(notifications[0].textContent).toBe('test notification');
});
- it('should create', () => {
- expect(component).toBeTruthy();
+ it('should render multiple notifications added by notification service', async () => {
+ const { nativeElement, fixture, notificationService } = await setup({
+ template: '',
+ });
+ notificationService.showNotification('test notification 1');
+ notificationService.showNotification('test notification 2', 'error');
+ notificationService.showNotification('test notification 3', 'success');
+ notificationService.showNotification('test notification 4', 'error');
+ fixture.detectChanges();
+ const notifications = Array.from(
+ nativeElement.querySelectorAll('app-notification')
+ );
+ expect(notifications).toHaveSize(4);
+ expect(notifications[0].textContent).toBe('test notification 1');
+ expect(notifications[0].classList.contains('success')).toBe(true);
+ expect(notifications[1].textContent).toBe('test notification 2');
+ expect(notifications[1].classList.contains('error')).toBe(true);
+ expect(notifications[2].textContent).toBe('test notification 3');
+ expect(notifications[2].classList.contains('success')).toBe(true);
+ expect(notifications[3].textContent).toBe('test notification 4');
+ expect(notifications[3].classList.contains('error')).toBe(true);
});
});
diff --git a/client/src/app/weight.service.spec.ts b/client/src/app/weight.service.spec.ts
index 4dfe564..33588fa 100644
--- a/client/src/app/weight.service.spec.ts
+++ b/client/src/app/weight.service.spec.ts
@@ -1,29 +1,26 @@
-import { of } from 'rxjs';
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
import { WeightResponse } from './types';
import { WeightService } from './weight.service';
-async function setup() {
- const mockHttpClient = jasmine.createSpyObj('HttpClient', ['get']);
-
- mockHttpClient.get.and.callFake((url: string) =>
- url === '/api/weight' ? of({ weight: 89.6 } as WeightResponse) : of()
- );
-
- const service = new WeightService(mockHttpClient);
-
- return {
- service,
- };
+function setup() {
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule]
+ });
+ const service = TestBed.inject(WeightService);
+ const httpTestingController = TestBed.inject(HttpTestingController)
+ return {service, httpTestingController}
}
describe('WeightService', () => {
describe('getWeight', () => {
- it('should return weight', async () => {
- const { service } = await setup();
- const weight = await new Promise((resolve) =>
- service.getWeight().subscribe(resolve)
- );
- expect(weight).toEqual(89.6);
+ it('should return weight', () => {
+ const { service, httpTestingController } = setup();
+ service.getWeight().subscribe(weight => {
+ expect(weight).toEqual(89.6);
+ })
+ httpTestingController.expectOne('/api/weight').flush({ weight: 89.6 } as WeightResponse)
+ httpTestingController.verify();
});
});
});
diff --git a/client/src/app/withings.service.spec.ts b/client/src/app/withings.service.spec.ts
index 689d9c8..4781567 100644
--- a/client/src/app/withings.service.spec.ts
+++ b/client/src/app/withings.service.spec.ts
@@ -1,49 +1,42 @@
-import { Observable, of, throwError } from 'rxjs';
+import {
+ HttpClientTestingModule,
+ HttpTestingController,
+} from '@angular/common/http/testing';
+import { TestBed } from '@angular/core/testing';
import { WithingsService } from './withings.service';
-import { HttpErrorResponse } from '@angular/common/http';
-async function setup(
- { $sync }: { $sync: Observable } = { $sync: of(undefined) }
-) {
- const locationAssign = jasmine.createSpy();
- const mockHttpClient = jasmine.createSpyObj('HttpClient', ['post']);
-
- mockHttpClient.post.and.callFake((url: string) =>
- url === '/api/withings/sync' ? $sync : of()
- );
-
- const service = new WithingsService(mockHttpClient, { assign: locationAssign } as unknown as Location );
-
- return {
- service,
- locationAssign
- };
+function setup() {
+ const mockLocation = jasmine.createSpyObj(['assign']) as Location;
+ TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [{ provide: Location, useValue: mockLocation }],
+ });
+ const service = TestBed.inject(WithingsService);
+ const httpTestingController = TestBed.inject(HttpTestingController);
+ return { service, httpTestingController, mockLocation };
}
describe('WithingsService', () => {
describe('sync', () => {
- it('should return undefined', async () => {
- const { service } = await setup();
- const response = await new Promise((resolve) =>
- service.sync().subscribe(resolve)
- );
- expect(response).toBe(undefined);
+ it('should sync with Withings', () => {
+ const { service, httpTestingController } = setup();
+ service.sync().subscribe();
+ const request = httpTestingController.expectOne('/api/withings/sync');
+ request.flush({});
+ expect(request.request.method).toBe('POST');
+ httpTestingController.verify();
});
it('should open authorization page if 401 is returned', async () => {
- const { service, locationAssign } = await setup({
- $sync: throwError(
- () =>
- new HttpErrorResponse({
- status: 401,
- error: { _links: { oauth2Login: { href: '/withings/auth' } } },
- })
- ),
- });
- const response = await new Promise((resolve) =>
- service.sync().subscribe(resolve)
+ const { service, mockLocation, httpTestingController } = setup();
+ service.sync().subscribe();
+ const request = httpTestingController.expectOne('/api/withings/sync');
+ request.flush(
+ { _links: { oauth2Login: { href: '/withings/auth' } } },
+ { status: 401, statusText: 'Unauthorized' }
);
- expect(locationAssign).toHaveBeenCalledWith('/withings/auth')
+ expect(mockLocation.assign).toHaveBeenCalledWith('/withings/auth');
+ httpTestingController.verify();
});
});
});