Browse Source

A lot more tests.

pull/1/head
Sebastian 9 years ago
parent
commit
a3b65bb5dd
  1. 66
      src/Squidex.Core/Contents/ContentData.cs
  2. 5
      src/Squidex.Core/Schemas/Schema.cs
  3. 8
      src/Squidex.Store.MongoDb/Apps/MongoAppEntity.cs
  4. 8
      src/Squidex/Controllers/ContentApi/ContentsController.cs
  5. 13
      src/Squidex/Controllers/ControllerBase.cs
  6. 2
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts
  7. 2
      src/Squidex/app/framework/angular/control-errors.component.ts
  8. 5
      src/Squidex/app/framework/angular/copy.directive.ts
  9. 2
      src/Squidex/app/framework/angular/http-utils.ts
  10. 3
      src/Squidex/app/framework/angular/modal-view.directive.ts
  11. 118
      src/Squidex/app/framework/angular/validators.spec.ts
  12. 16
      src/Squidex/app/framework/angular/validators.ts
  13. 2
      src/Squidex/app/framework/services/notification.service.spec.ts
  14. 6
      src/Squidex/app/framework/services/title.service.spec.ts
  15. 4
      src/Squidex/app/framework/services/title.service.ts
  16. 10
      src/Squidex/app/framework/utils/string-helper.spec.ts
  17. 6
      src/Squidex/app/shared/guards/app-must-exist.guard.spec.ts
  18. 4
      src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts
  19. 4
      src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts
  20. 18
      src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts
  21. 8
      src/Squidex/app/shared/guards/resolve-published-schema.guard.ts
  22. 16
      src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts
  23. 12
      src/Squidex/app/shared/guards/resolve-schema.guard.ts
  24. 14
      src/Squidex/app/shared/services/app-clients.service.spec.ts
  25. 10
      src/Squidex/app/shared/services/app-contributors.service.spec.ts
  26. 10
      src/Squidex/app/shared/services/app-languages.service.spec.ts
  27. 14
      src/Squidex/app/shared/services/apps-store.service.spec.ts
  28. 16
      src/Squidex/app/shared/services/apps.service.spec.ts
  29. 14
      src/Squidex/app/shared/services/contents.service.spec.ts
  30. 2
      src/Squidex/app/shared/services/history.service.spec.ts
  31. 2
      src/Squidex/app/shared/services/languages.service.spec.ts
  32. 334
      src/Squidex/app/shared/services/schemas.service.spec.ts
  33. 66
      src/Squidex/app/shared/services/schemas.service.ts
  34. 8
      src/Squidex/app/shared/services/users-provider.service.spec.ts
  35. 6
      src/Squidex/app/shared/services/users.service.spec.ts
  36. 123
      tests/Squidex.Core.Tests/Contents/ContentDataTests.cs

66
src/Squidex.Core/Contents/ContentData.cs

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
namespace Squidex.Core.Contents namespace Squidex.Core.Contents
@ -40,14 +41,71 @@ namespace Squidex.Core.Contents
return new ContentData(Fields.Add(fieldName, data)); return new ContentData(Fields.Add(fieldName, data));
} }
public static ContentData Create(Dictionary<string, Dictionary<string, JToken>> raw) public static ContentData FromApiRequest(Dictionary<string, Dictionary<string, JToken>> request)
{ {
return new ContentData(raw.ToImmutableDictionary(x => x.Key, x => new ContentFieldData(x.Value.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)), StringComparer.OrdinalIgnoreCase)); Guard.NotNull(request, nameof(request));
return new ContentData(request.ToImmutableDictionary(x => x.Key, x => new ContentFieldData(x.Value.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)), StringComparer.OrdinalIgnoreCase));
}
public Dictionary<string, Dictionary<string, JToken>> ToApiResponse(Schema schema, IReadOnlyCollection<Language> languages, Language masterLanguage)
{
Guard.NotNull(schema, nameof(schema));
Guard.NotNull(languages, nameof(languages));
Guard.NotNull(masterLanguage, nameof(masterLanguage));
var invariantCode = Language.Invariant.Iso2Code;
var result = new Dictionary<string, Dictionary<string, JToken>>();
foreach (var fieldValue in fields)
{
Field field;
if (!schema.FieldsByName.TryGetValue(fieldValue.Key, out field))
{
continue;
}
var fieldResult = new Dictionary<string, JToken>();
var fieldValues = fieldValue.Value.ValueByLanguage;
if (field.RawProperties.IsLocalizable)
{
foreach (var language in languages)
{
var languageCode = language.Iso2Code;
JToken value;
if (fieldValues.TryGetValue(languageCode, out value))
{
fieldResult.Add(languageCode, value);
}
} }
}
else
{
JToken value;
public Dictionary<string, Dictionary<string, JToken>> ToRaw() if (fieldValues.TryGetValue(invariantCode, out value))
{
fieldResult.Add(invariantCode, value);
}
else if (fieldValues.TryGetValue(masterLanguage.Iso2Code, out value))
{ {
return fields.ToDictionary(x => x.Key, x => x.Value.ValueByLanguage.ToDictionary(y => y.Key, y => y.Value)); fieldResult.Add(invariantCode, value);
}
else if (fieldValues.Count > 0)
{
fieldResult.Add(invariantCode, fieldValues.Values.First());
}
}
result.Add(field.Name, fieldResult);
}
return result;
} }
} }
} }

5
src/Squidex.Core/Schemas/Schema.cs

