Browse Source

More tests

pull/1/head
Sebastian 9 years ago
parent
commit
22f5aa8f6f
  1. 11
      src/Squidex/Config/Web/WebUsages.cs
  2. 2
      src/Squidex/app/framework/angular/name.pipe.spec.ts
  3. 32
      src/Squidex/app/framework/angular/validators.spec.ts
  4. 6
      src/Squidex/app/framework/angular/validators.ts
  5. 76
      src/Squidex/app/framework/services/panel.service.spec.ts
  6. 100
      src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts
  7. 4
      src/Squidex/app/shared/guards/resolve-published-schema.guard.ts
  8. 82
      src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts
  9. 35
      src/Squidex/app/shared/services/app-clients.service.spec.ts
  10. 4
      src/Squidex/app/shared/services/app-contributors.service.spec.ts
  11. 4
      src/Squidex/app/shared/services/apps.service.spec.ts
  12. 158
      src/Squidex/app/shared/services/contents.service.spec.ts
  13. 22
      src/Squidex/app/shared/services/contents.service.ts
  14. 27
      src/Squidex/app/shared/services/users-provider.service.spec.ts

11
src/Squidex/Config/Web/WebUsages.cs

@ -24,15 +24,22 @@ namespace Squidex.Config.Web
{
var response = context.Context.Response;
if (!string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase))
{
var headers = response.GetTypedHeaders();
if (!string.Equals(response.ContentType, "text/html", StringComparison.OrdinalIgnoreCase))
{
headers.CacheControl = new CacheControlHeaderValue
{
MaxAge = TimeSpan.FromDays(60)
};
}
else
{
headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true
};
}
}
});
}

2
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', () => {

32
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 = <any>ValidatorsEx.validValues([10, 20, 30])(input);
expect(error.validvalues).toBeDefined();
});
});

6
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 {

76
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, <any>renderer);
panelService.push(element2, <any>renderer);
panelService.push(element3, <any>renderer);
styles = [];
panelService.pop(element3, <any>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);
});
});

100
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<SchemasService>;
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, <any>router);
guard.resolve(<any>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, <any>router);
guard.resolve(<any>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, <any>router);
guard.resolve(<any>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, <any>router);
guard.resolve(<any>route, null)
.then(result => {
expect(result).toBe(schema);
done();
});
});
});

4
src/Squidex/app/shared/guards/resolve-published-schema.guard.ts

@ -27,11 +27,15 @@ export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> {
.then(dto => {
if (!dto || !dto.isPublished) {
this.router.navigate(['/404']);
return null;
}
return dto;
}).catch(() => {
this.router.navigate(['/404']);
return null;
});
return result;

82
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<SchemasService>;
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, <any>router);
guard.resolve(<any>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, <any>router);
guard.resolve(<any>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, <any>router);
guard.resolve(<any>route, null)
.then(result => {
expect(result).toBe(schema);
done();
});
});
});

35
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<AuthService>;
let appClientsService: AppClientsService;
let http: IMock<Http>;
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();
});
});

4
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();

4
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();

158
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<AuthService>;
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();
});
});

22
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<ContentDto[]> {
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<ContentDto> {
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<EntityCreatedDto> {
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<any> {
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<any> {
const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}/${id}/`);
public deleteContent(appName: string, schemaName: string, id: string): Observable<any> {
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.');
}
}

27
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(<any>{ 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(<any>{ 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();
});
});
Loading…
Cancel
Save