fixed tests and added some more documentation

This commit is contained in:
lotte
2019-02-19 15:59:03 +01:00
parent 0ebb0de3dd
commit 1cea791cba
10 changed files with 100 additions and 60 deletions

View File

@@ -50,6 +50,10 @@ export class EditItemPageComponent implements OnInit {
this.itemRD$ = this.route.data.pipe(map((data) => data.item)); this.itemRD$ = this.route.data.pipe(map((data) => data.item));
} }
/**
* Get the item page url
* @param item The item for which the url is requested
*/
getItemPage(item: Item): string { getItemPage(item: Item): string {
return getItemPageRoute(item.id) return getItemPageRoute(item.id)
} }

View File

@@ -89,7 +89,7 @@ describe('EditInPlaceFieldComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(EditInPlaceFieldComponent); fixture = TestBed.createComponent(EditInPlaceFieldComponent);
comp = fixture.componentInstance; // EditInPlaceFieldComponent test instance comp = fixture.componentInstance; // EditInPlaceFieldComponent test instance
de = fixture.debugElement.query(By.css('div.d-flex')); de = fixture.debugElement;
el = de.nativeElement; el = de.nativeElement;
comp.url = url; comp.url = url;
@@ -109,36 +109,6 @@ describe('EditInPlaceFieldComponent', () => {
}); });
}); });
describe('changeType is UPDATE', () => {
beforeEach(() => {
comp.fieldUpdate.changeType = FieldChangeType.UPDATE;
fixture.detectChanges();
});
it('the div should have class table-warning', () => {
expect(el.classList).toContain('table-warning');
});
});
describe('changeType is ADD', () => {
beforeEach(() => {
comp.fieldUpdate.changeType = FieldChangeType.ADD;
fixture.detectChanges();
});
it('the div should have class table-success', () => {
expect(el.classList).toContain('table-success');
});
});
describe('changeType is REMOVE', () => {
beforeEach(() => {
comp.fieldUpdate.changeType = FieldChangeType.REMOVE;
fixture.detectChanges();
});
it('the div should have class table-danger', () => {
expect(el.classList).toContain('table-danger');
});
});
describe('setEditable', () => { describe('setEditable', () => {
const editable = false; const editable = false;
beforeEach(() => { beforeEach(() => {
@@ -223,9 +193,9 @@ describe('EditInPlaceFieldComponent', () => {
const metadataFieldSuggestions: InputSuggestion[] = const metadataFieldSuggestions: InputSuggestion[] =
[ [
{ displayValue: mdField1.toString(), value: mdField1.toString() }, { displayValue: mdField1.toString().split('.').join('.​'), value: mdField1.toString() },
{ displayValue: mdField2.toString(), value: mdField2.toString() }, { displayValue: mdField2.toString().split('.').join('.​'), value: mdField2.toString() },
{ displayValue: mdField3.toString(), value: mdField3.toString() } { displayValue: mdField3.toString().split('.').join('.​'), value: mdField3.toString() }
]; ];
beforeEach(() => { beforeEach(() => {

View File

@@ -30,8 +30,8 @@
<th class="text-center">{{'item.edit.metadata.headers.language' | translate}}</th> <th class="text-center">{{'item.edit.metadata.headers.language' | translate}}</th>
<th class="text-center">{{'item.edit.metadata.headers.edit' | translate}}</th> <th class="text-center">{{'item.edit.metadata.headers.edit' | translate}}</th>
</tr> </tr>
<tr ds-edit-in-place-field <tr *ngFor="let updateValue of ((updates$ | async)| dsObjectValues); trackBy: trackUpdate"
*ngFor="let updateValue of ((updates$ | async)| dsObjectValues); trackBy: trackUpdate" ds-edit-in-place-field
[fieldUpdate]="updateValue || {}" [fieldUpdate]="updateValue || {}"
[url]="url" [url]="url"
[ngClass]="{ [ngClass]="{

View File

@@ -1,5 +1,5 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, DebugElement, NO_ERRORS_SCHEMA } from '@angular/core';
import { of as observableOf } from 'rxjs'; import { of as observableOf } from 'rxjs';
import { getTestScheduler } from 'jasmine-marbles'; import { getTestScheduler } from 'jasmine-marbles';
import { ItemMetadataComponent } from './item-metadata.component'; import { ItemMetadataComponent } from './item-metadata.component';
@@ -118,13 +118,11 @@ describe('ItemMetadataComponent', () => {
{ provide: ItemDataService, useValue: itemService }, { provide: ItemDataService, useValue: itemService },
{ provide: ObjectUpdatesService, useValue: objectUpdatesService }, { provide: ObjectUpdatesService, useValue: objectUpdatesService },
{ provide: Router, useValue: router }, { provide: Router, useValue: router },
{ { provide: ActivatedRoute, useValue: routeStub },
provide: ActivatedRoute, useValue: routeStub
},
{ provide: NotificationsService, useValue: notificationsService }, { provide: NotificationsService, useValue: notificationsService },
{ provide: GLOBAL_CONFIG, useValue: { notifications: { timeOut: 10 } } as any } { provide: GLOBAL_CONFIG, useValue: { notifications: { timeOut: 10 } } as any }
], schemas: [ ], schemas: [
CUSTOM_ELEMENTS_SCHEMA NO_ERRORS_SCHEMA
] ]
}).compileComponents(); }).compileComponents();
}) })
@@ -133,7 +131,7 @@ describe('ItemMetadataComponent', () => {
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ItemMetadataComponent); fixture = TestBed.createComponent(ItemMetadataComponent);
comp = fixture.componentInstance; // EditInPlaceFieldComponent test instance comp = fixture.componentInstance; // EditInPlaceFieldComponent test instance
de = fixture.debugElement.query(By.css('div.d-flex')); de = fixture.debugElement;
el = de.nativeElement; el = de.nativeElement;
comp.url = url; comp.url = url;
fixture.detectChanges(); fixture.detectChanges();
@@ -205,5 +203,37 @@ describe('ItemMetadataComponent', () => {
}); });
}); });
}); });
})
; describe('changeType is UPDATE', () => {
beforeEach(() => {
fieldUpdate1.changeType = FieldChangeType.UPDATE;
fixture.detectChanges();
});
it('the div should have class table-warning', () => {
const element = de.queryAll(By.css('tr'))[1].nativeElement;
expect(element.classList).toContain('table-warning');
});
});
describe('changeType is ADD', () => {
beforeEach(() => {
fieldUpdate1.changeType = FieldChangeType.ADD;
fixture.detectChanges();
});
it('the div should have class table-success', () => {
const element = de.queryAll(By.css('tr'))[1].nativeElement;
expect(element.classList).toContain('table-success');
});
});
describe('changeType is REMOVE', () => {
beforeEach(() => {
fieldUpdate1.changeType = FieldChangeType.REMOVE;
fixture.detectChanges();
});
it('the div should have class table-danger', () => {
const element = de.queryAll(By.css('tr'))[1].nativeElement;
expect(element.classList).toContain('table-danger');
});
});
});

