fa93173b1f
Replies (messages with parentInteractionId) now open in a right-hand ThreadPane instead of inline quoting: - extracted a shared Composer (draft + @mention autocomplete + attach) and MessageItem (bubble + mentions + attachment + reactions + reply affordance) - Thread shows top-level messages only; a message with replies gets a '💬 N replies' link, and hovering shows 💬 'Reply in thread' - ThreadPane renders the root + its replies + a composer that posts back with parentInteractionId; Messenger becomes 3-column (list | thread | pane), pane closes on conversation switch - no contract/adapter/backend change (parentInteractionId was already wired) - thread-pane render test (open → reply → parent shows the count); 58 green Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
37 lines
1.7 KiB
TypeScript
37 lines
1.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
import { MessagingProvider } from '../provider';
|
|
import { Messenger } from './messenger';
|
|
import { MockAdapter } from '../adapters/mock';
|
|
|
|
function mount() {
|
|
return render(
|
|
<MessagingProvider adapter={new MockAdapter()}>
|
|
<Messenger />
|
|
</MessagingProvider>,
|
|
);
|
|
}
|
|
|
|
describe('Slack-style thread pane', () => {
|
|
it('opens a thread on 💬, posts a reply into it, and shows the reply count on the parent', async () => {
|
|
mount();
|
|
// Wait for the auto-selected thread's message to render WITH its actions (not just the sidebar
|
|
// preview), then open the thread pane via the message's reply affordance (💬).
|
|
const replyButtons = await screen.findAllByTitle('Reply in thread');
|
|
fireEvent.click(replyButtons[0]!);
|
|
expect(await screen.findByText('Thread')).toBeTruthy(); // pane header
|
|
|
|
// The pane's composer (placeholder "Reply…") — send a threaded reply.
|
|
const replyInput = screen.getByPlaceholderText('Reply…') as HTMLInputElement;
|
|
fireEvent.change(replyInput, { target: { value: 'on it' } });
|
|
// The pane has its own Send; grab the last one (pane is rendered after the main composer).
|
|
const sends = screen.getAllByText('Send');
|
|
fireEvent.click(sends[sends.length - 1]!);
|
|
|
|
// The reply shows in the pane (replies are hidden from the main thread, so this is unique)...
|
|
await waitFor(() => expect(screen.getByText('on it')).toBeTruthy());
|
|
// ...and the parent now advertises the reply count as a thread-link button in the main thread.
|
|
await waitFor(() => expect(screen.getByRole('button', { name: /1 reply/ })).toBeTruthy());
|
|
});
|
|
});
|