]> git.ipfire.org Git - thirdparty/paperless-ngx.git/blob
ade5e2f31b4066a35b74fb9d6a67215212ec00bb
[thirdparty/paperless-ngx.git] /
1 import { provideHttpClientTesting } from '@angular/common/http/testing'
2 import { ComponentFixture, TestBed } from '@angular/core/testing'
3 import { FormsModule, ReactiveFormsModule } from '@angular/forms'
4 import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
5 import { NgSelectModule } from '@ng-select/ng-select'
6 import { of } from 'rxjs'
7 import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
8 import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
9 import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
10 import { CorrespondentService } from 'src/app/services/rest/correspondent.service'
11 import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
12 import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
13 import { StoragePathService } from 'src/app/services/rest/storage-path.service'
14 import { SettingsService } from 'src/app/services/settings.service'
15 import { NumberComponent } from '../../input/number/number.component'
16 import { PermissionsGroupComponent } from '../../input/permissions/permissions-group/permissions-group.component'
17 import { PermissionsUserComponent } from '../../input/permissions/permissions-user/permissions-user.component'
18 import { SelectComponent } from '../../input/select/select.component'
19 import { TagsComponent } from '../../input/tags/tags.component'
20 import { TextComponent } from '../../input/text/text.component'
21 import { SwitchComponent } from '../../input/switch/switch.component'
22 import { EditDialogMode } from '../edit-dialog.component'
23 import {
24 DOCUMENT_SOURCE_OPTIONS,
25 SCHEDULE_DATE_FIELD_OPTIONS,
26 WORKFLOW_ACTION_OPTIONS,
27 WORKFLOW_TYPE_OPTIONS,
28 WorkflowEditDialogComponent,
29 } from './workflow-edit-dialog.component'
30 import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
31 import { Workflow } from 'src/app/data/workflow'
32 import {
33 WorkflowTriggerType,
34 DocumentSource,
35 } from 'src/app/data/workflow-trigger'
36 import { CdkDragDrop } from '@angular/cdk/drag-drop'
37 import {
38 WorkflowAction,
39 WorkflowActionType,
40 } from 'src/app/data/workflow-action'
41 import { MATCHING_ALGORITHMS, MATCH_AUTO } from 'src/app/data/matching-model'
42 import { ConfirmButtonComponent } from '../../confirm-button/confirm-button.component'
43 import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
44 import { CustomFieldDataType } from 'src/app/data/custom-field'
45
46 const workflow: Workflow = {
47 name: 'Workflow 1',
48 id: 1,
49 order: 1,
50 enabled: true,
51 triggers: [
52 {
53 id: 1,
54 type: WorkflowTriggerType.Consumption,
55 sources: [DocumentSource.ConsumeFolder],
56 filter_filename: '*',
57 },
58 ],
59 actions: [
60 {
61 id: 1,
62 type: WorkflowActionType.Assignment,
63 assign_title: 'foo',
64 },
65 {
66 id: 4,
67 type: WorkflowActionType.Assignment,
68 assign_owner: 2,
69 },
70 ],
71 }
72
73 describe('WorkflowEditDialogComponent', () => {
74 let component: WorkflowEditDialogComponent
75 let settingsService: SettingsService
76 let fixture: ComponentFixture<WorkflowEditDialogComponent>
77
78 beforeEach(() => {
79 TestBed.configureTestingModule({
80 declarations: [
81 WorkflowEditDialogComponent,
82 IfPermissionsDirective,
83 IfOwnerDirective,
84 SelectComponent,
85 TextComponent,
86 NumberComponent,
87 SwitchComponent,
88 TagsComponent,
89 PermissionsUserComponent,
90 PermissionsGroupComponent,
91 SafeHtmlPipe,
92 ConfirmButtonComponent,
93 ],
94 imports: [FormsModule, ReactiveFormsModule, NgSelectModule, NgbModule],
95 providers: [
96 NgbActiveModal,
97 {
98 provide: CorrespondentService,
99 useValue: {
100 listAll: () =>
101 of({
102 results: [
103 {
104 id: 1,
105 username: 'c1',
106 },
107 ],
108 }),
109 },
110 },
111 {
112 provide: DocumentTypeService,
113 useValue: {
114 listAll: () =>
115 of({
116 results: [
117 {
118 id: 1,
119 username: 'dt1',
120 },
121 ],
122 }),
123 },
124 },
125 {
126 provide: StoragePathService,
127 useValue: {
128 listAll: () =>
129 of({
130 results: [
131 {
132 id: 1,
133 username: 'sp1',
134 },
135 ],
136 }),
137 },
138 },
139 {
140 provide: MailRuleService,
141 useValue: {
142 listAll: () =>
143 of({
144 results: [],
145 }),
146 },
147 },
148 {
149 provide: CustomFieldsService,
150 useValue: {
151 listAll: () =>
152 of({
153 results: [
154 {
155 id: 1,
156 name: 'cf1',
157 data_type: CustomFieldDataType.String,
158 },
159 {
160 id: 2,
161 name: 'cf2',
162 data_type: CustomFieldDataType.Date,
163 },
164 ],
165 }),
166 },
167 },
168 provideHttpClient(withInterceptorsFromDi()),
169 provideHttpClientTesting(),
170 ],
171 }).compileComponents()
172
173 fixture = TestBed.createComponent(WorkflowEditDialogComponent)
174 settingsService = TestBed.inject(SettingsService)
175 settingsService.currentUser = { id: 99, username: 'user99' }
176 component = fixture.componentInstance
177
178 fixture.detectChanges()
179 })
180
181 it('should support create and edit modes, support adding triggers and actions on new workflow', () => {
182 component.dialogMode = EditDialogMode.CREATE
183 const createTitleSpy = jest.spyOn(component, 'getCreateTitle')
184 const editTitleSpy = jest.spyOn(component, 'getEditTitle')
185 fixture.detectChanges()
186 expect(createTitleSpy).toHaveBeenCalled()
187 expect(editTitleSpy).not.toHaveBeenCalled()
188 expect(component.object).toBeUndefined()
189 component.addAction()
190 expect(component.object).not.toBeUndefined()
191 expect(component.object.actions).toHaveLength(1)
192 component.object = undefined
193 component.addTrigger()
194 expect(component.object).not.toBeUndefined()
195 expect(component.object.triggers).toHaveLength(1)
196
197 component.dialogMode = EditDialogMode.EDIT
198 fixture.detectChanges()
199 expect(editTitleSpy).toHaveBeenCalled()
200 })
201
202 it('should return source options, type options, type name, schedule date field options', () => {
203 // coverage
204 expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS)
205 expect(component.triggerTypeOptions).toEqual(WORKFLOW_TYPE_OPTIONS)
206 expect(
207 component.getTriggerTypeOptionName(WorkflowTriggerType.DocumentAdded)
208 ).toEqual('Document Added')
209 expect(component.getTriggerTypeOptionName(null)).toEqual('')
210 expect(component.sourceOptions).toEqual(DOCUMENT_SOURCE_OPTIONS)
211 expect(component.actionTypeOptions).toEqual(WORKFLOW_ACTION_OPTIONS)
212 expect(
213 component.getActionTypeOptionName(WorkflowActionType.Assignment)
214 ).toEqual('Assignment')
215 expect(component.getActionTypeOptionName(null)).toEqual('')
216 expect(component.scheduleDateFieldOptions).toEqual(
217 SCHEDULE_DATE_FIELD_OPTIONS
218 )
219 })
220
221 it('should support add and remove triggers and actions', () => {
222 component.object = workflow
223 component.addTrigger()
224 expect(component.object.triggers.length).toEqual(2)
225 component.addAction()
226 expect(component.object.actions.length).toEqual(3)
227 component.removeTrigger(1)
228 expect(component.object.triggers.length).toEqual(1)
229 component.removeAction(1)
230 expect(component.object.actions.length).toEqual(2)
231 })
232
233 it('should update order and remove ids from actions on drag n drop', () => {
234 const action1 = workflow.actions[0]
235 const action2 = workflow.actions[1]
236 component.object = workflow
237 component.ngOnInit()
238 component.onActionDrop({ previousIndex: 0, currentIndex: 1 } as CdkDragDrop<
239 WorkflowAction[]
240 >)
241 expect(component.object.actions).toEqual([action2, action1])
242 expect(action1.id).toBeNull()
243 expect(action2.id).toBeNull()
244 })
245
246 it('should not include auto matching in algorithms', () => {
247 expect(component.getMatchingAlgorithms()).not.toContain(
248 MATCHING_ALGORITHMS.find((a) => a.id === MATCH_AUTO)
249 )
250 })
251
252 it('should disable or enable action fields based on removal action type', () => {
253 const workflow: Workflow = {
254 name: 'Workflow 1',
255 id: 1,
256 order: 1,
257 enabled: true,
258 triggers: [],
259 actions: [
260 {
261 id: 1,
262 type: WorkflowActionType.Removal,
263 remove_all_tags: true,
264 remove_all_document_types: true,
265 remove_all_correspondents: true,
266 remove_all_storage_paths: true,
267 remove_all_custom_fields: true,
268 remove_all_owners: true,
269 remove_all_permissions: true,
270 },
271 ],
272 }
273 component.object = workflow
274 component.ngOnInit()
275
276 component['checkRemovalActionFields'](workflow)
277
278 // Assert that the action fields are disabled or enabled correctly
279 expect(
280 component.actionFields.at(0).get('remove_tags').disabled
281 ).toBeTruthy()
282 expect(
283 component.actionFields.at(0).get('remove_document_types').disabled
284 ).toBeTruthy()
285 expect(
286 component.actionFields.at(0).get('remove_correspondents').disabled
287 ).toBeTruthy()
288 expect(
289 component.actionFields.at(0).get('remove_storage_paths').disabled
290 ).toBeTruthy()
291 expect(
292 component.actionFields.at(0).get('remove_custom_fields').disabled
293 ).toBeTruthy()
294 expect(
295 component.actionFields.at(0).get('remove_owners').disabled
296 ).toBeTruthy()
297 expect(
298 component.actionFields.at(0).get('remove_view_users').disabled
299 ).toBeTruthy()
300 expect(
301 component.actionFields.at(0).get('remove_view_groups').disabled
302 ).toBeTruthy()
303 expect(
304 component.actionFields.at(0).get('remove_change_users').disabled
305 ).toBeTruthy()
306 expect(
307 component.actionFields.at(0).get('remove_change_groups').disabled
308 ).toBeTruthy()
309
310 workflow.actions[0].remove_all_tags = false
311 workflow.actions[0].remove_all_document_types = false
312 workflow.actions[0].remove_all_correspondents = false
313 workflow.actions[0].remove_all_storage_paths = false
314 workflow.actions[0].remove_all_custom_fields = false
315 workflow.actions[0].remove_all_owners = false
316 workflow.actions[0].remove_all_permissions = false
317
318 component['checkRemovalActionFields'](workflow)
319
320 // Assert that the action fields are disabled or enabled correctly
321 expect(component.actionFields.at(0).get('remove_tags').disabled).toBeFalsy()
322 expect(
323 component.actionFields.at(0).get('remove_document_types').disabled
324 ).toBeFalsy()
325 expect(
326 component.actionFields.at(0).get('remove_correspondents').disabled
327 ).toBeFalsy()
328 expect(
329 component.actionFields.at(0).get('remove_storage_paths').disabled
330 ).toBeFalsy()
331 expect(
332 component.actionFields.at(0).get('remove_custom_fields').disabled
333 ).toBeFalsy()
334 expect(
335 component.actionFields.at(0).get('remove_owners').disabled
336 ).toBeFalsy()
337 expect(
338 component.actionFields.at(0).get('remove_view_users').disabled
339 ).toBeFalsy()
340 expect(
341 component.actionFields.at(0).get('remove_view_groups').disabled
342 ).toBeFalsy()
343 expect(
344 component.actionFields.at(0).get('remove_change_users').disabled
345 ).toBeFalsy()
346 expect(
347 component.actionFields.at(0).get('remove_change_groups').disabled
348 ).toBeFalsy()
349 })
350
351 it('should prune empty nested objects on save', () => {
352 component.object = workflow
353 component.addTrigger()
354 component.addAction()
355 expect(component.objectForm.get('actions').value[0].email).not.toBeNull()
356 expect(component.objectForm.get('actions').value[0].webhook).not.toBeNull()
357 component.save()
358 expect(component.objectForm.get('actions').value[0].email).toBeNull()
359 expect(component.objectForm.get('actions').value[0].webhook).toBeNull()
360 })
361 })