mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-08-16 00:36:22 +00: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:
254
src-ui/src/app/services/consumer-status.service.spec.ts
Normal file
254
src-ui/src/app/services/consumer-status.service.spec.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import {
|
||||
ConsumerStatusService,
|
||||
FILE_STATUS_MESSAGES,
|
||||
FileStatusPhase,
|
||||
} from './consumer-status.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { DocumentService } from './rest/document.service'
|
||||
import { HttpEventType, HttpResponse } from '@angular/common/http'
|
||||
import WS from 'jest-websocket-mock'
|
||||
|
||||
describe('ConsumerStatusService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let consumerStatusService: ConsumerStatusService
|
||||
let documentService: DocumentService
|
||||
const server = new WS(
|
||||
`${environment.webSocketProtocol}//${environment.webSocketHost}${environment.webSocketBaseUrl}status/`,
|
||||
{ jsonProtocol: true }
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ConsumerStatusService, DocumentService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
consumerStatusService = TestBed.inject(ConsumerStatusService)
|
||||
documentService = TestBed.inject(DocumentService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('should update status on websocket processing progress', () => {
|
||||
const task_id = '1234'
|
||||
const status = consumerStatusService.newFileUpload('file.pdf')
|
||||
expect(status.getProgress()).toEqual(0)
|
||||
|
||||
consumerStatusService.connect()
|
||||
|
||||
consumerStatusService
|
||||
.onDocumentConsumptionFinished()
|
||||
.subscribe((filestatus) => {
|
||||
expect(filestatus.phase).toEqual(FileStatusPhase.SUCCESS)
|
||||
})
|
||||
|
||||
consumerStatusService.onDocumentDetected().subscribe((filestatus) => {
|
||||
expect(filestatus.phase).toEqual(FileStatusPhase.STARTED)
|
||||
})
|
||||
|
||||
server.send({
|
||||
task_id,
|
||||
filename: 'file.pdf',
|
||||
current_progress: 50,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
status: 'STARTING',
|
||||
})
|
||||
|
||||
expect(status.getProgress()).toBeCloseTo(0.6) // 0.8 * 50/100
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toEqual([
|
||||
status,
|
||||
])
|
||||
|
||||
server.send({
|
||||
task_id,
|
||||
filename: 'file.pdf',
|
||||
current_progress: 100,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
status: 'SUCCESS',
|
||||
message: FILE_STATUS_MESSAGES.finished,
|
||||
})
|
||||
|
||||
expect(status.getProgress()).toEqual(1)
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||
0
|
||||
)
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(1)
|
||||
|
||||
consumerStatusService.disconnect()
|
||||
})
|
||||
|
||||
it('should update status on websocket failed progress', () => {
|
||||
const task_id = '1234'
|
||||
const status = consumerStatusService.newFileUpload('file.pdf')
|
||||
status.taskId = task_id
|
||||
consumerStatusService.connect()
|
||||
|
||||
consumerStatusService
|
||||
.onDocumentConsumptionFailed()
|
||||
.subscribe((filestatus) => {
|
||||
expect(filestatus.phase).toEqual(FileStatusPhase.FAILED)
|
||||
})
|
||||
|
||||
server.send({
|
||||
task_id,
|
||||
filename: 'file.pdf',
|
||||
current_progress: 50,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
})
|
||||
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toEqual([
|
||||
status,
|
||||
])
|
||||
|
||||
server.send({
|
||||
task_id,
|
||||
filename: 'file.pdf',
|
||||
current_progress: 50,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
status: 'FAILED',
|
||||
message: FILE_STATUS_MESSAGES.document_already_exists,
|
||||
})
|
||||
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||
0
|
||||
)
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should update status on upload progress', () => {
|
||||
const task_id = '1234'
|
||||
const status = consumerStatusService.newFileUpload('file.pdf')
|
||||
|
||||
documentService.uploadDocument({}).subscribe((event) => {
|
||||
if (event.type === HttpEventType.Response) {
|
||||
status.taskId = event.body['task_id']
|
||||
status.message = $localize`Upload complete, waiting...`
|
||||
} else if (event.type === HttpEventType.UploadProgress) {
|
||||
status.updateProgress(
|
||||
FileStatusPhase.UPLOADING,
|
||||
event.loaded,
|
||||
event.total
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/post_document/`
|
||||
)
|
||||
|
||||
req.event(
|
||||
new HttpResponse({
|
||||
body: {
|
||||
task_id,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
req.event({
|
||||
type: HttpEventType.UploadProgress,
|
||||
loaded: 100,
|
||||
total: 300,
|
||||
})
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING)
|
||||
).toEqual([status])
|
||||
expect(consumerStatusService.getConsumerStatus()).toEqual([status])
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toEqual([
|
||||
status,
|
||||
])
|
||||
|
||||
req.event({
|
||||
type: HttpEventType.UploadProgress,
|
||||
loaded: 300,
|
||||
total: 300,
|
||||
})
|
||||
|
||||
expect(status.getProgress()).toEqual(0.2) // 0.2 * 300/300
|
||||
})
|
||||
|
||||
it('should support dismiss completed', () => {
|
||||
consumerStatusService.connect()
|
||||
server.send({
|
||||
task_id: '1234',
|
||||
filename: 'file.pdf',
|
||||
current_progress: 100,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
status: 'SUCCESS',
|
||||
message: 'finished',
|
||||
})
|
||||
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(1)
|
||||
consumerStatusService.dismissCompleted()
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should support dismiss', () => {
|
||||
const task_id = '1234'
|
||||
const status = consumerStatusService.newFileUpload('file.pdf')
|
||||
status.taskId = task_id
|
||||
status.updateProgress(FileStatusPhase.UPLOADING, 50, 100)
|
||||
|
||||
const status2 = consumerStatusService.newFileUpload('file2.pdf')
|
||||
status2.updateProgress(FileStatusPhase.UPLOADING, 50, 100)
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING)
|
||||
).toEqual([status, status2])
|
||||
expect(consumerStatusService.getConsumerStatus()).toEqual([status, status2])
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toEqual([
|
||||
status,
|
||||
status2,
|
||||
])
|
||||
|
||||
consumerStatusService.dismiss(status)
|
||||
expect(consumerStatusService.getConsumerStatus()).toEqual([status2])
|
||||
|
||||
consumerStatusService.dismiss(status2)
|
||||
expect(consumerStatusService.getConsumerStatus()).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('should support fail', () => {
|
||||
const task_id = '1234'
|
||||
const status = consumerStatusService.newFileUpload('file.pdf')
|
||||
status.taskId = task_id
|
||||
status.updateProgress(FileStatusPhase.UPLOADING, 50, 100)
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||
1
|
||||
)
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(0)
|
||||
consumerStatusService.fail(status, 'fail')
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||
0
|
||||
)
|
||||
expect(consumerStatusService.getConsumerStatusCompleted()).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should notify of document created on status message without upload', () => {
|
||||
consumerStatusService.onDocumentDetected().subscribe((filestatus) => {
|
||||
expect(filestatus.phase).toEqual(FileStatusPhase.STARTED)
|
||||
})
|
||||
|
||||
server.send({
|
||||
task_id: '1234',
|
||||
filename: 'file.pdf',
|
||||
current_progress: 50,
|
||||
max_progress: 100,
|
||||
document_id: 12,
|
||||
status: 'STARTING',
|
||||
})
|
||||
})
|
||||
})
|
428
src-ui/src/app/services/document-list-view.service.spec.ts
Normal file
428
src-ui/src/app/services/document-list-view.service.spec.ts
Normal file
@@ -0,0 +1,428 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { DocumentListViewService } from './document-list-view.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ConfirmDialogComponent } from '../components/common/confirm-dialog/confirm-dialog.component'
|
||||
import { Params, Router, convertToParamMap } from '@angular/router'
|
||||
import {
|
||||
FILTER_HAS_TAGS_ALL,
|
||||
FILTER_HAS_TAGS_ANY,
|
||||
} from '../data/filter-rule-type'
|
||||
import { PaperlessSavedView } from '../data/paperless-saved-view'
|
||||
import { FilterRule } from '../data/filter-rule'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import { routes } from 'src/app/app-routing.module'
|
||||
import { PermissionsGuard } from '../guards/permissions.guard'
|
||||
import { SettingsService } from './settings.service'
|
||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||
|
||||
const documents = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Doc 1',
|
||||
content: 'some content',
|
||||
tags: [1, 2, 3],
|
||||
correspondent: 11,
|
||||
document_type: 3,
|
||||
storage_path: 8,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Doc 2',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Doc 3',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Doc 4',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'Doc 5',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: 'Doc 6',
|
||||
content: 'some content',
|
||||
},
|
||||
]
|
||||
const full_results = {
|
||||
count: documents.length,
|
||||
results: documents,
|
||||
}
|
||||
|
||||
const tags__id__all = '9'
|
||||
const filterRules: FilterRule[] = [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ALL,
|
||||
value: tags__id__all,
|
||||
},
|
||||
]
|
||||
|
||||
const view: PaperlessSavedView = {
|
||||
id: 3,
|
||||
name: 'Saved View',
|
||||
sort_field: 'added',
|
||||
sort_reverse: true,
|
||||
filter_rules: filterRules,
|
||||
}
|
||||
|
||||
describe('DocumentListViewService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let documentListViewService: DocumentListViewService
|
||||
let subscriptions: Subscription[] = []
|
||||
let router: Router
|
||||
let settingsService: SettingsService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [DocumentListViewService, PermissionsGuard, SettingsService],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule.withRoutes(routes),
|
||||
],
|
||||
declarations: [ConfirmDialogComponent],
|
||||
teardown: { destroyAfterEach: true },
|
||||
})
|
||||
|
||||
sessionStorage.clear()
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
documentListViewService = TestBed.inject(DocumentListViewService)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
router = TestBed.inject(Router)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
httpTestingController.verify()
|
||||
sessionStorage.clear()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
subscriptions?.forEach((subscription) => {
|
||||
subscription.unsubscribe()
|
||||
})
|
||||
})
|
||||
|
||||
it('should reload the list', () => {
|
||||
expect(documentListViewService.currentPage).toEqual(1)
|
||||
documentListViewService.reload()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(full_results)
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/selection_data/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.isReloading).toBeFalsy()
|
||||
expect(documentListViewService.activeSavedViewId).toBeNull()
|
||||
expect(documentListViewService.activeSavedViewTitle).toBeNull()
|
||||
expect(documentListViewService.collectionSize).toEqual(documents.length)
|
||||
expect(documentListViewService.getLastPage()).toEqual(1)
|
||||
})
|
||||
|
||||
it('should handle error on page request out of range', () => {
|
||||
documentListViewService.currentPage = 50
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=50&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush([], { status: 404, statusText: 'Unexpected error' })
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.currentPage).toEqual(1)
|
||||
})
|
||||
|
||||
it('should handle error on filtering request', () => {
|
||||
documentListViewService.currentPage = 1
|
||||
const tags__id__in = 'hello'
|
||||
const filterRulesAny = [
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ANY,
|
||||
value: tags__id__in,
|
||||
},
|
||||
]
|
||||
documentListViewService.filterRules = filterRulesAny
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__in=${tags__id__in}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(
|
||||
{ archive_serial_number: 'hello' },
|
||||
{ status: 404, statusText: 'Unexpected error' }
|
||||
)
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
// reset the list
|
||||
documentListViewService.filterRules = []
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
})
|
||||
|
||||
it('should support setting sort', () => {
|
||||
expect(documentListViewService.sortField).toEqual('created')
|
||||
expect(documentListViewService.sortReverse).toBeTruthy()
|
||||
documentListViewService.setSort('added', false)
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=added&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.sortField).toEqual('added')
|
||||
expect(documentListViewService.sortReverse).toBeFalsy()
|
||||
|
||||
documentListViewService.sortField = 'created'
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=created&truncate_content=true`
|
||||
)
|
||||
expect(documentListViewService.sortField).toEqual('created')
|
||||
documentListViewService.sortReverse = true
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.sortReverse).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should load from query params', () => {
|
||||
expect(documentListViewService.currentPage).toEqual(1)
|
||||
const page = 2
|
||||
const sort = 'added'
|
||||
const reverse = true
|
||||
const params: Params = {
|
||||
page,
|
||||
sort,
|
||||
reverse,
|
||||
}
|
||||
documentListViewService.loadFromQueryParams(convertToParamMap(params))
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=${page}&page_size=${
|
||||
documentListViewService.currentPageSize
|
||||
}&ordering=${reverse ? '-' : ''}${sort}&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.currentPage).toEqual(page)
|
||||
expect(documentListViewService.filterRules).toEqual([])
|
||||
})
|
||||
|
||||
it('should load filter rules from query params', () => {
|
||||
const sort = 'added'
|
||||
const reverse = true
|
||||
const params: Params = {
|
||||
sort,
|
||||
reverse,
|
||||
tags__id__all,
|
||||
}
|
||||
documentListViewService.loadFromQueryParams(convertToParamMap(params))
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
expect(documentListViewService.filterRules).toEqual([
|
||||
{
|
||||
rule_type: FILTER_HAS_TAGS_ALL,
|
||||
value: tags__id__all,
|
||||
},
|
||||
])
|
||||
req.flush(full_results)
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/selection_data/`
|
||||
)
|
||||
})
|
||||
|
||||
it('should use filter rules to update query params', () => {
|
||||
documentListViewService.filterRules = filterRules
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should support quick filter', () => {
|
||||
documentListViewService.quickFilter(filterRules)
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=${documentListViewService.currentPage}&page_size=${documentListViewService.currentPageSize}&ordering=-created&truncate_content=true&tags__id__all=${tags__id__all}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should support loading saved view', () => {
|
||||
const routerSpy = jest.spyOn(router, 'navigate')
|
||||
documentListViewService.activateSavedView(view)
|
||||
expect(routerSpy).toHaveBeenCalledWith(['view', view.id])
|
||||
documentListViewService.activateSavedView(null)
|
||||
})
|
||||
|
||||
it('should support loading saved view view query params', () => {
|
||||
const page = 2
|
||||
const params: Params = {
|
||||
view: view.id,
|
||||
page,
|
||||
}
|
||||
documentListViewService.activateSavedViewWithQueryParams(
|
||||
view,
|
||||
convertToParamMap(params)
|
||||
)
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=${page}&page_size=${documentListViewService.currentPageSize}&ordering=-added&truncate_content=true&tags__id__all=${tags__id__all}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
// reset the list
|
||||
documentListViewService.currentPage = 1
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true&tags__id__all=9`
|
||||
)
|
||||
documentListViewService.filterRules = []
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-added&truncate_content=true`
|
||||
)
|
||||
documentListViewService.sortField = 'created'
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
documentListViewService.activateSavedView(null)
|
||||
})
|
||||
|
||||
it('should support navigating next / previous', () => {
|
||||
documentListViewService.filterRules = []
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(documentListViewService.currentPage).toEqual(1)
|
||||
documentListViewService.currentPageSize = 3
|
||||
documentListViewService.reload()
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush({
|
||||
count: 3,
|
||||
results: documents.slice(0, 3),
|
||||
})
|
||||
httpTestingController
|
||||
.expectOne(`${environment.apiBaseUrl}documents/selection_data/`)
|
||||
.flush([])
|
||||
expect(documentListViewService.hasNext(documents[0].id)).toBeTruthy()
|
||||
expect(documentListViewService.hasPrevious(documents[0].id)).toBeFalsy()
|
||||
documentListViewService.getNext(documents[0].id).subscribe((docId) => {
|
||||
expect(docId).toEqual(documents[1].id)
|
||||
})
|
||||
documentListViewService.getNext(documents[2].id).subscribe((docId) => {
|
||||
expect(docId).toEqual(documents[3].id)
|
||||
expect(documentListViewService.currentPage).toEqual(2)
|
||||
})
|
||||
documentListViewService.getPrevious(documents[3].id).subscribe((docId) => {
|
||||
expect(docId).toEqual(documents[2].id)
|
||||
expect(documentListViewService.currentPage).toEqual(1)
|
||||
})
|
||||
})
|
||||
|
||||
it('should update page size from settings', () => {
|
||||
settingsService.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, 10)
|
||||
documentListViewService.updatePageSize()
|
||||
expect(documentListViewService.currentPageSize).toEqual(10)
|
||||
})
|
||||
|
||||
it('should support select a document', () => {
|
||||
documentListViewService.reload()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(full_results)
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/selection_data/`
|
||||
)
|
||||
documentListViewService.toggleSelected(documents[0])
|
||||
expect(documentListViewService.isSelected(documents[0])).toBeTruthy()
|
||||
documentListViewService.toggleSelected(documents[0])
|
||||
expect(documentListViewService.isSelected(documents[0])).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should support select all', () => {
|
||||
documentListViewService.selectAll()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(full_results)
|
||||
expect(documentListViewService.selected.size).toEqual(documents.length)
|
||||
expect(documentListViewService.isSelected(documents[0])).toBeTruthy()
|
||||
documentListViewService.selectNone()
|
||||
})
|
||||
|
||||
it('should support select page', () => {
|
||||
documentListViewService.currentPageSize = 3
|
||||
documentListViewService.reload()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=3&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush({
|
||||
count: 3,
|
||||
results: documents.slice(0, 3),
|
||||
})
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/selection_data/`
|
||||
)
|
||||
documentListViewService.selectPage()
|
||||
expect(documentListViewService.selected.size).toEqual(3)
|
||||
expect(documentListViewService.isSelected(documents[5])).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should support select range', () => {
|
||||
documentListViewService.reload()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(full_results)
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/selection_data/`
|
||||
)
|
||||
documentListViewService.toggleSelected(documents[0])
|
||||
expect(documentListViewService.isSelected(documents[0])).toBeTruthy()
|
||||
documentListViewService.selectRangeTo(documents[2])
|
||||
expect(documentListViewService.isSelected(documents[1])).toBeTruthy()
|
||||
documentListViewService.selectRangeTo(documents[4])
|
||||
expect(documentListViewService.isSelected(documents[3])).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should support selection range reduction', () => {
|
||||
documentListViewService.selectAll()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(full_results)
|
||||
expect(documentListViewService.selected.size).toEqual(6)
|
||||
|
||||
documentListViewService.filterRules = filterRules
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=50&ordering=-created&truncate_content=true&tags__id__all=9`
|
||||
)
|
||||
const reqs = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}documents/?page=1&page_size=100000&fields=id&tags__id__all=9`
|
||||
)
|
||||
reqs[0].flush({
|
||||
count: 3,
|
||||
results: documents.slice(0, 3),
|
||||
})
|
||||
expect(documentListViewService.selected.size).toEqual(3)
|
||||
})
|
||||
})
|
@@ -1,12 +1,12 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ParamMap, Router } from '@angular/router'
|
||||
import { Observable, first } from 'rxjs'
|
||||
import { FilterRule } from '../data/filter-rule'
|
||||
import {
|
||||
filterRulesDiffer,
|
||||
cloneFilterRules,
|
||||
FilterRule,
|
||||
isFullTextFilterRule,
|
||||
} from '../data/filter-rule'
|
||||
} from '../utils/filter-rules'
|
||||
import { PaperlessDocument } from '../data/paperless-document'
|
||||
import { PaperlessSavedView } from '../data/paperless-saved-view'
|
||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||
|
224
src-ui/src/app/services/open-documents.service.spec.ts
Normal file
224
src-ui/src/app/services/open-documents.service.spec.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { OpenDocumentsService } from './open-documents.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { ConfirmDialogComponent } from '../components/common/confirm-dialog/confirm-dialog.component'
|
||||
import { OPEN_DOCUMENT_SERVICE } from '../data/storage-keys'
|
||||
|
||||
const documents = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Doc 1',
|
||||
content: 'some content',
|
||||
tags: [1, 2, 3],
|
||||
correspondent: 11,
|
||||
document_type: 3,
|
||||
storage_path: 8,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Doc 2',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Doc 3',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Doc 4',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'Doc 5',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: 'Doc 6',
|
||||
content: 'some content',
|
||||
},
|
||||
]
|
||||
|
||||
describe('OpenDocumentsService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let openDocumentsService: OpenDocumentsService
|
||||
let modalService: NgbModal
|
||||
let subscriptions: Subscription[] = []
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [OpenDocumentsService, NgbModal],
|
||||
imports: [HttpClientTestingModule],
|
||||
declarations: [ConfirmDialogComponent],
|
||||
})
|
||||
|
||||
sessionStorage.clear()
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
openDocumentsService = TestBed.inject(OpenDocumentsService)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
subscriptions?.forEach((subscription) => {
|
||||
subscription.unsubscribe()
|
||||
})
|
||||
})
|
||||
|
||||
it('should open documents', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(1)
|
||||
const doc = openDocumentsService.getOpenDocument(documents[0].id)
|
||||
expect(doc.id).toEqual(documents[0].id)
|
||||
})
|
||||
|
||||
it('should limit number of open documents', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[2]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[3]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[4]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[5]).subscribe()
|
||||
)
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(5)
|
||||
})
|
||||
|
||||
it('should close documents', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(1)
|
||||
openDocumentsService.closeDocument(documents[0])
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(0)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(2)
|
||||
subscriptions.push(openDocumentsService.closeAll().subscribe())
|
||||
})
|
||||
|
||||
it('should allow set dirty status, warn on close', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
openDocumentsService.setDirty(documents[0], false)
|
||||
expect(openDocumentsService.hasDirty()).toBeFalsy()
|
||||
openDocumentsService.setDirty(documents[0], true)
|
||||
expect(openDocumentsService.hasDirty()).toBeTruthy()
|
||||
const modalSpy = jest.spyOn(modalService, 'open')
|
||||
subscriptions.push(
|
||||
openDocumentsService.closeDocument(documents[0]).subscribe()
|
||||
)
|
||||
expect(modalSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should allow set dirty status, warn on closeAll', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
openDocumentsService.setDirty(documents[0], true)
|
||||
expect(openDocumentsService.hasDirty()).toBeTruthy()
|
||||
const modalSpy = jest.spyOn(modalService, 'open')
|
||||
subscriptions.push(openDocumentsService.closeAll().subscribe())
|
||||
expect(modalSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should load open documents from localStorage', () => {
|
||||
sessionStorage.setItem(
|
||||
OPEN_DOCUMENT_SERVICE.DOCUMENTS,
|
||||
JSON.stringify(documents)
|
||||
)
|
||||
const testOpenDocumentsService = new OpenDocumentsService(
|
||||
null,
|
||||
modalService
|
||||
)
|
||||
expect(testOpenDocumentsService.getOpenDocuments()).toHaveLength(
|
||||
documents.length
|
||||
)
|
||||
})
|
||||
|
||||
it('should remove open documents from localStorage on error', () => {
|
||||
sessionStorage.setItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS, 'hello world')
|
||||
const testOpenDocumentsService = new OpenDocumentsService(
|
||||
null,
|
||||
modalService
|
||||
)
|
||||
expect(testOpenDocumentsService.getOpenDocuments()).toHaveLength(0)
|
||||
expect(sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)).toBeNull()
|
||||
})
|
||||
|
||||
it('should save open documents to localStorage', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[2]).subscribe()
|
||||
)
|
||||
openDocumentsService.save()
|
||||
const localStorageDocs = JSON.parse(
|
||||
sessionStorage.getItem(OPEN_DOCUMENT_SERVICE.DOCUMENTS)
|
||||
)
|
||||
expect(localStorageDocs).toContainEqual(documents[0])
|
||||
expect(localStorageDocs).toContainEqual(documents[1])
|
||||
expect(localStorageDocs).toContainEqual(documents[2])
|
||||
})
|
||||
|
||||
it('should refresh documents', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
openDocumentsService.refreshDocument(documents[1].id)
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/${documents[1].id}/?full_perms=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush(documents[1])
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should handle error on refresh documents', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[1]).subscribe()
|
||||
)
|
||||
openDocumentsService.refreshDocument(documents[1].id)
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/${documents[1].id}/?full_perms=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.error(new ErrorEvent('timeout'))
|
||||
expect(openDocumentsService.getOpenDocuments()).toHaveLength(0)
|
||||
})
|
||||
})
|
405
src-ui/src/app/services/permissions.service.spec.ts
Normal file
405
src-ui/src/app/services/permissions.service.spec.ts
Normal file
@@ -0,0 +1,405 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import {
|
||||
PermissionAction,
|
||||
PermissionType,
|
||||
PermissionsService,
|
||||
} from './permissions.service'
|
||||
import { PaperlessDocument } from '../data/paperless-document'
|
||||
|
||||
describe('PermissionsService', () => {
|
||||
let permissionsService: PermissionsService
|
||||
|
||||
const docUnowned: PaperlessDocument = {
|
||||
title: 'Doc title',
|
||||
owner: null,
|
||||
}
|
||||
|
||||
const docOwned: PaperlessDocument = {
|
||||
title: 'Doc title 2',
|
||||
owner: 1,
|
||||
}
|
||||
|
||||
const docNotOwned: PaperlessDocument = {
|
||||
title: 'Doc title 3',
|
||||
owner: 2,
|
||||
}
|
||||
|
||||
const docUserViewGranted: PaperlessDocument = {
|
||||
title: 'Doc title 4',
|
||||
owner: 2,
|
||||
permissions: {
|
||||
view: {
|
||||
users: [1],
|
||||
groups: [],
|
||||
},
|
||||
change: {
|
||||
users: [],
|
||||
groups: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const docUserEditGranted: PaperlessDocument = {
|
||||
title: 'Doc title 5',
|
||||
owner: 2,
|
||||
permissions: {
|
||||
view: {
|
||||
users: [1],
|
||||
groups: [],
|
||||
},
|
||||
change: {
|
||||
users: [1],
|
||||
groups: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const docGroupViewGranted: PaperlessDocument = {
|
||||
title: 'Doc title 4',
|
||||
owner: 2,
|
||||
permissions: {
|
||||
view: {
|
||||
users: [],
|
||||
groups: [1],
|
||||
},
|
||||
change: {
|
||||
users: [],
|
||||
groups: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const docGroupEditGranted: PaperlessDocument = {
|
||||
title: 'Doc title 5',
|
||||
owner: 2,
|
||||
permissions: {
|
||||
view: {
|
||||
users: [],
|
||||
groups: [1],
|
||||
},
|
||||
change: {
|
||||
users: [],
|
||||
groups: [1],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [PermissionsService],
|
||||
})
|
||||
|
||||
permissionsService = TestBed.inject(PermissionsService)
|
||||
})
|
||||
|
||||
it('correctly interpolates action codes to keys', () => {
|
||||
expect(
|
||||
permissionsService.getPermissionCode(
|
||||
PermissionAction.View,
|
||||
PermissionType.Document
|
||||
)
|
||||
).toEqual('view_document')
|
||||
expect(permissionsService.getPermissionKeys('view_document')).toEqual({
|
||||
actionKey: 'View', // PermissionAction.View
|
||||
typeKey: 'Document', // PermissionType.Document
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly checks explicit global permissions', () => {
|
||||
permissionsService.initialize(
|
||||
[
|
||||
'change_savedview',
|
||||
'change_schedule',
|
||||
'change_failure',
|
||||
'delete_token',
|
||||
'add_mailrule',
|
||||
'view_failure',
|
||||
'view_groupresult',
|
||||
'add_note',
|
||||
'change_taskresult',
|
||||
'view_tag',
|
||||
'view_user',
|
||||
'add_tag',
|
||||
'change_processedmail',
|
||||
'change_session',
|
||||
'view_taskattributes',
|
||||
'delete_groupresult',
|
||||
'delete_correspondent',
|
||||
'delete_schedule',
|
||||
'delete_contenttype',
|
||||
'view_chordcounter',
|
||||
'view_success',
|
||||
'delete_documenttype',
|
||||
'add_tokenproxy',
|
||||
'delete_paperlesstask',
|
||||
'add_log',
|
||||
'view_mailaccount',
|
||||
'add_uisettings',
|
||||
'view_savedview',
|
||||
'view_uisettings',
|
||||
'delete_storagepath',
|
||||
'delete_frontendsettings',
|
||||
'change_paperlesstask',
|
||||
'view_taskresult',
|
||||
'delete_processedmail',
|
||||
'view_processedmail',
|
||||
'view_session',
|
||||
'delete_chordcounter',
|
||||
'view_note',
|
||||
'delete_session',
|
||||
'view_document',
|
||||
'change_mailaccount',
|
||||
'delete_taskattributes',
|
||||
'add_groupobjectpermission',
|
||||
'view_mailrule',
|
||||
'change_savedviewfilterrule',
|
||||
'change_log',
|
||||
'change_comment',
|
||||
'add_mailaccount',
|
||||
'add_frontendsettings',
|
||||
'add_userobjectpermission',
|
||||
'delete_note',
|
||||
'view_token',
|
||||
'add_failure',
|
||||
'delete_user',
|
||||
'add_success',
|
||||
'view_ormq',
|
||||
'view_tokenproxy',
|
||||
'delete_uisettings',
|
||||
'change_groupobjectpermission',
|
||||
'add_logentry',
|
||||
'add_ormq',
|
||||
'view_frontendsettings',
|
||||
'view_schedule',
|
||||
'change_taskattributes',
|
||||
'view_documenttype',
|
||||
'view_logentry',
|
||||
'change_correspondent',
|
||||
'add_groupresult',
|
||||
'delete_groupobjectpermission',
|
||||
'change_mailrule',
|
||||
'change_permission',
|
||||
'delete_log',
|
||||
'view_userobjectpermission',
|
||||
'view_correspondent',
|
||||
'delete_document',
|
||||
'change_uisettings',
|
||||
'change_storagepath',
|
||||
'change_document',
|
||||
'delete_tokenproxy',
|
||||
'change_note',
|
||||
'delete_permission',
|
||||
'change_contenttype',
|
||||
'add_token',
|
||||
'change_success',
|
||||
'delete_logentry',
|
||||
'view_savedviewfilterrule',
|
||||
'delete_task',
|
||||
'add_savedview',
|
||||
'add_paperlesstask',
|
||||
'add_task',
|
||||
'change_documenttype',
|
||||
'add_documenttype',
|
||||
'change_token',
|
||||
'view_task',
|
||||
'view_permission',
|
||||
'change_task',
|
||||
'delete_userobjectpermission',
|
||||
'change_group',
|
||||
'add_group',
|
||||
'change_tag',
|
||||
'change_chordcounter',
|
||||
'add_storagepath',
|
||||
'delete_group',
|
||||
'add_taskattributes',
|
||||
'delete_mailaccount',
|
||||
'delete_tag',
|
||||
'add_schedule',
|
||||
'delete_failure',
|
||||
'delete_mailrule',
|
||||
'add_savedviewfilterrule',
|
||||
'change_ormq',
|
||||
'change_logentry',
|
||||
'add_taskresult',
|
||||
'view_group',
|
||||
'delete_comment',
|
||||
'add_contenttype',
|
||||
'add_document',
|
||||
'change_tokenproxy',
|
||||
'delete_success',
|
||||
'add_comment',
|
||||
'delete_ormq',
|
||||
'add_processedmail',
|
||||
'view_paperlesstask',
|
||||
'delete_savedview',
|
||||
'change_user',
|
||||
'add_session',
|
||||
'view_groupobjectpermission',
|
||||
'add_user',
|
||||
'add_correspondent',
|
||||
'delete_taskresult',
|
||||
'view_contenttype',
|
||||
'view_storagepath',
|
||||
'add_permission',
|
||||
'change_userobjectpermission',
|
||||
'delete_savedviewfilterrule',
|
||||
'change_groupresult',
|
||||
'add_chordcounter',
|
||||
'view_log',
|
||||
'view_comment',
|
||||
'change_frontendsettings',
|
||||
],
|
||||
{
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
}
|
||||
)
|
||||
|
||||
Object.values(PermissionType).forEach((type) => {
|
||||
Object.values(PermissionAction).forEach((action) => {
|
||||
expect(permissionsService.currentUserCan(action, type)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
})
|
||||
|
||||
Object.values(PermissionType).forEach((type) => {
|
||||
Object.values(PermissionAction).forEach((action) => {
|
||||
expect(permissionsService.currentUserCan(action, type)).toBeFalsy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly checks global permissions for superuser', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
is_superuser: true,
|
||||
})
|
||||
|
||||
Object.values(PermissionType).forEach((type) => {
|
||||
Object.values(PermissionAction).forEach((action) => {
|
||||
expect(permissionsService.currentUserCan(action, type)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly checks object owner permissions', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
id: 1,
|
||||
})
|
||||
|
||||
expect(permissionsService.currentUserOwnsObject(docUnowned)).toBeTruthy()
|
||||
expect(permissionsService.currentUserOwnsObject(docOwned)).toBeTruthy()
|
||||
expect(permissionsService.currentUserOwnsObject(docNotOwned)).toBeFalsy()
|
||||
})
|
||||
|
||||
it('correctly checks object owner permissions for superuser', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
id: 1,
|
||||
is_superuser: true,
|
||||
})
|
||||
|
||||
expect(permissionsService.currentUserOwnsObject(docUnowned)).toBeTruthy()
|
||||
expect(permissionsService.currentUserOwnsObject(docOwned)).toBeTruthy()
|
||||
expect(permissionsService.currentUserOwnsObject(docNotOwned)).toBeTruthy()
|
||||
})
|
||||
|
||||
it('correctly checks granted object permissions', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
id: 1,
|
||||
})
|
||||
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docNotOwned
|
||||
)
|
||||
).toBeFalsy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docUserViewGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.Change,
|
||||
docUserEditGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
it('correctly checks granted object permissions for superuser', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
id: 1,
|
||||
is_superuser: true,
|
||||
})
|
||||
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docNotOwned
|
||||
)
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docUserViewGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.Change,
|
||||
docUserEditGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
|
||||
it('correctly checks granted object permissions from group', () => {
|
||||
permissionsService.initialize([], {
|
||||
username: 'testuser',
|
||||
last_name: 'User',
|
||||
first_name: 'Test',
|
||||
id: 1,
|
||||
groups: [1],
|
||||
})
|
||||
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docNotOwned
|
||||
)
|
||||
).toBeFalsy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.View,
|
||||
docGroupViewGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
permissionsService.currentUserHasObjectPermissions(
|
||||
PermissionAction.Change,
|
||||
docGroupEditGranted
|
||||
)
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
@@ -42,7 +42,10 @@ export class PermissionsService {
|
||||
action: PermissionAction,
|
||||
type: PermissionType
|
||||
): boolean {
|
||||
return this.permissions.includes(this.getPermissionCode(action, type))
|
||||
return (
|
||||
this.currentUser?.is_superuser ||
|
||||
this.permissions?.includes(this.getPermissionCode(action, type))
|
||||
)
|
||||
}
|
||||
|
||||
public currentUserOwnsObject(object: ObjectWithPermissions): boolean {
|
||||
|
@@ -0,0 +1,60 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { AbstractNameFilterService } from './abstract-name-filter-service'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: AbstractNameFilterService<any>
|
||||
let subscription: Subscription
|
||||
|
||||
export const commonAbstractNameFilterPaperlessServiceTests = (
|
||||
endpoint,
|
||||
ServiceClass
|
||||
) => {
|
||||
commonAbstractPaperlessServiceTests(endpoint, ServiceClass)
|
||||
|
||||
describe(`Common name filter service tests for ${endpoint}`, () => {
|
||||
test('should call appropriate api endpoint for list filtering', () => {
|
||||
const page = 2
|
||||
const pageSize = 50
|
||||
const sortField = 'name'
|
||||
const sortReverse = true
|
||||
const nameFilter = 'hello'
|
||||
const fullPerms = true
|
||||
subscription = service
|
||||
.listFiltered(
|
||||
page,
|
||||
pageSize,
|
||||
sortField,
|
||||
sortReverse,
|
||||
nameFilter,
|
||||
fullPerms
|
||||
)
|
||||
.subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=${page}&page_size=${pageSize}&ordering=-${sortField}&name__icontains=${nameFilter}&full_perms=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush([])
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
// TestBed.configureTestingModule({
|
||||
// providers: [ServiceClass],
|
||||
// imports: [HttpClientTestingModule],
|
||||
// teardown: { destroyAfterEach: true },
|
||||
// })
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(ServiceClass)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
// httpTestingController.verify()
|
||||
})
|
||||
}
|
116
src-ui/src/app/services/rest/abstract-paperless-service.spec.ts
Normal file
116
src-ui/src/app/services/rest/abstract-paperless-service.spec.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: AbstractPaperlessService<any>
|
||||
let subscription: Subscription
|
||||
|
||||
export const commonAbstractPaperlessServiceTests = (endpoint, ServiceClass) => {
|
||||
describe(`Common service tests for ${endpoint}`, () => {
|
||||
test('should call appropriate api endpoint for list all', () => {
|
||||
subscription = service.listAll().subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush([])
|
||||
})
|
||||
|
||||
test('should call appropriate api endpoint for get a single object', () => {
|
||||
const id = 0
|
||||
subscription = service.get(id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush([])
|
||||
})
|
||||
|
||||
test('should call appropriate api endpoint for create a single object', () => {
|
||||
const o = {
|
||||
name: 'Name',
|
||||
}
|
||||
subscription = service.create(o).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
req.flush([])
|
||||
})
|
||||
|
||||
test('should call appropriate api endpoint for delete a single object', () => {
|
||||
const id = 10
|
||||
const o = {
|
||||
name: 'Name',
|
||||
id,
|
||||
}
|
||||
subscription = service.delete(o).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('DELETE')
|
||||
req.flush([])
|
||||
})
|
||||
|
||||
test('should call appropriate api endpoint for update a single object', () => {
|
||||
const id = 10
|
||||
const o = {
|
||||
name: 'Name',
|
||||
id,
|
||||
}
|
||||
|
||||
// some services need to call listAll first
|
||||
subscription = service.listAll().subscribe()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
req.flush({
|
||||
results: [o],
|
||||
})
|
||||
subscription.unsubscribe()
|
||||
|
||||
subscription = service.update(o).subscribe()
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('PUT')
|
||||
req.flush([])
|
||||
})
|
||||
|
||||
test('should call appropriate api endpoint for patch a single object', () => {
|
||||
const id = 10
|
||||
const o = {
|
||||
name: 'Name',
|
||||
id,
|
||||
}
|
||||
subscription = service.patch(o).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
req.flush([])
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ServiceClass],
|
||||
imports: [HttpClientTestingModule],
|
||||
teardown: { destroyAfterEach: true },
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(ServiceClass)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
// httpTestingController.verify()
|
||||
})
|
||||
}
|
@@ -10,9 +10,9 @@ export abstract class AbstractPaperlessService<T extends ObjectWithId> {
|
||||
|
||||
constructor(protected http: HttpClient, private resourceName: string) {}
|
||||
|
||||
protected getResourceUrl(id?: number, action?: string): string {
|
||||
protected getResourceUrl(id: number = null, action: string = null): string {
|
||||
let url = `${this.baseUrl}${this.resourceName}/`
|
||||
if (id) {
|
||||
if (id !== null) {
|
||||
url += `${id}/`
|
||||
}
|
||||
if (action) {
|
||||
|
@@ -0,0 +1,7 @@
|
||||
import { CorrespondentService } from './correspondent.service'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
|
||||
commonAbstractNameFilterPaperlessServiceTests(
|
||||
'correspondents',
|
||||
CorrespondentService
|
||||
)
|
79
src-ui/src/app/services/rest/document-notes.service.spec.ts
Normal file
79
src-ui/src/app/services/rest/document-notes.service.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
import { MailFilterAttachmentType } from 'src/app/data/paperless-mail-rule'
|
||||
import { MailMetadataTitleOption } from 'src/app/data/paperless-mail-rule'
|
||||
import { MailAction } from 'src/app/data/paperless-mail-rule'
|
||||
import { DocumentNotesService } from './document-notes.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: DocumentNotesService
|
||||
let subscription: Subscription
|
||||
const documentId = 12
|
||||
const endpoint = 'documents'
|
||||
const endpoint2 = 'notes'
|
||||
const notes = [
|
||||
{
|
||||
created: new Date(),
|
||||
note: 'contents 1',
|
||||
user: 1,
|
||||
},
|
||||
{
|
||||
created: new Date(),
|
||||
note: 'contents 2',
|
||||
user: 1,
|
||||
},
|
||||
{
|
||||
created: new Date(),
|
||||
note: 'contents 3',
|
||||
user: 2,
|
||||
},
|
||||
]
|
||||
|
||||
// run common tests
|
||||
commonAbstractPaperlessServiceTests(endpoint, DocumentNotesService)
|
||||
|
||||
describe(`Additional service tests for DocumentNotesService`, () => {
|
||||
test('should call correct api endpoint on get notes', () => {
|
||||
subscription = service.getNotes(documentId).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documentId}/${endpoint2}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
test('should call correct api endpoint on add note', () => {
|
||||
const content = 'some new text'
|
||||
subscription = service.addNote(documentId, content).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documentId}/${endpoint2}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
note: content,
|
||||
})
|
||||
})
|
||||
|
||||
test('should call correct api endpoint on delete note', () => {
|
||||
const noteId = 11
|
||||
subscription = service.deleteNote(documentId, noteId).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documentId}/${endpoint2}/?id=${noteId}`
|
||||
)
|
||||
expect(req.request.method).toEqual('DELETE')
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(DocumentNotesService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
@@ -0,0 +1,7 @@
|
||||
import { DocumentTypeService } from './document-type.service'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
|
||||
commonAbstractNameFilterPaperlessServiceTests(
|
||||
'document_types',
|
||||
DocumentTypeService
|
||||
)
|
247
src-ui/src/app/services/rest/document.service.spec.ts
Normal file
247
src-ui/src/app/services/rest/document.service.spec.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { DocumentService } from './document.service'
|
||||
import { FILTER_TITLE } from 'src/app/data/filter-rule-type'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: DocumentService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'documents'
|
||||
const documents = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Doc 1',
|
||||
content: 'some content',
|
||||
tags: [1, 2, 3],
|
||||
correspondent: 11,
|
||||
document_type: 3,
|
||||
storage_path: 8,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Doc 2',
|
||||
content: 'some content',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Doc 3',
|
||||
content: 'some content',
|
||||
},
|
||||
]
|
||||
|
||||
describe(`DocumentService`, () => {
|
||||
// common tests e.g. commonAbstractPaperlessServiceTests differ slightly
|
||||
it('should call appropriate api endpoint for list all', () => {
|
||||
subscription = service.listAll().subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for get a single document', () => {
|
||||
subscription = service.get(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/?full_perms=true`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for create a single document', () => {
|
||||
subscription = service.create(documents[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for delete a single document', () => {
|
||||
subscription = service.delete(documents[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('DELETE')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for update a single document', () => {
|
||||
subscription = service.update(documents[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('PUT')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for patch a single document', () => {
|
||||
subscription = service.patch(documents[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for listing all documents ids in a filter set', () => {
|
||||
subscription = service
|
||||
.listAllFilteredIds([
|
||||
{
|
||||
rule_type: FILTER_TITLE,
|
||||
value: 'apple',
|
||||
},
|
||||
])
|
||||
.subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000&fields=id&title__icontains=apple`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for uploading a document', () => {
|
||||
subscription = service.uploadDocument(documents[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/post_document/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting metadata', () => {
|
||||
subscription = service.getMetadata(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/metadata/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting selection data', () => {
|
||||
const ids = [documents[0].id]
|
||||
subscription = service.getSelectionData(ids).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/selection_data/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
documents: ids,
|
||||
})
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for getting suggestions', () => {
|
||||
subscription = service.getSuggestions(documents[0].id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/suggestions/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for bulk download', () => {
|
||||
const ids = [1, 2, 3]
|
||||
const content = 'both'
|
||||
const useFilenameFormatting = false
|
||||
subscription = service
|
||||
.bulkDownload(ids, content, useFilenameFormatting)
|
||||
.subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/bulk_download/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
documents: ids,
|
||||
content,
|
||||
follow_formatting: useFilenameFormatting,
|
||||
})
|
||||
})
|
||||
|
||||
it('should call appropriate api endpoint for bulk edit', () => {
|
||||
const ids = [1, 2, 3]
|
||||
const method = 'modify_tags'
|
||||
const parameters = {
|
||||
add_tags: [15],
|
||||
remove_tags: [6],
|
||||
}
|
||||
subscription = service.bulkEdit(ids, method, parameters).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/bulk_edit/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
documents: ids,
|
||||
method,
|
||||
parameters,
|
||||
})
|
||||
})
|
||||
|
||||
it('should return the correct preview URL for a single document', () => {
|
||||
let url = service.getPreviewUrl(documents[0].id)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/preview/`
|
||||
)
|
||||
url = service.getPreviewUrl(documents[0].id, true)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/preview/?original=true`
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the correct thumb URL for a single document', () => {
|
||||
let url = service.getThumbUrl(documents[0].id)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/thumb/`
|
||||
)
|
||||
})
|
||||
|
||||
it('should return the correct download URL for a single document', () => {
|
||||
let url = service.getDownloadUrl(documents[0].id)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/download/`
|
||||
)
|
||||
url = service.getDownloadUrl(documents[0].id, true)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/download/?original=true`
|
||||
)
|
||||
})
|
||||
|
||||
it('should add observables to document', () => {
|
||||
subscription = service
|
||||
.listFiltered(1, 25, 'title', false, [])
|
||||
.subscribe((result) => {
|
||||
expect(result.results).toHaveLength(3)
|
||||
const doc = result.results[0]
|
||||
expect(doc.correspondent$).not.toBeNull()
|
||||
expect(doc.document_type$).not.toBeNull()
|
||||
expect(doc.tags$).not.toBeNull()
|
||||
expect(doc.storage_path$).not.toBeNull()
|
||||
})
|
||||
httpTestingController
|
||||
.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=25&ordering=title`
|
||||
)
|
||||
.flush({
|
||||
results: documents,
|
||||
})
|
||||
})
|
||||
|
||||
it('should set search query', () => {
|
||||
const searchQuery = 'hello'
|
||||
service.searchQuery = searchQuery
|
||||
let url = service.getPreviewUrl(documents[0].id)
|
||||
expect(url).toEqual(
|
||||
`${environment.apiBaseUrl}${endpoint}/${documents[0].id}/preview/#search="${searchQuery}"`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [DocumentService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(DocumentService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
192
src-ui/src/app/services/rest/group.service.spec.ts
Normal file
192
src-ui/src/app/services/rest/group.service.spec.ts
Normal file
@@ -0,0 +1,192 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { GroupService } from './group.service'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: GroupService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'groups'
|
||||
const group = {
|
||||
name: 'Group Name',
|
||||
id: 1,
|
||||
user_count: 1,
|
||||
permissions: [
|
||||
'change_savedview',
|
||||
'change_schedule',
|
||||
'change_failure',
|
||||
'delete_token',
|
||||
'add_mailrule',
|
||||
'view_failure',
|
||||
'view_groupresult',
|
||||
'add_note',
|
||||
'change_taskresult',
|
||||
'view_tag',
|
||||
'view_user',
|
||||
'add_tag',
|
||||
'change_processedmail',
|
||||
'change_session',
|
||||
'view_taskattributes',
|
||||
'delete_groupresult',
|
||||
'delete_correspondent',
|
||||
'delete_schedule',
|
||||
'delete_contenttype',
|
||||
'view_chordcounter',
|
||||
'view_success',
|
||||
'delete_documenttype',
|
||||
'add_tokenproxy',
|
||||
'delete_paperlesstask',
|
||||
'add_log',
|
||||
'view_mailaccount',
|
||||
'add_uisettings',
|
||||
'view_savedview',
|
||||
'view_uisettings',
|
||||
'delete_storagepath',
|
||||
'delete_frontendsettings',
|
||||
'change_paperlesstask',
|
||||
'view_taskresult',
|
||||
'delete_processedmail',
|
||||
'view_processedmail',
|
||||
'view_session',
|
||||
'delete_chordcounter',
|
||||
'view_note',
|
||||
'delete_session',
|
||||
'view_document',
|
||||
'change_mailaccount',
|
||||
'delete_taskattributes',
|
||||
'add_groupobjectpermission',
|
||||
'view_mailrule',
|
||||
'change_savedviewfilterrule',
|
||||
'change_log',
|
||||
'change_comment',
|
||||
'add_mailaccount',
|
||||
'add_frontendsettings',
|
||||
'add_userobjectpermission',
|
||||
'delete_note',
|
||||
'view_token',
|
||||
'add_failure',
|
||||
'delete_user',
|
||||
'add_success',
|
||||
'view_ormq',
|
||||
'view_tokenproxy',
|
||||
'delete_uisettings',
|
||||
'change_groupobjectpermission',
|
||||
'add_logentry',
|
||||
'add_ormq',
|
||||
'view_frontendsettings',
|
||||
'view_schedule',
|
||||
'change_taskattributes',
|
||||
'view_documenttype',
|
||||
'view_logentry',
|
||||
'change_correspondent',
|
||||
'add_groupresult',
|
||||
'delete_groupobjectpermission',
|
||||
'change_mailrule',
|
||||
'change_permission',
|
||||
'delete_log',
|
||||
'view_userobjectpermission',
|
||||
'view_correspondent',
|
||||
'delete_document',
|
||||
'change_uisettings',
|
||||
'change_storagepath',
|
||||
'change_document',
|
||||
'delete_tokenproxy',
|
||||
'change_note',
|
||||
'delete_permission',
|
||||
'change_contenttype',
|
||||
'add_token',
|
||||
'change_success',
|
||||
'delete_logentry',
|
||||
'view_savedviewfilterrule',
|
||||
'delete_task',
|
||||
'add_savedview',
|
||||
'add_paperlesstask',
|
||||
'add_task',
|
||||
'change_documenttype',
|
||||
'add_documenttype',
|
||||
'change_token',
|
||||
'view_task',
|
||||
'view_permission',
|
||||
'change_task',
|
||||
'delete_userobjectpermission',
|
||||
'change_group',
|
||||
'add_group',
|
||||
'change_tag',
|
||||
'change_chordcounter',
|
||||
'add_storagepath',
|
||||
'delete_group',
|
||||
'add_taskattributes',
|
||||
'delete_mailaccount',
|
||||
'delete_tag',
|
||||
'add_schedule',
|
||||
'delete_failure',
|
||||
'delete_mailrule',
|
||||
'add_savedviewfilterrule',
|
||||
'change_ormq',
|
||||
'change_logentry',
|
||||
'add_taskresult',
|
||||
'view_group',
|
||||
'delete_comment',
|
||||
'add_contenttype',
|
||||
'add_document',
|
||||
'change_tokenproxy',
|
||||
'delete_success',
|
||||
'add_comment',
|
||||
'delete_ormq',
|
||||
'add_processedmail',
|
||||
'view_paperlesstask',
|
||||
'delete_savedview',
|
||||
'change_user',
|
||||
'add_session',
|
||||
'view_groupobjectpermission',
|
||||
'add_user',
|
||||
'add_correspondent',
|
||||
'delete_taskresult',
|
||||
'view_contenttype',
|
||||
'view_storagepath',
|
||||
'add_permission',
|
||||
'change_userobjectpermission',
|
||||
'delete_savedviewfilterrule',
|
||||
'change_groupresult',
|
||||
'add_chordcounter',
|
||||
'view_log',
|
||||
'view_comment',
|
||||
'change_frontendsettings',
|
||||
],
|
||||
}
|
||||
|
||||
// run common tests
|
||||
commonAbstractNameFilterPaperlessServiceTests(endpoint, GroupService)
|
||||
|
||||
describe('Additional service tests for GroupService', () => {
|
||||
it('should retain permissions on update', () => {
|
||||
subscription = service.listAll().subscribe()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
req.flush({
|
||||
results: [group],
|
||||
})
|
||||
subscription.unsubscribe()
|
||||
|
||||
subscription = service.update(group).subscribe()
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${group.id}/`
|
||||
)
|
||||
expect(req.request.body.permissions).toHaveLength(group.permissions.length)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(GroupService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
47
src-ui/src/app/services/rest/log.service.spec.ts
Normal file
47
src-ui/src/app/services/rest/log.service.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { LogService } from './log.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: LogService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'logs'
|
||||
|
||||
describe('LogService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [LogService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(LogService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('should call correct api endpoint on logs list', () => {
|
||||
subscription = service.list().subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('should call correct api endpoint on logs get', () => {
|
||||
const id: string = 'mail'
|
||||
subscription = service.get(id).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${id}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
})
|
80
src-ui/src/app/services/rest/mail-account.service.spec.ts
Normal file
80
src-ui/src/app/services/rest/mail-account.service.spec.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
import { MailAccountService } from './mail-account.service'
|
||||
import { IMAPSecurity } from 'src/app/data/paperless-mail-account'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: MailAccountService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'mail_accounts'
|
||||
const mail_accounts = [
|
||||
{
|
||||
name: 'Mail Account',
|
||||
id: 1,
|
||||
imap_server: 'imap.example.com',
|
||||
imap_port: 443,
|
||||
imap_security: IMAPSecurity.SSL,
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
is_token: false,
|
||||
},
|
||||
{
|
||||
name: 'Mail Account 2',
|
||||
id: 2,
|
||||
imap_server: 'imap.example.com',
|
||||
imap_port: 443,
|
||||
imap_security: IMAPSecurity.SSL,
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
is_token: false,
|
||||
},
|
||||
{
|
||||
name: 'Mail Account 3',
|
||||
id: 3,
|
||||
imap_server: 'imap.example.com',
|
||||
imap_port: 443,
|
||||
imap_security: IMAPSecurity.SSL,
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
is_token: false,
|
||||
},
|
||||
]
|
||||
|
||||
// run common tests
|
||||
commonAbstractPaperlessServiceTests(endpoint, MailAccountService)
|
||||
|
||||
describe(`Additional service tests for MailAccountService`, () => {
|
||||
it('should correct api endpoint on test account', () => {
|
||||
subscription = service.test(mail_accounts[0]).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/test/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
})
|
||||
|
||||
it('should support patchMany', () => {
|
||||
subscription = service.patchMany(mail_accounts).subscribe()
|
||||
mail_accounts.forEach((mail_account) => {
|
||||
const reqs = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}${endpoint}/${mail_account.id}/`
|
||||
)
|
||||
expect(reqs).toHaveLength(1)
|
||||
expect(reqs[0].request.method).toEqual('PATCH')
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(MailAccountService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
92
src-ui/src/app/services/rest/mail-rule.service.spec.ts
Normal file
92
src-ui/src/app/services/rest/mail-rule.service.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
import { MailRuleService } from './mail-rule.service'
|
||||
import { MailFilterAttachmentType } from 'src/app/data/paperless-mail-rule'
|
||||
import { MailMetadataTitleOption } from 'src/app/data/paperless-mail-rule'
|
||||
import { MailAction } from 'src/app/data/paperless-mail-rule'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: MailRuleService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'mail_rules'
|
||||
const mail_rules = [
|
||||
{
|
||||
name: 'Mail Rule',
|
||||
id: 1,
|
||||
account: 1,
|
||||
order: 1,
|
||||
folder: 'INBOX',
|
||||
filter_from: null,
|
||||
filter_to: null,
|
||||
filter_subject: null,
|
||||
filter_body: null,
|
||||
filter_attachment_filename: null,
|
||||
maximum_age: 30,
|
||||
attachment_type: MailFilterAttachmentType.Everything,
|
||||
action: MailAction.MarkRead,
|
||||
assign_title_from: MailMetadataTitleOption.FromSubject,
|
||||
},
|
||||
{
|
||||
name: 'Mail Rule 2',
|
||||
id: 2,
|
||||
account: 1,
|
||||
order: 1,
|
||||
folder: 'INBOX',
|
||||
filter_from: null,
|
||||
filter_to: null,
|
||||
filter_subject: null,
|
||||
filter_body: null,
|
||||
filter_attachment_filename: null,
|
||||
maximum_age: 30,
|
||||
attachment_type: MailFilterAttachmentType.Everything,
|
||||
action: MailAction.Delete,
|
||||
assign_title_from: MailMetadataTitleOption.FromSubject,
|
||||
},
|
||||
{
|
||||
name: 'Mail Rule 3',
|
||||
id: 3,
|
||||
account: 1,
|
||||
order: 1,
|
||||
folder: 'INBOX',
|
||||
filter_from: null,
|
||||
filter_to: null,
|
||||
filter_subject: null,
|
||||
filter_body: null,
|
||||
filter_attachment_filename: null,
|
||||
maximum_age: 30,
|
||||
attachment_type: MailFilterAttachmentType.Everything,
|
||||
action: MailAction.Flag,
|
||||
assign_title_from: MailMetadataTitleOption.FromSubject,
|
||||
},
|
||||
]
|
||||
|
||||
// run common tests
|
||||
commonAbstractPaperlessServiceTests(endpoint, MailRuleService)
|
||||
|
||||
describe(`Additional service tests for MailRuleService`, () => {
|
||||
it('should support patchMany', () => {
|
||||
subscription = service.patchMany(mail_rules).subscribe()
|
||||
mail_rules.forEach((mail_rule) => {
|
||||
const reqs = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}${endpoint}/${mail_rule.id}/`
|
||||
)
|
||||
expect(reqs).toHaveLength(1)
|
||||
expect(reqs[0].request.method).toEqual('PATCH')
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(MailRuleService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
38
src-ui/src/app/services/rest/remote-version.service.spec.ts
Normal file
38
src-ui/src/app/services/rest/remote-version.service.spec.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { RemoteVersionService } from './remote-version.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: RemoteVersionService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'remote_version'
|
||||
|
||||
describe('RemoteVersionService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [RemoteVersionService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(RemoteVersionService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('should call correct api endpoint on update check', () => {
|
||||
subscription = service.checkForUpdates().subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
})
|
81
src-ui/src/app/services/rest/saved-view.service.spec.ts
Normal file
81
src-ui/src/app/services/rest/saved-view.service.spec.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractPaperlessServiceTests } from './abstract-paperless-service.spec'
|
||||
import { SavedViewService } from './saved-view.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: SavedViewService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'saved_views'
|
||||
const saved_views = [
|
||||
{
|
||||
name: 'Saved View',
|
||||
id: 1,
|
||||
show_on_dashboard: true,
|
||||
show_in_sidebar: true,
|
||||
sort_field: 'name',
|
||||
sort_reverse: true,
|
||||
filter_rules: [],
|
||||
},
|
||||
{
|
||||
name: 'Saved View 2',
|
||||
id: 2,
|
||||
show_on_dashboard: false,
|
||||
show_in_sidebar: false,
|
||||
sort_field: 'name',
|
||||
sort_reverse: true,
|
||||
filter_rules: [],
|
||||
},
|
||||
{
|
||||
name: 'Saved View 3',
|
||||
id: 3,
|
||||
show_on_dashboard: true,
|
||||
show_in_sidebar: false,
|
||||
sort_field: 'name',
|
||||
sort_reverse: true,
|
||||
filter_rules: [],
|
||||
},
|
||||
]
|
||||
|
||||
// run common tests
|
||||
commonAbstractPaperlessServiceTests(endpoint, SavedViewService)
|
||||
|
||||
describe(`Additional service tests for SavedViewService`, () => {
|
||||
it('should retrieve saved views and sort them', () => {
|
||||
service.initialize()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
req.flush({
|
||||
results: saved_views,
|
||||
})
|
||||
expect(service.allViews).toHaveLength(3)
|
||||
expect(service.dashboardViews).toHaveLength(2)
|
||||
expect(service.sidebarViews).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('should support patchMany', () => {
|
||||
subscription = service.patchMany(saved_views).subscribe()
|
||||
saved_views.forEach((saved_view) => {
|
||||
const reqs = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}${endpoint}/${saved_view.id}/`
|
||||
)
|
||||
expect(reqs).toHaveLength(1)
|
||||
expect(reqs[0].request.method).toEqual('PATCH')
|
||||
})
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(SavedViewService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
39
src-ui/src/app/services/rest/search.service.spec.ts
Normal file
39
src-ui/src/app/services/rest/search.service.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { SearchService } from './search.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: SearchService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'search/autocomplete'
|
||||
|
||||
describe('SearchService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [SearchService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(SearchService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('should call correct api endpoint on autocomplete', () => {
|
||||
const term = 'apple'
|
||||
subscription = service.autocomplete(term).subscribe()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?term=${term}`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
})
|
@@ -0,0 +1,7 @@
|
||||
import { StoragePathService } from './storage-path.service'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
|
||||
commonAbstractNameFilterPaperlessServiceTests(
|
||||
'storage_paths',
|
||||
StoragePathService
|
||||
)
|
4
src-ui/src/app/services/rest/tag.service.spec.ts
Normal file
4
src-ui/src/app/services/rest/tag.service.spec.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { TagService } from './tag.service'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
|
||||
commonAbstractNameFilterPaperlessServiceTests('tags', TagService)
|
193
src-ui/src/app/services/rest/user.service.spec.ts
Normal file
193
src-ui/src/app/services/rest/user.service.spec.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
import { HttpTestingController } from '@angular/common/http/testing'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { commonAbstractNameFilterPaperlessServiceTests } from './abstract-name-filter-service.spec'
|
||||
import { UserService } from './user.service'
|
||||
|
||||
let httpTestingController: HttpTestingController
|
||||
let service: UserService
|
||||
let subscription: Subscription
|
||||
const endpoint = 'users'
|
||||
const user = {
|
||||
username: 'username',
|
||||
id: 1,
|
||||
user_permissions: [
|
||||
'change_savedview',
|
||||
'change_schedule',
|
||||
'change_failure',
|
||||
'delete_token',
|
||||
'add_mailrule',
|
||||
'view_failure',
|
||||
'view_groupresult',
|
||||
'add_note',
|
||||
'change_taskresult',
|
||||
'view_tag',
|
||||
'view_user',
|
||||
'add_tag',
|
||||
'change_processedmail',
|
||||
'change_session',
|
||||
'view_taskattributes',
|
||||
'delete_groupresult',
|
||||
'delete_correspondent',
|
||||
'delete_schedule',
|
||||
'delete_contenttype',
|
||||
'view_chordcounter',
|
||||
'view_success',
|
||||
'delete_documenttype',
|
||||
'add_tokenproxy',
|
||||
'delete_paperlesstask',
|
||||
'add_log',
|
||||
'view_mailaccount',
|
||||
'add_uisettings',
|
||||
'view_savedview',
|
||||
'view_uisettings',
|
||||
'delete_storagepath',
|
||||
'delete_frontendsettings',
|
||||
'change_paperlesstask',
|
||||
'view_taskresult',
|
||||
'delete_processedmail',
|
||||
'view_processedmail',
|
||||
'view_session',
|
||||
'delete_chordcounter',
|
||||
'view_note',
|
||||
'delete_session',
|
||||
'view_document',
|
||||
'change_mailaccount',
|
||||
'delete_taskattributes',
|
||||
'add_groupobjectpermission',
|
||||
'view_mailrule',
|
||||
'change_savedviewfilterrule',
|
||||
'change_log',
|
||||
'change_comment',
|
||||
'add_mailaccount',
|
||||
'add_frontendsettings',
|
||||
'add_userobjectpermission',
|
||||
'delete_note',
|
||||
'view_token',
|
||||
'add_failure',
|
||||
'delete_user',
|
||||
'add_success',
|
||||
'view_ormq',
|
||||
'view_tokenproxy',
|
||||
'delete_uisettings',
|
||||
'change_groupobjectpermission',
|
||||
'add_logentry',
|
||||
'add_ormq',
|
||||
'view_frontendsettings',
|
||||
'view_schedule',
|
||||
'change_taskattributes',
|
||||
'view_documenttype',
|
||||
'view_logentry',
|
||||
'change_correspondent',
|
||||
'add_groupresult',
|
||||
'delete_groupobjectpermission',
|
||||
'change_mailrule',
|
||||
'change_permission',
|
||||
'delete_log',
|
||||
'view_userobjectpermission',
|
||||
'view_correspondent',
|
||||
'delete_document',
|
||||
'change_uisettings',
|
||||
'change_storagepath',
|
||||
'change_document',
|
||||
'delete_tokenproxy',
|
||||
'change_note',
|
||||
'delete_permission',
|
||||
'change_contenttype',
|
||||
'add_token',
|
||||
'change_success',
|
||||
'delete_logentry',
|
||||
'view_savedviewfilterrule',
|
||||
'delete_task',
|
||||
'add_savedview',
|
||||
'add_paperlesstask',
|
||||
'add_task',
|
||||
'change_documenttype',
|
||||
'add_documenttype',
|
||||
'change_token',
|
||||
'view_task',
|
||||
'view_permission',
|
||||
'change_task',
|
||||
'delete_userobjectpermission',
|
||||
'change_group',
|
||||
'add_group',
|
||||
'change_tag',
|
||||
'change_chordcounter',
|
||||
'add_storagepath',
|
||||
'delete_group',
|
||||
'add_taskattributes',
|
||||
'delete_mailaccount',
|
||||
'delete_tag',
|
||||
'add_schedule',
|
||||
'delete_failure',
|
||||
'delete_mailrule',
|
||||
'add_savedviewfilterrule',
|
||||
'change_ormq',
|
||||
'change_logentry',
|
||||
'add_taskresult',
|
||||
'view_group',
|
||||
'delete_comment',
|
||||
'add_contenttype',
|
||||
'add_document',
|
||||
'change_tokenproxy',
|
||||
'delete_success',
|
||||
'add_comment',
|
||||
'delete_ormq',
|
||||
'add_processedmail',
|
||||
'view_paperlesstask',
|
||||
'delete_savedview',
|
||||
'change_user',
|
||||
'add_session',
|
||||
'view_groupobjectpermission',
|
||||
'add_user',
|
||||
'add_correspondent',
|
||||
'delete_taskresult',
|
||||
'view_contenttype',
|
||||
'view_storagepath',
|
||||
'add_permission',
|
||||
'change_userobjectpermission',
|
||||
'delete_savedviewfilterrule',
|
||||
'change_groupresult',
|
||||
'add_chordcounter',
|
||||
'view_log',
|
||||
'view_comment',
|
||||
'change_frontendsettings',
|
||||
],
|
||||
}
|
||||
|
||||
// run common tests
|
||||
commonAbstractNameFilterPaperlessServiceTests(endpoint, UserService)
|
||||
|
||||
describe('Additional service tests for UserService', () => {
|
||||
it('should retain permissions on update', () => {
|
||||
subscription = service.listAll().subscribe()
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
req.flush({
|
||||
results: [user],
|
||||
})
|
||||
subscription.unsubscribe()
|
||||
|
||||
subscription = service.update(user).subscribe()
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${user.id}/`
|
||||
)
|
||||
expect(req.request.body.user_permissions).toHaveLength(
|
||||
user.user_permissions.length
|
||||
)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
// Dont need to setup again
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
service = TestBed.inject(UserService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
})
|
212
src-ui/src/app/services/settings.service.spec.ts
Normal file
212
src-ui/src/app/services/settings.service.spec.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { SettingsService } from './settings.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { PaperlessUiSettings } from '../data/paperless-uisettings'
|
||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { AppModule } from '../app.module'
|
||||
|
||||
describe('SettingsService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let settingsService: SettingsService
|
||||
let subscription: Subscription
|
||||
|
||||
const ui_settings: PaperlessUiSettings = {
|
||||
user: {
|
||||
username: 'testuser',
|
||||
first_name: 'Test',
|
||||
last_name: 'User',
|
||||
id: 1,
|
||||
is_superuser: true,
|
||||
},
|
||||
settings: {
|
||||
language: '',
|
||||
bulk_edit: { confirmation_dialogs: true, apply_on_close: false },
|
||||
documentListSize: 50,
|
||||
dark_mode: { use_system: true, enabled: 'false', thumb_inverted: 'true' },
|
||||
theme: { color: '#9fbf2f' },
|
||||
document_details: { native_pdf_viewer: false },
|
||||
date_display: { date_locale: '', date_format: 'mediumDate' },
|
||||
notifications: {
|
||||
consumer_new_documents: true,
|
||||
consumer_success: true,
|
||||
consumer_failed: true,
|
||||
consumer_suppress_on_dashboard: true,
|
||||
},
|
||||
comments_enabled: true,
|
||||
slim_sidebar: false,
|
||||
update_checking: { enabled: false, backend_setting: 'default' },
|
||||
saved_views: { warn_on_unsaved_change: true },
|
||||
notes_enabled: true,
|
||||
tour_complete: false,
|
||||
},
|
||||
permissions: [],
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [],
|
||||
providers: [SettingsService],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
NgbModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
AppModule,
|
||||
],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
subscription?.unsubscribe()
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('calls ui_settings api endpoint on initialize', () => {
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('calls ui_settings api endpoint with POST on store', () => {
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(ui_settings)
|
||||
|
||||
subscription = settingsService.storeSettings().subscribe()
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
settings: ui_settings.settings,
|
||||
})
|
||||
})
|
||||
|
||||
it('correctly loads settings of various types', () => {
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(ui_settings)
|
||||
|
||||
expect(settingsService.displayName).toEqual('Test')
|
||||
expect(settingsService.getLanguage()).toEqual('')
|
||||
expect(settingsService.get(SETTINGS_KEYS.DARK_MODE_ENABLED)).toBeFalsy()
|
||||
expect(
|
||||
settingsService.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT)
|
||||
).toBeTruthy()
|
||||
expect(settingsService.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)).toEqual(50)
|
||||
expect(settingsService.get(SETTINGS_KEYS.THEME_COLOR)).toEqual('#9fbf2f')
|
||||
})
|
||||
|
||||
it('correctly allows updating settings of various types', () => {
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(ui_settings)
|
||||
|
||||
settingsService.setLanguage('de-de')
|
||||
settingsService.set(SETTINGS_KEYS.DARK_MODE_ENABLED, true)
|
||||
settingsService.set(
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT,
|
||||
false
|
||||
)
|
||||
settingsService.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, 25)
|
||||
settingsService.set(SETTINGS_KEYS.THEME_COLOR, '#000000')
|
||||
|
||||
expect(settingsService.getLanguage()).toEqual('de-de')
|
||||
expect(settingsService.get(SETTINGS_KEYS.DARK_MODE_ENABLED)).toBeTruthy()
|
||||
expect(
|
||||
settingsService.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT)
|
||||
).toBeFalsy()
|
||||
expect(settingsService.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)).toEqual(25)
|
||||
expect(settingsService.get(SETTINGS_KEYS.THEME_COLOR)).toEqual('#000000')
|
||||
})
|
||||
|
||||
it('updates appearnce settings', () => {
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(ui_settings)
|
||||
|
||||
expect(
|
||||
document.body.style.getPropertyValue('--pngx-primary-lightness')
|
||||
).toEqual('')
|
||||
|
||||
const addClassSpy = jest.spyOn(settingsService.renderer, 'addClass')
|
||||
const removeClassSpy = jest.spyOn(settingsService.renderer, 'removeClass')
|
||||
|
||||
settingsService.updateAppearanceSettings(true, true, '#fff000')
|
||||
expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-light')
|
||||
expect(addClassSpy).toHaveBeenCalledWith(
|
||||
document.body,
|
||||
'color-scheme-system'
|
||||
)
|
||||
expect(
|
||||
document.body.style.getPropertyValue('--pngx-primary-lightness')
|
||||
).toEqual('50%')
|
||||
|
||||
settingsService.updateAppearanceSettings(false, false, '#000000')
|
||||
expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-light')
|
||||
expect(removeClassSpy).toHaveBeenCalledWith(
|
||||
document.body,
|
||||
'color-scheme-system'
|
||||
)
|
||||
expect(
|
||||
document.body.style.getPropertyValue('--pngx-primary-lightness')
|
||||
).toEqual('0%')
|
||||
|
||||
settingsService.updateAppearanceSettings(false, true, '#ffffff')
|
||||
expect(addClassSpy).toHaveBeenCalledWith(document.body, 'primary-dark')
|
||||
expect(removeClassSpy).toHaveBeenCalledWith(
|
||||
document.body,
|
||||
'color-scheme-system'
|
||||
)
|
||||
expect(addClassSpy).toHaveBeenCalledWith(document.body, 'color-scheme-dark')
|
||||
expect(
|
||||
document.body.style.getPropertyValue('--pngx-primary-lightness')
|
||||
).toEqual('100%')
|
||||
})
|
||||
|
||||
it('migrates settings automatically', () => {
|
||||
const oldSettings = Object.assign({}, ui_settings)
|
||||
delete oldSettings.settings['documentListSize']
|
||||
window.localStorage.setItem(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, '50')
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(oldSettings)
|
||||
|
||||
req = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)[0]
|
||||
expect(req.request.method).toEqual('POST')
|
||||
})
|
||||
|
||||
it('updates settings on complete tour', () => {
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)
|
||||
req.flush(ui_settings)
|
||||
|
||||
settingsService.completeTour()
|
||||
|
||||
req = httpTestingController.match(
|
||||
`${environment.apiBaseUrl}ui_settings/`
|
||||
)[0]
|
||||
expect(req.request.method).toEqual('POST')
|
||||
})
|
||||
})
|
@@ -43,7 +43,6 @@ export interface LanguageOption {
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SettingsService {
|
||||
private renderer: Renderer2
|
||||
protected baseUrl: string = environment.apiBaseUrl + 'ui_settings/'
|
||||
|
||||
private settings: Object = {}
|
||||
@@ -51,6 +50,11 @@ export class SettingsService {
|
||||
|
||||
public settingsSaved: EventEmitter<any> = new EventEmitter()
|
||||
|
||||
private _renderer: Renderer2
|
||||
public get renderer(): Renderer2 {
|
||||
return this._renderer
|
||||
}
|
||||
|
||||
constructor(
|
||||
rendererFactory: RendererFactory2,
|
||||
@Inject(DOCUMENT) private document,
|
||||
@@ -62,7 +66,7 @@ export class SettingsService {
|
||||
private savedViewService: SavedViewService,
|
||||
private permissionsService: PermissionsService
|
||||
) {
|
||||
this.renderer = rendererFactory.createRenderer(null, null)
|
||||
this._renderer = rendererFactory.createRenderer(null, null)
|
||||
}
|
||||
|
||||
// this is called by the app initializer in app.module
|
||||
@@ -102,49 +106,49 @@ export class SettingsService {
|
||||
themeColor ??= this.get(SETTINGS_KEYS.THEME_COLOR)
|
||||
|
||||
if (darkModeUseSystem) {
|
||||
this.renderer.addClass(this.document.body, 'color-scheme-system')
|
||||
this.renderer.removeClass(this.document.body, 'color-scheme-dark')
|
||||
this._renderer.addClass(this.document.body, 'color-scheme-system')
|
||||
this._renderer.removeClass(this.document.body, 'color-scheme-dark')
|
||||
} else {
|
||||
this.renderer.removeClass(this.document.body, 'color-scheme-system')
|
||||
this._renderer.removeClass(this.document.body, 'color-scheme-system')
|
||||
darkModeEnabled
|
||||
? this.renderer.addClass(this.document.body, 'color-scheme-dark')
|
||||
: this.renderer.removeClass(this.document.body, 'color-scheme-dark')
|
||||
? this._renderer.addClass(this.document.body, 'color-scheme-dark')
|
||||
: this._renderer.removeClass(this.document.body, 'color-scheme-dark')
|
||||
}
|
||||
|
||||
// remove these in case they were there
|
||||
this.renderer.removeClass(this.document.body, 'primary-dark')
|
||||
this.renderer.removeClass(this.document.body, 'primary-light')
|
||||
this._renderer.removeClass(this.document.body, 'primary-dark')
|
||||
this._renderer.removeClass(this.document.body, 'primary-light')
|
||||
|
||||
if (themeColor) {
|
||||
const hsl = hexToHsl(themeColor)
|
||||
const bgBrightnessEstimate = estimateBrightnessForColor(themeColor)
|
||||
|
||||
if (bgBrightnessEstimate == BRIGHTNESS.DARK) {
|
||||
this.renderer.addClass(this.document.body, 'primary-dark')
|
||||
this.renderer.removeClass(this.document.body, 'primary-light')
|
||||
this._renderer.addClass(this.document.body, 'primary-dark')
|
||||
this._renderer.removeClass(this.document.body, 'primary-light')
|
||||
} else {
|
||||
this.renderer.addClass(this.document.body, 'primary-light')
|
||||
this.renderer.removeClass(this.document.body, 'primary-dark')
|
||||
this._renderer.addClass(this.document.body, 'primary-light')
|
||||
this._renderer.removeClass(this.document.body, 'primary-dark')
|
||||
}
|
||||
this.renderer.setStyle(
|
||||
this._renderer.setStyle(
|
||||
document.body,
|
||||
'--pngx-primary',
|
||||
`${+hsl.h * 360},${hsl.s * 100}%`,
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
this.renderer.setStyle(
|
||||
this._renderer.setStyle(
|
||||
document.body,
|
||||
'--pngx-primary-lightness',
|
||||
`${hsl.l * 100}%`,
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
} else {
|
||||
this.renderer.removeStyle(
|
||||
this._renderer.removeStyle(
|
||||
document.body,
|
||||
'--pngx-primary',
|
||||
RendererStyleFlags2.DashCase
|
||||
)
|
||||
this.renderer.removeStyle(
|
||||
this._renderer.removeStyle(
|
||||
document.body,
|
||||
'--pngx-primary-lightness',
|
||||
RendererStyleFlags2.DashCase
|
||||
|
110
src-ui/src/app/services/tasks.service.spec.ts
Normal file
110
src-ui/src/app/services/tasks.service.spec.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { TasksService } from './tasks.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { PaperlessTaskType } from '../data/paperless-task'
|
||||
import { PaperlessTaskStatus } from '../data/paperless-task'
|
||||
|
||||
describe('TasksService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let tasksService: TasksService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [TasksService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
tasksService = TestBed.inject(TasksService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('calls tasks api endpoint on reload', () => {
|
||||
tasksService.reload()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}tasks/`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
})
|
||||
|
||||
it('calls acknowledge_tasks api endpoint on dismiss and reloads', () => {
|
||||
tasksService.dismissTasks(new Set([1, 2, 3]))
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}acknowledge_tasks/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
expect(req.request.body).toEqual({
|
||||
tasks: [1, 2, 3],
|
||||
})
|
||||
req.flush([])
|
||||
// reload is then called
|
||||
httpTestingController.expectOne(`${environment.apiBaseUrl}tasks/`).flush([])
|
||||
})
|
||||
|
||||
it('sorts tasks returned from api', () => {
|
||||
expect(tasksService.total).toEqual(0)
|
||||
const mockTasks = [
|
||||
{
|
||||
type: PaperlessTaskType.File,
|
||||
status: PaperlessTaskStatus.Complete,
|
||||
acknowledged: false,
|
||||
task_id: '1234',
|
||||
task_file_name: 'file1.pdf',
|
||||
date_created: new Date(),
|
||||
},
|
||||
{
|
||||
type: PaperlessTaskType.File,
|
||||
status: PaperlessTaskStatus.Failed,
|
||||
acknowledged: false,
|
||||
task_id: '1235',
|
||||
task_file_name: 'file2.pdf',
|
||||
date_created: new Date(),
|
||||
},
|
||||
{
|
||||
type: PaperlessTaskType.File,
|
||||
status: PaperlessTaskStatus.Pending,
|
||||
acknowledged: false,
|
||||
task_id: '1236',
|
||||
task_file_name: 'file3.pdf',
|
||||
date_created: new Date(),
|
||||
},
|
||||
{
|
||||
type: PaperlessTaskType.File,
|
||||
status: PaperlessTaskStatus.Started,
|
||||
acknowledged: false,
|
||||
task_id: '1237',
|
||||
task_file_name: 'file4.pdf',
|
||||
date_created: new Date(),
|
||||
},
|
||||
{
|
||||
type: PaperlessTaskType.File,
|
||||
status: PaperlessTaskStatus.Complete,
|
||||
acknowledged: false,
|
||||
task_id: '1238',
|
||||
task_file_name: 'file5.pdf',
|
||||
date_created: new Date(),
|
||||
},
|
||||
]
|
||||
|
||||
tasksService.reload()
|
||||
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}tasks/`
|
||||
)
|
||||
|
||||
req.flush(mockTasks)
|
||||
|
||||
expect(tasksService.allFileTasks).toHaveLength(5)
|
||||
expect(tasksService.completedFileTasks).toHaveLength(2)
|
||||
expect(tasksService.failedFileTasks).toHaveLength(1)
|
||||
expect(tasksService.queuedFileTasks).toHaveLength(1)
|
||||
expect(tasksService.startedFileTasks).toHaveLength(1)
|
||||
})
|
||||
})
|
@@ -19,7 +19,7 @@ export class TasksService {
|
||||
private fileTasks: PaperlessTask[] = []
|
||||
|
||||
public get total(): number {
|
||||
return this.fileTasks?.length
|
||||
return this.fileTasks.length
|
||||
}
|
||||
|
||||
public get allFileTasks(): PaperlessTask[] {
|
||||
|
57
src-ui/src/app/services/toast.service.spec.ts
Normal file
57
src-ui/src/app/services/toast.service.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { ToastService } from './toast.service'
|
||||
|
||||
describe('ToastService', () => {
|
||||
let toastService: ToastService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [ToastService],
|
||||
})
|
||||
|
||||
toastService = TestBed.inject(ToastService)
|
||||
})
|
||||
|
||||
it('adds toast on show', () => {
|
||||
const toast = {
|
||||
title: 'Title',
|
||||
content: 'content',
|
||||
delay: 5000,
|
||||
}
|
||||
toastService.show(toast)
|
||||
|
||||
toastService.getToasts().subscribe((toasts) => {
|
||||
expect(toasts).toContainEqual(toast)
|
||||
})
|
||||
})
|
||||
|
||||
it('creates toasts with defaults on showInfo and showError', () => {
|
||||
toastService.showInfo('Info toast')
|
||||
toastService.showError('Error toast')
|
||||
|
||||
toastService.getToasts().subscribe((toasts) => {
|
||||
expect(toasts).toContainEqual({
|
||||
content: 'Info toast',
|
||||
delay: 5000,
|
||||
})
|
||||
expect(toasts).toContainEqual({
|
||||
content: 'Error toast',
|
||||
delay: 10000,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('removes toast on close', () => {
|
||||
const toast = {
|
||||
title: 'Title',
|
||||
content: 'content',
|
||||
delay: 5000,
|
||||
}
|
||||
toastService.show(toast)
|
||||
toastService.closeToast(toast)
|
||||
|
||||
toastService.getToasts().subscribe((toasts) => {
|
||||
expect(toasts).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
})
|
169
src-ui/src/app/services/upload-documents.service.spec.ts
Normal file
169
src-ui/src/app/services/upload-documents.service.spec.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { TestBed } from '@angular/core/testing'
|
||||
import { UploadDocumentsService } from './upload-documents.service'
|
||||
import {
|
||||
HttpClientTestingModule,
|
||||
HttpTestingController,
|
||||
} from '@angular/common/http/testing'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { HttpEventType, HttpResponse } from '@angular/common/http'
|
||||
import {
|
||||
ConsumerStatusService,
|
||||
FileStatusPhase,
|
||||
} from './consumer-status.service'
|
||||
|
||||
describe('UploadDocumentsService', () => {
|
||||
let httpTestingController: HttpTestingController
|
||||
let uploadDocumentsService: UploadDocumentsService
|
||||
let consumerStatusService: ConsumerStatusService
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [UploadDocumentsService, ConsumerStatusService],
|
||||
imports: [HttpClientTestingModule],
|
||||
})
|
||||
|
||||
httpTestingController = TestBed.inject(HttpTestingController)
|
||||
uploadDocumentsService = TestBed.inject(UploadDocumentsService)
|
||||
consumerStatusService = TestBed.inject(ConsumerStatusService)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
httpTestingController.verify()
|
||||
})
|
||||
|
||||
it('calls post_document api endpoint on upload', () => {
|
||||
const fileEntry = {
|
||||
name: 'file.pdf',
|
||||
isDirectory: false,
|
||||
isFile: true,
|
||||
file: (callback) => {
|
||||
return callback(
|
||||
new File(
|
||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||
'file.pdf'
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
uploadDocumentsService.uploadFiles([
|
||||
{
|
||||
relativePath: 'path/to/file.pdf',
|
||||
fileEntry,
|
||||
},
|
||||
])
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/post_document/`
|
||||
)
|
||||
expect(req.request.method).toEqual('POST')
|
||||
|
||||
req.flush('123-456')
|
||||
})
|
||||
|
||||
it('updates progress during upload and failure', () => {
|
||||
const fileEntry = {
|
||||
name: 'file.pdf',
|
||||
isDirectory: false,
|
||||
isFile: true,
|
||||
file: (callback) => {
|
||||
return callback(
|
||||
new File(
|
||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||
'file.pdf'
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
uploadDocumentsService.uploadFiles([
|
||||
{
|
||||
relativePath: 'path/to/file.pdf',
|
||||
fileEntry,
|
||||
},
|
||||
])
|
||||
|
||||
expect(consumerStatusService.getConsumerStatusNotCompleted()).toHaveLength(
|
||||
1
|
||||
)
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING)
|
||||
).toHaveLength(0)
|
||||
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/post_document/`
|
||||
)
|
||||
|
||||
req.event({
|
||||
type: HttpEventType.UploadProgress,
|
||||
loaded: 100,
|
||||
total: 300,
|
||||
})
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING)
|
||||
).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('updates progress on failure', () => {
|
||||
const fileEntry = {
|
||||
name: 'file.pdf',
|
||||
isDirectory: false,
|
||||
isFile: true,
|
||||
file: (callback) => {
|
||||
return callback(
|
||||
new File(
|
||||
[new Blob(['testing'], { type: 'application/pdf' })],
|
||||
'file.pdf'
|
||||
)
|
||||
)
|
||||
},
|
||||
}
|
||||
uploadDocumentsService.uploadFiles([
|
||||
{
|
||||
relativePath: 'path/to/file.pdf',
|
||||
fileEntry,
|
||||
},
|
||||
])
|
||||
|
||||
let req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/post_document/`
|
||||
)
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
||||
).toHaveLength(0)
|
||||
|
||||
req.flush(
|
||||
{},
|
||||
{
|
||||
status: 400,
|
||||
statusText: 'failed',
|
||||
}
|
||||
)
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
||||
).toHaveLength(1)
|
||||
|
||||
uploadDocumentsService.uploadFiles([
|
||||
{
|
||||
relativePath: 'path/to/file.pdf',
|
||||
fileEntry,
|
||||
},
|
||||
])
|
||||
|
||||
req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}documents/post_document/`
|
||||
)
|
||||
|
||||
req.flush(
|
||||
{},
|
||||
{
|
||||
status: 500,
|
||||
statusText: 'failed',
|
||||
}
|
||||
)
|
||||
|
||||
expect(
|
||||
consumerStatusService.getConsumerStatus(FileStatusPhase.FAILED)
|
||||
).toHaveLength(2)
|
||||
})
|
||||
})
|
@@ -7,7 +7,6 @@ import {
|
||||
} from './consumer-status.service'
|
||||
import { DocumentService } from './rest/document.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { SettingsService } from './settings.service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -17,8 +16,7 @@ export class UploadDocumentsService {
|
||||
|
||||
constructor(
|
||||
private documentService: DocumentService,
|
||||
private consumerStatusService: ConsumerStatusService,
|
||||
private settings: SettingsService
|
||||
private consumerStatusService: ConsumerStatusService
|
||||
) {}
|
||||
|
||||
uploadFiles(files: NgxFileDropEntry[]) {
|
||||
|
Reference in New Issue
Block a user