@@ -75,6 +75,49 @@ it('director change replaces memberships on open projects', async () => {
75
75
} ) ;
76
76
return project ;
77
77
} ) ( ) ,
78
+ alreadyHasNewDirectorActive : await ( async ( ) => {
79
+ const project = await createProject ( app ) ;
80
+ await createProjectMember ( app , {
81
+ projectId : project . id ,
82
+ userId : directors . old . id ,
83
+ roles : [ Role . RegionalDirector ] ,
84
+ } ) ;
85
+ await createProjectMember ( app , {
86
+ projectId : project . id ,
87
+ userId : directors . new . id ,
88
+ roles : [ Role . RegionalDirector ] ,
89
+ } ) ;
90
+ return project ;
91
+ } ) ( ) ,
92
+ alreadyHasNewDirectorInactive : await ( async ( ) => {
93
+ const project = await createProject ( app ) ;
94
+ await createProjectMember ( app , {
95
+ projectId : project . id ,
96
+ userId : directors . old . id ,
97
+ roles : [ Role . RegionalDirector ] ,
98
+ } ) ;
99
+ await createProjectMember ( app , {
100
+ projectId : project . id ,
101
+ userId : directors . new . id ,
102
+ roles : [ Role . RegionalDirector ] ,
103
+ inactiveAt : DateTime . now ( ) . plus ( { minute : 1 } ) . toISO ( ) ,
104
+ } ) ;
105
+ return project ;
106
+ } ) ( ) ,
107
+ alreadyHasNewDirectorWithoutRole : await ( async ( ) => {
108
+ const project = await createProject ( app ) ;
109
+ await createProjectMember ( app , {
110
+ projectId : project . id ,
111
+ userId : directors . old . id ,
112
+ roles : [ Role . RegionalDirector ] ,
113
+ } ) ;
114
+ await createProjectMember ( app , {
115
+ projectId : project . id ,
116
+ userId : directors . new . id ,
117
+ roles : [ Role . ProjectManager ] ,
118
+ } ) ;
119
+ return project ;
120
+ } ) ( ) ,
78
121
closed : await ( async ( ) => {
79
122
const project = await createProject ( app , {
80
123
mouStart : '2025-06-05' ,
@@ -107,37 +150,82 @@ it('director change replaces memberships on open projects', async () => {
107
150
app ,
108
151
projects . alreadyHasRoleFilled . id ,
109
152
) ,
153
+ alreadyHasNewDirectorActive : await fetchMembers (
154
+ app ,
155
+ projects . alreadyHasNewDirectorActive . id ,
156
+ ) ,
157
+ alreadyHasNewDirectorInactive : await fetchMembers (
158
+ app ,
159
+ projects . alreadyHasNewDirectorInactive . id ,
160
+ ) ,
161
+ alreadyHasNewDirectorWithoutRole : await fetchMembers (
162
+ app ,
163
+ projects . alreadyHasNewDirectorWithoutRole . id ,
164
+ ) ,
110
165
closed : await fetchMembers ( app , projects . closed . id ) ,
111
166
} ;
167
+
112
168
return {
113
- get : ( project : keyof typeof results , key : keyof typeof directors ) =>
114
- results [ project ] . find (
169
+ get : ( project : keyof typeof results , key : keyof typeof directors ) => {
170
+ const member = results [ project ] . find (
115
171
( member ) => member . user . value ! . id === directors [ key ] . id ,
116
- ) ?. active ,
172
+ ) ;
173
+ return member
174
+ ? {
175
+ active : member . active ,
176
+ roles : member . roles . value ,
177
+ }
178
+ : undefined ;
179
+ } ,
117
180
} ;
118
181
} ;
119
182
// endregion
120
183
121
184
// region validate setup
122
185
const before = await getResults ( ) ;
123
186
124
- expect ( before . get ( 'needsSwapA' , 'old' ) ) . toBe ( true ) ;
187
+ const ActiveRD = { active : true , roles : [ 'RegionalDirector' ] } ;
188
+ const InactiveRD = { active : false , roles : [ 'RegionalDirector' ] } ;
189
+
190
+ expect ( before . get ( 'needsSwapA' , 'old' ) ) . toEqual ( ActiveRD ) ;
125
191
expect ( before . get ( 'needsSwapA' , 'new' ) ) . toBeUndefined ( ) ;
126
- expect ( before . get ( 'needsSwapB' , 'old' ) ) . toBe ( true ) ;
192
+ expect ( before . get ( 'needsSwapB' , 'old' ) ) . toEqual ( ActiveRD ) ;
127
193
expect ( before . get ( 'needsSwapB' , 'new' ) ) . toBeUndefined ( ) ;
128
194
129
195
expect ( before . get ( 'needsSwapA' , 'unrelated' ) ) . toBeUndefined ( ) ;
130
196
expect ( before . get ( 'needsSwapB' , 'unrelated' ) ) . toBeUndefined ( ) ;
131
197
expect ( before . get ( 'doesNotHaveMember' , 'old' ) ) . toBeUndefined ( ) ;
132
198
expect ( before . get ( 'doesNotHaveMember' , 'new' ) ) . toBeUndefined ( ) ;
133
199
expect ( before . get ( 'doesNotHaveMember' , 'unrelated' ) ) . toBeUndefined ( ) ;
134
- expect ( before . get ( 'hasMemberButInactive' , 'old' ) ) . toBe ( false ) ;
200
+ expect ( before . get ( 'hasMemberButInactive' , 'old' ) ) . toEqual ( InactiveRD ) ;
135
201
expect ( before . get ( 'hasMemberButInactive' , 'new' ) ) . toBeUndefined ( ) ;
136
202
expect ( before . get ( 'hasMemberButInactive' , 'unrelated' ) ) . toBeUndefined ( ) ;
137
203
expect ( before . get ( 'alreadyHasRoleFilled' , 'old' ) ) . toBeUndefined ( ) ;
138
204
expect ( before . get ( 'alreadyHasRoleFilled' , 'new' ) ) . toBeUndefined ( ) ;
139
- expect ( before . get ( 'alreadyHasRoleFilled' , 'unrelated' ) ) . toBe ( true ) ;
140
- expect ( before . get ( 'closed' , 'old' ) ) . toBe ( true ) ;
205
+ expect ( before . get ( 'alreadyHasRoleFilled' , 'unrelated' ) ) . toEqual ( ActiveRD ) ;
206
+ expect ( before . get ( 'alreadyHasNewDirectorActive' , 'old' ) ) . toEqual ( ActiveRD ) ;
207
+ expect ( before . get ( 'alreadyHasNewDirectorActive' , 'new' ) ) . toEqual ( ActiveRD ) ;
208
+ expect (
209
+ before . get ( 'alreadyHasNewDirectorActive' , 'unrelated' ) ,
210
+ ) . toBeUndefined ( ) ;
211
+ expect ( before . get ( 'alreadyHasNewDirectorInactive' , 'old' ) ) . toEqual ( ActiveRD ) ;
212
+ expect ( before . get ( 'alreadyHasNewDirectorInactive' , 'new' ) ) . toEqual (
213
+ InactiveRD ,
214
+ ) ;
215
+ expect (
216
+ before . get ( 'alreadyHasNewDirectorInactive' , 'unrelated' ) ,
217
+ ) . toBeUndefined ( ) ;
218
+ expect ( before . get ( 'alreadyHasNewDirectorWithoutRole' , 'old' ) ) . toEqual (
219
+ ActiveRD ,
220
+ ) ;
221
+ expect ( before . get ( 'alreadyHasNewDirectorWithoutRole' , 'new' ) ) . toEqual ( {
222
+ active : true ,
223
+ roles : [ Role . ProjectManager ] ,
224
+ } ) ;
225
+ expect (
226
+ before . get ( 'alreadyHasNewDirectorWithoutRole' , 'unrelated' ) ,
227
+ ) . toBeUndefined ( ) ;
228
+ expect ( before . get ( 'closed' , 'old' ) ) . toEqual ( ActiveRD ) ;
141
229
expect ( before . get ( 'closed' , 'new' ) ) . toBeUndefined ( ) ;
142
230
expect ( before . get ( 'closed' , 'unrelated' ) ) . toBeUndefined ( ) ;
143
231
// endregion
@@ -163,23 +251,41 @@ it('director change replaces memberships on open projects', async () => {
163
251
// region assertions
164
252
const after = await getResults ( ) ;
165
253
166
- expect ( after . get ( 'needsSwapA' , 'old' ) ) . toBe ( false ) ;
167
- expect ( after . get ( 'needsSwapA' , 'new' ) ) . toBe ( true ) ;
168
- expect ( after . get ( 'needsSwapB' , 'old' ) ) . toBe ( false ) ;
169
- expect ( after . get ( 'needsSwapB' , 'new' ) ) . toBe ( true ) ;
254
+ expect ( after . get ( 'needsSwapA' , 'old' ) ) . toEqual ( InactiveRD ) ;
255
+ expect ( after . get ( 'needsSwapA' , 'new' ) ) . toEqual ( ActiveRD ) ;
256
+ expect ( after . get ( 'needsSwapB' , 'old' ) ) . toEqual ( InactiveRD ) ;
257
+ expect ( after . get ( 'needsSwapB' , 'new' ) ) . toEqual ( ActiveRD ) ;
170
258
171
259
expect ( after . get ( 'needsSwapA' , 'unrelated' ) ) . toBeUndefined ( ) ;
172
260
expect ( after . get ( 'needsSwapB' , 'unrelated' ) ) . toBeUndefined ( ) ;
173
261
expect ( after . get ( 'doesNotHaveMember' , 'old' ) ) . toBeUndefined ( ) ;
174
262
expect ( after . get ( 'doesNotHaveMember' , 'new' ) ) . toBeUndefined ( ) ;
175
263
expect ( after . get ( 'doesNotHaveMember' , 'unrelated' ) ) . toBeUndefined ( ) ;
176
- expect ( after . get ( 'hasMemberButInactive' , 'old' ) ) . toBe ( false ) ;
264
+ expect ( after . get ( 'hasMemberButInactive' , 'old' ) ) . toEqual ( InactiveRD ) ;
177
265
expect ( after . get ( 'hasMemberButInactive' , 'new' ) ) . toBeUndefined ( ) ;
178
266
expect ( after . get ( 'hasMemberButInactive' , 'unrelated' ) ) . toBeUndefined ( ) ;
179
267
expect ( after . get ( 'alreadyHasRoleFilled' , 'old' ) ) . toBeUndefined ( ) ;
180
268
expect ( after . get ( 'alreadyHasRoleFilled' , 'new' ) ) . toBeUndefined ( ) ;
181
- expect ( after . get ( 'alreadyHasRoleFilled' , 'unrelated' ) ) . toBe ( true ) ;
182
- expect ( after . get ( 'closed' , 'old' ) ) . toBe ( true ) ;
269
+ expect ( after . get ( 'alreadyHasRoleFilled' , 'unrelated' ) ) . toEqual ( ActiveRD ) ;
270
+ expect ( after . get ( 'alreadyHasNewDirectorActive' , 'old' ) ) . toEqual ( InactiveRD ) ;
271
+ expect ( after . get ( 'alreadyHasNewDirectorActive' , 'new' ) ) . toEqual ( ActiveRD ) ;
272
+ expect ( after . get ( 'alreadyHasNewDirectorActive' , 'unrelated' ) ) . toBeUndefined ( ) ;
273
+ expect ( after . get ( 'alreadyHasNewDirectorInactive' , 'old' ) ) . toEqual ( InactiveRD ) ;
274
+ expect ( after . get ( 'alreadyHasNewDirectorInactive' , 'new' ) ) . toEqual ( ActiveRD ) ;
275
+ expect (
276
+ after . get ( 'alreadyHasNewDirectorInactive' , 'unrelated' ) ,
277
+ ) . toBeUndefined ( ) ;
278
+ expect ( after . get ( 'alreadyHasNewDirectorWithoutRole' , 'old' ) ) . toEqual (
279
+ InactiveRD ,
280
+ ) ;
281
+ expect ( after . get ( 'alreadyHasNewDirectorWithoutRole' , 'new' ) ) . toEqual ( {
282
+ active : true ,
283
+ roles : [ Role . ProjectManager , Role . RegionalDirector ] ,
284
+ } ) ;
285
+ expect (
286
+ after . get ( 'alreadyHasNewDirectorWithoutRole' , 'unrelated' ) ,
287
+ ) . toBeUndefined ( ) ;
288
+ expect ( after . get ( 'closed' , 'old' ) ) . toEqual ( ActiveRD ) ;
183
289
expect ( after . get ( 'closed' , 'new' ) ) . toBeUndefined ( ) ;
184
290
expect ( after . get ( 'closed' , 'unrelated' ) ) . toBeUndefined ( ) ;
185
291
// endregion
@@ -203,6 +309,9 @@ async function fetchMembers(app: TestApp, projectId: ID) {
203
309
inactiveAt {
204
310
value
205
311
}
312
+ roles {
313
+ value
314
+ }
206
315
}
207
316
}
208
317
}
@@ -211,5 +320,9 @@ async function fetchMembers(app: TestApp, projectId: ID) {
211
320
) ,
212
321
{ projectId } ,
213
322
) ;
214
- return res . project . team . items ;
323
+ const members = res . project . team . items ;
324
+ if ( members . length !== new Set ( members . map ( ( m ) => m . user . value ! . id ) ) . size ) {
325
+ throw new Error ( 'Duplicate members detected' ) ;
326
+ }
327
+ return members ;
215
328
}
0 commit comments