View File

@@ -6,8 +6,7 @@ import { CommonModule } from '@angular/common';
import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub'; import { HostWindowServiceStub } from '../../../shared/testing/host-window-service-stub';
import { HostWindowService } from '../../../shared/host-window.service'; import { HostWindowService } from '../../../shared/host-window.service';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { RouterStub } from '../../../shared/testing/router-stub';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@@ -24,10 +23,7 @@ describe('ItemStatusComponent', () => {
lastModified: '2018' lastModified: '2018'
}); });
const itemPageUrl = `fake-url/${mockItem.id}`; const itemPageUrl = `items/${mockItem.id}`;
const routerStub = Object.assign(new RouterStub(), {
url: `${itemPageUrl}/edit`
});
const routeStub = { const routeStub = {
parent: { parent: {
@@ -40,7 +36,6 @@ describe('ItemStatusComponent', () => {
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()], imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), NgbModule.forRoot()],
declarations: [ItemStatusComponent], declarations: [ItemStatusComponent],
providers: [ providers: [
{ provide: Router, useValue: routerStub },
{ provide: ActivatedRoute, useValue: routeStub }, { provide: ActivatedRoute, useValue: routeStub },
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) } { provide: HostWindowService, useValue: new HostWindowServiceStub(0) }
], schemas: [CUSTOM_ELEMENTS_SCHEMA] ], schemas: [CUSTOM_ELEMENTS_SCHEMA]

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { fadeIn, fadeInOut } from '../../../shared/animations/fade'; import { fadeIn, fadeInOut } from '../../../shared/animations/fade';
import { Item } from '../../../core/shared/item.model'; import { Item } from '../../../core/shared/item.model';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { ItemOperation } from '../item-operation/itemOperation.model'; import { ItemOperation } from '../item-operation/itemOperation.model';
import { first, map } from 'rxjs/operators'; import { first, map } from 'rxjs/operators';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@@ -47,7 +47,7 @@ export class ItemStatusComponent implements OnInit {
*/ */
actionsKeys; actionsKeys;
constructor(private router: Router, private route: ActivatedRoute) { constructor(private route: ActivatedRoute) {
} }
ngOnInit(): void { ngOnInit(): void {

View File

@@ -122,7 +122,7 @@ export class SetValidFieldUpdateAction implements Action {
}; };
/** /**
* Create a new SetEditableFieldUpdateAction * Create a new SetValidFieldUpdateAction
* *
* @param url * @param url
* the unique url of the page * the unique url of the page
@@ -206,6 +206,9 @@ export class RemoveObjectUpdatesAction implements Action {
} }
} }
/**
* An ngrx action to remove a single field update in the ObjectUpdates state for a certain page url and field uuid
*/
export class RemoveFieldUpdateAction implements Action { export class RemoveFieldUpdateAction implements Action {
type = ObjectUpdatesActionTypes.REMOVE_FIELD; type = ObjectUpdatesActionTypes.REMOVE_FIELD;
payload: { payload: {

View File

@@ -11,43 +11,73 @@ import {
} from './object-updates.actions'; } from './object-updates.actions';
import { hasNoValue, hasValue } from '../../../shared/empty.util'; import { hasNoValue, hasValue } from '../../../shared/empty.util';
/**
* Path where discarded objects are saved
*/
export const OBJECT_UPDATES_TRASH_PATH = '/trash'; export const OBJECT_UPDATES_TRASH_PATH = '/trash';
/**
* The state for a single field
*/
export interface FieldState { export interface FieldState {
editable: boolean, editable: boolean,
isNew: boolean, isNew: boolean,
isValid: boolean isValid: boolean
} }
/**
* A list of states for all the fields for a single page, mapped by uuid
*/
export interface FieldStates { export interface FieldStates {
[uuid: string]: FieldState; [uuid: string]: FieldState;
} }
/**
* Represents every object that has a UUID
*/
export interface Identifiable { export interface Identifiable {
uuid: string uuid: string
} }
/**
* The state of a single field update
*/
export interface FieldUpdate { export interface FieldUpdate {
field: Identifiable, field: Identifiable,
changeType: FieldChangeType changeType: FieldChangeType
} }
/**
* The states of all field updates available for a single page, mapped by uuid
*/
export interface FieldUpdates { export interface FieldUpdates {
[uuid: string]: FieldUpdate; [uuid: string]: FieldUpdate;
} }
/**
* The updated state of a single page
*/
export interface ObjectUpdatesEntry { export interface ObjectUpdatesEntry {
fieldStates: FieldStates; fieldStates: FieldStates;
fieldUpdates: FieldUpdates fieldUpdates: FieldUpdates
lastModified: Date; lastModified: Date;
// lastUpdate: Date;
} }
/**
* The updated state of all pages, mapped by the page URL
*/
export interface ObjectUpdatesState { export interface ObjectUpdatesState {
[url: string]: ObjectUpdatesEntry; [url: string]: ObjectUpdatesEntry;
} }
/**
* Initial state for an existing initialized field
*/
const initialFieldState = { editable: false, isNew: false, isValid: true }; const initialFieldState = { editable: false, isNew: false, isValid: true };
/**
* Initial state for a newly added field
*/
const initialNewFieldState = { editable: true, isNew: true, isValid: true }; const initialNewFieldState = { editable: true, isNew: true, isValid: true };
// Object.create(null) ensures the object has no default js properties (e.g. `__proto__`) // Object.create(null) ensures the object has no default js properties (e.g. `__proto__`)

View File

@@ -224,6 +224,7 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange
this.submitSuggestion.emit(data); this.submitSuggestion.emit(data);
} }
/* START - Method's needed to add ngModel (ControlValueAccessor) to a component */
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
this.propagateChange = fn; this.propagateChange = fn;
} }
@@ -248,8 +249,5 @@ export class InputSuggestionsComponent implements ControlValueAccessor, OnChange
this._value = val; this._value = val;
this.propagateChange(this._value); this.propagateChange(this._value);
} }
/* END - Method's needed to add ngModel to a component */
focus() {
this.queryInput.nativeElement.focus();
}
} }

View File

@@ -1,4 +1,14 @@
/**
* Interface representing a single suggestion for the input suggestions component
*/
export interface InputSuggestion { export interface InputSuggestion {
/**
* The displayed value of the suggestion
*/
displayValue: string, displayValue: string,
/**
* The actual value of the suggestion
*/
value: string value: string
} }