mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-13 14:41:20 +00:00
Enhancement: improve layout for custom fields dropdown (#6362)
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
fakeAsync,
|
||||
tick,
|
||||
} from '@angular/core/testing'
|
||||
import { CustomFieldsDropdownComponent } from './custom-fields-dropdown.component'
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
@@ -71,28 +75,33 @@ describe('CustomFieldsDropdownComponent', () => {
|
||||
let addedField
|
||||
component.added.subscribe((f) => (addedField = f))
|
||||
component.documentId = 11
|
||||
component.field = fields[0].id
|
||||
component.addField()
|
||||
component.addField({ field: fields[0].id } as any)
|
||||
expect(addedField).not.toBeUndefined()
|
||||
})
|
||||
|
||||
it('should clear field on open / close, updated unused fields', () => {
|
||||
component.field = fields[1].id
|
||||
component.onOpenClose()
|
||||
expect(component.field).toBeUndefined()
|
||||
|
||||
expect(component.unusedFields).toEqual(fields)
|
||||
const updateSpy = jest.spyOn(
|
||||
CustomFieldsDropdownComponent.prototype as any,
|
||||
'updateUnusedFields'
|
||||
)
|
||||
component.existingFields = [{ field: fields[1].id } as any]
|
||||
component.onOpenClose()
|
||||
expect(updateSpy).toHaveBeenCalled()
|
||||
expect(component.unusedFields).toEqual([fields[0]])
|
||||
it('should support filtering fields', () => {
|
||||
const input = fixture.debugElement.query(By.css('input'))
|
||||
input.nativeElement.value = 'Field 1'
|
||||
input.triggerEventHandler('input', { target: input.nativeElement })
|
||||
fixture.detectChanges()
|
||||
expect(component.filteredFields.length).toEqual(1)
|
||||
expect(component.filteredFields[0].name).toEqual('Field 1')
|
||||
})
|
||||
|
||||
it('should support creating field, show error if necessary', () => {
|
||||
it('should support update unused fields', () => {
|
||||
component.existingFields = [{ field: fields[0].id } as any]
|
||||
component['updateUnusedFields']()
|
||||
expect(component['unusedFields'].length).toEqual(1)
|
||||
expect(component['unusedFields'][0].name).toEqual('Field 2')
|
||||
})
|
||||
|
||||
it('should support getting data type label', () => {
|
||||
expect(component.getDataTypeLabel(CustomFieldDataType.Integer)).toEqual(
|
||||
'Integer'
|
||||
)
|
||||
})
|
||||
|
||||
it('should support creating field, show error if necessary, then add', fakeAsync(() => {
|
||||
let modal: NgbModalRef
|
||||
modalService.activeInstances.subscribe((m) => (modal = m[m.length - 1]))
|
||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||
@@ -101,8 +110,9 @@ describe('CustomFieldsDropdownComponent', () => {
|
||||
CustomFieldsDropdownComponent.prototype as any,
|
||||
'getFields'
|
||||
)
|
||||
const addFieldSpy = jest.spyOn(component, 'addField')
|
||||
|
||||
const createButton = fixture.debugElement.queryAll(By.css('button'))[1]
|
||||
const createButton = fixture.debugElement.queryAll(By.css('button'))[3]
|
||||
createButton.triggerEventHandler('click')
|
||||
|
||||
expect(modal).not.toBeUndefined()
|
||||
@@ -115,9 +125,11 @@ describe('CustomFieldsDropdownComponent', () => {
|
||||
|
||||
// succeed
|
||||
editDialog.succeeded.emit(fields[0])
|
||||
tick(100)
|
||||
expect(toastInfoSpy).toHaveBeenCalled()
|
||||
expect(getFieldsSpy).toHaveBeenCalled()
|
||||
})
|
||||
expect(addFieldSpy).toHaveBeenCalled()
|
||||
}))
|
||||
|
||||
it('should support creating field with name', () => {
|
||||
let modal: NgbModalRef
|
||||
@@ -128,4 +140,106 @@ describe('CustomFieldsDropdownComponent', () => {
|
||||
const editDialog = modal.componentInstance as CustomFieldEditDialogComponent
|
||||
expect(editDialog.object.name).toEqual('Foo bar')
|
||||
})
|
||||
|
||||
it('should support arrow keyboard navigation', fakeAsync(() => {
|
||||
fixture.nativeElement
|
||||
.querySelector('button')
|
||||
.dispatchEvent(new MouseEvent('click')) // open
|
||||
fixture.detectChanges()
|
||||
tick(100)
|
||||
const filterInputEl: HTMLInputElement =
|
||||
component.listFilterTextInput.nativeElement
|
||||
expect(document.activeElement).toEqual(filterInputEl)
|
||||
const itemButtons = Array.from(
|
||||
(fixture.nativeElement as HTMLDivElement).querySelectorAll(
|
||||
'.custom-fields-dropdown button'
|
||||
)
|
||||
).filter((b) => b.textContent.includes('Field'))
|
||||
filterInputEl.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(itemButtons[0])
|
||||
itemButtons[0].dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(itemButtons[1])
|
||||
itemButtons[1].dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(itemButtons[0])
|
||||
itemButtons[0].dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(filterInputEl)
|
||||
filterInputEl.value = 'foo'
|
||||
component.filterText = 'foo'
|
||||
|
||||
// dont move focus if we're traversing the field
|
||||
filterInputEl.selectionStart = 1
|
||||
expect(document.activeElement).toEqual(filterInputEl)
|
||||
|
||||
// now we're at end, so move focus
|
||||
filterInputEl.selectionStart = 3
|
||||
filterInputEl.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(itemButtons[0])
|
||||
}))
|
||||
|
||||
it('should support arrow keyboard navigation after tab keyboard navigation', fakeAsync(() => {
|
||||
fixture.nativeElement
|
||||
.querySelector('button')
|
||||
.dispatchEvent(new MouseEvent('click')) // open
|
||||
fixture.detectChanges()
|
||||
tick(100)
|
||||
const filterInputEl: HTMLInputElement =
|
||||
component.listFilterTextInput.nativeElement
|
||||
expect(document.activeElement).toEqual(filterInputEl)
|
||||
const itemButtons = Array.from(
|
||||
(fixture.nativeElement as HTMLDivElement).querySelectorAll(
|
||||
'.custom-fields-dropdown button'
|
||||
)
|
||||
).filter((b) => b.textContent.includes('Field'))
|
||||
filterInputEl.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
|
||||
)
|
||||
itemButtons[0]['focus']() // normally handled by browser
|
||||
itemButtons[0].dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })
|
||||
)
|
||||
itemButtons[1]['focus']() // normally handled by browser
|
||||
itemButtons[1].dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
key: 'Tab',
|
||||
shiftKey: true,
|
||||
bubbles: true,
|
||||
})
|
||||
)
|
||||
itemButtons[0]['focus']() // normally handled by browser
|
||||
itemButtons[0].dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })
|
||||
)
|
||||
expect(document.activeElement).toEqual(itemButtons[1])
|
||||
}))
|
||||
|
||||
it('should support enter keyboard navigation', fakeAsync(() => {
|
||||
jest.spyOn(component, 'canCreateFields', 'get').mockReturnValue(true)
|
||||
const addFieldSpy = jest.spyOn(component, 'addField')
|
||||
const createFieldSpy = jest.spyOn(component, 'createField')
|
||||
component.filterText = 'Field 1'
|
||||
component.listFilterEnter()
|
||||
expect(addFieldSpy).toHaveBeenCalled()
|
||||
|
||||
component.filterText = 'Field 3'
|
||||
component.listFilterEnter()
|
||||
expect(createFieldSpy).toHaveBeenCalledWith('Field 3')
|
||||
|
||||
addFieldSpy.mockClear()
|
||||
createFieldSpy.mockClear()
|
||||
|
||||
component.filterText = undefined
|
||||
component.listFilterEnter()
|
||||
expect(createFieldSpy).not.toHaveBeenCalled()
|
||||
expect(addFieldSpy).not.toHaveBeenCalled()
|
||||
}))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user