@ -44,6 +44,11 @@ namespace Squidex.Core.Schemas
get { return fieldsById; } get { return fieldsById; }
} }
public ImmutableDictionary<string, Field> FieldsByName
{
get { return fieldsByName; }
}
public SchemaProperties Properties public SchemaProperties Properties
{ {
get { return properties; } get { return properties; }

8
src/Squidex.Store.MongoDb/Apps/MongoAppEntity.cs

@ -37,19 +37,19 @@ namespace Squidex.Store.MongoDb.Apps
[BsonElement] [BsonElement]
public Dictionary<string, MongoAppContributorEntity> Contributors { get; set; } public Dictionary<string, MongoAppContributorEntity> Contributors { get; set; }
IEnumerable<IAppClientEntity> IAppEntity.Clients IReadOnlyCollection<IAppClientEntity> IAppEntity.Clients
{ {
get { return Clients.Values; } get { return Clients.Values; }
} }
IEnumerable<IAppContributorEntity> IAppEntity.Contributors IReadOnlyCollection<IAppContributorEntity> IAppEntity.Contributors
{ {
get { return Contributors.Values; } get { return Contributors.Values; }
} }
IEnumerable<Language> IAppEntity.Languages IReadOnlyCollection<Language> IAppEntity.Languages
{ {
get { return Languages.Select(Language.GetLanguage); } get { return Languages.Select(Language.GetLanguage).ToList(); }
} }
Language IAppEntity.MasterLanguage Language IAppEntity.MasterLanguage

8
src/Squidex/Controllers/ContentApi/ContentsController.cs

@ -65,7 +65,7 @@ namespace Squidex.Controllers.ContentApi
if (x.Data != null) if (x.Data != null)
{ {
itemModel.Data = x.Data.ToRaw(); itemModel.Data = x.Data.ToApiResponse(schemaEntity.Schema, App.Languages, App.MasterLanguage);
} }
return itemModel; return itemModel;
@ -97,7 +97,7 @@ namespace Squidex.Controllers.ContentApi
if (content.Data != null) if (content.Data != null)
{ {
model.Data = content.Data.ToRaw(); model.Data = content.Data.ToApiResponse(schemaEntity.Schema, App.Languages, App.MasterLanguage);
} }
return Ok(model); return Ok(model);
@ -107,7 +107,7 @@ namespace Squidex.Controllers.ContentApi
[Route("content/{app}/{name}/")] [Route("content/{app}/{name}/")]
public async Task<IActionResult> PostContent([FromBody] Dictionary<string, Dictionary<string, JToken>> request) public async Task<IActionResult> PostContent([FromBody] Dictionary<string, Dictionary<string, JToken>> request)
{ {
var command = new CreateContent { Data = ContentData.Create(request), AggregateId = Guid.NewGuid() }; var command = new CreateContent { Data = ContentData.FromApiRequest(request), AggregateId = Guid.NewGuid() };
var context = await CommandBus.PublishAsync(command); var context = await CommandBus.PublishAsync(command);
var result = context.Result<Guid>(); var result = context.Result<Guid>();
@ -119,7 +119,7 @@ namespace Squidex.Controllers.ContentApi
[Route("content/{app}/{name}/{id}")] [Route("content/{app}/{name}/{id}")]
public async Task<IActionResult> PutContent(Guid id, [FromBody] Dictionary<string, Dictionary<string, JToken>> request) public async Task<IActionResult> PutContent(Guid id, [FromBody] Dictionary<string, Dictionary<string, JToken>> request)
{ {
var command = new UpdateContent { AggregateId = id, Data = ContentData.Create(request) }; var command = new UpdateContent { AggregateId = id, Data = ContentData.FromApiRequest(request) };
await CommandBus.PublishAsync(command); await CommandBus.PublishAsync(command);

13
src/Squidex/Controllers/ControllerBase.cs

@ -10,6 +10,7 @@ using System;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.CQRS.Commands;
using Squidex.Pipeline; using Squidex.Pipeline;
using Squidex.Read.Apps;
namespace Squidex.Controllers namespace Squidex.Controllers
{ {
@ -27,7 +28,7 @@ namespace Squidex.Controllers
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Guid AppId public IAppEntity App
{ {
get get
{ {
@ -38,7 +39,15 @@ namespace Squidex.Controllers
throw new InvalidOperationException("Not in a app context"); throw new InvalidOperationException("Not in a app context");
} }
return appFeature.App.Id; return appFeature.App;
}
}
public Guid AppId
{
get
{
return App.Id;
} }
} }
} }

2
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.ts

@ -86,7 +86,7 @@ export class SchemasPageComponent extends AppComponentBase implements OnDestroy,
const oldSchema = schemas.find(i => i.name === message.name); const oldSchema = schemas.find(i => i.name === message.name);
if (oldSchema) { if (oldSchema) {
const me = `subject:${this.authService.user.id}`; const me = `subject:${this.authService.user!.id}`;
const newSchema = const newSchema =
new SchemaDto( new SchemaDto(

2
src/Squidex/app/framework/angular/control-errors.component.ts

@ -46,7 +46,7 @@ export class ControlErrorsComponent implements OnChanges, OnInit {
@Input() @Input()
public submitted: boolean; public submitted: boolean;
public get errorMessages(): string[] { public get errorMessages(): string[] | null {
if (!this.control) { if (!this.control) {
return null; return null;
} }

5
src/Squidex/app/framework/angular/copy.directive.ts

@ -28,7 +28,10 @@ export class CopyDirective {
const prevSelectionEnd = element.selectionEnd; const prevSelectionEnd = element.selectionEnd;
element.focus(); element.focus();
if (element instanceof HTMLInputElement) {
element.setSelectionRange(0, element.value.length); element.setSelectionRange(0, element.value.length);
}
try { try {
document.execCommand('copy'); document.execCommand('copy');
@ -40,6 +43,8 @@ export class CopyDirective {
currentFocus.focus(); currentFocus.focus();
} }
if (element instanceof HTMLInputElement) {
element.setSelectionRange(prevSelectionStart, prevSelectionEnd); element.setSelectionRange(prevSelectionStart, prevSelectionEnd);
} }
}
} }

2
src/Squidex/app/framework/angular/http-utils.ts

@ -10,7 +10,7 @@ import { Observable } from 'rxjs';
export class EntityCreatedDto { export class EntityCreatedDto {
constructor( constructor(
public readonly id: string public readonly id: any
) { ) {
} }
} }

3
src/Squidex/app/framework/angular/modal-view.directive.ts

@ -62,10 +62,7 @@ export class ModalViewDirective implements OnChanges, OnInit, OnDestroy {
} }
public ngOnChanges() { public ngOnChanges() {
if (this.subscription) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
this.subscription = null;
}
if (this.modalView) { if (this.modalView) {
this.subscription = this.modalView.isOpen.subscribe(isOpen => { this.subscription = this.modalView.isOpen.subscribe(isOpen => {

118
src/Squidex/app/framework/angular/validators.spec.ts

@ -9,31 +9,33 @@ import { FormControl, Validators } from '@angular/forms';
import { ValidatorsEx } from './../'; import { ValidatorsEx } from './../';
describe('Validators', () => { describe('ValidatorsEx.between', () => {
let validateBetween: any;
beforeEach(() => {
validateBetween = ValidatorsEx.between(10, 200);
});
it('should return null validator if no min value or max value', () => { it('should return null validator if no min value or max value', () => {
const validator = ValidatorsEx.between(undefined, undefined); const validator = ValidatorsEx.between(undefined, undefined);
expect(validator).toBe(Validators.nullValidator); expect(validator).toBe(Validators.nullValidator);
}); });
it('should return empty value when value is valid', () => {
const input = new FormControl(4);
const error = <any>ValidatorsEx.between(1, 5)(input);
expect(error).toEqual({});
});
it('should return error when not a number', () => { it('should return error when not a number', () => {
const input = new FormControl('text'); const input = new FormControl('text');
const error = validateBetween(input); const error = <any>ValidatorsEx.between(1, 5)(input);
expect(error.validnumber).toBeFalsy(); expect(error.validnumber).toBeFalsy();
}); });
it('should return error if less than minimum setting', () => { it('should return error if less than minimum setting', () => {
const input = new FormControl(5); const input = new FormControl(-5);
const error = validateBetween(input); const error = <any>ValidatorsEx.between(1, 5)(input);
expect(error.minvalue).toBeDefined(); expect(error.minvalue).toBeDefined();
}); });
@ -41,17 +43,17 @@ describe('Validators', () => {
it('should return error if greater than maximum setting', () => { it('should return error if greater than maximum setting', () => {
const input = new FormControl(300); const input = new FormControl(300);
const error = validateBetween(input); const error = <any>ValidatorsEx.between(1, 5)(input);
expect(error.maxvalue).toBeDefined(); expect(error.maxvalue).toBeDefined();
}); });
});
it('should return empty value when value is valid', () => { describe('ValidatorsEx.validValues', () => {
const input = new FormControl(50); it('should return null validator if values not defined', () => {
const validator = ValidatorsEx.validValues(null!);
const error = validateBetween(input);
expect(error).toEqual({}); expect(validator).toBe(Validators.nullValidator);
}); });
it('should return empty value if value is in allowed values', () => { it('should return empty value if value is in allowed values', () => {
@ -70,3 +72,87 @@ describe('Validators', () => {
expect(error.validvalues).toBeDefined(); expect(error.validvalues).toBeDefined();
}); });
}); });
describe('ValidatorsEx.pattern', () => {
it('should return null validator if pattern not defined', () => {
const validator = ValidatorsEx.pattern(undefined!, undefined);
expect(validator).toBe(Validators.nullValidator);
});
it('should return empty value when value is valid pattern', () => {
const input = new FormControl('1234');
const error = ValidatorsEx.pattern(/^[0-9]{1,4}$/)(input);
expect(error).toEqual({});
});
it('should return empty value when value is null string', () => {
const input = new FormControl(null);
const error = ValidatorsEx.pattern(/^[0-9]{1,4}$/)(input);
expect(error).toEqual({});
});
it('should return empty value when value is empty string', () => {
const input = new FormControl('');
const error = ValidatorsEx.pattern(/^[0-9]{1,4}$/)(input);
expect(error).toEqual({});
});
it('should return error with message if value does not match pattern string', () => {
const input = new FormControl('abc');
const error = <any>ValidatorsEx.pattern('[0-9]{1,4}', 'My-Message')(input);
const expected: any = {
patternmessage: {
requiredPattern: '^[0-9]{1,4}$', actualValue: 'abc', message: 'My-Message'
}
};
expect(error).toEqual(expected);
});
it('should return error with message if value does not match pattern', () => {
const input = new FormControl('abc');
const error = <any>ValidatorsEx.pattern(/^[0-9]{1,4}$/, 'My-Message')(input);
const expected: any = {
patternmessage: {
requiredPattern: '/^[0-9]{1,4}$/', actualValue: 'abc', message: 'My-Message'
}
};
expect(error).toEqual(expected);
});
it('should return error without message if value does not match pattern string', () => {
const input = new FormControl('abc');
const error = <any>ValidatorsEx.pattern('[0-9]{1,4}')(input);
const expected: any = {
pattern: {
requiredPattern: '^[0-9]{1,4}$', actualValue: 'abc'
}
};
expect(error).toEqual(expected);
});
it('should return error without message if value does not match pattern', () => {
const input = new FormControl('abc');
const error = <any>ValidatorsEx.pattern(/^[0-9]{1,4}$/)(input);
const expected: any = {
pattern: {
requiredPattern: '/^[0-9]{1,4}$/', actualValue: 'abc'
}
};
expect(error).toEqual(expected);
});
});

16
src/Squidex/app/framework/angular/validators.ts

@ -11,8 +11,8 @@ import {
Validators Validators
} from '@angular/forms'; } from '@angular/forms';
export class ValidatorsEx { export module ValidatorsEx {
public static pattern(pattern: string | RegExp, message: string | undefined = undefined): ValidatorFn { export function pattern(pattern: string | RegExp, message?: string): ValidatorFn {
if (!pattern) { if (!pattern) {
return Validators.nullValidator; return Validators.nullValidator;
} }
@ -32,7 +32,7 @@ export class ValidatorsEx {
const n: string = control.value; const n: string = control.value;
if (n == null || n.length === 0) { if (n == null || n.length === 0) {
return null; return {};
} }
if (!regex.test(n)) { if (!regex.test(n)) {
@ -43,11 +43,11 @@ export class ValidatorsEx {
} }
} }
return null; return {};
}; };
} }
public static between(minValue: number | undefined, maxValue: number | undefined) { export function between(minValue?: number, maxValue?: number) {
if (!minValue || !maxValue) { if (!minValue || !maxValue) {
return Validators.nullValidator; return Validators.nullValidator;
} }
@ -67,7 +67,11 @@ export class ValidatorsEx {
}; };
} }
public static validValues<T>(values: T[]) { export function validValues<T>(values: T[]) {
if (!values) {
return Validators.nullValidator;
}
return (control: AbstractControl): { [key: string]: any } => { return (control: AbstractControl): { [key: string]: any } => {
const n: T = control.value; const n: T = control.value;

2
src/Squidex/app/framework/services/notification.service.spec.ts

@ -44,7 +44,7 @@ describe('NotificationService', () => {
const notificationService = new NotificationService(); const notificationService = new NotificationService();
const notification = Notification.error('Message'); const notification = Notification.error('Message');
let publishedNotification: Notification; let publishedNotification: Notification | null = null;
notificationService.notifications.subscribe(result => { notificationService.notifications.subscribe(result => {
publishedNotification = result; publishedNotification = result;

6
src/Squidex/app/framework/services/title.service.spec.ts

@ -45,7 +45,7 @@ describe('TitleService', () => {
}); });
it('should append suffix to title', () => { it('should append suffix to title', () => {
const titleService = new TitleService(new TitlesConfig({}, null, 'myapp')); const titleService = new TitleService(new TitlesConfig({}, undefined, 'myapp'));
titleService.setTitle('my-title', {}); titleService.setTitle('my-title', {});
@ -53,9 +53,9 @@ describe('TitleService', () => {
}); });
it('should do nothing if title is null', () => { it('should do nothing if title is null', () => {
const titleService = new TitleService(new TitlesConfig({}, null, 'myapp')); const titleService = new TitleService(new TitlesConfig({}, undefined, 'myapp'));
titleService.setTitle(null, {}); titleService.setTitle(null!, {});
expect(document.title).toBe(''); expect(document.title).toBe('');
}); });

4
src/Squidex/app/framework/services/title.service.ts

@ -10,8 +10,8 @@ import { Injectable } from '@angular/core';
export class TitlesConfig { export class TitlesConfig {
constructor( constructor(
public readonly value: { [key: string]: string }, public readonly value: { [key: string]: string },
public readonly prefix: string = null, public readonly prefix?: string,
public readonly suffix: string = null public readonly suffix?: string
) { ) {
} }
} }

10
src/Squidex/app/framework/utils/string-helper.spec.ts

@ -10,13 +10,13 @@ import { StringHelper } from './../';
describe('StringHelper', () => { describe('StringHelper', () => {
it('should return empty text if value is null or undefined', () => { it('should return empty text if value is null or undefined', () => {
expect(StringHelper.firstNonEmpty(null)).toBe(''); expect(StringHelper.firstNonEmpty(null!)).toBe('');
expect(StringHelper.firstNonEmpty(undefined)).toBe(''); expect(StringHelper.firstNonEmpty(undefined!)).toBe('');
}); });
it('should return fallback name if label is undefined or null', () => { it('should return fallback name if label is undefined or null', () => {
expect(StringHelper.firstNonEmpty(null, 'fallback')).toBe('fallback'); expect(StringHelper.firstNonEmpty(null!, 'fallback')).toBe('fallback');
expect(StringHelper.firstNonEmpty(undefined, 'fallback')).toBe('fallback'); expect(StringHelper.firstNonEmpty(undefined!, 'fallback')).toBe('fallback');
}); });
it('should return label if value is valid', () => { it('should return label if value is valid', () => {
@ -36,6 +36,6 @@ describe('StringHelper', () => {
}); });
it('should return empty string if also fallback not found', () => { it('should return empty string if also fallback not found', () => {
expect(StringHelper.firstNonEmpty(null, undefined, '')).toBe(''); expect(StringHelper.firstNonEmpty(null!, undefined!, '')).toBe('');
}); });
}); });

6
src/Squidex/app/shared/guards/app-must-exist.guard.spec.ts

@ -27,7 +27,7 @@ describe('AppMustExistGuard', () => {
const guard = new AppMustExistGuard(appsStore.object, <any>router); const guard = new AppMustExistGuard(appsStore.object, <any>router);
guard.canActivate(route, null) guard.canActivate(route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -44,7 +44,7 @@ describe('AppMustExistGuard', () => {
const guard = new AppMustExistGuard(appsStore.object, <any>router); const guard = new AppMustExistGuard(appsStore.object, <any>router);
guard.canActivate(route, null) guard.canActivate(route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -61,7 +61,7 @@ describe('AppMustExistGuard', () => {
const guard = new AppMustExistGuard(appsStore.object, <any>router); const guard = new AppMustExistGuard(appsStore.object, <any>router);
guard.canActivate(route, null) guard.canActivate(route, <any>{})
.then(result => { .then(result => {
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(router.lastNavigation).toBeUndefined(); expect(router.lastNavigation).toBeUndefined();

4
src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts

@ -26,7 +26,7 @@ describe('MustBeAuthenticatedGuard', () => {
const guard = new MustBeAuthenticatedGuard(authService.object, <any>router); const guard = new MustBeAuthenticatedGuard(authService.object, <any>router);
guard.canActivate(null, null) guard.canActivate(<any>{}, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['']); expect(router.lastNavigation).toEqual(['']);
@ -42,7 +42,7 @@ describe('MustBeAuthenticatedGuard', () => {
const guard = new MustBeAuthenticatedGuard(authService.object, <any>router); const guard = new MustBeAuthenticatedGuard(authService.object, <any>router);
guard.canActivate(null, null) guard.canActivate(<any>{}, <any>{})
.then(result => { .then(result => {
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(router.lastNavigation).toBeUndefined(); expect(router.lastNavigation).toBeUndefined();

4
src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts

@ -26,7 +26,7 @@ describe('MustBeNotAuthenticatedGuard', () => {
const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router); const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router);
guard.canActivate(null, null) guard.canActivate(<any>{}, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['app']); expect(router.lastNavigation).toEqual(['app']);
@ -42,7 +42,7 @@ describe('MustBeNotAuthenticatedGuard', () => {
const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router); const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router);
guard.canActivate(null, null) guard.canActivate(<any>{}, <any>{})
.then(result => { .then(result => {
expect(result).toBeTruthy(); expect(result).toBeTruthy();
expect(router.lastNavigation).toBeUndefined(); expect(router.lastNavigation).toBeUndefined();

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

@ -13,7 +13,7 @@ import { SchemasService } from 'shared';
import { ResolvePublishedSchemaGuard } from './resolve-published-schema.guard'; import { ResolvePublishedSchemaGuard } from './resolve-published-schema.guard';
import { RouterMockup } from './router-mockup'; import { RouterMockup } from './router-mockup';
describe('ResolveSchemaGuard', () => { describe('ResolvePublishedSchemaGuard', () => {
const route = { const route = {
params: { params: {
appName: 'my-app' appName: 'my-app'
@ -31,14 +31,20 @@ describe('ResolveSchemaGuard', () => {
appsStore = Mock.ofType(SchemasService); appsStore = Mock.ofType(SchemasService);
}); });
it('should throw if route does not contain parameter', () => {
const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app and schema name.');
});
it('should navigate to 404 page if schema is not found', (done) => { it('should navigate to 404 page if schema is not found', (done) => {
appsStore.setup(x => x.getSchema('my-app', 'my-schema')) appsStore.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router); const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -54,7 +60,7 @@ describe('ResolveSchemaGuard', () => {
const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router); const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -72,7 +78,7 @@ describe('ResolveSchemaGuard', () => {
const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router); const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -90,7 +96,7 @@ describe('ResolveSchemaGuard', () => {
const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router); const guard = new ResolvePublishedSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBe(schema); expect(result).toBe(schema);

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

@ -22,6 +22,10 @@ export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> {
const appName = this.findParameter(route, 'appName'); const appName = this.findParameter(route, 'appName');
const schemaName = this.findParameter(route, 'schemaName'); const schemaName = this.findParameter(route, 'schemaName');
if (!appName || !schemaName) {
throw 'Route must contain app and schema name.';
}
const result = const result =
this.schemasService.getSchema(appName, schemaName).toPromise() this.schemasService.getSchema(appName, schemaName).toPromise()
.then(dto => { .then(dto => {
@ -41,8 +45,8 @@ export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> {
return result; return result;
} }
private findParameter(route: ActivatedRouteSnapshot, name: string) { private findParameter(route: ActivatedRouteSnapshot, name: string): string | null {
let result: string; let result: string | null = null;
while (route) { while (route) {
result = route.params[name]; result = route.params[name];

16
src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts

@ -31,14 +31,20 @@ describe('ResolveSchemaGuard', () => {
appsStore = Mock.ofType(SchemasService); appsStore = Mock.ofType(SchemasService);
}); });
it('should throw if route does not contain parameter', () => {
const guard = new ResolveSchemaGuard(appsStore.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app and schema name.');
});
it('should navigate to 404 page if schema is not found', (done) => { it('should navigate to 404 page if schema is not found', (done) => {
appsStore.setup(x => x.getSchema('my-app', 'my-schema')) appsStore.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null)); .returns(() => Observable.of(null!));
const router = new RouterMockup(); const router = new RouterMockup();
const guard = new ResolveSchemaGuard(appsStore.object, <any>router); const guard = new ResolveSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -49,12 +55,12 @@ describe('ResolveSchemaGuard', () => {
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema loading fails', (done) => {
appsStore.setup(x => x.getSchema('my-app', 'my-schema')) appsStore.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.throw(null)); .returns(() => Observable.throw(null!));
const router = new RouterMockup(); const router = new RouterMockup();
const guard = new ResolveSchemaGuard(appsStore.object, <any>router); const guard = new ResolveSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBeFalsy(); expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']); expect(router.lastNavigation).toEqual(['/404']);
@ -72,7 +78,7 @@ describe('ResolveSchemaGuard', () => {
const guard = new ResolveSchemaGuard(appsStore.object, <any>router); const guard = new ResolveSchemaGuard(appsStore.object, <any>router);
guard.resolve(<any>route, null) guard.resolve(<any>route, <any>{})
.then(result => { .then(result => {
expect(result).toBe(schema); expect(result).toBe(schema);

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

@ -22,23 +22,31 @@ export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto> {
const appName = this.findParameter(route, 'appName'); const appName = this.findParameter(route, 'appName');
const schemaName = this.findParameter(route, 'schemaName'); const schemaName = this.findParameter(route, 'schemaName');
if (!appName || !schemaName) {
throw 'Route must contain app and schema name.';
}
const result = const result =
this.schemasService.getSchema(appName, schemaName).toPromise() this.schemasService.getSchema(appName, schemaName).toPromise()
.then(dto => { .then(dto => {
if (!dto) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
return null;
} }
return dto; return dto;
}).catch(() => { }).catch(() => {
this.router.navigate(['/404']); this.router.navigate(['/404']);
return null;
}); });
return result; return result;
} }
private findParameter(route: ActivatedRouteSnapshot, name: string) { private findParameter(route: ActivatedRouteSnapshot, name: string): string | null {
let result: string; let result: string | null = null;
while (route) { while (route) {
result = route.params[name]; result = route.params[name];

14
src/Squidex/app/shared/services/app-clients.service.spec.ts

@ -53,7 +53,7 @@ describe('AppClientsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let clients: AppClientDto[] = null; let clients: AppClientDto[] | null = null;
appClientsService.getClients('my-app').subscribe(result => { appClientsService.getClients('my-app').subscribe(result => {
clients = result; clients = result;
@ -71,7 +71,7 @@ describe('AppClientsService', () => {
it('should make post request to create client', () => { it('should make post request to create client', () => {
const dto = new CreateAppClientDto('client1'); const dto = new CreateAppClientDto('client1');
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/clients', It.isValue(dto))) authService.setup(x => x.authPost('http://service/p/api/apps/my-app/clients', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions({ new ResponseOptions({
@ -86,7 +86,7 @@ describe('AppClientsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let client: AppClientDto = null; let client: AppClientDto | null = null;
appClientsService.postClient('my-app', dto).subscribe(result => { appClientsService.postClient('my-app', dto).subscribe(result => {
client = result; client = result;
@ -101,7 +101,7 @@ describe('AppClientsService', () => {
it('should make put request to rename client', () => { it('should make put request to rename client', () => {
const dto = new UpdateAppClientDto('Client 1 New'); const dto = new UpdateAppClientDto('Client 1 New');
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/clients/client1', It.isValue(dto))) authService.setup(x => x.authPut('http://service/p/api/apps/my-app/clients/client1', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions() new ResponseOptions()
@ -131,7 +131,7 @@ describe('AppClientsService', () => {
it('should make form request to create token', () => { 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'; 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())) http.setup(x => x.post('http://service/p/identity-server/connect/token', body, It.isAny()))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions({ new ResponseOptions({
@ -143,9 +143,9 @@ describe('AppClientsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let accessTokenDto: AccessTokenDto = null; let accessTokenDto: AccessTokenDto | null = null;
appClientsService.createToken('my-app', new AppClientDto('myClientId', null, 'mySecret', null)).subscribe(result => { appClientsService.createToken('my-app', new AppClientDto('myClientId', 'myClient', 'mySecret', DateTime.now())).subscribe(result => {
accessTokenDto = result; accessTokenDto = result;
}); });

10
src/Squidex/app/shared/services/app-contributors.service.spec.ts

@ -7,7 +7,7 @@
import { Response, ResponseOptions } from '@angular/http'; import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { It, IMock, Mock, Times } from 'typemoq'; import { IMock, Mock, Times } from 'typemoq';
import { import {
ApiUrlConfig, ApiUrlConfig,
@ -42,7 +42,7 @@ describe('AppContributorsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let contributors: AppContributorDto[] = null; let contributors: AppContributorDto[] | null = null;
appContributorsService.getContributors('my-app').subscribe(result => { appContributorsService.getContributors('my-app').subscribe(result => {
contributors = result; contributors = result;
@ -58,9 +58,9 @@ describe('AppContributorsService', () => {
}); });
it('should make post request to assign contributor', () => { it('should make post request to assign contributor', () => {
const contributor = new AppContributorDto('123', 'Owner'); const dto = new AppContributorDto('123', 'Owner');
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/contributors', It.isValue(contributor))) authService.setup(x => x.authPost('http://service/p/api/apps/my-app/contributors', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions() new ResponseOptions()
@ -68,7 +68,7 @@ describe('AppContributorsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
appContributorsService.postContributor('my-app', contributor); appContributorsService.postContributor('my-app', dto);
authService.verifyAll(); authService.verifyAll();
}); });

10
src/Squidex/app/shared/services/app-languages.service.spec.ts

@ -7,7 +7,7 @@
import { Response, ResponseOptions } from '@angular/http'; import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { It, IMock, Mock, Times } from 'typemoq'; import { IMock, Mock, Times } from 'typemoq';
import { import {
AddAppLanguageDto, AddAppLanguageDto,
@ -45,7 +45,7 @@ describe('AppLanguagesService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let languages: AppLanguageDto[] = null; let languages: AppLanguageDto[] | null = null;
appLanguagesService.getLanguages('my-app').subscribe(result => { appLanguagesService.getLanguages('my-app').subscribe(result => {
languages = result; languages = result;
@ -63,7 +63,7 @@ describe('AppLanguagesService', () => {
it('should make post request to add language', () => { it('should make post request to add language', () => {
const dto = new AddAppLanguageDto('de'); const dto = new AddAppLanguageDto('de');
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/languages', It.isValue(dto))) authService.setup(x => x.authPost('http://service/p/api/apps/my-app/languages', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions({ new ResponseOptions({
@ -76,7 +76,7 @@ describe('AppLanguagesService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let language: AppLanguageDto; let language: AppLanguageDto | null = null;
appLanguagesService.postLanguages('my-app', dto).subscribe(result => { appLanguagesService.postLanguages('my-app', dto).subscribe(result => {
language = result; language = result;
@ -91,7 +91,7 @@ describe('AppLanguagesService', () => {
it('should make put request to make master language', () => { it('should make put request to make master language', () => {
const dto = new UpdateAppLanguageDto(true); const dto = new UpdateAppLanguageDto(true);
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/languages/de', It.isValue(dto))) authService.setup(x => x.authPut('http://service/p/api/apps/my-app/languages/de', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions() new ResponseOptions()

14
src/Squidex/app/shared/services/apps-store.service.spec.ts

@ -42,8 +42,8 @@ describe('AppsStoreService', () => {
const store = new AppsStoreService(authService.object, appsService.object); const store = new AppsStoreService(authService.object, appsService.object);
let result1: AppDto[]; let result1: AppDto[] | null = null;
let result2: AppDto[]; let result2: AppDto[] | null = null;
store.apps.subscribe(x => { store.apps.subscribe(x => {
result1 = x; result1 = x;
@ -70,8 +70,8 @@ describe('AppsStoreService', () => {
const store = new AppsStoreService(authService.object, appsService.object); const store = new AppsStoreService(authService.object, appsService.object);
let result1: AppDto[]; let result1: AppDto[] | null = null;
let result2: AppDto[]; let result2: AppDto[] | null = null;
store.apps.subscribe(x => { store.apps.subscribe(x => {
result1 = x; result1 = x;
@ -104,8 +104,8 @@ describe('AppsStoreService', () => {
const store = new AppsStoreService(authService.object, appsService.object); const store = new AppsStoreService(authService.object, appsService.object);
let result1: AppDto[]; let result1: AppDto[] | null = null;
let result2: AppDto[]; let result2: AppDto[] | null = null;
store.apps.subscribe(x => { store.apps.subscribe(x => {
result1 = x; result1 = x;
@ -134,7 +134,7 @@ describe('AppsStoreService', () => {
const store = new AppsStoreService(authService.object, appsService.object); const store = new AppsStoreService(authService.object, appsService.object);
let result: AppDto[] = null; let result: AppDto[] | null = null;
store.createApp(new CreateAppDto('new-name'), now).subscribe(x => { /* Do Nothing */ }); store.createApp(new CreateAppDto('new-name'), now).subscribe(x => { /* Do Nothing */ });

16
src/Squidex/app/shared/services/apps.service.spec.ts

@ -7,7 +7,7 @@
import { Response, ResponseOptions } from '@angular/http'; import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { It, IMock, Mock, Times } from 'typemoq'; import { IMock, Mock, Times } from 'typemoq';
import { import {
ApiUrlConfig, ApiUrlConfig,
@ -51,7 +51,7 @@ describe('AppsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let apps: AppDto[] = null; let apps: AppDto[] | null = null;
appsService.getApps().subscribe(result => { appsService.getApps().subscribe(result => {
apps = result; apps = result;
@ -66,9 +66,9 @@ describe('AppsService', () => {
}); });
it('should make post request to create app', () => { it('should make post request to create app', () => {
const createApp = new CreateAppDto('new-app'); const dto = new CreateAppDto('new-app');
authService.setup(x => x.authPost('http://service/p/api/apps', It.isValue(createApp))) authService.setup(x => x.authPost('http://service/p/api/apps', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions({ new ResponseOptions({
@ -80,13 +80,13 @@ describe('AppsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let newCreated: EntityCreatedDto = null; let created: EntityCreatedDto | null = null;
appsService.postApp(createApp).subscribe(result => { appsService.postApp(dto).subscribe(result => {
newCreated = result; created = result;
}).unsubscribe(); }).unsubscribe();
expect(newCreated).toEqual(new EntityCreatedDto('123')); expect(created).toEqual(new EntityCreatedDto('123'));
authService.verifyAll(); authService.verifyAll();
}); });

14
src/Squidex/app/shared/services/contents.service.spec.ts

@ -7,7 +7,7 @@
import { Response, ResponseOptions } from '@angular/http'; import { Response, ResponseOptions } from '@angular/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { It, IMock, Mock, Times } from 'typemoq'; import { IMock, Mock, Times } from 'typemoq';
import { import {
ApiUrlConfig, ApiUrlConfig,
@ -27,7 +27,7 @@ describe('ContentsService', () => {
contentsService = new ContentsService(authService.object, new ApiUrlConfig('http://service/p/')); contentsService = new ContentsService(authService.object, new ApiUrlConfig('http://service/p/'));
}); });
it('should make get request to get content1', () => { it('should make get request to get contents', () => {
authService.setup(x => x.authGet('http://service/p/api/content/my-app/my-schema?take=17&skip=13&query=my-query&nonPublished=true')) 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( .returns(() => Observable.of(
new Response( new Response(
@ -54,7 +54,7 @@ describe('ContentsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let contents: ContentDto[] = null; let contents: ContentDto[] | null = null;
contentsService.getContents('my-app', 'my-schema', 17, 13, 'my-query').subscribe(result => { contentsService.getContents('my-app', 'my-schema', 17, 13, 'my-query').subscribe(result => {
contents = result; contents = result;
@ -87,7 +87,7 @@ describe('ContentsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let content: ContentDto = null; let content: ContentDto | null = null;
contentsService.getContent('my-app', 'my-schema', 'content1').subscribe(result => { contentsService.getContent('my-app', 'my-schema', 'content1').subscribe(result => {
content = result; content = result;
@ -102,7 +102,7 @@ describe('ContentsService', () => {
it('should make post request to create content', () => { it('should make post request to create content', () => {
const dto = {}; const dto = {};
authService.setup(x => x.authPost('http://service/p/api/content/my-app/my-schema', It.isValue(dto))) authService.setup(x => x.authPost('http://service/p/api/content/my-app/my-schema', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions({ new ResponseOptions({
@ -114,7 +114,7 @@ describe('ContentsService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let created: EntityCreatedDto = null; let created: EntityCreatedDto | null = null;
contentsService.postContent('my-app', 'my-schema', dto).subscribe(result => { contentsService.postContent('my-app', 'my-schema', dto).subscribe(result => {
created = result; created = result;
@ -129,7 +129,7 @@ describe('ContentsService', () => {
it('should make put request to update content', () => { it('should make put request to update content', () => {
const dto = {}; const dto = {};
authService.setup(x => x.authPut('http://service/p/api/content/my-app/my-schema/content1', It.isValue(dto))) authService.setup(x => x.authPut('http://service/p/api/content/my-app/my-schema/content1', dto))
.returns(() => Observable.of( .returns(() => Observable.of(
new Response( new Response(
new ResponseOptions() new ResponseOptions()

2
src/Squidex/app/shared/services/history.service.spec.ts

@ -48,7 +48,7 @@ describe('HistoryService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let events: HistoryEventDto[] = null; let events: HistoryEventDto[] | null = null;
languageService.getHistory('my-app', 'settings.contributors').subscribe(result => { languageService.getHistory('my-app', 'settings.contributors').subscribe(result => {
events = result; events = result;

2
src/Squidex/app/shared/services/languages.service.spec.ts

@ -42,7 +42,7 @@ describe('LanguageService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let languages: LanguageDto[] = null; let languages: LanguageDto[] | null = null;
languageService.getLanguages().subscribe(result => { languageService.getLanguages().subscribe(result => {
languages = result; languages = result;

334
src/Squidex/app/shared/services/schemas.service.spec.ts

@ -0,0 +1,334 @@
/*
* 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 {
AddFieldDto,
ApiUrlConfig,
AuthService,
CreateSchemaDto,
createProperties,
DateTime,
EntityCreatedDto,
FieldDto,
SchemaDetailsDto,
SchemaDto,
SchemasService,
UpdateFieldDto,
UpdateSchemaDto
} from './../';
describe('SchemasService', () => {
let authService: IMock<AuthService>;
let schemasService: SchemasService;
beforeEach(() => {
authService = Mock.ofType(AuthService);
schemasService = new SchemasService(authService.object, new ApiUrlConfig('http://service/p/'));
});
it('should throw if creating invalid property type', () => {
expect(() => createProperties('invalid')).toThrow('Invalid properties type');
});
it('should make get request to get schemas', () => {
authService.setup(x => x.authGet('http://service/p/api/apps/my-app/schemas'))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: [{
id: 'id1',
name: 'name1',
label: 'label1',
isPublished: true,
created: '2016-12-12T10:10',
createdBy: 'Created1',
lastModified: '2017-12-12T10:10',
lastModifiedBy: 'LastModifiedBy1',
data: {}
}, {
id: 'id2',
name: 'name2',
label: 'label2',
isPublished: true,
created: '2016-10-12T10:10',
createdBy: 'Created2',
lastModified: '2017-10-12T10:10',
lastModifiedBy: 'LastModifiedBy2',
data: {}
}]
})
)
))
.verifiable(Times.once());
let schemas: SchemaDto[] | null = null;
schemasService.getSchemas('my-app').subscribe(result => {
schemas = result;
}).unsubscribe();
expect(schemas).toEqual([
new SchemaDto('id1', 'name1', 'label1', true, 'Created1', 'LastModifiedBy1', DateTime.parseISO_UTC('2016-12-12T10:10'), DateTime.parseISO_UTC('2017-12-12T10:10')),
new SchemaDto('id2', 'name2', 'label2', 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 schema', () => {
authService.setup(x => x.authGet('http://service/p/api/apps/my-app/schemas/my-schema'))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: {
id: 'id1',
name: 'name1',
label: 'label1',
hints: 'hints1',
isPublished: true,
created: '2016-12-12T10:10',
createdBy: 'Created1',
lastModified: '2017-12-12T10:10',
lastModifiedBy: 'LastModifiedBy1',
fields: [{
fieldId: 123,
name: 'field1',
isHidden: true,
isDisabled: true,
properties: {
fieldType: 'number'
}
}, {
fieldId: 234,
name: 'field2',
isHidden: true,
isDisabled: true,
properties: {
fieldType: 'string'
}
}, {
fieldId: 345,
name: 'field3',
isHidden: true,
isDisabled: true,
properties: {
fieldType: 'boolean'
}
}]
}
})
)
))
.verifiable(Times.once());
let schema: SchemaDetailsDto | null = null;
schemasService.getSchema('my-app', 'my-schema').subscribe(result => {
schema = result;
}).unsubscribe();
expect(schema).toEqual(
new SchemaDetailsDto('id1', 'name1', 'label1', 'hints1', true, 'Created1', 'LastModifiedBy1',
DateTime.parseISO_UTC('2016-12-12T10:10'),
DateTime.parseISO_UTC('2017-12-12T10:10'), [
new FieldDto(123, 'field1', true, true, createProperties('number')),
new FieldDto(234, 'field2', true, true, createProperties('string')),
new FieldDto(345, 'field3', true, true, createProperties('boolean'))
]));
authService.verifyAll();
});
it('should make post request to create schema', () => {
const dto = new CreateSchemaDto('name');
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/schemas', dto))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: {
id: 'my-schema'
}
})
)
))
.verifiable(Times.once());
let created: EntityCreatedDto | null = null;
schemasService.postSchema('my-app', dto).subscribe(result => {
created = result;
});
expect(created).toEqual(
new EntityCreatedDto('my-schema'));
authService.verifyAll();
});
it('should make post request to add field', () => {
const dto = new AddFieldDto('name', createProperties('number'));
authService.setup(x => x.authPost('http://service/p/api/apps/my-app/schemas/my-schema/fields', dto))
.returns(() => Observable.of(
new Response(
new ResponseOptions({
body: {
id: 123
}
})
)
))
.verifiable(Times.once());
let created: EntityCreatedDto | null = null;
schemasService.postField('my-app', 'my-schema', dto).subscribe(result => {
created = result;
});
expect(created).toEqual(
new EntityCreatedDto(123));
authService.verifyAll();
});
it('should make put request to update schema', () => {
const dto = new UpdateSchemaDto('label', 'hints');
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema', dto))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.putSchema('my-app', 'my-schema', dto);
authService.verifyAll();
});
it('should make put request to update field', () => {
const dto = new UpdateFieldDto(createProperties('number'));
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/1', dto))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.putField('my-app', 'my-schema', 1, dto);
authService.verifyAll();
});
it('should make put request to publish schema', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/publish', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.publishSchema('my-app', 'my-schema');
authService.verifyAll();
});
it('should make put request to unpublish schema', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/unpublish', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.unpublishSchema('my-app', 'my-schema');
authService.verifyAll();
});
it('should make put request to enable field', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/1/enable', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.enableField('my-app', 'my-schema', 1);
authService.verifyAll();
});
it('should make put request to disable field', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/1/disable', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.disableField('my-app', 'my-schema', 1);
authService.verifyAll();
});
it('should make put request to show field', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/1/show', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.showField('my-app', 'my-schema', 1);
authService.verifyAll();
});
it('should make put request to hide field', () => {
authService.setup(x => x.authPut('http://service/p/api/apps/my-app/schemas/my-schema/fields/1/hide', It.isAny()))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.hideField('my-app', 'my-schema', 1);
authService.verifyAll();
});
it('should make delete request to delete field', () => {
authService.setup(x => x.authDelete('http://service/p/api/apps/my-app/schemas/my-schema/fields/1'))
.returns(() => Observable.of(
new Response(
new ResponseOptions()
)
))
.verifiable(Times.once());
schemasService.deleteField('my-app', 'my-schema', 1);
authService.verifyAll();
});
});

66
src/Squidex/app/shared/services/schemas.service.ts

@ -18,7 +18,7 @@ import {
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
export function createProperties(fieldType: string, values: {} | null = null): FieldPropertiesDto { export function createProperties(fieldType: string, values: Object | null = null): FieldPropertiesDto {
let properties: FieldPropertiesDto; let properties: FieldPropertiesDto;
switch (fieldType) { switch (fieldType) {
@ -55,7 +55,7 @@ export class SchemaDto {
constructor( constructor(
public readonly id: string, public readonly id: string,
public readonly name: string, public readonly name: string,
public readonly label: string, public readonly label: string | undefined,
public readonly isPublished: boolean, public readonly isPublished: boolean,
public readonly createdBy: string, public readonly createdBy: string,
public readonly lastModifiedBy: string, public readonly lastModifiedBy: string,
@ -71,12 +71,12 @@ export class SchemaDetailsDto {
public readonly name: string, public readonly name: string,
public readonly label: string, public readonly label: string,
public readonly hints: string, public readonly hints: string,
public readonly fields: FieldDto[],
public readonly isPublished: boolean, public readonly isPublished: boolean,
public readonly createdBy: string, public readonly createdBy: string,
public readonly lastModifiedBy: string, public readonly lastModifiedBy: string,
public readonly created: DateTime, public readonly created: DateTime,
public readonly lastModified: DateTime public readonly lastModified: DateTime,
public readonly fields: FieldDto[]
) { ) {
} }
} }
@ -103,12 +103,12 @@ export abstract class FieldPropertiesDto {
} }
export class NumberFieldPropertiesDto extends FieldPropertiesDto { export class NumberFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string, hints: string, placeholder: string, isRequired: boolean, constructor(label: string | undefined, hints: string | undefined, placeholder: string | undefined, isRequired: boolean,
public readonly editor: string, public readonly editor: string,
public readonly defaultValue: number | null, public readonly defaultValue?: number,
public readonly maxValue: number | null, public readonly maxValue?: number,
public readonly minValue: number | null, public readonly minValue?: number,
public readonly allowedValues: number[] | undefined public readonly allowedValues?: number[]
) { ) {
super(label, hints, placeholder, isRequired); super(label, hints, placeholder, isRequired);
@ -117,14 +117,14 @@ export class NumberFieldPropertiesDto extends FieldPropertiesDto {
} }
export class StringFieldPropertiesDto extends FieldPropertiesDto { export class StringFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string, hints: string, placeholder: string, isRequired: boolean, constructor(label: string | undefined, hints: string | undefined, placeholder: string | undefined, isRequired: boolean,
public readonly editor: string, public readonly editor: string,
public readonly defaultValue: string, public readonly defaultValue?: string,
public readonly pattern: string, public readonly pattern?: string,
public readonly patternMessage: string, public readonly patternMessage?: string,
public readonly minLength: number | null, public readonly minLength?: number | null,
public readonly maxLength: number | null, public readonly maxLength?: number | null,
public readonly allowedValues: string[] public readonly allowedValues?: string[]
) { ) {
super(label, hints, placeholder, isRequired); super(label, hints, placeholder, isRequired);
@ -133,9 +133,9 @@ export class StringFieldPropertiesDto extends FieldPropertiesDto {
} }
export class BooleanFieldPropertiesDto extends FieldPropertiesDto { export class BooleanFieldPropertiesDto extends FieldPropertiesDto {
constructor(label: string, hints: string, placeholder: string, isRequired: boolean, constructor(label: string | undefined, hints: string | undefined, placeholder: string | undefined, isRequired: boolean,
public readonly editor: string, public readonly editor: string,
public readonly defaultValue: boolean | null public readonly defaultValue?: boolean
) { ) {
super(label, hints, placeholder, isRequired); super(label, hints, placeholder, isRequired);
@ -145,8 +145,8 @@ export class BooleanFieldPropertiesDto extends FieldPropertiesDto {
export class UpdateSchemaDto { export class UpdateSchemaDto {
constructor( constructor(
public readonly label: string, public readonly label?: string,
public readonly hints: string public readonly hints?: string
) { ) {
} }
} }
@ -229,18 +229,18 @@ export class SchemasService {
response.name, response.name,
response.label, response.label,
response.hints, response.hints,
fields,
response.isPublished, response.isPublished,
response.createdBy, response.createdBy,
response.lastModifiedBy, response.lastModifiedBy,
DateTime.parseISO_UTC(response.created), DateTime.parseISO_UTC(response.created),
DateTime.parseISO_UTC(response.lastModified)); DateTime.parseISO_UTC(response.lastModified),
fields);
}) })
.catchError('Failed to load schema. Please reload.'); .catchError('Failed to load schema. Please reload.');
} }
public postSchema(appName: string, dto: CreateSchemaDto): Observable<EntityCreatedDto> { public postSchema(appName: string, dto: CreateSchemaDto): Observable<EntityCreatedDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas`);
return this.authService.authPost(url, dto) return this.authService.authPost(url, dto)
.map(response => response.json()) .map(response => response.json())
@ -251,7 +251,7 @@ export class SchemasService {
} }
public postField(appName: string, schemaName: string, dto: AddFieldDto): Observable<EntityCreatedDto> { public postField(appName: string, schemaName: string, dto: AddFieldDto): Observable<EntityCreatedDto> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields`);
return this.authService.authPost(url, dto) return this.authService.authPost(url, dto)
.map(response => response.json()) .map(response => response.json())
@ -262,63 +262,63 @@ export class SchemasService {
} }
public putSchema(appName: string, schemaName: string, dto: UpdateSchemaDto): Observable<any> { public putSchema(appName: string, schemaName: string, dto: UpdateSchemaDto): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}`);
return this.authService.authPut(url, dto) return this.authService.authPut(url, dto)
.catchError('Failed to update schema. Please reload.'); .catchError('Failed to update schema. Please reload.');
} }
public publishSchema(appName: string, schemaName: string): Observable<any> { public publishSchema(appName: string, schemaName: string): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/publish`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to publish schema. Please reload.'); .catchError('Failed to publish schema. Please reload.');
} }
public unpublishSchema(appName: string, schemaName: string): Observable<any> { public unpublishSchema(appName: string, schemaName: string): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/unpublish`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to unpublish schema. Please reload.'); .catchError('Failed to unpublish schema. Please reload.');
} }
public putField(appName: string, schemaName: string, fieldId: number, dto: UpdateFieldDto): Observable<any> { public putField(appName: string, schemaName: string, fieldId: number, dto: UpdateFieldDto): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return this.authService.authPut(url, dto) return this.authService.authPut(url, dto)
.catchError('Failed to update field. Please reload.'); .catchError('Failed to update field. Please reload.');
} }
public enableField(appName: string, schemaName: string, fieldId: number): Observable<any> { public enableField(appName: string, schemaName: string, fieldId: number): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/enable`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to enable field. Please reload.'); .catchError('Failed to enable field. Please reload.');
} }
public disableField(appName: string, schemaName: string, fieldId: number): Observable<any> { public disableField(appName: string, schemaName: string, fieldId: number): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/disable`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to disable field. Please reload.'); .catchError('Failed to disable field. Please reload.');
} }
public showField(appName: string, schemaName: string, fieldId: number): Observable<any> { public showField(appName: string, schemaName: string, fieldId: number): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/show`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to show field. Please reload.'); .catchError('Failed to show field. Please reload.');
} }
public hideField(appName: string, schemaName: string, fieldId: number): Observable<any> { public hideField(appName: string, schemaName: string, fieldId: number): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/hide`);
return this.authService.authPut(url, {}) return this.authService.authPut(url, {})
.catchError('Failed to hide field. Please reload.'); .catchError('Failed to hide field. Please reload.');
} }
public deleteField(appName: string, schemaName: string, fieldId: number): Observable<any> { public deleteField(appName: string, schemaName: string, fieldId: number): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}/`); const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas/${schemaName}/fields/${fieldId}`);
return this.authService.authDelete(url) return this.authService.authDelete(url)
.catchError('Failed to delete field. Please reload.'); .catchError('Failed to delete field. Please reload.');

8
src/Squidex/app/shared/services/users-provider.service.spec.ts

@ -33,7 +33,7 @@ describe('UsersProviderService', () => {
usersService.setup(x => x.getUser('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; let resultingUser: UserDto | null = null;
usersProviderService.getUser('123').subscribe(result => { usersProviderService.getUser('123').subscribe(result => {
resultingUser = result; resultingUser = result;
@ -52,7 +52,7 @@ describe('UsersProviderService', () => {
usersProviderService.getUser('123'); usersProviderService.getUser('123');
let resultingUser: UserDto = null; let resultingUser: UserDto | null = null;
usersProviderService.getUser('123').subscribe(result => { usersProviderService.getUser('123').subscribe(result => {
resultingUser = result; resultingUser = result;
@ -72,7 +72,7 @@ describe('UsersProviderService', () => {
usersService.setup(x => x.getUser('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; let resultingUser: UserDto | null = null;
usersProviderService.getUser('123').subscribe(result => { usersProviderService.getUser('123').subscribe(result => {
resultingUser = result; resultingUser = result;
@ -90,7 +90,7 @@ describe('UsersProviderService', () => {
usersService.setup(x => x.getUser('123')) usersService.setup(x => x.getUser('123'))
.returns(() => Observable.throw('NOT FOUND')).verifiable(Times.once()); .returns(() => Observable.throw('NOT FOUND')).verifiable(Times.once());
let resultingUser: UserDto = null; let resultingUser: UserDto | null = null;
usersProviderService.getUser('123').subscribe(result => { usersProviderService.getUser('123').subscribe(result => {
resultingUser = result; resultingUser = result;

6
src/Squidex/app/shared/services/users.service.spec.ts

@ -46,7 +46,7 @@ describe('UsersService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let user: UserDto[] = null; let user: UserDto[] | null = null;
usersService.getUsers().subscribe(result => { usersService.getUsers().subscribe(result => {
user = result; user = result;
@ -82,7 +82,7 @@ describe('UsersService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let user: UserDto[] = null; let user: UserDto[] | null = null;
usersService.getUsers('my-query').subscribe(result => { usersService.getUsers('my-query').subscribe(result => {
user = result; user = result;
@ -113,7 +113,7 @@ describe('UsersService', () => {
)) ))
.verifiable(Times.once()); .verifiable(Times.once());
let user: UserDto = null; let user: UserDto | null = null;
usersService.getUser('123').subscribe(result => { usersService.getUser('123').subscribe(result => {
user = result; user = result;

123
tests/Squidex.Core.Tests/Contents/ContentDataTests.cs

@ -9,12 +9,23 @@
using System.Collections.Generic; using System.Collections.Generic;
using FluentAssertions; using FluentAssertions;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
using Xunit; using Xunit;
namespace Squidex.Core.Contents namespace Squidex.Core.Contents
{ {
public class ContentDataTests public class ContentDataTests
{ {
private readonly Schema schema =
Schema.Create("schema", new SchemaProperties())
.AddOrUpdateField(
new NumberField(1, "field1", new NumberFieldProperties { IsLocalizable = true }))
.AddOrUpdateField(
new NumberField(2, "field2", new NumberFieldProperties { IsLocalizable = false }));
private readonly Language[] languages = { Language.GetLanguage("de"), Language.GetLanguage("en") };
private readonly Language masterLanguage = Language.GetLanguage("en");
[Fact] [Fact]
public void Should_convert_from_dictionary() public void Should_convert_from_dictionary()
{ {
@ -28,12 +39,11 @@ namespace Squidex.Core.Contents
}, },
["field2"] = new Dictionary<string, JToken> ["field2"] = new Dictionary<string, JToken>
{ {
["en"] = 1, ["iv"] = 3
["de"] = 2
} }
}; };
var actual = ContentData.Create(input); var actual = ContentData.FromApiRequest(input);
var expected = var expected =
ContentData.Empty ContentData.Empty
@ -43,13 +53,114 @@ namespace Squidex.Core.Contents
.AddValue("de", "de_string")) .AddValue("de", "de_string"))
.AddField("field2", .AddField("field2",
ContentFieldData.Empty ContentFieldData.Empty
.AddValue("en", 1) .AddValue("iv", 3));
.AddValue("de", 2));
var output = actual.ToRaw(); var output = actual.ToApiResponse(schema, languages, masterLanguage);
actual.ShouldBeEquivalentTo(expected); actual.ShouldBeEquivalentTo(expected);
output.ShouldBeEquivalentTo(input); output.ShouldBeEquivalentTo(input);
} }
[Fact]
public void Should_cleanup_old_fields()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field1"] = new Dictionary<string, JToken>
{
["en"] = "en_string",
["de"] = "de_string"
}
};
var input =
ContentData.Empty
.AddField("field0",
ContentFieldData.Empty
.AddValue("en", "en_string"))
.AddField("field1",
ContentFieldData.Empty
.AddValue("en", "en_string")
.AddValue("de", "de_string"));
var output = input.ToApiResponse(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
}
[Fact]
public void Should_cleanup_old_languages()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field1"] = new Dictionary<string, JToken>
{
["en"] = "en_string",
["de"] = "de_string"
}
};
var input =
ContentData.Empty
.AddField("field1",
ContentFieldData.Empty
.AddValue("en", "en_string")
.AddValue("de", "de_string")
.AddValue("it", "it_string"));
var output = input.ToApiResponse(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
}
[Fact]
public void Should_provide_invariant_from_master_language()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field2"] = new Dictionary<string, JToken>
{
["iv"] = 3
}
};
var input =
ContentData.Empty
.AddField("field2",
ContentFieldData.Empty
.AddValue("de", 2)
.AddValue("en", 3));
var output = input.ToApiResponse(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
}
[Fact]
public void Should_provide_invariant_from_first_language()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field2"] = new Dictionary<string, JToken>
{
["iv"] = 2
}
};
var input =
ContentData.Empty
.AddField("field2",
ContentFieldData.Empty
.AddValue("de", 2)
.AddValue("it", 3));
var output = input.ToApiResponse(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
}
} }
} }

Loading…
Cancel
Save