刘光辉
4 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import type { FilePermissionView } from './filePermissionContext';
 
import { mount } from '@vue/test-utils';
import { defineComponent, h, provide, reactive } from 'vue';
 
import { describe, expect, it } from 'vitest';
 
import { fieldFileAccess, filePermissionFormKey, useFilePermissionAccess } from './filePermissionContext';
 
const view = (): FilePermissionView => ({
  enabled: true,
  taskId: 'task',
  formId: 'form',
  status: 'ready',
  revision: 'state',
  fields: {
    files: { status: 'ready', actions: { ADD: true, DOWNLOAD: true, EDIT: true, REMOVE: true, REPLACE: true, VIEW: true } },
    'rows-files': { status: 'ready', actions: { DOWNLOAD: false, VIEW: true } },
  },
});
describe('runtime file permission context', () => {
  it('isolates the same field name in main and child forms', () => {
    expect(fieldFileAccess(view(), 'form', 'files')?.actions?.DOWNLOAD).toBe(true);
    expect(fieldFileAccess(view(), 'form', 'files', 'rows')?.actions?.DOWNLOAD).toBe(false);
    expect(fieldFileAccess(view(), 'form', 'missing')?.status).toBe('error');
  });
  it('retains legacy behavior only for a valid legacy response or a non-workflow form', () => {
    expect(fieldFileAccess(undefined, 'form', 'files')).toBeUndefined();
    expect(fieldFileAccess({ ...view(), enabled: false }, 'form', 'files')).toBeUndefined();
    expect(fieldFileAccess({ ...view(), enabled: false, status: 'error' }, 'form', 'files')?.status).toBe('error');
  });
  it('closes actions for incomplete or foreign responses', () => {
    expect(fieldFileAccess(view(), 'other-form', 'files')?.status).toBe('error');
    expect(fieldFileAccess({ ...view(), taskId: '' }, 'form', 'files')?.status).toBe('error');
    expect(fieldFileAccess({ ...view(), revision: undefined }, 'form', 'files')?.status).toBe('error');
    expect(fieldFileAccess({ ...view(), status: 'loading' }, 'form', 'files')?.status).toBe('loading');
  });
  it('cannot elevate runtime permission through component props and reacts to revocation', () => {
    const state = reactive({ view: view() });
    let access!: ReturnType<typeof useFilePermissionAccess>;
    const child = defineComponent({
      setup() {
        access = useFilePermissionAccess({
          editField: 'files',
          editParentField: 'rows',
          fileAccess: { status: 'ready', actions: { DOWNLOAD: true, VIEW: true } },
        });
        return () => h('div');
      },
    });
    const wrapper = mount(
      defineComponent({
        setup() {
          provide(filePermissionFormKey, () => ({ modelId: 'form', view: state.view }));
          return () => h(child);
        },
      }),
    );
    expect(access.value?.actions?.DOWNLOAD).toBe(false);
    expect(access.value?.actions?.VIEW).toBe(true);
    state.view = { ...view(), status: 'error' };
    expect(access.value?.status).toBe('error');
    wrapper.unmount();
  });
  it('keeps configured download but closes mutation actions in list details', () => {
    const state = reactive({ readOnly: true, view: view() });
    let access!: ReturnType<typeof useFilePermissionAccess>;
    const child = defineComponent({
      setup() {
        access = useFilePermissionAccess({ editField: 'files' });
        return () => h('div');
      },
    });
    const wrapper = mount(
      defineComponent({
        setup() {
          provide(filePermissionFormKey, () => ({ modelId: 'form', readOnly: state.readOnly, view: state.view }));
          return () => h(child);
        },
      }),
    );
    expect(access.value?.actions).toMatchObject({ ADD: false, DOWNLOAD: true, EDIT: false, REMOVE: false, REPLACE: false, VIEW: true });
    state.view.fields!.files!.actions!.DOWNLOAD = false;
    expect(access.value?.actions?.DOWNLOAD).toBe(false);
    state.readOnly = false;
    expect(access.value?.actions?.EDIT).toBe(true);
    wrapper.unmount();
  });
});