@things-factory/worklist 9.1.19 → 10.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/components/activity-thread-timeline.d.ts +1 -9
- package/dist-client/components/activity-thread-timeline.js +1 -3
- package/dist-client/components/activity-thread-timeline.js.map +1 -1
- package/dist-client/pages/activity/activity-list-page.d.ts +1 -7
- package/dist-client/pages/activity/activity-list-page.js +125 -234
- package/dist-client/pages/activity/activity-list-page.js.map +1 -1
- package/dist-client/pages/activity/activity-page.d.ts +1 -7
- package/dist-client/pages/activity/activity-page.js +51 -93
- package/dist-client/pages/activity/activity-page.js.map +1 -1
- package/dist-client/pages/activity/starter-list-page.d.ts +1 -7
- package/dist-client/pages/activity/starter-list-page.js +33 -62
- package/dist-client/pages/activity/starter-list-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-list-page.d.ts +1 -7
- package/dist-client/pages/activity-approval/activity-approval-list-page.js +50 -95
- package/dist-client/pages/activity-approval/activity-approval-list-page.js.map +1 -1
- package/dist-client/pages/activity-approval/activity-approval-page.d.ts +1 -7
- package/dist-client/pages/activity-approval/activity-approval-page.js +73 -119
- package/dist-client/pages/activity-approval/activity-approval-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-list-page.d.ts +0 -6
- package/dist-client/pages/activity-instance/activity-instance-list-page.js +63 -120
- package/dist-client/pages/activity-instance/activity-instance-list-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-search-page.d.ts +1 -7
- package/dist-client/pages/activity-instance/activity-instance-search-page.js +55 -101
- package/dist-client/pages/activity-instance/activity-instance-search-page.js.map +1 -1
- package/dist-client/pages/activity-instance/activity-instance-start-page.d.ts +1 -7
- package/dist-client/pages/activity-instance/activity-instance-start-page.js +65 -109
- package/dist-client/pages/activity-instance/activity-instance-start-page.js.map +1 -1
- package/dist-client/pages/activity-stats/activity-stats-list-page.d.ts +1 -7
- package/dist-client/pages/activity-stats/activity-stats-list-page.js +50 -95
- package/dist-client/pages/activity-stats/activity-stats-list-page.js.map +1 -1
- package/dist-client/pages/activity-store/activity-store-page.d.ts +1 -7
- package/dist-client/pages/activity-store/activity-store-page.js +2 -3
- package/dist-client/pages/activity-store/activity-store-page.js.map +1 -1
- package/dist-client/pages/activity-supervisor/reporter-list-page.d.ts +1 -7
- package/dist-client/pages/activity-supervisor/reporter-list-page.js +36 -66
- package/dist-client/pages/activity-supervisor/reporter-list-page.js.map +1 -1
- package/dist-client/pages/activity-template/activity-template-list-page.d.ts +1 -7
- package/dist-client/pages/activity-template/activity-template-list-page.js +70 -134
- package/dist-client/pages/activity-template/activity-template-list-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-list-page.d.ts +1 -7
- package/dist-client/pages/activity-thread/activity-thread-list-page.js +49 -93
- package/dist-client/pages/activity-thread/activity-thread-list-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.d.ts +1 -7
- package/dist-client/pages/activity-thread/activity-thread-page.js +80 -135
- package/dist-client/pages/activity-thread/activity-thread-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view-page.d.ts +1 -7
- package/dist-client/pages/activity-thread/activity-thread-view-page.js +54 -80
- package/dist-client/pages/activity-thread/activity-thread-view-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-view.js +4 -0
- package/dist-client/pages/activity-thread/activity-thread-view.js.map +1 -1
- package/dist-client/pages/dashboard/dashboard-home.js +3 -5
- package/dist-client/pages/dashboard/dashboard-home.js.map +1 -1
- package/dist-client/pages/installable-activity/installable-activity-list-page.d.ts +0 -6
- package/dist-client/pages/installable-activity/installable-activity-list-page.js +68 -130
- package/dist-client/pages/installable-activity/installable-activity-list-page.js.map +1 -1
- package/dist-client/pages/todo/approval-done-list-page.d.ts +1 -7
- package/dist-client/pages/todo/approval-done-list-page.js +53 -100
- package/dist-client/pages/todo/approval-done-list-page.js.map +1 -1
- package/dist-client/pages/todo/approval-pending-list-page.d.ts +0 -6
- package/dist-client/pages/todo/approval-pending-list-page.js +63 -119
- package/dist-client/pages/todo/approval-pending-list-page.js.map +1 -1
- package/dist-client/pages/todo/done-list-calendar-page.d.ts +1 -7
- package/dist-client/pages/todo/done-list-calendar-page.js +2 -3
- package/dist-client/pages/todo/done-list-calendar-page.js.map +1 -1
- package/dist-client/pages/todo/done-list-page.d.ts +1 -7
- package/dist-client/pages/todo/done-list-page.js +56 -106
- package/dist-client/pages/todo/done-list-page.js.map +1 -1
- package/dist-client/pages/todo/draft-list-page.d.ts +1 -7
- package/dist-client/pages/todo/draft-list-page.js +49 -88
- package/dist-client/pages/todo/draft-list-page.js.map +1 -1
- package/dist-client/pages/todo/pickable-list-page.d.ts +1 -7
- package/dist-client/pages/todo/pickable-list-page.js +48 -91
- package/dist-client/pages/todo/pickable-list-page.js.map +1 -1
- package/dist-client/pages/todo/todo-list-page.d.ts +0 -6
- package/dist-client/pages/todo/todo-list-page.js +56 -106
- package/dist-client/pages/todo/todo-list-page.js.map +1 -1
- package/dist-client/pages/worklist-home.js +2 -3
- package/dist-client/pages/worklist-home.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/templates/activity-approval-context-template.js +8 -12
- package/dist-client/templates/activity-approval-context-template.js.map +1 -1
- package/dist-client/templates/activity-instance-context-template.js +8 -12
- package/dist-client/templates/activity-instance-context-template.js.map +1 -1
- package/dist-client/templates/activity-thread-context-template.js +8 -12
- package/dist-client/templates/activity-thread-context-template.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/activity-approval/approve.js +2 -2
- package/dist-server/controllers/activity-approval/approve.js.map +1 -1
- package/dist-server/controllers/activity-thread/submit.js +2 -2
- package/dist-server/controllers/activity-thread/submit.js.map +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/spec/integration/approval-mixed-types.spec.ts +491 -0
- package/spec/integration/approval-role-based.spec.ts +389 -0
- package/spec/integration/instance-lifecycle.spec.ts +406 -0
- package/spec/integration/role-approval-edge-cases.spec.ts +581 -0
- package/spec/unit/controllers/activity-instance-issue.spec.ts +360 -0
- package/spec/unit/controllers/activity-thread-submit.spec.ts +384 -0
- package/spec/unit/role-approval-escalate-logic.spec.ts +499 -0
- package/spec/unit/role-approval-submit-logic.spec.ts +481 -0
- package/spec/unit/thread-state-helpers.spec.ts +253 -0
- package/translations/en.json +1 -1
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role-Based Approval Workflow Integration Tests
|
|
3
|
+
* 역할 기반 승인 워크플로우 통합 테스트
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { TestDatabase } from '../../../../test/test-database'
|
|
7
|
+
import { withTestTransaction } from '../../../../test/test-context'
|
|
8
|
+
import {
|
|
9
|
+
domainFactory,
|
|
10
|
+
userFactory,
|
|
11
|
+
roleFactory,
|
|
12
|
+
activityFactory,
|
|
13
|
+
activityInstanceFactory,
|
|
14
|
+
activityThreadFactory,
|
|
15
|
+
activityApprovalFactory
|
|
16
|
+
} from '../../../../test/factories'
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
ActivityInstanceStatus,
|
|
20
|
+
ActivityThreadStatus,
|
|
21
|
+
ActivityApprovalJudgment
|
|
22
|
+
} from '../../../../test/entities/schemas'
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
createRoleApprovalLineItem,
|
|
26
|
+
simulateApproval,
|
|
27
|
+
simulateRejection,
|
|
28
|
+
simulateEscalation
|
|
29
|
+
} from '../../../../test/helpers/workflow-helpers'
|
|
30
|
+
|
|
31
|
+
describe('Role-Based Approval Workflow Integration Tests', () => {
|
|
32
|
+
let testDb: TestDatabase
|
|
33
|
+
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
testDb = TestDatabase.getInstance()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('ROLE 타입 Approval Line 설정', () => {
|
|
39
|
+
it('approvalLine에 Role 타입이 설정되어야 한다', async () => {
|
|
40
|
+
await withTestTransaction(async (context) => {
|
|
41
|
+
const { tx } = context.state
|
|
42
|
+
const domain = await domainFactory.create({}, tx)
|
|
43
|
+
const approverRole = await roleFactory.create({ name: 'Approver Role', domain }, tx)
|
|
44
|
+
|
|
45
|
+
// Given: Role 타입 approval line
|
|
46
|
+
const approvalLine = [createRoleApprovalLineItem(approverRole)]
|
|
47
|
+
|
|
48
|
+
// When: ActivityInstance 생성
|
|
49
|
+
const instance = await activityInstanceFactory.createWithApprovalLine(
|
|
50
|
+
approvalLine,
|
|
51
|
+
{ state: ActivityInstanceStatus.Issued },
|
|
52
|
+
undefined,
|
|
53
|
+
domain,
|
|
54
|
+
tx
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
// Then
|
|
58
|
+
expect(instance.approvalLine).toBeDefined()
|
|
59
|
+
expect(instance.approvalLine?.length).toBe(1)
|
|
60
|
+
expect(instance.approvalLine?.[0].type).toBe('Role')
|
|
61
|
+
expect(instance.approvalLine?.[0].value).toBe(approverRole.id)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('Role 타입 ActivityApproval 생성 시 approverRole이 설정되어야 한다', async () => {
|
|
66
|
+
await withTestTransaction(async (context) => {
|
|
67
|
+
const { tx } = context.state
|
|
68
|
+
const domain = await domainFactory.create({}, tx)
|
|
69
|
+
const approverRole = await roleFactory.create({ name: 'Approver Role', domain }, tx)
|
|
70
|
+
|
|
71
|
+
// When: Role 기반 approval 생성
|
|
72
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
73
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
74
|
+
undefined,
|
|
75
|
+
approverRole,
|
|
76
|
+
tx
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
// Then
|
|
80
|
+
expect(approval.approverRole?.id).toBe(approverRole.id)
|
|
81
|
+
expect(approval.approver).toBeUndefined()
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('Role 타입 approval 생성 시 approver는 설정되지 않아야 한다', async () => {
|
|
86
|
+
await withTestTransaction(async (context) => {
|
|
87
|
+
const { tx } = context.state
|
|
88
|
+
const domain = await domainFactory.create({}, tx)
|
|
89
|
+
const approverRole = await roleFactory.create({ name: 'Approver', domain }, tx)
|
|
90
|
+
|
|
91
|
+
// When
|
|
92
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
93
|
+
{},
|
|
94
|
+
undefined,
|
|
95
|
+
approverRole,
|
|
96
|
+
tx
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
// Then: approver는 undefined, approverRole만 설정됨
|
|
100
|
+
expect(approval.approver).toBeUndefined()
|
|
101
|
+
expect(approval.approverRole).toBeDefined()
|
|
102
|
+
expect(approval.approverRole?.id).toBe(approverRole.id)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('Role 기반 승인 권한 검증', () => {
|
|
108
|
+
it('해당 Role을 가진 사용자가 승인할 수 있어야 한다', async () => {
|
|
109
|
+
await withTestTransaction(async (context) => {
|
|
110
|
+
const { tx } = context.state
|
|
111
|
+
const domain = await domainFactory.create({}, tx)
|
|
112
|
+
const approverRole = await roleFactory.create({ name: 'Approver', domain }, tx)
|
|
113
|
+
|
|
114
|
+
// Given: Role을 가진 사용자
|
|
115
|
+
const userWithRole = await userFactory.createWithRole({}, approverRole, tx)
|
|
116
|
+
|
|
117
|
+
// Given: Role 기반 approval
|
|
118
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
119
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
120
|
+
undefined,
|
|
121
|
+
approverRole,
|
|
122
|
+
tx
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
// When: 승인 시뮬레이션
|
|
126
|
+
const approved = await simulateApproval(
|
|
127
|
+
approval,
|
|
128
|
+
userWithRole,
|
|
129
|
+
'Approved by role member',
|
|
130
|
+
{ tx, domain, user: userWithRole }
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
// Then
|
|
134
|
+
expect(approved.judgment).toBe(ActivityApprovalJudgment.Approved)
|
|
135
|
+
expect(approved.approver?.id).toBe(userWithRole.id)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('첫 번째 승인자가 Role 기반 approval에 자동 할당되어야 한다', async () => {
|
|
140
|
+
await withTestTransaction(async (context) => {
|
|
141
|
+
const { tx } = context.state
|
|
142
|
+
const domain = await domainFactory.create({}, tx)
|
|
143
|
+
const approverRole = await roleFactory.create({ name: 'Approver', domain }, tx)
|
|
144
|
+
const userWithRole = await userFactory.createWithRole({}, approverRole, tx)
|
|
145
|
+
|
|
146
|
+
// Given: approver가 없는 Role 기반 approval
|
|
147
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
148
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
149
|
+
undefined,
|
|
150
|
+
approverRole,
|
|
151
|
+
tx
|
|
152
|
+
)
|
|
153
|
+
expect(approval.approver).toBeUndefined()
|
|
154
|
+
|
|
155
|
+
// When: 승인 실행 시
|
|
156
|
+
const approved = await simulateApproval(
|
|
157
|
+
approval,
|
|
158
|
+
userWithRole,
|
|
159
|
+
undefined,
|
|
160
|
+
{ tx, domain, user: userWithRole }
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
// Then: 승인한 사용자가 approver로 할당됨
|
|
164
|
+
expect(approved.approver?.id).toBe(userWithRole.id)
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
describe('다단계 Role 기반 승인', () => {
|
|
170
|
+
it('여러 레벨의 Role 기반 approval line이 처리되어야 한다', async () => {
|
|
171
|
+
await withTestTransaction(async (context) => {
|
|
172
|
+
const { tx } = context.state
|
|
173
|
+
const domain = await domainFactory.create({}, tx)
|
|
174
|
+
|
|
175
|
+
// Given: 2개의 approver roles
|
|
176
|
+
const firstApproverRole = await roleFactory.create({ name: 'First Approver', domain }, tx)
|
|
177
|
+
const secondApproverRole = await roleFactory.create({ name: 'Second Approver', domain }, tx)
|
|
178
|
+
|
|
179
|
+
const firstApprover = await userFactory.createWithRole({}, firstApproverRole, tx)
|
|
180
|
+
const secondApprover = await userFactory.createWithRole({}, secondApproverRole, tx)
|
|
181
|
+
|
|
182
|
+
// Given: 2단계 approval line
|
|
183
|
+
const approvalLine = [
|
|
184
|
+
createRoleApprovalLineItem(firstApproverRole),
|
|
185
|
+
createRoleApprovalLineItem(secondApproverRole)
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
const instance = await activityInstanceFactory.createWithApprovalLine(
|
|
189
|
+
approvalLine,
|
|
190
|
+
{ state: ActivityInstanceStatus.Started },
|
|
191
|
+
undefined,
|
|
192
|
+
domain,
|
|
193
|
+
tx
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// When: 첫 번째 레벨 approval 생성 및 승인
|
|
197
|
+
const firstApproval = await activityApprovalFactory.createWithRole(
|
|
198
|
+
{ order: 1, judgment: ActivityApprovalJudgment.Pending },
|
|
199
|
+
undefined,
|
|
200
|
+
firstApproverRole,
|
|
201
|
+
tx
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
const escalated = await simulateEscalation(
|
|
205
|
+
firstApproval,
|
|
206
|
+
firstApprover,
|
|
207
|
+
'Escalating to next level',
|
|
208
|
+
{ tx, domain, user: firstApprover }
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
// Then: 에스컬레이션됨
|
|
212
|
+
expect(escalated.judgment).toBe(ActivityApprovalJudgment.Escalated)
|
|
213
|
+
|
|
214
|
+
// When: 두 번째 레벨 approval 생성 및 승인
|
|
215
|
+
const secondApproval = await activityApprovalFactory.createWithRole(
|
|
216
|
+
{ order: 2, judgment: ActivityApprovalJudgment.Pending },
|
|
217
|
+
undefined,
|
|
218
|
+
secondApproverRole,
|
|
219
|
+
tx
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
const approved = await simulateApproval(
|
|
223
|
+
secondApproval,
|
|
224
|
+
secondApprover,
|
|
225
|
+
'Final approval',
|
|
226
|
+
{ tx, domain, user: secondApprover }
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
// Then: 최종 승인
|
|
230
|
+
expect(approved.judgment).toBe(ActivityApprovalJudgment.Approved)
|
|
231
|
+
expect(approved.approver?.id).toBe(secondApprover.id)
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it('Role 기반 승인에서 어느 레벨에서든 반려할 수 있어야 한다', async () => {
|
|
236
|
+
await withTestTransaction(async (context) => {
|
|
237
|
+
const { tx } = context.state
|
|
238
|
+
const domain = await domainFactory.create({}, tx)
|
|
239
|
+
const approverRole = await roleFactory.create({ name: 'Approver', domain }, tx)
|
|
240
|
+
const approver = await userFactory.createWithRole({}, approverRole, tx)
|
|
241
|
+
|
|
242
|
+
// Given: Role 기반 approval
|
|
243
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
244
|
+
{ order: 1, judgment: ActivityApprovalJudgment.Pending },
|
|
245
|
+
undefined,
|
|
246
|
+
approverRole,
|
|
247
|
+
tx
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
// When: 반려
|
|
251
|
+
const rejected = await simulateRejection(
|
|
252
|
+
approval,
|
|
253
|
+
approver,
|
|
254
|
+
'Needs revision',
|
|
255
|
+
{ tx, domain, user: approver }
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
// Then
|
|
259
|
+
expect(rejected.judgment).toBe(ActivityApprovalJudgment.Rejected)
|
|
260
|
+
expect(rejected.comment).toBe('Needs revision')
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
describe('OOC Resolve에서 Role 기반 승인', () => {
|
|
266
|
+
it('OOC Resolve Activity에 outlierApprovalLine(Role 타입)이 적용되어야 한다', async () => {
|
|
267
|
+
await withTestTransaction(async (context) => {
|
|
268
|
+
const { tx } = context.state
|
|
269
|
+
const domain = await domainFactory.create({}, tx)
|
|
270
|
+
const approverRole = await roleFactory.create({ name: 'OOC Approver', domain }, tx)
|
|
271
|
+
|
|
272
|
+
// Given: OOC Resolve Activity with Role-based approval line
|
|
273
|
+
const resolveActivity = await activityFactory.createOocResolveActivity(domain, tx)
|
|
274
|
+
const outlierApprovalLine = [createRoleApprovalLineItem(approverRole)]
|
|
275
|
+
|
|
276
|
+
// When: Instance 생성
|
|
277
|
+
const instance = await activityInstanceFactory.createWithActivity(
|
|
278
|
+
{
|
|
279
|
+
state: ActivityInstanceStatus.Issued,
|
|
280
|
+
approvalLine: outlierApprovalLine
|
|
281
|
+
},
|
|
282
|
+
resolveActivity,
|
|
283
|
+
domain,
|
|
284
|
+
tx
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
// Then
|
|
288
|
+
expect(instance.approvalLine?.length).toBe(1)
|
|
289
|
+
expect(instance.approvalLine?.[0].type).toBe('Role')
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('OOC Resolve 승인 시 Role을 가진 사용자만 승인 가능해야 한다', async () => {
|
|
294
|
+
await withTestTransaction(async (context) => {
|
|
295
|
+
const { tx } = context.state
|
|
296
|
+
const domain = await domainFactory.create({}, tx)
|
|
297
|
+
const approverRole = await roleFactory.create({ name: 'OOC Approver', domain }, tx)
|
|
298
|
+
const userWithRole = await userFactory.createWithRole({}, approverRole, tx)
|
|
299
|
+
|
|
300
|
+
// Given: Role 기반 approval
|
|
301
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
302
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
303
|
+
undefined,
|
|
304
|
+
approverRole,
|
|
305
|
+
tx
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
// When: Role을 가진 사용자가 승인
|
|
309
|
+
const approved = await simulateApproval(
|
|
310
|
+
approval,
|
|
311
|
+
userWithRole,
|
|
312
|
+
'OOC Corrective action approved',
|
|
313
|
+
{ tx, domain, user: userWithRole }
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
// Then
|
|
317
|
+
expect(approved.judgment).toBe(ActivityApprovalJudgment.Approved)
|
|
318
|
+
expect(approved.terminatedAt).toBeDefined()
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
describe('ActivityApprovalJudgment Enum', () => {
|
|
324
|
+
it('Pending은 빈 문자열이어야 한다', () => {
|
|
325
|
+
expect(ActivityApprovalJudgment.Pending).toBe('')
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it('모든 judgment 값이 정의되어야 한다', () => {
|
|
329
|
+
expect(ActivityApprovalJudgment.Rejected).toBe('rejected')
|
|
330
|
+
expect(ActivityApprovalJudgment.Escalated).toBe('escalated')
|
|
331
|
+
expect(ActivityApprovalJudgment.Delegated).toBe('delegated')
|
|
332
|
+
expect(ActivityApprovalJudgment.Approved).toBe('approved')
|
|
333
|
+
expect(ActivityApprovalJudgment.Aborted).toBe('aborted')
|
|
334
|
+
})
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
describe('Edge Cases', () => {
|
|
338
|
+
it('Role에 사용자가 없어도 approval이 생성되어야 한다', async () => {
|
|
339
|
+
await withTestTransaction(async (context) => {
|
|
340
|
+
const { tx } = context.state
|
|
341
|
+
const domain = await domainFactory.create({}, tx)
|
|
342
|
+
|
|
343
|
+
// Given: 사용자가 없는 Role
|
|
344
|
+
const emptyRole = await roleFactory.create({ name: 'Empty Role', domain }, tx)
|
|
345
|
+
|
|
346
|
+
// When: Role 기반 approval 생성
|
|
347
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
348
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
349
|
+
undefined,
|
|
350
|
+
emptyRole,
|
|
351
|
+
tx
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
// Then: approval은 생성됨 (나중에 Role에 사용자가 추가될 수 있음)
|
|
355
|
+
expect(approval).toBeDefined()
|
|
356
|
+
expect(approval.approverRole?.id).toBe(emptyRole.id)
|
|
357
|
+
})
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
it('승인 완료 시 terminatedAt이 설정되어야 한다', async () => {
|
|
361
|
+
await withTestTransaction(async (context) => {
|
|
362
|
+
const { tx } = context.state
|
|
363
|
+
const domain = await domainFactory.create({}, tx)
|
|
364
|
+
const approverRole = await roleFactory.create({ name: 'Approver', domain }, tx)
|
|
365
|
+
const approver = await userFactory.createWithRole({}, approverRole, tx)
|
|
366
|
+
|
|
367
|
+
// Given
|
|
368
|
+
const approval = await activityApprovalFactory.createWithRole(
|
|
369
|
+
{ judgment: ActivityApprovalJudgment.Pending },
|
|
370
|
+
undefined,
|
|
371
|
+
approverRole,
|
|
372
|
+
tx
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
// When
|
|
376
|
+
const approved = await simulateApproval(
|
|
377
|
+
approval,
|
|
378
|
+
approver,
|
|
379
|
+
undefined,
|
|
380
|
+
{ tx, domain, user: approver }
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
// Then
|
|
384
|
+
expect(approved.terminatedAt).toBeDefined()
|
|
385
|
+
expect(approved.terminatedAt).toBeInstanceOf(Date)
|
|
386
|
+
})
|
|
387
|
+
})
|
|
388
|
+
})
|
|
389
|
+
})
|