Browse Source

Fixed tests and performance improvements.

pull/592/head
Sebastian 5 years ago
parent
commit
81e5756197
  1. 17
      frontend/app/framework/angular/routers/router-2-state.spec.ts
  2. 10
      frontend/app/framework/angular/routers/router-2-state.ts
  3. 72
      frontend/app/framework/state.spec.ts
  4. 50
      frontend/app/framework/state.ts
  5. 12
      frontend/app/framework/utils/types.ts

17
frontend/app/framework/angular/routers/router-2-state.spec.ts

@ -307,13 +307,28 @@ describe('Router2State', () => {
routerQueryParams.next({ routerQueryParams.next({
key1: 'hello', key1: 'hello',
key2: 'squidex', key2: 'cms',
key3: '!' key3: '!'
}); });
expect(invoked).toEqual(2); expect(invoked).toEqual(2);
}); });
it('Should not sync again when no state as changed', () => {
routerQueryParams.next({
key1: 'hello',
key2: 'squidex'
});
routerQueryParams.next({
key1: 'hello',
key2: 'squidex',
key3: '!'
});
expect(invoked).toEqual(1);
});
it('Should reset other values when synced from route', () => { it('Should reset other values when synced from route', () => {
state.next({ other: 123 }); state.next({ other: 123 });

10
frontend/app/framework/angular/routers/router-2-state.ts

@ -299,10 +299,10 @@ export class Router2StateMap<T extends object> implements StateSynchronizerMap<T
update[key] = this.state.snapshot[key]; update[key] = this.state.snapshot[key];
} }
this.state.resetState(update); if (this.state.resetState(update)) {
for (const action of this.syncDone) {
for (const action of this.syncDone) { action();
action(); }
} }
} }
@ -344,7 +344,7 @@ function cleanupParams(query: Params) {
if (query.hasOwnProperty(key)) { if (query.hasOwnProperty(key)) {
const value = query[key]; const value = query[key];
if (Types.isNull(value) || Types.isUndefined(key)) { if (Types.isNull(value) || Types.isUndefined(value)) {
delete query[key]; delete query[key];
} }
} }

72
frontend/app/framework/state.spec.ts

@ -0,0 +1,72 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { State } from './state';
describe('State', () => {
let state: State<any>;
beforeEach(() => {
state = new State<any>({});
});
it('should update state with new value', () => {
let updateCount = 0;
state.changes.subscribe(() => {
updateCount++;
});
const updated = state.next({ value: 1 });
expect(updateCount).toEqual(2);
expect(updated).toBeTruthy();
});
it('should reset state with new value', () => {
let updateCount = 0;
state.changes.subscribe(() => {
updateCount++;
});
const updated = state.resetState({ value: 1 });
expect(updateCount).toEqual(2);
expect(updated).toBeTruthy();
});
it('should not update state when nothing changed', () => {
let updateCount = 0;
state.changes.subscribe(() => {
updateCount++;
});
state.next({ value: 1 });
const updated = state.next({ value: 1 });
expect(updateCount).toEqual(2);
expect(updated).toBeFalsy();
});
it('should not reset state when nothing changed', () => {
let updateCount = 0;
state.changes.subscribe(() => {
updateCount++;
});
state.resetState({ value: 1 });
const updated = state.resetState({ value: 1 });
expect(updateCount).toEqual(2);
expect(updated).toBeFalsy();
});
});

50
frontend/app/framework/state.ts

@ -164,7 +164,6 @@ export class ResultSet<T> {
export class State<T extends {}> { export class State<T extends {}> {
private readonly state: BehaviorSubject<Readonly<T>>; private readonly state: BehaviorSubject<Readonly<T>>;
private readonly initialState: Readonly<T>;
public get changes(): Observable<Readonly<T>> { public get changes(): Observable<Readonly<T>> {
return this.state; return this.state;
@ -185,39 +184,54 @@ export class State<T extends {}> {
} }
public projectFrom2<M, N, O>(lhs: Observable<M>, rhs: Observable<N>, project: (l: M, r: N) => O, compare?: (x: O, y: O) => boolean) { public projectFrom2<M, N, O>(lhs: Observable<M>, rhs: Observable<N>, project: (l: M, r: N) => O, compare?: (x: O, y: O) => boolean) {
return combineLatest(lhs, rhs, (x, y) => project(x, y)).pipe( return combineLatest([lhs, rhs]).pipe(
distinctUntilChanged(compare), shareReplay(1)); map(([x, y]) => project(x, y)), distinctUntilChanged(compare), shareReplay(1));
} }
constructor(state: Readonly<T>) { constructor(
this.initialState = state; private readonly initialState: Readonly<T>
) {
this.state = new BehaviorSubject(state); this.state = new BehaviorSubject(initialState);
} }
public resetState(update?: ((v: T) => Readonly<T>) | Partial<T>) { public resetState(update?: ((v: T) => Readonly<T>) | Partial<T>) {
let newState = this.initialState; return this.updateState(this.initialState, update);
}
public next(update: ((v: T) => Readonly<T>) | Partial<T>) {
return this.updateState(this.state.value, update);
}
private updateState(state: T, update?: ((v: T) => Readonly<T>) | Partial<T>) {
let newState = state;
if (update) { if (update) {
if (Types.isFunction(update)) { if (Types.isFunction(update)) {
newState = update(this.initialState); newState = update(state);
} else { } else {
newState = { ...this.initialState, ...update }; newState = { ...state, ...update };
} }
} }
this.state.next(newState); let isChanged = false;
}
public next(update: ((v: T) => Readonly<T>) | Partial<T>) { const newKeys = Object.keys(newState);
let newState: T;
if (Types.isFunction(update)) { if (newKeys.length !== Object.keys(this.snapshot).length) {
newState = update(this.state.value); isChanged = true;
} else { } else {
newState = { ...this.state.value, ...update }; for (const key of newKeys) {
if (newState[key] !== this.snapshot[key]) {
isChanged = true;
break;
}
}
}
if (isChanged) {
this.state.next(newState);
} }
this.state.next(newState); return isChanged;
} }
} }

12
frontend/app/framework/utils/types.ts

@ -162,15 +162,15 @@ export module Types {
return true; return true;
} else if (Types.isObject(lhs) && Types.isObject(rhs)) { } else if (Types.isObject(lhs) && Types.isObject(rhs)) {
if (Object.keys(lhs).length !== Object.keys(rhs).length) { const lhsKeys = Object.keys(lhs);
if (lhsKeys.length !== Object.keys(rhs).length) {
return false; return false;
} }
for (const key in lhs) { for (const key of lhsKeys) {
if (lhs.hasOwnProperty(key)) { if (!equals(lhs[key], rhs[key], lazyString)) {
if (!equals(lhs[key], rhs[key], lazyString)) { return false;
return false;
}
} }
} }

Loading…
Cancel
Save