diff --git a/src/Squidex/Config/Web/WebUsages.cs b/src/Squidex/Config/Web/WebUsages.cs index 4b74771f7..0de9c3638 100644 --- a/src/Squidex/Config/Web/WebUsages.cs +++ b/src/Squidex/Config/Web/WebUsages.cs @@ -24,15 +24,22 @@ namespace Squidex.Config.Web { var response = context.Context.Response; + var headers = response.GetTypedHeaders(); + if (!string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase)) { - var headers = response.GetTypedHeaders(); - headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromDays(60) }; } + else + { + headers.CacheControl = new CacheControlHeaderValue + { + NoCache = true + }; + } } }); } diff --git a/src/Squidex/app/framework/angular/name.pipe.spec.ts b/src/Squidex/app/framework/angular/name.pipe.spec.ts index 18c36d138..90c08f177 100644 --- a/src/Squidex/app/framework/angular/name.pipe.spec.ts +++ b/src/Squidex/app/framework/angular/name.pipe.spec.ts @@ -18,7 +18,7 @@ describe('DisplayNamePipe', () => { it('should return value from nested object', () => { const pipe = new DisplayNamePipe(); - expect(pipe.transform({ propertes: { label: 'name' } }, 'properties.label')).toBe('name'); + expect(pipe.transform({ properties: { label: 'name' } }, 'properties.label')).toBe('name'); }); it('should return label if value is valid', () => { diff --git a/src/Squidex/app/framework/angular/validators.spec.ts b/src/Squidex/app/framework/angular/validators.spec.ts index 342710ac1..4b0b3f0d1 100644 --- a/src/Squidex/app/framework/angular/validators.spec.ts +++ b/src/Squidex/app/framework/angular/validators.spec.ts @@ -5,7 +5,7 @@ * Copyright (c) Sebastian Stehle. All rights reserved */ -import { FormControl } from '@angular/forms'; +import { FormControl, Validators } from '@angular/forms'; import { ValidatorsEx } from './../'; @@ -16,12 +16,18 @@ describe('Validators', () => { validateBetween = ValidatorsEx.between(10, 200); }); + it('should return null validator if no min value or max value', () => { + const validator = ValidatorsEx.between(undefined, undefined); + + expect(validator).toBe(Validators.nullValidator); + }); + it('should return error when not a number', () => { const input = new FormControl('text'); const error = validateBetween(input); - expect(error.validNumber).toBeFalsy(); + expect(error.validnumber).toBeFalsy(); }); it('should return error if less than minimum setting', () => { @@ -29,7 +35,7 @@ describe('Validators', () => { const error = validateBetween(input); - expect(error.minValue).toBeDefined(); + expect(error.minvalue).toBeDefined(); }); it('should return error if greater than maximum setting', () => { @@ -37,7 +43,7 @@ describe('Validators', () => { const error = validateBetween(input); - expect(error.maxValue).toBeDefined(); + expect(error.maxvalue).toBeDefined(); }); it('should return empty value when value is valid', () => { @@ -45,6 +51,22 @@ describe('Validators', () => { const error = validateBetween(input); - expect(error).toBeDefined(); + expect(error).toEqual({}); + }); + + it('should return empty value if value is in allowed values', () => { + const input = new FormControl(10); + + const error = ValidatorsEx.validValues([10, 20, 30])(input); + + expect(error).toEqual({}); + }); + + it('should return error if value is not in allowed values', () => { + const input = new FormControl(50); + + const error = ValidatorsEx.validValues([10, 20, 30])(input); + + expect(error.validvalues).toBeDefined(); }); }); diff --git a/src/Squidex/app/framework/angular/validators.ts b/src/Squidex/app/framework/angular/validators.ts index 7a97378f6..3d75936e5 100644 --- a/src/Squidex/app/framework/angular/validators.ts +++ b/src/Squidex/app/framework/angular/validators.ts @@ -5,7 +5,11 @@ * Copyright (c) Sebastian Stehle. All rights reserved */ -import { AbstractControl, ValidatorFn, Validators } from '@angular/forms'; +import { + AbstractControl, + ValidatorFn, + Validators +} from '@angular/forms'; export class ValidatorsEx { public static pattern(pattern: string | RegExp, message: string | undefined = undefined): ValidatorFn { diff --git a/src/Squidex/app/framework/services/panel.service.spec.ts b/src/Squidex/app/framework/services/panel.service.spec.ts new file mode 100644 index 000000000..34e061c86 --- /dev/null +++ b/src/Squidex/app/framework/services/panel.service.spec.ts @@ -0,0 +1,76 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { PanelService, PanelServiceFactory } from './../'; + +interface Styling { element: any; property: string; value: string; } + +describe('PanelService', () => { + it('should instantiate from factory', () => { + const panelService = PanelServiceFactory(); + + expect(panelService).toBeDefined(); + }); + + it('should instantiate', () => { + const panelService = new PanelService(); + + expect(panelService).toBeDefined(); + }); + + it('should update elements with renderer service', () => { + let styles: Styling[] = []; + + const renderer = { + setElementStyle: (element: any, property: string, value: string) => { + styles.push({element, property, value}); + } + }; + + const panelService = new PanelService(); + + const element1 = { + getBoundingClientRect: () => { + return { width: 100 }; + } + }; + + const element2 = { + getBoundingClientRect: () => { + return { width: 200 }; + } + }; + + const element3 = { + getBoundingClientRect: () => { + return { width: 300 }; + } + }; + + let numPublished = 0; + panelService.changed.subscribe(() => { + numPublished++; + }); + + panelService.push(element1, renderer); + panelService.push(element2, renderer); + panelService.push(element3, renderer); + + styles = []; + + panelService.pop(element3, renderer); + + expect(styles).toEqual([ + { element: element1, property: 'left', value: '0px' }, + { element: element1, property: 'z-index', value: '20' }, + { element: element2, property: 'left', value: '100px' }, + { element: element2, property: 'z-index', value: '10' } + ]); + + expect(numPublished).toBe(4); + }); +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts b/src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts new file mode 100644 index 000000000..ea7d85a63 --- /dev/null +++ b/src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts @@ -0,0 +1,100 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { IMock, Mock } from 'typemoq'; +import { Observable } from 'rxjs'; + +import { SchemasService } from 'shared'; + +import { ResolvePublishedSchemaGuard } from './resolve-published-schema.guard'; +import { RouterMockup } from './router-mockup'; + +describe('ResolveSchemaGuard', () => { + const route = { + params: { + appName: 'my-app' + }, + parent: { + params: { + schemaName: 'my-schema' + } + } + }; + + let appsStore: IMock; + + beforeEach(() => { + appsStore = Mock.ofType(SchemasService); + }); + + it('should navigate to 404 page if schema is not found', (done) => { + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.of(null)); + const router = new RouterMockup(); + + const guard = new ResolvePublishedSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBeFalsy(); + expect(router.lastNavigation).toEqual(['/404']); + + done(); + }); + }); + + it('should navigate to 404 page if schema loading fails', (done) => { + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.throw(null)); + const router = new RouterMockup(); + + const guard = new ResolvePublishedSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBeFalsy(); + expect(router.lastNavigation).toEqual(['/404']); + + done(); + }); + }); + + it('should navigate to 404 page if schema not published', (done) => { + const schema = { isPublished: false }; + + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.of(schema)); + const router = new RouterMockup(); + + const guard = new ResolvePublishedSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBeFalsy(); + expect(router.lastNavigation).toEqual(['/404']); + + done(); + }); + }); + + it('should return schema if loading succeeded', (done) => { + const schema = { isPublished: true }; + + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.of(schema)); + const router = new RouterMockup(); + + const guard = new ResolvePublishedSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBe(schema); + + done(); + }); + }); +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/guards/resolve-published-schema.guard.ts b/src/Squidex/app/shared/guards/resolve-published-schema.guard.ts index 5f2686872..bd19dc7ff 100644 --- a/src/Squidex/app/shared/guards/resolve-published-schema.guard.ts +++ b/src/Squidex/app/shared/guards/resolve-published-schema.guard.ts @@ -27,11 +27,15 @@ export class ResolvePublishedSchemaGuard implements Resolve { .then(dto => { if (!dto || !dto.isPublished) { this.router.navigate(['/404']); + + return null; } return dto; }).catch(() => { this.router.navigate(['/404']); + + return null; }); return result; diff --git a/src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts b/src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts new file mode 100644 index 000000000..b95ffef99 --- /dev/null +++ b/src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts @@ -0,0 +1,82 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { IMock, Mock } from 'typemoq'; +import { Observable } from 'rxjs'; + +import { SchemasService } from 'shared'; + +import { ResolveSchemaGuard } from './resolve-schema.guard'; +import { RouterMockup } from './router-mockup'; + +describe('ResolveSchemaGuard', () => { + const route = { + params: { + appName: 'my-app' + }, + parent: { + params: { + schemaName: 'my-schema' + } + } + }; + + let appsStore: IMock; + + beforeEach(() => { + appsStore = Mock.ofType(SchemasService); + }); + + it('should navigate to 404 page if schema is not found', (done) => { + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.of(null)); + const router = new RouterMockup(); + + const guard = new ResolveSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBeFalsy(); + expect(router.lastNavigation).toEqual(['/404']); + + done(); + }); + }); + + it('should navigate to 404 page if schema loading fails', (done) => { + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.throw(null)); + const router = new RouterMockup(); + + const guard = new ResolveSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBeFalsy(); + expect(router.lastNavigation).toEqual(['/404']); + + done(); + }); + }); + + it('should return schema if loading succeeded', (done) => { + const schema = {}; + + appsStore.setup(x => x.getSchema('my-app', 'my-schema')) + .returns(() => Observable.of(schema)); + const router = new RouterMockup(); + + const guard = new ResolveSchemaGuard(appsStore.object, router); + + guard.resolve(route, null) + .then(result => { + expect(result).toBe(schema); + + done(); + }); + }); +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/services/app-clients.service.spec.ts b/src/Squidex/app/shared/services/app-clients.service.spec.ts index 7eea6edb2..0068f24ee 100644 --- a/src/Squidex/app/shared/services/app-clients.service.spec.ts +++ b/src/Squidex/app/shared/services/app-clients.service.spec.ts @@ -5,11 +5,12 @@ * Copyright (c) Sebastian Stehle. All rights reserved */ -import { Response, ResponseOptions } from '@angular/http'; +import { Http, Response, ResponseOptions } from '@angular/http'; import { Observable } from 'rxjs'; import { It, IMock, Mock, Times } from 'typemoq'; import { + AccessTokenDto, ApiUrlConfig, AppClientDto, AppClientsService, @@ -22,10 +23,13 @@ import { describe('AppClientsService', () => { let authService: IMock; let appClientsService: AppClientsService; + let http: IMock; beforeEach(() => { + http = Mock.ofType(Http); + authService = Mock.ofType(AuthService); - appClientsService = new AppClientsService(authService.object, new ApiUrlConfig('http://service/p/'), null); + appClientsService = new AppClientsService(authService.object, new ApiUrlConfig('http://service/p/'), http.object); }); it('should make get request to get app clients', () => { @@ -123,4 +127,31 @@ describe('AppClientsService', () => { authService.verifyAll(); }); + + it('should make form request to create token', () => { + const body = 'grant_type=client_credentials&scope=squidex-api&client_id=my-app:myClientId&client_secret=mySecret'; + + http.setup(x => x.post('http://service/p/identity-server/connect/token', It.isValue(body), It.isAny())) + .returns(() => Observable.of( + new Response( + new ResponseOptions({ + body: { + access_token: 'token1', token_type: 'type1' + } + }) + ) + )) + .verifiable(Times.once()); + + let accessTokenDto: AccessTokenDto = null; + + appClientsService.createToken('my-app', new AppClientDto('myClientId', null, 'mySecret', null)).subscribe(result => { + accessTokenDto = result; + }); + + expect(accessTokenDto).toEqual( + new AccessTokenDto('token1', 'type1')); + + http.verifyAll(); + }); }); \ No newline at end of file diff --git a/src/Squidex/app/shared/services/app-contributors.service.spec.ts b/src/Squidex/app/shared/services/app-contributors.service.spec.ts index b14c2dc54..bfb49ee21 100644 --- a/src/Squidex/app/shared/services/app-contributors.service.spec.ts +++ b/src/Squidex/app/shared/services/app-contributors.service.spec.ts @@ -35,7 +35,7 @@ describe('AppContributorsService', () => { permission: 'Owner' }, { contributorId: '456', - permission: 'Editor' + permission: 'Owner' }] }) ) @@ -51,7 +51,7 @@ describe('AppContributorsService', () => { expect(contributors).toEqual( [ new AppContributorDto('123', 'Owner'), - new AppContributorDto('456', 'Editor') + new AppContributorDto('456', 'Owner') ]); authService.verifyAll(); diff --git a/src/Squidex/app/shared/services/apps.service.spec.ts b/src/Squidex/app/shared/services/apps.service.spec.ts index 5cf33db4d..37216fcfe 100644 --- a/src/Squidex/app/shared/services/apps.service.spec.ts +++ b/src/Squidex/app/shared/services/apps.service.spec.ts @@ -42,7 +42,7 @@ describe('AppsService', () => { }, { id: '456', name: 'name2', - permission: 'Editor', + permission: 'Owner', created: '2017-01-01', lastModified: '2017-02-02' }] @@ -59,7 +59,7 @@ describe('AppsService', () => { expect(apps).toEqual([ new AppDto('123', 'name1', 'Owner', DateTime.parseISO('2016-01-01'), DateTime.parseISO('2016-02-02')), - new AppDto('456', 'name2', 'Editor', DateTime.parseISO('2017-01-01'), DateTime.parseISO('2017-02-02')) + new AppDto('456', 'name2', 'Owner', DateTime.parseISO('2017-01-01'), DateTime.parseISO('2017-02-02')) ]); authService.verifyAll(); diff --git a/src/Squidex/app/shared/services/contents.service.spec.ts b/src/Squidex/app/shared/services/contents.service.spec.ts new file mode 100644 index 000000000..abf7cdd5c --- /dev/null +++ b/src/Squidex/app/shared/services/contents.service.spec.ts @@ -0,0 +1,158 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Sebastian Stehle. All rights reserved + */ + +import { Response, ResponseOptions } from '@angular/http'; +import { Observable } from 'rxjs'; +import { It, IMock, Mock, Times } from 'typemoq'; + +import { + ApiUrlConfig, + AuthService, + EntityCreatedDto, + ContentDto, + ContentsService, + DateTime +} from './../'; + +describe('ContentsService', () => { + let authService: IMock; + let contentsService: ContentsService; + + beforeEach(() => { + authService = Mock.ofType(AuthService); + contentsService = new ContentsService(authService.object, new ApiUrlConfig('http://service/p/')); + }); + + it('should make get request to get content1', () => { + authService.setup(x => x.authGet('http://service/p/api/content/my-app/my-schema?take=17&skip=13&query=my-query&nonPublished=true')) + .returns(() => Observable.of( + new Response( + new ResponseOptions({ + body: [{ + id: 'id1', + isPublished: true, + created: '2016-12-12T10:10', + createdBy: 'Created1', + lastModified: '2017-12-12T10:10', + lastModifiedBy: 'LastModifiedBy1', + data: {} + }, { + id: 'id2', + isPublished: true, + created: '2016-10-12T10:10', + createdBy: 'Created2', + lastModified: '2017-10-12T10:10', + lastModifiedBy: 'LastModifiedBy2', + data: {} + }] + }) + ) + )) + .verifiable(Times.once()); + + let contents: ContentDto[] = null; + + contentsService.getContents('my-app', 'my-schema', 17, 13, 'my-query').subscribe(result => { + contents = result; + }).unsubscribe(); + + expect(contents).toEqual([ + new ContentDto('id1', true, 'Created1', 'LastModifiedBy1', DateTime.parseISO_UTC('2016-12-12T10:10'), DateTime.parseISO_UTC('2017-12-12T10:10'), {}), + new ContentDto('id2', true, 'Created2', 'LastModifiedBy2', DateTime.parseISO_UTC('2016-10-12T10:10'), DateTime.parseISO_UTC('2017-10-12T10:10'), {}) + ]); + + authService.verifyAll(); + }); + + it('should make get request to get content', () => { + authService.setup(x => x.authGet('http://service/p/api/content/my-app/my-schema/content1')) + .returns(() => Observable.of( + new Response( + new ResponseOptions({ + body: { + id: 'id1', + isPublished: true, + created: '2016-12-12T10:10', + createdBy: 'Created1', + lastModified: '2017-12-12T10:10', + lastModifiedBy: 'LastModifiedBy1', + data: {} + } + }) + ) + )) + .verifiable(Times.once()); + + let content: ContentDto = null; + + contentsService.getContent('my-app', 'my-schema', 'content1').subscribe(result => { + content = result; + }).unsubscribe(); + + expect(content).toEqual( + new ContentDto('id1', true, 'Created1', 'LastModifiedBy1', DateTime.parseISO_UTC('2016-12-12T10:10'), DateTime.parseISO_UTC('2017-12-12T10:10'), {})); + + authService.verifyAll(); + }); + + it('should make post request to create content', () => { + const dto = {}; + + authService.setup(x => x.authPost('http://service/p/api/content/my-app/my-schema', It.isValue(dto))) + .returns(() => Observable.of( + new Response( + new ResponseOptions({ + body: { + id: 'content1' + } + }) + ) + )) + .verifiable(Times.once()); + + let created: EntityCreatedDto = null; + + contentsService.postContent('my-app', 'my-schema', dto).subscribe(result => { + created = result; + }); + + expect(created).toEqual( + new EntityCreatedDto('content1')); + + authService.verifyAll(); + }); + + it('should make put request to update content', () => { + const dto = {}; + + authService.setup(x => x.authPut('http://service/p/api/content/my-app/my-schema/content1', It.isValue(dto))) + .returns(() => Observable.of( + new Response( + new ResponseOptions() + ) + )) + .verifiable(Times.once()); + + contentsService.putContent('my-app', 'my-schema', 'content1', dto); + + authService.verifyAll(); + }); + + it('should make delete request to delete content', () => { + authService.setup(x => x.authDelete('http://service/p/api/content/my-app/my-schema/content1')) + .returns(() => Observable.of( + new Response( + new ResponseOptions() + ) + )) + .verifiable(Times.once()); + + contentsService.deleteContent('my-app', 'my-schema', 'content1'); + + authService.verifyAll(); + }); +}); \ No newline at end of file diff --git a/src/Squidex/app/shared/services/contents.service.ts b/src/Squidex/app/shared/services/contents.service.ts index 35e9097c5..c5d5727af 100644 --- a/src/Squidex/app/shared/services/contents.service.ts +++ b/src/Squidex/app/shared/services/contents.service.ts @@ -40,7 +40,7 @@ export class ContentsService { } public getContents(appName: string, schemaName: string, take: number, skip: number, query: string): Observable { - const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/?query=${query}&take=${take}&skip=${skip}&query=${query}&nonPublished=true`); + const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?take=${take}&skip=${skip}&query=${query}&nonPublished=true`); return this.authService.authGet(url) .map(response => response.json()) @@ -53,8 +53,8 @@ export class ContentsService { item.isPublished, item.createdBy, item.lastModifiedBy, - DateTime.parseISO(item.created), - DateTime.parseISO(item.lastModified), + DateTime.parseISO_UTC(item.created), + DateTime.parseISO_UTC(item.lastModified), item.data); }); }) @@ -62,7 +62,7 @@ export class ContentsService { } public getContent(appName: string, schemaName: string, id: string): Observable { - const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); + const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); return this.authService.authGet(url) .map(response => response.json()) @@ -72,15 +72,15 @@ export class ContentsService { response.isPublished, response.createdBy, response.lastModifiedBy, - DateTime.parseISO(response.created), - DateTime.parseISO(response.lastModified), + DateTime.parseISO_UTC(response.created), + DateTime.parseISO_UTC(response.lastModified), response.data); }) .catchError('Failed to load content. Please reload.'); } public postContent(appName: string, schemaName: string, dto: any): Observable { - const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/`); + const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}`); return this.authService.authPost(url, dto) .map(response => response.json()) @@ -91,16 +91,16 @@ export class ContentsService { } public putContent(appName: string, schemaName: string, id: string, dto: any): Observable { - const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); + const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); return this.authService.authPut(url, dto) .catchError('Failed to update Content. Please reload.'); } - public deleteContent(appName: string, schemaName: string, id: string, dto: any): Observable { - const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`); + public deleteContent(appName: string, schemaName: string, id: string): Observable { + const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}`); - return this.authService.authDelete(url, dto) + return this.authService.authDelete(url) .catchError('Failed to delete Content. Please reload.'); } } \ No newline at end of file diff --git a/src/Squidex/app/shared/services/users-provider.service.spec.ts b/src/Squidex/app/shared/services/users-provider.service.spec.ts index 26a5e1ae4..fb976020c 100644 --- a/src/Squidex/app/shared/services/users-provider.service.spec.ts +++ b/src/Squidex/app/shared/services/users-provider.service.spec.ts @@ -31,8 +31,7 @@ describe('UsersProviderService', () => { const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image'); usersService.setup(x => x.getUser('123')) - .returns(() => Observable.of(user)) - .verifiable(Times.once()); + .returns(() => Observable.of(user)).verifiable(Times.once()); let resultingUser: UserDto = null; @@ -49,8 +48,7 @@ describe('UsersProviderService', () => { const user = new UserDto('123', 'mail@domain.com', 'User1', 'path/to/image'); usersService.setup(x => x.getUser('123')) - .returns(() => Observable.of(user)) - .verifiable(Times.once()); + .returns(() => Observable.of(user)).verifiable(Times.once()); usersProviderService.getUser('123'); @@ -72,8 +70,7 @@ describe('UsersProviderService', () => { .returns(() => new Profile({ profile: { sub: '123'}})); usersService.setup(x => x.getUser('123')) - .returns(() => Observable.of(user)) - .verifiable(Times.once()); + .returns(() => Observable.of(user)).verifiable(Times.once()); let resultingUser: UserDto = null; @@ -85,4 +82,22 @@ describe('UsersProviderService', () => { usersService.verifyAll(); }); + + it('Should return invalid user when not found', () => { + authService.setup(x => x.user) + .returns(() => new Profile({ profile: { sub: '123'}})); + + usersService.setup(x => x.getUser('123')) + .returns(() => Observable.throw('NOT FOUND')).verifiable(Times.once()); + + let resultingUser: UserDto = null; + + usersProviderService.getUser('123').subscribe(result => { + resultingUser = result; + }).unsubscribe(); + + expect(resultingUser).toEqual(new UserDto('NOT FOUND', 'NOT FOUND', 'NOT FOUND', '')); + + usersService.verifyAll(); + }); }); \ No newline at end of file