( parentTs: string, expectedEventType: string, )
| 72 | const wait = (ms: number) => new Promise((r) => setTimeout(r, ms)); |
| 73 | |
| 74 | async function waitForPicker( |
| 75 | parentTs: string, |
| 76 | expectedEventType: string, |
| 77 | ): Promise<{ |
| 78 | ts: string; |
| 79 | buttons: Array<{ action_id: string; value: string; text: string }>; |
| 80 | metadata: { event_type?: string; event_payload?: Record<string, unknown> }; |
| 81 | }> { |
| 82 | const t0 = Date.now(); |
| 83 | while (Date.now() - t0 < 30_000) { |
| 84 | await wait(1500); |
| 85 | const r = await threadReplies(TEST_CHANNEL, parentTs, true); |
| 86 | const picker = r.find((m) => { |
| 87 | const md = (m as { metadata?: { event_type?: string } }).metadata; |
| 88 | return m.user === BOT_USER_ID && md?.event_type === expectedEventType; |
| 89 | }) as |
| 90 | | { |
| 91 | ts?: string; |
| 92 | blocks?: Array<Record<string, unknown>>; |
| 93 | metadata?: { |
| 94 | event_type?: string; |
| 95 | event_payload?: Record<string, unknown>; |
| 96 | }; |
| 97 | } |
| 98 | | undefined; |
| 99 | if (!picker) continue; |
| 100 | const buttons: Array<{ action_id: string; value: string; text: string }> = |
| 101 | []; |
| 102 | // confirm_write wraps its blocks in a colored attachment, so the action |
| 103 | // buttons live under attachments[].blocks; older pickers use top-level |
| 104 | // blocks. Scan both. |
| 105 | const pickerAtt = ( |
| 106 | picker as { |
| 107 | attachments?: Array<{ blocks?: Array<Record<string, unknown>> }>; |
| 108 | } |
| 109 | ).attachments; |
| 110 | const allBlocks = [ |
| 111 | ...(picker.blocks ?? []), |
| 112 | ...(pickerAtt ?? []).flatMap((a) => a.blocks ?? []), |
| 113 | ]; |
| 114 | for (const b of allBlocks) { |
| 115 | if ( |
| 116 | b.type === "actions" && |
| 117 | Array.isArray((b as { elements?: unknown[] }).elements) |
| 118 | ) { |
| 119 | for (const el of ( |
| 120 | b as { |
| 121 | elements: Array<{ |
| 122 | type?: string; |
| 123 | action_id?: string; |
| 124 | value?: string; |
| 125 | text?: { text?: string }; |
| 126 | }>; |
| 127 | } |
| 128 | ).elements) { |
| 129 | if (el.type === "button" && el.action_id && el.value) { |
| 130 | buttons.push({ |
| 131 | action_id: el.action_id, |
no test coverage detected