mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
frontend unit tests
toasts component testing conditional import of angular setup-jest for vscode-jest support Update jest.config.js Create open-documents.service.spec.ts Add unit tests for all REST services settings service test Remove component from settings service test Create permissions.service.spec.ts upload documents service tests Update package.json Create toast.service.spec.ts Tasks service test Statistics widget component tests Update permissions.service.ts Create app.component.spec.ts settings component testing tasks component unit testing Management list component generic tests Some management component tests document notes component unit tests Create document-list.component.spec.ts Create save-view-config-dialog.component.spec.ts Create filter-editor.component.spec.ts small and large document cards unit testing Create bulk-editor.component.spec.ts document detail unit tests saving work on documentdetail component spec Create document-asn.component.spec.ts dashboard & widgets unit testing Fix ResizeObserver mock common component unit tests fix some merge errors Update app-frame.component.spec.ts Create page-header.component.spec.ts input component unit tests FilterableDropdownComponent unit testing and found minor errors update taskservice unit tests Edit dialogs unit tests Create date-dropdown.component.spec.ts Remove selectors from guard tests confirm dialog component tests app frame component test Miscellaneous component tests Update document-list-view.service.spec.ts directives unit tests Remove unused resizeobserver mock guard unit tests Update query-params.spec.ts try to fix flaky playwright filter rules utils & testing Interceptor unit tests Pipes unit testing Utils unit tests Update upload-documents.service.spec.ts consumer status service tests Update setup-jest.ts Create document-list-view.service.spec.ts Update app-routing.module.ts
This commit is contained in:
@@ -0,0 +1,869 @@
|
||||
import {
|
||||
HttpTestingController,
|
||||
HttpClientTestingModule,
|
||||
} from '@angular/common/http/testing'
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import {
|
||||
NgbModal,
|
||||
NgbModule,
|
||||
NgbModalModule,
|
||||
NgbModalRef,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { of, throwError } from 'rxjs'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { FilterPipe } from 'src/app/pipes/filter.pipe'
|
||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||
import {
|
||||
SelectionData,
|
||||
DocumentService,
|
||||
} from 'src/app/services/rest/document.service'
|
||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||
import { TagService } from 'src/app/services/rest/tag.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { ConfirmDialogComponent } from '../../common/confirm-dialog/confirm-dialog.component'
|
||||
import { FilterableDropdownComponent } from '../../common/filterable-dropdown/filterable-dropdown.component'
|
||||
import { ToggleableDropdownButtonComponent } from '../../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
|
||||
import { PermissionsDialogComponent } from '../../common/permissions-dialog/permissions-dialog.component'
|
||||
import { PermissionsFormComponent } from '../../common/input/permissions/permissions-form/permissions-form.component'
|
||||
import { BulkEditorComponent } from './bulk-editor.component'
|
||||
import { SelectComponent } from '../../common/input/select/select.component'
|
||||
import { UserService } from 'src/app/services/rest/user.service'
|
||||
import { PermissionsGroupComponent } from '../../common/input/permissions/permissions-group/permissions-group.component'
|
||||
import { PermissionsUserComponent } from '../../common/input/permissions/permissions-user/permissions-user.component'
|
||||
import { NgSelectModule } from '@ng-select/ng-select'
|
||||
import { GroupService } from 'src/app/services/rest/group.service'
|
||||
|
||||
const selectionData: SelectionData = {
|
||||
selected_tags: [
|
||||
{ id: 12, document_count: 3 },
|
||||
{ id: 22, document_count: 1 },
|
||||
{ id: 19, document_count: 0 },
|
||||
],
|
||||
selected_correspondents: [{ id: 33, document_count: 1 }],
|
||||
selected_document_types: [{ id: 44, document_count: 3 }],
|
||||
selected_storage_paths: [
|
||||
{ id: 66, document_count: 3 },
|
||||
{ id: 55, document_count: 0 },
|
||||
],
|
||||
}
|
||||
|
||||
describe('BulkEditorComponent', () => {
|
||||
let component: BulkEditorComponent
|
||||
let fixture: ComponentFixture<BulkEditorComponent>
|
||||
let permissionsService: PermissionsService
|
||||
let documentListViewService: DocumentListViewService
|
||||
let documentService: DocumentService
|
||||
let toastService: ToastService
|
||||
let modalService: NgbModal
|
||||
let httpTestingController: HttpTestingController
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
BulkEditorComponent,
|
||||
IfPermissionsDirective,
|
||||
FilterableDropdownComponent,
|
||||
ToggleableDropdownButtonComponent,
|
||||
FilterPipe,
|
||||
ConfirmDialogComponent,
|
||||
SafeHtmlPipe,
|
||||
PermissionsDialogComponent,
|
||||
PermissionsFormComponent,
|
||||
SelectComponent,
|
||||
PermissionsGroupComponent,
|
||||
PermissionsUserComponent,
|
||||
],
|
||||
providers: [
|
||||
PermissionsService,
|
||||
{
|
||||
provide: TagService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [
|
||||
{ id: 12, name: 'tag12' },
|
||||
{ id: 22, name: 'tag22' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: CorrespondentService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [{ id: 33, name: 'correspondent33' }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: DocumentTypeService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [{ id: 44, name: 'doctype44' }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: StoragePathService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [
|
||||
{ id: 66, name: 'storagepath66' },
|
||||
{ id: 55, name: 'storagepath55' },
|
||||
],
|
||||
}),
|
||||
},
|
||||
},
|
||||
FilterPipe,
|
||||
SettingsService,
|
||||
{
|
||||
provide: UserService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [{ id: 1, username: 'user1' }],
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: GroupService,
|
||||
useValue: {
|
||||
listAll: () =>
|
||||
of({
|
||||
results: [],
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NgbModule,
|
||||
NgbModalModule,
|
||||
NgSelectModule,
|
||||
],
|
||||
}).compileComponents()
|
||||
|
||||
permissionsService = TestBed.inject(PermissionsService)
|
||||
documentListViewService = TestBed.inject(DocumentListViewService)
|
||||
documentService = TestBed.inject(DocumentService)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
|
||||
fixture = TestBed.createComponent(BulkEditorComponent)
|
||||
component = fixture.componentInstance
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('should apply selection data to tags menu', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
fixture.detectChanges()
|
||||
expect(component.tagSelectionModel.getSelectedItems()).toHaveLength(0)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 5, 7]))
|
||||
jest
|
||||
.spyOn(documentService, 'getSelectionData')
|
||||
.mockReturnValue(of(selectionData))
|
||||
component.openTagsDropdown()
|
||||
expect(component.tagSelectionModel.selectionSize()).toEqual(1)
|
||||
})
|
||||
|
||||
it('should apply selection data to correspondents menu', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
component.correspondentSelectionModel.getSelectedItems()
|
||||
).toHaveLength(0)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 5, 7]))
|
||||
jest
|
||||
.spyOn(documentService, 'getSelectionData')
|
||||
.mockReturnValue(of(selectionData))
|
||||
component.openCorrespondentDropdown()
|
||||
expect(component.correspondentSelectionModel.items).toHaveLength(2)
|
||||
expect(component.correspondentSelectionModel.selectionSize()).toEqual(0)
|
||||
})
|
||||
|
||||
it('should apply selection data to doc types menu', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
component.documentTypeSelectionModel.getSelectedItems()
|
||||
).toHaveLength(0)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 5, 7]))
|
||||
jest
|
||||
.spyOn(documentService, 'getSelectionData')
|
||||
.mockReturnValue(of(selectionData))
|
||||
component.openDocumentTypeDropdown()
|
||||
expect(component.documentTypeSelectionModel.selectionSize()).toEqual(1)
|
||||
})
|
||||
|
||||
it('should apply selection data to storage path menu', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
component.storagePathsSelectionModel.getSelectedItems()
|
||||
).toHaveLength(0)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 5, 7]))
|
||||
jest
|
||||
.spyOn(documentService, 'getSelectionData')
|
||||
.mockReturnValue(of(selectionData))
|
||||
component.openStoragePathDropdown()
|
||||
expect(component.storagePathsSelectionModel.selectionSize()).toEqual(1)
|
||||
})
|
||||
|
||||
it('should execute modify tags bulk operation', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = false
|
||||
fixture.detectChanges()
|
||||
component.setTags({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'modify_tags',
|
||||
parameters: { add_tags: [101], remove_tags: [] },
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should execute modify tags bulk operation with confirmation dialog if enabled', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setTags({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
httpTestingController
|
||||
.expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`)
|
||||
.flush(true)
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should set modal dialog text accordingly for tag edit confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setTags({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [{ id: 101, name: 'Tag 101' }],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will remove the tag "Tag 101" from 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setTags({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [
|
||||
{ id: 101, name: 'Tag 101' },
|
||||
{ id: 102, name: 'Tag 102' },
|
||||
],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will remove the tags "Tag 101" and "Tag 102" from 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setTags({
|
||||
itemsToAdd: [
|
||||
{ id: 101, name: 'Tag 101' },
|
||||
{ id: 102, name: 'Tag 102' },
|
||||
],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will add the tags "Tag 101" and "Tag 102" to 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setTags({
|
||||
itemsToAdd: [
|
||||
{ id: 101, name: 'Tag 101' },
|
||||
{ id: 102, name: 'Tag 102' },
|
||||
],
|
||||
itemsToRemove: [{ id: 103, name: 'Tag 103' }],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will add the tags "Tag 101" and "Tag 102" and remove the tags "Tag 103" on 2 selected document(s).'
|
||||
)
|
||||
})
|
||||
|
||||
it('should execute modify correspondent bulk operation', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = false
|
||||
fixture.detectChanges()
|
||||
component.setCorrespondents({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'set_correspondent',
|
||||
parameters: { correspondent: 101 },
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should execute modify correspondent bulk operation with confirmation dialog if enabled', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setCorrespondents({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
httpTestingController
|
||||
.expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`)
|
||||
.flush(true)
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should set modal dialog text accordingly for correspondent edit confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setCorrespondents({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [{ id: 101, name: 'Correspondent 101' }],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will remove the correspondent from 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setCorrespondents({
|
||||
itemsToAdd: [{ id: 101, name: 'Correspondent 101' }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will assign the correspondent "Correspondent 101" to 2 selected document(s).'
|
||||
)
|
||||
})
|
||||
|
||||
it('should execute modify document type bulk operation', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = false
|
||||
fixture.detectChanges()
|
||||
component.setDocumentTypes({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'set_document_type',
|
||||
parameters: { document_type: 101 },
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should execute modify document type bulk operation with confirmation dialog if enabled', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setDocumentTypes({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
httpTestingController
|
||||
.expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`)
|
||||
.flush(true)
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should set modal dialog text accordingly for document type edit confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setDocumentTypes({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [{ id: 101, name: 'DocType 101' }],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will remove the document type from 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setDocumentTypes({
|
||||
itemsToAdd: [{ id: 101, name: 'DocType 101' }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will assign the document type "DocType 101" to 2 selected document(s).'
|
||||
)
|
||||
})
|
||||
|
||||
it('should execute modify storage path bulk operation', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = false
|
||||
fixture.detectChanges()
|
||||
component.setStoragePaths({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'set_storage_path',
|
||||
parameters: { storage_path: 101 },
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should execute modify storage path bulk operation with confirmation dialog if enabled', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setStoragePaths({
|
||||
itemsToAdd: [{ id: 101 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
httpTestingController
|
||||
.expectOne(`${environment.apiBaseUrl}documents/bulk_edit/`)
|
||||
.flush(true)
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should set modal dialog text accordingly for storage path edit confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setStoragePaths({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [{ id: 101, name: 'StoragePath 101' }],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will remove the storage path from 2 selected document(s).'
|
||||
)
|
||||
modal.close()
|
||||
component.setStoragePaths({
|
||||
itemsToAdd: [{ id: 101, name: 'StoragePath 101' }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(modal.componentInstance.message).toEqual(
|
||||
'This operation will assign the storage path "StoragePath 101" to 2 selected document(s).'
|
||||
)
|
||||
})
|
||||
|
||||
it('should only execute bulk operations when changes are detected', () => {
|
||||
component.setTags({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
component.setCorrespondents({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
component.setDocumentTypes({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
component.setStoragePaths({
|
||||
itemsToAdd: [],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
httpTestingController.expectNone(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
})
|
||||
|
||||
it('should support bulk delete with confirmation', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.applyDelete()
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'delete',
|
||||
parameters: {},
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should not be accessible with insufficient global permissions', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(false)
|
||||
fixture.detectChanges()
|
||||
const dropdown = fixture.debugElement.query(
|
||||
By.directive(FilterableDropdownComponent)
|
||||
)
|
||||
expect(dropdown).toBeNull()
|
||||
})
|
||||
|
||||
it('should disable with insufficient object permissions', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(false)
|
||||
fixture.detectChanges()
|
||||
const button = fixture.debugElement
|
||||
.query(By.directive(FilterableDropdownComponent))
|
||||
.query(By.css('button'))
|
||||
expect(button.nativeElement.disabled).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should show a warning toast on bulk edit error', () => {
|
||||
jest
|
||||
.spyOn(documentService, 'bulkEdit')
|
||||
.mockReturnValue(
|
||||
throwError(() => new Error('error executing bulk operation'))
|
||||
)
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = false
|
||||
fixture.detectChanges()
|
||||
const toastSpy = jest.spyOn(toastService, 'showError')
|
||||
component.setTags({
|
||||
itemsToAdd: [{ id: 0 }],
|
||||
itemsToRemove: [],
|
||||
})
|
||||
expect(toastSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should support redo ocr', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.redoOcrSelected()
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirm()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'redo_ocr',
|
||||
parameters: {},
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
|
||||
it('should support bulk download with archive, originals or both and file formatting', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.downloadForm.get('downloadFileTypeArchive').patchValue(true)
|
||||
fixture.detectChanges()
|
||||
let downloadSpy = jest.spyOn(documentService, 'bulkDownload')
|
||||
//archive
|
||||
component.downloadSelected()
|
||||
expect(downloadSpy).toHaveBeenCalledWith([3, 4], 'archive', false)
|
||||
//originals
|
||||
component.downloadForm.get('downloadFileTypeArchive').patchValue(false)
|
||||
component.downloadForm.get('downloadFileTypeOriginals').patchValue(true)
|
||||
component.downloadSelected()
|
||||
expect(downloadSpy).toHaveBeenCalledWith([3, 4], 'originals', false)
|
||||
//both
|
||||
component.downloadForm.get('downloadFileTypeArchive').patchValue(true)
|
||||
component.downloadSelected()
|
||||
expect(downloadSpy).toHaveBeenCalledWith([3, 4], 'both', false)
|
||||
//formatting
|
||||
component.downloadForm.get('downloadUseFormatting').patchValue(true)
|
||||
component.downloadSelected()
|
||||
expect(downloadSpy).toHaveBeenCalledWith([3, 4], 'both', true)
|
||||
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/bulk_download/`
|
||||
)
|
||||
})
|
||||
|
||||
it('should support bulk permissions update', () => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[0]))
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
jest
|
||||
.spyOn(documentListViewService, 'documents', 'get')
|
||||
.mockReturnValue([{ id: 3 }, { id: 4 }])
|
||||
jest
|
||||
.spyOn(documentListViewService, 'selected', 'get')
|
||||
.mockReturnValue(new Set([3, 4]))
|
||||
jest
|
||||
.spyOn(permissionsService, 'currentUserHasObjectPermissions')
|
||||
.mockReturnValue(true)
|
||||
component.showConfirmationDialogs = true
|
||||
fixture.detectChanges()
|
||||
component.setPermissions()
|
||||
expect(modal).not.toBeUndefined()
|
||||
modal.componentInstance.confirmClicked.next()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/bulk_edit/`
|
||||
)
|
||||
req.flush(true)
|
||||
expect(req.request.body).toEqual({
|
||||
documents: [3, 4],
|
||||
method: 'set_permissions',
|
||||
parameters: undefined,
|
||||
})
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
) // list reload
|
||||
httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
) // listAllFilteredIds
|
||||
})
|
||||
})
|
@@ -0,0 +1,129 @@
|
||||
import { DatePipe } from '@angular/common'
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
fakeAsync,
|
||||
tick,
|
||||
} from '@angular/core/testing'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import {
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
NgbProgressbarModule,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe'
|
||||
import { DocumentCardLargeComponent } from './document-card-large.component'
|
||||
|
||||
const doc = {
|
||||
id: 10,
|
||||
title: 'Document 10',
|
||||
tags: [3, 4, 5],
|
||||
correspondent: 8,
|
||||
document_type: 10,
|
||||
storage_path: null,
|
||||
notes: [
|
||||
{
|
||||
id: 11,
|
||||
note: 'This is some note content bananas',
|
||||
},
|
||||
],
|
||||
content:
|
||||
'Cupcake ipsum dolor sit amet ice cream. Donut shortbread cheesecake caramels tiramisu pastry caramels chocolate bar. Tart tootsie roll muffin icing cotton candy topping sweet roll. Pie lollipop dragée sesame snaps donut tart pudding. Oat cake apple pie danish danish candy canes. Shortbread candy canes sesame snaps muffin tiramisu marshmallow chocolate bar halvah. Cake lemon drops candy apple pie carrot cake bonbon halvah pastry gummi bears. Sweet roll candy ice cream sesame snaps marzipan cookie ice cream. Cake cheesecake apple pie muffin candy toffee lollipop. Carrot cake oat cake cookie biscuit cupcake cake marshmallow. Sweet roll jujubes carrot cake cheesecake cake candy canes sweet roll gingerbread jelly beans. Apple pie sugar plum oat cake halvah cake. Pie oat cake chocolate cake cookie gingerbread marzipan. Lemon drops cheesecake lollipop danish marzipan candy.',
|
||||
}
|
||||
|
||||
describe('DocumentCardLargeComponent', () => {
|
||||
let component: DocumentCardLargeComponent
|
||||
let fixture: ComponentFixture<DocumentCardLargeComponent>
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
DocumentCardLargeComponent,
|
||||
DocumentTitlePipe,
|
||||
CustomDatePipe,
|
||||
IfPermissionsDirective,
|
||||
SafeUrlPipe,
|
||||
],
|
||||
providers: [DatePipe],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
NgbProgressbarModule,
|
||||
],
|
||||
}).compileComponents()
|
||||
|
||||
fixture = TestBed.createComponent(DocumentCardLargeComponent)
|
||||
component = fixture.componentInstance
|
||||
component.document = doc
|
||||
fixture.detectChanges()
|
||||
})
|
||||
|
||||
it('should display a document', () => {
|
||||
expect(fixture.nativeElement.textContent).toContain('Document 10')
|
||||
expect(fixture.nativeElement.textContent).toContain('Cupcake ipsum')
|
||||
})
|
||||
|
||||
it('should show preview on mouseover after delay to preload content', fakeAsync(() => {
|
||||
component.mouseEnterPreview()
|
||||
expect(component.popover.isOpen()).toBeTruthy()
|
||||
expect(component.popoverHidden).toBeTruthy()
|
||||
tick(600)
|
||||
expect(component.popoverHidden).toBeFalsy()
|
||||
component.mouseLeaveCard()
|
||||
|
||||
component.mouseEnterPreview()
|
||||
tick(100)
|
||||
component.mouseLeavePreview()
|
||||
tick(600)
|
||||
expect(component.popover.isOpen()).toBeFalsy()
|
||||
}))
|
||||
|
||||
it('should trim content', () => {
|
||||
expect(component.contentTrimmed).toHaveLength(503) // includes ...
|
||||
})
|
||||
|
||||
it('should display search hits with colored score', () => {
|
||||
// high
|
||||
component.document.__search_hit__ = {
|
||||
score: 0.9,
|
||||
rank: 1,
|
||||
highlights: 'cheesecake',
|
||||
}
|
||||
fixture.detectChanges()
|
||||
let search_hit = fixture.debugElement.query(By.css('.search-score'))
|
||||
expect(search_hit).not.toBeUndefined()
|
||||
expect(component.searchScoreClass).toEqual('success')
|
||||
|
||||
// medium
|
||||
component.document.__search_hit__.score = 0.6
|
||||
fixture.detectChanges()
|
||||
search_hit = fixture.debugElement.query(By.css('.search-score'))
|
||||
expect(search_hit).not.toBeUndefined()
|
||||
expect(component.searchScoreClass).toEqual('warning')
|
||||
|
||||
// low
|
||||
component.document.__search_hit__.score = 0.1
|
||||
fixture.detectChanges()
|
||||
search_hit = fixture.debugElement.query(By.css('.search-score'))
|
||||
expect(search_hit).not.toBeUndefined()
|
||||
expect(component.searchScoreClass).toEqual('danger')
|
||||
})
|
||||
|
||||
it('should display note highlights', () => {
|
||||
component.document.__search_hit__ = {
|
||||
score: 0.9,
|
||||
rank: 1,
|
||||
note_highlights: '<span>bananas</span>',
|
||||
}
|
||||
fixture.detectChanges()
|
||||
expect(fixture.nativeElement.textContent).toContain('bananas')
|
||||
expect(component.searchNoteHighlights).toContain('<span>bananas</span>')
|
||||
})
|
||||
})
|
@@ -133,7 +133,7 @@ export class DocumentCardLargeComponent extends ComponentWithPermissions {
|
||||
|
||||
get contentTrimmed() {
|
||||
return (
|
||||
this.document.content.substr(0, 500) +
|
||||
this.document.content.substring(0, 500) +
|
||||
(this.document.content.length > 500 ? '...' : '')
|
||||
)
|
||||
}
|
||||
|
@@ -0,0 +1,120 @@
|
||||
import { DatePipe } from '@angular/common'
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
fakeAsync,
|
||||
tick,
|
||||
} from '@angular/core/testing'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import {
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
NgbProgressbarModule,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe'
|
||||
import { DocumentCardSmallComponent } from './document-card-small.component'
|
||||
import { of } from 'rxjs'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { TagComponent } from '../../common/tag/tag.component'
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag'
|
||||
|
||||
const doc = {
|
||||
id: 10,
|
||||
title: 'Document 10',
|
||||
tags: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||
correspondent: 8,
|
||||
document_type: 10,
|
||||
storage_path: null,
|
||||
notes: [
|
||||
{
|
||||
id: 11,
|
||||
note: 'This is some note content bananas',
|
||||
},
|
||||
],
|
||||
tags$: of([
|
||||
{ id: 1, name: 'Tag1' },
|
||||
{ id: 2, name: 'Tag2' },
|
||||
{ id: 3, name: 'Tag3' },
|
||||
{ id: 4, name: 'Tag4' },
|
||||
{ id: 5, name: 'Tag5' },
|
||||
{ id: 6, name: 'Tag6' },
|
||||
{ id: 7, name: 'Tag7' },
|
||||
{ id: 8, name: 'Tag8' },
|
||||
]),
|
||||
content:
|
||||
'Cupcake ipsum dolor sit amet ice cream. Donut shortbread cheesecake caramels tiramisu pastry caramels chocolate bar. Tart tootsie roll muffin icing cotton candy topping sweet roll. Pie lollipop dragée sesame snaps donut tart pudding. Oat cake apple pie danish danish candy canes. Shortbread candy canes sesame snaps muffin tiramisu marshmallow chocolate bar halvah. Cake lemon drops candy apple pie carrot cake bonbon halvah pastry gummi bears. Sweet roll candy ice cream sesame snaps marzipan cookie ice cream. Cake cheesecake apple pie muffin candy toffee lollipop. Carrot cake oat cake cookie biscuit cupcake cake marshmallow. Sweet roll jujubes carrot cake cheesecake cake candy canes sweet roll gingerbread jelly beans. Apple pie sugar plum oat cake halvah cake. Pie oat cake chocolate cake cookie gingerbread marzipan. Lemon drops cheesecake lollipop danish marzipan candy.',
|
||||
}
|
||||
|
||||
describe('DocumentCardSmallComponent', () => {
|
||||
let component: DocumentCardSmallComponent
|
||||
let fixture: ComponentFixture<DocumentCardSmallComponent>
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
DocumentCardSmallComponent,
|
||||
DocumentTitlePipe,
|
||||
CustomDatePipe,
|
||||
IfPermissionsDirective,
|
||||
SafeUrlPipe,
|
||||
TagComponent,
|
||||
],
|
||||
providers: [DatePipe],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
NgbProgressbarModule,
|
||||
],
|
||||
}).compileComponents()
|
||||
|
||||
fixture = TestBed.createComponent(DocumentCardSmallComponent)
|
||||
component = fixture.componentInstance
|
||||
component.document = Object.assign({}, doc)
|
||||
fixture.detectChanges()
|
||||
})
|
||||
|
||||
it('should display a document, limit tags to 5', () => {
|
||||
expect(fixture.nativeElement.textContent).toContain('Document 10')
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(TagComponent))
|
||||
).toHaveLength(5)
|
||||
component.document.tags = [1, 2]
|
||||
component.document.tags$ = of([
|
||||
{ id: 1 } as PaperlessTag,
|
||||
{ id: 2 } as PaperlessTag,
|
||||
])
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(TagComponent))
|
||||
).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('should increase limit tags to 6 if no notes', () => {
|
||||
component.document.notes = []
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(TagComponent))
|
||||
).toHaveLength(6)
|
||||
})
|
||||
|
||||
it('should show preview on mouseover after delay to preload content', fakeAsync(() => {
|
||||
component.mouseEnterPreview()
|
||||
expect(component.popover.isOpen()).toBeTruthy()
|
||||
expect(component.popoverHidden).toBeTruthy()
|
||||
tick(600)
|
||||
expect(component.popoverHidden).toBeFalsy()
|
||||
component.mouseLeaveCard()
|
||||
|
||||
component.mouseEnterPreview()
|
||||
tick(100)
|
||||
component.mouseLeavePreview()
|
||||
tick(600)
|
||||
expect(component.popover.isOpen()).toBeFalsy()
|
||||
}))
|
||||
})
|
@@ -0,0 +1,591 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { DocumentListComponent } from './document-list.component'
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import { routes } from 'src/app/app-routing.module'
|
||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||
import { PermissionsFilterDropdownComponent } from '../common/permissions-filter-dropdown/permissions-filter-dropdown.component'
|
||||
import { DateDropdownComponent } from '../common/date-dropdown/date-dropdown.component'
|
||||
import { FilterableDropdownComponent } from '../common/filterable-dropdown/filterable-dropdown.component'
|
||||
import { PageHeaderComponent } from '../common/page-header/page-header.component'
|
||||
import { BulkEditorComponent } from './bulk-editor/bulk-editor.component'
|
||||
import { FilterPipe } from 'src/app/pipes/filter.pipe'
|
||||
import {
|
||||
NgbDatepickerModule,
|
||||
NgbDropdown,
|
||||
NgbDropdownItem,
|
||||
NgbDropdownModule,
|
||||
NgbModal,
|
||||
NgbModalRef,
|
||||
NgbPagination,
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ClearableBadgeComponent } from '../common/clearable-badge/clearable-badge.component'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { ToggleableDropdownButtonComponent } from '../common/filterable-dropdown/toggleable-dropdown-button/toggleable-dropdown-button.component'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DatePipe } from '@angular/common'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
import {
|
||||
ConsumerStatusService,
|
||||
FileStatus,
|
||||
} from 'src/app/services/consumer-status.service'
|
||||
import { Subject, of, throwError } from 'rxjs'
|
||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
||||
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
||||
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
|
||||
import {
|
||||
FILTER_FULLTEXT_MORELIKE,
|
||||
FILTER_FULLTEXT_QUERY,
|
||||
FILTER_HAS_TAGS_ANY,
|
||||
} from 'src/app/data/filter-rule-type'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { SortableDirective } from 'src/app/directives/sortable.directive'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { DocumentCardSmallComponent } from './document-card-small/document-card-small.component'
|
||||
import { DocumentCardLargeComponent } from './document-card-large/document-card-large.component'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
||||
import {
|
||||
DOCUMENT_SORT_FIELDS,
|
||||
DOCUMENT_SORT_FIELDS_FULLTEXT,
|
||||
DocumentService,
|
||||
} from 'src/app/services/rest/document.service'
|
||||
import { ConfirmDialogComponent } from '../common/confirm-dialog/confirm-dialog.component'
|
||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
|
||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-view-config-dialog.component'
|
||||
import { TextComponent } from '../common/input/text/text.component'
|
||||
import { CheckComponent } from '../common/input/check/check.component'
|
||||
import { HttpErrorResponse } from '@angular/common/http'
|
||||
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||
|
||||
const docs: PaperlessDocument[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Doc1',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
content: 'document content 1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Doc2',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
content: 'document content 2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Doc3',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
content: 'document content 3',
|
||||
},
|
||||
]
|
||||
|
||||
describe('DocumentListComponent', () => {
|
||||
let component: DocumentListComponent
|
||||
let fixture: ComponentFixture<DocumentListComponent>
|
||||
let documentListService: DocumentListViewService
|
||||
let documentService: DocumentService
|
||||
let consumerStatusService: ConsumerStatusService
|
||||
let savedViewService: SavedViewService
|
||||
let router: Router
|
||||
let activatedRoute: ActivatedRoute
|
||||
let toastService: ToastService
|
||||
let modalService: NgbModal
|
||||
let settingsService: SettingsService
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
DocumentListComponent,
|
||||
PageHeaderComponent,
|
||||
FilterEditorComponent,
|
||||
FilterableDropdownComponent,
|
||||
DateDropdownComponent,
|
||||
PermissionsFilterDropdownComponent,
|
||||
ToggleableDropdownButtonComponent,
|
||||
BulkEditorComponent,
|
||||
ClearableBadgeComponent,
|
||||
DocumentCardSmallComponent,
|
||||
DocumentCardLargeComponent,
|
||||
ConfirmDialogComponent,
|
||||
SaveViewConfigDialogComponent,
|
||||
TextComponent,
|
||||
CheckComponent,
|
||||
IfPermissionsDirective,
|
||||
FilterPipe,
|
||||
CustomDatePipe,
|
||||
SortableDirective,
|
||||
DocumentTitlePipe,
|
||||
UsernamePipe,
|
||||
SafeHtmlPipe,
|
||||
],
|
||||
providers: [
|
||||
FilterPipe,
|
||||
CustomDatePipe,
|
||||
DatePipe,
|
||||
DocumentTitlePipe,
|
||||
UsernamePipe,
|
||||
SafeHtmlPipe,
|
||||
PermissionsGuard,
|
||||
],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NgbDropdownModule,
|
||||
NgbDatepickerModule,
|
||||
NgbPopoverModule,
|
||||
NgbTooltipModule,
|
||||
],
|
||||
}).compileComponents()
|
||||
|
||||
documentListService = TestBed.inject(DocumentListViewService)
|
||||
documentService = TestBed.inject(DocumentService)
|
||||
consumerStatusService = TestBed.inject(ConsumerStatusService)
|
||||
savedViewService = TestBed.inject(SavedViewService)
|
||||
router = TestBed.inject(Router)
|
||||
activatedRoute = TestBed.inject(ActivatedRoute)
|
||||
toastService = TestBed.inject(ToastService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
fixture = TestBed.createComponent(DocumentListComponent)
|
||||
component = fixture.componentInstance
|
||||
})
|
||||
|
||||
it('should load display mode from local storage', () => {
|
||||
window.localStorage.setItem('document-list:displayMode', 'largeCards')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('largeCards')
|
||||
component.displayMode = 'smallCards'
|
||||
component.saveDisplayMode()
|
||||
expect(window.localStorage.getItem('document-list:displayMode')).toEqual(
|
||||
'smallCards'
|
||||
)
|
||||
})
|
||||
|
||||
it('should reload on new document consumed', () => {
|
||||
const reloadSpy = jest.spyOn(documentListService, 'reload')
|
||||
const fileStatusSubject = new Subject<FileStatus>()
|
||||
jest
|
||||
.spyOn(consumerStatusService, 'onDocumentConsumptionFinished')
|
||||
.mockReturnValue(fileStatusSubject)
|
||||
fixture.detectChanges()
|
||||
fileStatusSubject.next(new FileStatus())
|
||||
expect(reloadSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should show score sort fields on fulltext queries', () => {
|
||||
documentListService.filterRules = [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '10',
|
||||
},
|
||||
]
|
||||
fixture.detectChanges()
|
||||
expect(component.getSortFields()).toEqual(DOCUMENT_SORT_FIELDS)
|
||||
|
||||
documentListService.filterRules = [
|
||||
{
|
||||
rule_type: FILTER_FULLTEXT_QUERY,
|
||||
value: 'foo',
|
||||
},
|
||||
]
|
||||
fixture.detectChanges()
|
||||
expect(component.getSortFields()).toEqual(DOCUMENT_SORT_FIELDS_FULLTEXT)
|
||||
})
|
||||
|
||||
it('should determine if filtered, support reset', () => {
|
||||
fixture.detectChanges()
|
||||
documentListService.filterRules = [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '10',
|
||||
},
|
||||
]
|
||||
documentListService.isReloading = false
|
||||
fixture.detectChanges()
|
||||
expect(component.isFiltered).toBeTruthy()
|
||||
expect(fixture.nativeElement.textContent.match(/Reset/g)).toHaveLength(2)
|
||||
component.resetFilters()
|
||||
fixture.detectChanges()
|
||||
expect(fixture.nativeElement.textContent.match(/Reset/g)).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should load saved view from URL', () => {
|
||||
const view: PaperlessSavedView = {
|
||||
id: 10,
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '20',
|
||||
},
|
||||
],
|
||||
}
|
||||
const queryParams = { id: view.id.toString() }
|
||||
const getSavedViewSpy = jest.spyOn(savedViewService, 'getCached')
|
||||
getSavedViewSpy.mockReturnValue(of(view))
|
||||
const activateSavedViewSpy = jest.spyOn(
|
||||
documentListService,
|
||||
'activateSavedViewWithQueryParams'
|
||||
)
|
||||
activateSavedViewSpy.mockImplementation((view, params) => {})
|
||||
jest
|
||||
.spyOn(activatedRoute, 'paramMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||
activatedRoute.snapshot.queryParams = queryParams
|
||||
fixture.detectChanges()
|
||||
expect(getSavedViewSpy).toHaveBeenCalledWith(view.id)
|
||||
expect(activateSavedViewSpy).toHaveBeenCalledWith(
|
||||
view,
|
||||
convertToParamMap(queryParams)
|
||||
)
|
||||
})
|
||||
|
||||
it('should 404 on load saved view from URL if no view', () => {
|
||||
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(null)) // e.g. no saved view found
|
||||
jest
|
||||
.spyOn(activatedRoute, 'paramMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap({ id: '10' })))
|
||||
const navigateSpy = jest.spyOn(router, 'navigate')
|
||||
fixture.detectChanges()
|
||||
expect(navigateSpy).toHaveBeenCalledWith(['404'])
|
||||
})
|
||||
|
||||
it('should load saved view from query params', () => {
|
||||
const view: PaperlessSavedView = {
|
||||
id: 10,
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '20',
|
||||
},
|
||||
],
|
||||
}
|
||||
const getSavedViewSpy = jest.spyOn(savedViewService, 'getCached')
|
||||
getSavedViewSpy.mockReturnValue(of(view))
|
||||
jest
|
||||
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap({ view: view.id.toString() })))
|
||||
fixture.detectChanges()
|
||||
expect(getSavedViewSpy).toHaveBeenCalledWith(view.id)
|
||||
})
|
||||
|
||||
it('should support 3 different display modes', () => {
|
||||
jest.spyOn(documentListService, 'documents', 'get').mockReturnValue(docs)
|
||||
fixture.detectChanges()
|
||||
const displayModeButtons = fixture.debugElement.queryAll(
|
||||
By.css('input[type="radio"]')
|
||||
)
|
||||
expect(component.displayMode).toEqual('smallCards')
|
||||
|
||||
displayModeButtons[0].nativeElement.checked = true
|
||||
displayModeButtons[0].triggerEventHandler('change')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('details')
|
||||
expect(fixture.debugElement.queryAll(By.css('tr'))).toHaveLength(3)
|
||||
|
||||
displayModeButtons[1].nativeElement.checked = true
|
||||
displayModeButtons[1].triggerEventHandler('change')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('smallCards')
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(DocumentCardSmallComponent))
|
||||
).toHaveLength(3)
|
||||
|
||||
displayModeButtons[2].nativeElement.checked = true
|
||||
displayModeButtons[2].triggerEventHandler('change')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('largeCards')
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(DocumentCardLargeComponent))
|
||||
).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('should support setting sort field', () => {
|
||||
expect(documentListService.sortField).toEqual('created')
|
||||
fixture.detectChanges()
|
||||
const sortDropdown = fixture.debugElement.queryAll(
|
||||
By.directive(NgbDropdown)
|
||||
)[1]
|
||||
const asnSortFieldButton = sortDropdown.query(By.directive(NgbDropdownItem))
|
||||
|
||||
asnSortFieldButton.triggerEventHandler('click')
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.sortField).toEqual('archive_serial_number')
|
||||
documentListService.sortField = 'created'
|
||||
})
|
||||
|
||||
it('should support setting sort field by table head', () => {
|
||||
jest.spyOn(documentListService, 'documents', 'get').mockReturnValue(docs)
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.sortField).toEqual('created')
|
||||
|
||||
const detailsDisplayModeButton = fixture.debugElement.query(
|
||||
By.css('input[type="radio"]')
|
||||
)
|
||||
detailsDisplayModeButton.nativeElement.checked = true
|
||||
detailsDisplayModeButton.triggerEventHandler('change')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('details')
|
||||
|
||||
const sortTh = fixture.debugElement.query(By.directive(SortableDirective))
|
||||
sortTh.triggerEventHandler('click')
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.sortField).toEqual('archive_serial_number')
|
||||
documentListService.sortField = 'created'
|
||||
expect(documentListService.sortReverse).toBeFalsy()
|
||||
component.listSortReverse = true
|
||||
expect(documentListService.sortReverse).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should support select all, none, page & range', () => {
|
||||
jest.spyOn(documentListService, 'documents', 'get').mockReturnValue(docs)
|
||||
jest
|
||||
.spyOn(documentService, 'listAllFilteredIds')
|
||||
.mockReturnValue(of(docs.map((d) => d.id)))
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(0)
|
||||
const docCards = fixture.debugElement.queryAll(
|
||||
By.directive(DocumentCardLargeComponent)
|
||||
)
|
||||
const displayModeButtons = fixture.debugElement.queryAll(
|
||||
By.directive(NgbDropdownItem)
|
||||
)
|
||||
|
||||
const selectAllSpy = jest.spyOn(documentListService, 'selectAll')
|
||||
displayModeButtons[2].triggerEventHandler('click')
|
||||
expect(selectAllSpy).toHaveBeenCalled()
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(3)
|
||||
docCards.forEach((card) => {
|
||||
expect(card.context.selected).toBeTruthy()
|
||||
})
|
||||
|
||||
const selectNoneSpy = jest.spyOn(documentListService, 'selectNone')
|
||||
displayModeButtons[0].triggerEventHandler('click')
|
||||
expect(selectNoneSpy).toHaveBeenCalled()
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(0)
|
||||
docCards.forEach((card) => {
|
||||
expect(card.context.selected).toBeFalsy()
|
||||
})
|
||||
|
||||
const selectPageSpy = jest.spyOn(documentListService, 'selectPage')
|
||||
displayModeButtons[1].triggerEventHandler('click')
|
||||
expect(selectPageSpy).toHaveBeenCalled()
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(3)
|
||||
docCards.forEach((card) => {
|
||||
expect(card.context.selected).toBeTruthy()
|
||||
})
|
||||
|
||||
component.toggleSelected(docs[0], new MouseEvent('click'))
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(2)
|
||||
// reset
|
||||
displayModeButtons[0].triggerEventHandler('click')
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(0)
|
||||
|
||||
// select a range
|
||||
component.toggleSelected(docs[0], new MouseEvent('click'))
|
||||
component.toggleSelected(
|
||||
docs[2],
|
||||
new MouseEvent('click', { shiftKey: true })
|
||||
)
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.selected.size).toEqual(3)
|
||||
})
|
||||
|
||||
it('should support saving an edited view', () => {
|
||||
const view: PaperlessSavedView = {
|
||||
id: 10,
|
||||
name: 'Saved View 10',
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '20',
|
||||
},
|
||||
],
|
||||
}
|
||||
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(view))
|
||||
const queryParams = { view: view.id.toString() }
|
||||
jest
|
||||
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||
activatedRoute.snapshot.queryParams = queryParams
|
||||
router.routerState.snapshot.url = '/view/10/'
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.activeSavedViewId).toEqual(10)
|
||||
|
||||
const modifiedView = Object.assign({}, view)
|
||||
delete modifiedView.name
|
||||
const savedViewServicePatch = jest.spyOn(savedViewService, 'patch')
|
||||
savedViewServicePatch.mockReturnValue(of(modifiedView))
|
||||
const toastSpy = jest.spyOn(toastService, 'showInfo')
|
||||
|
||||
component.saveViewConfig()
|
||||
expect(savedViewServicePatch).toHaveBeenCalledWith(modifiedView)
|
||||
expect(toastSpy).toHaveBeenCalledWith(
|
||||
`View "${view.name}" saved successfully.`
|
||||
)
|
||||
})
|
||||
|
||||
it('should support edited view saving as', () => {
|
||||
const view: PaperlessSavedView = {
|
||||
id: 10,
|
||||
name: 'Saved View 10',
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '20',
|
||||
},
|
||||
],
|
||||
}
|
||||
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(view))
|
||||
const queryParams = { view: view.id.toString() }
|
||||
jest
|
||||
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||
activatedRoute.snapshot.queryParams = queryParams
|
||||
router.routerState.snapshot.url = '/view/10/'
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.activeSavedViewId).toEqual(10)
|
||||
|
||||
const modifiedView = Object.assign({}, view)
|
||||
modifiedView.name = 'Foo Bar'
|
||||
|
||||
let openModal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((modal) => (openModal = modal[0]))
|
||||
const modalSpy = jest.spyOn(modalService, 'open')
|
||||
const toastSpy = jest.spyOn(toastService, 'showInfo')
|
||||
const savedViewServiceCreate = jest.spyOn(savedViewService, 'create')
|
||||
savedViewServiceCreate.mockReturnValueOnce(of(modifiedView))
|
||||
component.saveViewConfigAs()
|
||||
|
||||
const modalCloseSpy = jest.spyOn(openModal, 'close')
|
||||
openModal.componentInstance.saveClicked.next({
|
||||
name: 'Foo Bar',
|
||||
show_on_dashboard: true,
|
||||
show_in_sidebar: true,
|
||||
})
|
||||
expect(savedViewServiceCreate).toHaveBeenCalled()
|
||||
expect(modalSpy).toHaveBeenCalled()
|
||||
expect(toastSpy).toHaveBeenCalled()
|
||||
expect(modalCloseSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle error on edited view saving as', () => {
|
||||
const view: PaperlessSavedView = {
|
||||
id: 10,
|
||||
name: 'Saved View 10',
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: '20',
|
||||
},
|
||||
],
|
||||
}
|
||||
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(view))
|
||||
const queryParams = { view: view.id.toString() }
|
||||
jest
|
||||
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||
activatedRoute.snapshot.queryParams = queryParams
|
||||
router.routerState.snapshot.url = '/view/10/'
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.activeSavedViewId).toEqual(10)
|
||||
|
||||
const modifiedView = Object.assign({}, view)
|
||||
modifiedView.name = 'Foo Bar'
|
||||
|
||||
let openModal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((modal) => (openModal = modal[0]))
|
||||
jest.spyOn(savedViewService, 'create').mockReturnValueOnce(
|
||||
throwError(
|
||||
() =>
|
||||
new HttpErrorResponse({
|
||||
error: { filter_rules: [{ value: '11' }] },
|
||||
})
|
||||
)
|
||||
)
|
||||
component.saveViewConfigAs()
|
||||
|
||||
openModal.componentInstance.saveClicked.next({
|
||||
name: 'Foo Bar',
|
||||
show_on_dashboard: true,
|
||||
show_in_sidebar: true,
|
||||
})
|
||||
expect(openModal.componentInstance.error).toEqual({ filter_rules: ['11'] })
|
||||
})
|
||||
|
||||
it('should navigate to a document', () => {
|
||||
fixture.detectChanges()
|
||||
const routerSpy = jest.spyOn(router, 'navigate')
|
||||
component.openDocumentDetail({ id: 99 })
|
||||
expect(routerSpy).toHaveBeenCalledWith(['documents', 99])
|
||||
})
|
||||
|
||||
it('should support checking if notes enabled to hide column', () => {
|
||||
jest.spyOn(documentListService, 'documents', 'get').mockReturnValue(docs)
|
||||
fixture.detectChanges()
|
||||
expect(documentListService.sortField).toEqual('created')
|
||||
|
||||
const detailsDisplayModeButton = fixture.debugElement.query(
|
||||
By.css('input[type="radio"]')
|
||||
)
|
||||
detailsDisplayModeButton.nativeElement.checked = true
|
||||
detailsDisplayModeButton.triggerEventHandler('change')
|
||||
fixture.detectChanges()
|
||||
expect(component.displayMode).toEqual('details')
|
||||
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(SortableDirective))
|
||||
).toHaveLength(9)
|
||||
|
||||
expect(component.notesEnabled).toBeTruthy()
|
||||
settingsService.set(SETTINGS_KEYS.NOTES_ENABLED, false)
|
||||
fixture.detectChanges()
|
||||
expect(component.notesEnabled).toBeFalsy()
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(SortableDirective))
|
||||
).toHaveLength(8)
|
||||
})
|
||||
|
||||
it('should support toggle on document objects', () => {
|
||||
// TODO: this is just for coverage atm
|
||||
fixture.detectChanges()
|
||||
component.clickTag(1)
|
||||
component.clickCorrespondent(2)
|
||||
component.clickDocumentType(3)
|
||||
component.clickStoragePath(4)
|
||||
})
|
||||
|
||||
it('should support quick filter on document more like', () => {
|
||||
fixture.detectChanges()
|
||||
const qfSpy = jest.spyOn(documentListService, 'quickFilter')
|
||||
component.clickMoreLike(99)
|
||||
expect(qfSpy).toHaveBeenCalledWith([
|
||||
{ rule_type: FILTER_FULLTEXT_MORELIKE, value: '99' },
|
||||
])
|
||||
})
|
||||
})
|
@@ -9,11 +9,11 @@ import {
|
||||
import { ActivatedRoute, convertToParamMap, Router } from '@angular/router'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { filter, first, map, Subject, switchMap, takeUntil } from 'rxjs'
|
||||
import { FilterRule } from 'src/app/data/filter-rule'
|
||||
import {
|
||||
FilterRule,
|
||||
filterRulesDiffer,
|
||||
isFullTextFilterRule,
|
||||
} from 'src/app/data/filter-rule'
|
||||
} from 'src/app/utils/filter-rules'
|
||||
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
||||
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,8 @@ import { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators'
|
||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
|
||||
import { TagService } from 'src/app/services/rest/tag.service'
|
||||
import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
|
||||
import { filterRulesDiffer, FilterRule } from 'src/app/data/filter-rule'
|
||||
import { FilterRule } from 'src/app/data/filter-rule'
|
||||
import { filterRulesDiffer } from 'src/app/utils/filter-rules'
|
||||
import {
|
||||
FILTER_ADDED_AFTER,
|
||||
FILTER_ADDED_BEFORE,
|
||||
@@ -67,7 +68,6 @@ import {
|
||||
OwnerFilterType,
|
||||
PermissionsSelectionModel,
|
||||
} from '../../common/permissions-filter-dropdown/permissions-filter-dropdown.component'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
|
||||
const TEXT_FILTER_TARGET_TITLE = 'title'
|
||||
const TEXT_FILTER_TARGET_TITLE_CONTENT = 'title-content'
|
||||
@@ -111,7 +111,8 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
||||
generateFilterName() {
|
||||
if (this.filterRules.length == 1) {
|
||||
let rule = this.filterRules[0]
|
||||
switch (this.filterRules[0].rule_type) {
|
||||
switch (rule.rule_type) {
|
||||
case FILTER_CORRESPONDENT:
|
||||
case FILTER_HAS_CORRESPONDENT_ANY:
|
||||
if (rule.value) {
|
||||
return $localize`Correspondent: ${
|
||||
@@ -121,15 +122,26 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
||||
return $localize`Without correspondent`
|
||||
}
|
||||
|
||||
case FILTER_DOCUMENT_TYPE:
|
||||
case FILTER_HAS_DOCUMENT_TYPE_ANY:
|
||||
if (rule.value) {
|
||||
return $localize`Type: ${
|
||||
return $localize`Document type: ${
|
||||
this.documentTypes.find((dt) => dt.id == +rule.value)?.name
|
||||
}`
|
||||
} else {
|
||||
return $localize`Without document type`
|
||||
}
|
||||
|
||||
case FILTER_STORAGE_PATH:
|
||||
case FILTER_HAS_STORAGE_PATH_ANY:
|
||||
if (rule.value) {
|
||||
return $localize`Storage path: ${
|
||||
this.storagePaths.find((sp) => sp.id == +rule.value)?.name
|
||||
}`
|
||||
} else {
|
||||
return $localize`Without storage path`
|
||||
}
|
||||
|
||||
case FILTER_HAS_TAGS_ALL:
|
||||
return $localize`Tag: ${
|
||||
this.tags.find((t) => t.id == +rule.value)?.name
|
||||
@@ -165,8 +177,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
||||
private tagService: TagService,
|
||||
private correspondentService: CorrespondentService,
|
||||
private documentService: DocumentService,
|
||||
private storagePathService: StoragePathService,
|
||||
private settingsService: SettingsService
|
||||
private storagePathService: StoragePathService
|
||||
) {}
|
||||
|
||||
@ViewChild('textFilterInput')
|
||||
@@ -557,7 +568,7 @@ export class FilterEditorComponent implements OnInit, OnDestroy {
|
||||
) {
|
||||
filterRules.push({
|
||||
rule_type: FILTER_FULLTEXT_MORELIKE,
|
||||
value: this._moreLikeId?.toString(),
|
||||
value: this._moreLikeId.toString(),
|
||||
})
|
||||
}
|
||||
if (this.tagSelectionModel.isNoneSelected()) {
|
||||
|
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
fakeAsync,
|
||||
tick,
|
||||
} from '@angular/core/testing'
|
||||
import { SaveViewConfigDialogComponent } from './save-view-config-dialog.component'
|
||||
import { NgbActiveModal, NgbModalModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { TextComponent } from '../../common/input/text/text.component'
|
||||
import { CheckComponent } from '../../common/input/check/check.component'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
|
||||
describe('SaveViewConfigDialogComponent', () => {
|
||||
let component: SaveViewConfigDialogComponent
|
||||
let fixture: ComponentFixture<SaveViewConfigDialogComponent>
|
||||
let modal: NgbActiveModal
|
||||
|
||||
beforeEach(fakeAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
SaveViewConfigDialogComponent,
|
||||
TextComponent,
|
||||
CheckComponent,
|
||||
],
|
||||
providers: [NgbActiveModal],
|
||||
imports: [NgbModalModule, FormsModule, ReactiveFormsModule],
|
||||
}).compileComponents()
|
||||
|
||||
modal = TestBed.inject(NgbActiveModal)
|
||||
fixture = TestBed.createComponent(SaveViewConfigDialogComponent)
|
||||
component = fixture.componentInstance
|
||||
fixture.detectChanges()
|
||||
tick()
|
||||
}))
|
||||
|
||||
it('should support default name', () => {
|
||||
const name = 'Tag: Inbox'
|
||||
let result
|
||||
component.saveClicked.subscribe((saveResult) => (result = saveResult))
|
||||
component.defaultName = name
|
||||
component.save()
|
||||
expect(component.defaultName).toEqual(name)
|
||||
expect(result).toEqual({
|
||||
name,
|
||||
showInSideBar: false,
|
||||
showOnDashboard: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('should support user input', () => {
|
||||
const name = 'Tag: Inbox'
|
||||
let result
|
||||
component.saveClicked.subscribe((saveResult) => (result = saveResult))
|
||||
|
||||
const nameInput = fixture.debugElement
|
||||
.query(By.directive(TextComponent))
|
||||
.query(By.css('input'))
|
||||
nameInput.nativeElement.value = name
|
||||
component.saveViewConfigForm.get('name').patchValue(name) // normally done by angular
|
||||
|
||||
const sidebarCheckInput = fixture.debugElement
|
||||
.queryAll(By.directive(CheckComponent))[0]
|
||||
.query(By.css('input'))
|
||||
sidebarCheckInput.nativeElement.checked = true
|
||||
component.saveViewConfigForm.get('showInSideBar').patchValue(true) // normally done by angular
|
||||
|
||||
const dashboardCheckInput = fixture.debugElement
|
||||
.queryAll(By.directive(CheckComponent))[1]
|
||||
.query(By.css('input'))
|
||||
dashboardCheckInput.nativeElement.checked = true
|
||||
component.saveViewConfigForm.get('showOnDashboard').patchValue(true) // normally done by angular
|
||||
|
||||
component.save()
|
||||
expect(result).toEqual({
|
||||
name,
|
||||
showInSideBar: true,
|
||||
showOnDashboard: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should support default name', () => {
|
||||
const saveClickedSpy = jest.spyOn(component.saveClicked, 'emit')
|
||||
const modalCloseSpy = jest.spyOn(modal, 'close')
|
||||
component.cancel()
|
||||
expect(saveClickedSpy).not.toHaveBeenCalled()
|
||||
expect(modalCloseSpy).toHaveBeenCalled()
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user