mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
363 lines
13 KiB
TypeScript
363 lines
13 KiB
TypeScript
import { CdkDragDrop, DragDropModule } from '@angular/cdk/drag-drop'
|
|
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
|
import {
|
|
HttpTestingController,
|
|
provideHttpClientTesting,
|
|
} from '@angular/common/http/testing'
|
|
import {
|
|
ComponentFixture,
|
|
TestBed,
|
|
fakeAsync,
|
|
tick,
|
|
} from '@angular/core/testing'
|
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
|
import { BrowserModule } from '@angular/platform-browser'
|
|
import { ActivatedRoute, Router } from '@angular/router'
|
|
import { RouterTestingModule } from '@angular/router/testing'
|
|
import { NgbModal, NgbModalModule, NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
|
import { of, throwError } from 'rxjs'
|
|
import { routes } from 'src/app/app-routing.module'
|
|
import { SavedView } from 'src/app/data/saved-view'
|
|
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
|
import { PermissionsGuard } from 'src/app/guards/permissions.guard'
|
|
import {
|
|
DjangoMessageLevel,
|
|
DjangoMessagesService,
|
|
} from 'src/app/services/django-messages.service'
|
|
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
|
|
import { PermissionsService } from 'src/app/services/permissions.service'
|
|
import { RemoteVersionService } from 'src/app/services/rest/remote-version.service'
|
|
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
|
import { SearchService } from 'src/app/services/rest/search.service'
|
|
import { SettingsService } from 'src/app/services/settings.service'
|
|
import { ToastService } from 'src/app/services/toast.service'
|
|
import { environment } from 'src/environments/environment'
|
|
import { ProfileEditDialogComponent } from '../common/profile-edit-dialog/profile-edit-dialog.component'
|
|
import { DocumentDetailComponent } from '../document-detail/document-detail.component'
|
|
import { AppFrameComponent } from './app-frame.component'
|
|
import { GlobalSearchComponent } from './global-search/global-search.component'
|
|
|
|
const saved_views = [
|
|
{
|
|
name: 'Saved View 0',
|
|
id: 0,
|
|
show_on_dashboard: true,
|
|
show_in_sidebar: true,
|
|
sort_field: 'name',
|
|
sort_reverse: true,
|
|
filter_rules: [],
|
|
},
|
|
{
|
|
name: 'Saved View 1',
|
|
id: 1,
|
|
show_on_dashboard: false,
|
|
show_in_sidebar: false,
|
|
sort_field: 'name',
|
|
sort_reverse: true,
|
|
filter_rules: [],
|
|
},
|
|
{
|
|
name: 'Saved View 2',
|
|
id: 2,
|
|
show_on_dashboard: true,
|
|
show_in_sidebar: true,
|
|
sort_field: 'name',
|
|
sort_reverse: true,
|
|
filter_rules: [],
|
|
},
|
|
{
|
|
name: 'Saved View 3',
|
|
id: 3,
|
|
show_on_dashboard: true,
|
|
show_in_sidebar: true,
|
|
sort_field: 'name',
|
|
sort_reverse: true,
|
|
filter_rules: [],
|
|
},
|
|
]
|
|
const document = { id: 2, title: 'Hello world' }
|
|
|
|
describe('AppFrameComponent', () => {
|
|
let component: AppFrameComponent
|
|
let fixture: ComponentFixture<AppFrameComponent>
|
|
let httpTestingController: HttpTestingController
|
|
let settingsService: SettingsService
|
|
let permissionsService: PermissionsService
|
|
let remoteVersionService: RemoteVersionService
|
|
let toastService: ToastService
|
|
let messagesService: DjangoMessagesService
|
|
let openDocumentsService: OpenDocumentsService
|
|
let router: Router
|
|
let savedViewSpy
|
|
let modalService: NgbModal
|
|
|
|
beforeEach(async () => {
|
|
TestBed.configureTestingModule({
|
|
imports: [
|
|
BrowserModule,
|
|
RouterTestingModule.withRoutes(routes),
|
|
NgbModule,
|
|
FormsModule,
|
|
ReactiveFormsModule,
|
|
DragDropModule,
|
|
NgbModalModule,
|
|
NgxBootstrapIconsModule.pick(allIcons),
|
|
AppFrameComponent,
|
|
IfPermissionsDirective,
|
|
GlobalSearchComponent,
|
|
],
|
|
providers: [
|
|
SettingsService,
|
|
{
|
|
provide: SavedViewService,
|
|
useValue: {
|
|
reload: () => {},
|
|
listAll: () =>
|
|
of({
|
|
all: [saved_views.map((v) => v.id)],
|
|
count: saved_views.length,
|
|
results: saved_views,
|
|
}),
|
|
sidebarViews: saved_views.filter((v) => v.show_in_sidebar),
|
|
},
|
|
},
|
|
PermissionsService,
|
|
RemoteVersionService,
|
|
IfPermissionsDirective,
|
|
ToastService,
|
|
DjangoMessagesService,
|
|
OpenDocumentsService,
|
|
SearchService,
|
|
NgbModal,
|
|
{
|
|
provide: ActivatedRoute,
|
|
useValue: {
|
|
firstChild: {
|
|
component: DocumentDetailComponent,
|
|
},
|
|
snapshot: {
|
|
firstChild: {
|
|
component: DocumentDetailComponent,
|
|
params: {
|
|
id: document.id,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PermissionsGuard,
|
|
provideHttpClient(withInterceptorsFromDi()),
|
|
provideHttpClientTesting(),
|
|
],
|
|
}).compileComponents()
|
|
|
|
settingsService = TestBed.inject(SettingsService)
|
|
const savedViewService = TestBed.inject(SavedViewService)
|
|
permissionsService = TestBed.inject(PermissionsService)
|
|
remoteVersionService = TestBed.inject(RemoteVersionService)
|
|
toastService = TestBed.inject(ToastService)
|
|
messagesService = TestBed.inject(DjangoMessagesService)
|
|
openDocumentsService = TestBed.inject(OpenDocumentsService)
|
|
modalService = TestBed.inject(NgbModal)
|
|
router = TestBed.inject(Router)
|
|
|
|
jest
|
|
.spyOn(settingsService, 'displayName', 'get')
|
|
.mockReturnValue('Hello World')
|
|
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
|
|
|
savedViewSpy = jest.spyOn(savedViewService, 'reload')
|
|
|
|
fixture = TestBed.createComponent(AppFrameComponent)
|
|
component = fixture.componentInstance
|
|
|
|
httpTestingController = TestBed.inject(HttpTestingController)
|
|
|
|
fixture.detectChanges()
|
|
})
|
|
|
|
it('should initialize the saved view service', () => {
|
|
expect(savedViewSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should check for update if enabled', () => {
|
|
const updateCheckSpy = jest.spyOn(remoteVersionService, 'checkForUpdates')
|
|
updateCheckSpy.mockImplementation(() => {
|
|
return of({
|
|
version: 'v100.0',
|
|
update_available: true,
|
|
})
|
|
})
|
|
settingsService.set(SETTINGS_KEYS.UPDATE_CHECKING_ENABLED, true)
|
|
component.ngOnInit()
|
|
expect(updateCheckSpy).toHaveBeenCalled()
|
|
fixture.detectChanges()
|
|
expect(fixture.nativeElement.textContent).toContain('Update available')
|
|
})
|
|
|
|
it('should check not for update if disabled', () => {
|
|
const updateCheckSpy = jest.spyOn(remoteVersionService, 'checkForUpdates')
|
|
settingsService.set(SETTINGS_KEYS.UPDATE_CHECKING_ENABLED, false)
|
|
component.ngOnInit()
|
|
fixture.detectChanges()
|
|
expect(updateCheckSpy).not.toHaveBeenCalled()
|
|
expect(fixture.nativeElement.textContent).not.toContain('Update available')
|
|
})
|
|
|
|
it('should check for update if was disabled and then enabled', () => {
|
|
const updateCheckSpy = jest.spyOn(remoteVersionService, 'checkForUpdates')
|
|
settingsService.set(SETTINGS_KEYS.UPDATE_CHECKING_ENABLED, false)
|
|
component.setUpdateChecking(true)
|
|
fixture.detectChanges()
|
|
expect(updateCheckSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should show error on toggle update checking if store settings fails', () => {
|
|
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
const toastSpy = jest.spyOn(toastService, 'showError')
|
|
settingsService.set(SETTINGS_KEYS.UPDATE_CHECKING_ENABLED, false)
|
|
component.setUpdateChecking(true)
|
|
httpTestingController
|
|
.expectOne(`${environment.apiBaseUrl}ui_settings/`)
|
|
.flush('error', {
|
|
status: 500,
|
|
statusText: 'error',
|
|
})
|
|
expect(toastSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should support toggling slim sidebar and saving', fakeAsync(() => {
|
|
const saveSettingSpy = jest.spyOn(settingsService, 'set')
|
|
expect(component.slimSidebarEnabled).toBeFalsy()
|
|
expect(component.slimSidebarAnimating).toBeFalsy()
|
|
component.toggleSlimSidebar()
|
|
expect(component.slimSidebarAnimating).toBeTruthy()
|
|
tick(200)
|
|
expect(component.slimSidebarAnimating).toBeFalsy()
|
|
expect(component.slimSidebarEnabled).toBeTruthy()
|
|
expect(saveSettingSpy).toHaveBeenCalledWith(
|
|
SETTINGS_KEYS.SLIM_SIDEBAR,
|
|
true
|
|
)
|
|
}))
|
|
|
|
it('should show error on toggle slim sidebar if store settings fails', () => {
|
|
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
const toastSpy = jest.spyOn(toastService, 'showError')
|
|
component.toggleSlimSidebar()
|
|
httpTestingController
|
|
.expectOne(`${environment.apiBaseUrl}ui_settings/`)
|
|
.flush('error', {
|
|
status: 500,
|
|
statusText: 'error',
|
|
})
|
|
expect(toastSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should support collapsible menu', () => {
|
|
const button: HTMLButtonElement = (
|
|
fixture.nativeElement as HTMLDivElement
|
|
).querySelector('button[data-toggle=collapse]')
|
|
button.dispatchEvent(new MouseEvent('click'))
|
|
expect(component.isMenuCollapsed).toBeFalsy()
|
|
component.closeMenu()
|
|
expect(component.isMenuCollapsed).toBeTruthy()
|
|
})
|
|
|
|
it('should support close document & navigate on close current doc', () => {
|
|
const closeSpy = jest.spyOn(openDocumentsService, 'closeDocument')
|
|
closeSpy.mockReturnValue(of(true))
|
|
const routerSpy = jest.spyOn(router, 'navigate')
|
|
component.closeDocument(document)
|
|
expect(closeSpy).toHaveBeenCalledWith(document)
|
|
expect(routerSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should support close all documents & navigate on close current doc', () => {
|
|
const closeAllSpy = jest.spyOn(openDocumentsService, 'closeAll')
|
|
closeAllSpy.mockReturnValue(of(true))
|
|
const routerSpy = jest.spyOn(router, 'navigate')
|
|
component.closeAll()
|
|
expect(closeAllSpy).toHaveBeenCalled()
|
|
expect(routerSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should close all documents on logout', () => {
|
|
const closeAllSpy = jest.spyOn(openDocumentsService, 'closeAll')
|
|
component.onLogout()
|
|
expect(closeAllSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should warn before close if dirty documents', () => {
|
|
jest.spyOn(openDocumentsService, 'hasDirty').mockReturnValue(true)
|
|
expect(component.canDeactivate()).toBeFalsy()
|
|
})
|
|
|
|
it('should disable global dropzone on start drag + drop, re-enable after', () => {
|
|
expect(settingsService.globalDropzoneEnabled).toBeTruthy()
|
|
component.onDragStart(null)
|
|
expect(settingsService.globalDropzoneEnabled).toBeFalsy()
|
|
component.onDragEnd(null)
|
|
expect(settingsService.globalDropzoneEnabled).toBeTruthy()
|
|
})
|
|
|
|
it('should update saved view sorting on drag + drop, show info', () => {
|
|
const settingsSpy = jest.spyOn(settingsService, 'updateSidebarViewsSort')
|
|
const toastSpy = jest.spyOn(toastService, 'showInfo')
|
|
jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of(true))
|
|
component.onDrop({ previousIndex: 0, currentIndex: 1 } as CdkDragDrop<
|
|
SavedView[]
|
|
>)
|
|
expect(settingsSpy).toHaveBeenCalledWith([
|
|
saved_views[2],
|
|
saved_views[0],
|
|
saved_views[3],
|
|
])
|
|
expect(toastSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should update saved view sorting on drag + drop, show error', () => {
|
|
jest.spyOn(settingsService, 'get').mockImplementation((key) => {
|
|
if (key === SETTINGS_KEYS.SIDEBAR_VIEWS_SORT_ORDER) return []
|
|
})
|
|
fixture.destroy()
|
|
fixture = TestBed.createComponent(AppFrameComponent)
|
|
component = fixture.componentInstance
|
|
fixture.detectChanges()
|
|
const toastSpy = jest.spyOn(toastService, 'showError')
|
|
jest
|
|
.spyOn(settingsService, 'storeSettings')
|
|
.mockReturnValue(throwError(() => new Error('unable to save')))
|
|
component.onDrop({ previousIndex: 0, currentIndex: 2 } as CdkDragDrop<
|
|
SavedView[]
|
|
>)
|
|
expect(toastSpy).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should support edit profile', () => {
|
|
const modalSpy = jest.spyOn(modalService, 'open')
|
|
component.editProfile()
|
|
expect(modalSpy).toHaveBeenCalledWith(ProfileEditDialogComponent, {
|
|
backdrop: 'static',
|
|
size: 'xl',
|
|
})
|
|
})
|
|
|
|
it('should show toasts for django messages', () => {
|
|
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
|
const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
|
|
jest.spyOn(messagesService, 'get').mockReturnValue([
|
|
{ level: DjangoMessageLevel.WARNING, message: 'Test warning' },
|
|
{ level: DjangoMessageLevel.ERROR, message: 'Test error' },
|
|
{ level: DjangoMessageLevel.SUCCESS, message: 'Test success' },
|
|
{ level: DjangoMessageLevel.INFO, message: 'Test info' },
|
|
{ level: DjangoMessageLevel.DEBUG, message: 'Test debug' },
|
|
])
|
|
component.ngOnInit()
|
|
expect(toastErrorSpy).toHaveBeenCalledTimes(2)
|
|
expect(toastInfoSpy).toHaveBeenCalledTimes(3)
|
|
})
|
|
})
|