Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
feat(list-editor): add deletion functionality (DSP-1334) (#378)
* feat(list-editor): adds deletion functionality * feat: adds simple error handling * test: adds unit tests * test: adds even more unit tests! * chore: adds comments to explain some code * refactor: small name change * fix: list of children nodes are now correctly updated in the parent list node * chore: remove package-lock.json
- Loading branch information
Showing
9 changed files
with
471 additions
and
108 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
176 changes: 144 additions & 32 deletions
176
src/app/project/list/list-item-form/list-item-form.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,69 +1,181 @@ | ||
import { HttpClientModule } from '@angular/common/http'; | ||
import { OverlayContainer } from '@angular/cdk/overlay'; | ||
import { HarnessLoader } from '@angular/cdk/testing'; | ||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; | ||
import { Component, OnInit, ViewChild } from '@angular/core'; | ||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { ReactiveFormsModule } from '@angular/forms'; | ||
import { MatButtonModule } from '@angular/material/button'; | ||
import { MatButtonHarness } from '@angular/material/button/testing'; | ||
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; | ||
import { MatDialogHarness } from '@angular/material/dialog/testing'; | ||
import { MatIconModule } from '@angular/material/icon'; | ||
import { MatInputModule } from '@angular/material/input'; | ||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||
import { RouterTestingModule } from '@angular/router/testing'; | ||
import { KnoraApiConnection } from '@dasch-swiss/dsp-js'; | ||
import { ApiResponseData, DeleteListNodeResponse, ListsEndpointAdmin, StringLiteral } from '@dasch-swiss/dsp-js'; | ||
import { | ||
AppInitService, | ||
DspActionModule, | ||
DspApiConfigToken, | ||
DspApiConnectionToken, | ||
DspCoreModule | ||
DspApiConnectionToken | ||
} from '@dasch-swiss/dsp-ui'; | ||
import { TranslateModule } from '@ngx-translate/core'; | ||
import { of } from 'rxjs'; | ||
import { AjaxResponse } from 'rxjs/ajax'; | ||
import { DialogHeaderComponent } from 'src/app/main/dialog/dialog-header/dialog-header.component'; | ||
import { DialogComponent } from 'src/app/main/dialog/dialog.component'; | ||
import { ErrorComponent } from 'src/app/main/error/error.component'; | ||
import { TestConfig } from 'test.config'; | ||
import { ListItemFormComponent } from './list-item-form.component'; | ||
import { ListItemFormComponent, ListNodeOperation } from './list-item-form.component'; | ||
|
||
/** | ||
* Test host component to simulate parent component. | ||
*/ | ||
@Component({ | ||
template: ` | ||
<app-list-item-form | ||
#listItemForm | ||
[iri]="iri" | ||
[language]="language" | ||
(refreshParent)="updateView($event)" | ||
[projectIri]="projectIri" | ||
[projectcode]="projectCode" | ||
[labels]="labels"> | ||
</app-list-item-form>` | ||
}) | ||
class TestHostComponent implements OnInit { | ||
|
||
@ViewChild('listItemForm') listItemForm: ListItemFormComponent; | ||
|
||
iri = 'http://rdfh.ch/lists/0001/notUsedList01'; | ||
|
||
language = 'en'; | ||
|
||
projectIri = 'http://rdfh.ch/projects/0001'; | ||
|
||
projectCode = '0001'; | ||
|
||
labels: StringLiteral[]; | ||
|
||
constructor() {} | ||
|
||
ngOnInit() { | ||
this.labels = [ | ||
{ | ||
value: 'node 1', | ||
language: 'en' | ||
} | ||
]; | ||
} | ||
|
||
} | ||
|
||
describe('ListItemFormComponent', () => { | ||
let component: ListItemFormComponent; | ||
let fixture: ComponentFixture<ListItemFormComponent>; | ||
let testHostComponent: TestHostComponent; | ||
let testHostFixture: ComponentFixture<TestHostComponent>; | ||
let rootLoader: HarnessLoader; | ||
let overlayContainer: OverlayContainer; | ||
|
||
beforeEach(async(() => { | ||
|
||
const listsEndpointSpyObj = { | ||
admin: { | ||
listsEndpoint: jasmine.createSpyObj('listsEndpoint', ['deleteListNode']) | ||
} | ||
}; | ||
|
||
TestBed.configureTestingModule({ | ||
declarations: [ | ||
ListItemFormComponent, | ||
TestHostComponent, | ||
DialogComponent, | ||
ErrorComponent | ||
DialogHeaderComponent | ||
], | ||
imports: [ | ||
BrowserAnimationsModule, | ||
DspActionModule, | ||
DspCoreModule, | ||
HttpClientModule, | ||
MatIconModule, | ||
MatInputModule, | ||
ReactiveFormsModule, | ||
RouterTestingModule, | ||
MatDialogModule, | ||
MatButtonModule, | ||
TranslateModule.forRoot() | ||
], | ||
providers: [ | ||
AppInitService, | ||
{ | ||
provide: DspApiConfigToken, | ||
useValue: TestConfig.ApiConfig | ||
provide: DspApiConnectionToken, | ||
useValue: listsEndpointSpyObj | ||
}, | ||
{ | ||
provide: DspApiConnectionToken, | ||
useValue: new KnoraApiConnection(TestConfig.ApiConfig) | ||
} | ||
provide: MAT_DIALOG_DATA, | ||
useValue: {} | ||
}, | ||
{ | ||
provide: MatDialogRef, | ||
useValue: {} | ||
}, | ||
] | ||
|
||
}) | ||
.compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(ListItemFormComponent); | ||
component = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
testHostFixture = TestBed.createComponent(TestHostComponent); | ||
testHostComponent = testHostFixture.componentInstance; | ||
testHostFixture.detectChanges(); | ||
|
||
expect(testHostComponent).toBeTruthy(); | ||
|
||
testHostComponent.listItemForm.showActionBubble = true; | ||
testHostFixture.detectChanges(); | ||
|
||
overlayContainer = TestBed.inject(OverlayContainer); | ||
rootLoader = TestbedHarnessEnvironment.documentRootLoader(testHostFixture); | ||
}); | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy(); | ||
afterEach(async () => { | ||
const dialogs = await rootLoader.getAllHarnesses(MatDialogHarness); | ||
await Promise.all(dialogs.map(async d => await d.close())); | ||
|
||
// angular won't call this for us so we need to do it ourselves to avoid leaks. | ||
overlayContainer.ngOnDestroy(); | ||
}); | ||
|
||
it('should show a dialog box when the delete button is clicked', async () => { | ||
|
||
const deleteListNodeResponse: DeleteListNodeResponse = new DeleteListNodeResponse(); | ||
deleteListNodeResponse.node.children = []; | ||
deleteListNodeResponse.node.id = 'http://rdfh.ch/lists/0001/notUsedList'; | ||
deleteListNodeResponse.node.isRootNode = true; | ||
deleteListNodeResponse.node.name = 'notUsedList'; | ||
deleteListNodeResponse.node.projectIri = 'http://rdfh.ch/projects/0001'; | ||
|
||
const listSpy = TestBed.inject(DspApiConnectionToken); | ||
|
||
(listSpy.admin.listsEndpoint as jasmine.SpyObj<ListsEndpointAdmin>).deleteListNode.and.callFake( | ||
() => { | ||
|
||
const response = deleteListNodeResponse; | ||
|
||
return of(ApiResponseData.fromAjaxResponse({response} as AjaxResponse)); | ||
} | ||
); | ||
|
||
spyOn(testHostComponent.listItemForm.refreshParent, 'emit'); | ||
|
||
const deleteButton = await rootLoader.getHarness(MatButtonHarness.with({selector: '.delete'})); | ||
await deleteButton.click(); | ||
|
||
const dialogHarnesses = await rootLoader.getAllHarnesses(MatDialogHarness); | ||
|
||
expect(dialogHarnesses.length).toEqual(1); | ||
|
||
const confirmButton = await rootLoader.getHarness(MatButtonHarness.with({selector: '.confirm-button'})); | ||
|
||
await confirmButton.click(); | ||
|
||
const listNodeOperation: ListNodeOperation = new ListNodeOperation(); | ||
listNodeOperation.listNode = deleteListNodeResponse.node; | ||
listNodeOperation.operation = 'delete'; | ||
|
||
testHostFixture.whenStable().then(() => { | ||
expect(listSpy.admin.listsEndpoint.deleteListNode).toHaveBeenCalledWith(testHostComponent.iri); | ||
expect(listSpy.admin.listsEndpoint.deleteListNode).toHaveBeenCalledTimes(1); | ||
|
||
expect(testHostComponent.listItemForm.refreshParent.emit).toHaveBeenCalledWith(listNodeOperation); | ||
expect(testHostComponent.listItemForm.refreshParent.emit).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
}); | ||
}); |
Oops, something went wrong.