Skip to content

Commit d74f91a

Browse files
[fix] mark as seen and update tests (#174)
Fixes an error introduced in #166. Updates mock client with the new added methods, updates test case to include opening thread with a simple "Enter" user action. In the future the same pattern can be expanded to test slightly more complex user interactions.
1 parent ae2f8f1 commit d74f91a

File tree

4 files changed

+67
-16
lines changed

4 files changed

+67
-16
lines changed

instagram-ts/source/client.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -461,23 +461,26 @@ export class InstagramClient extends EventEmitter {
461461
}
462462
}
463463

464+
public async markThreadAsSeen(
465+
threadId: string,
466+
itemId: string,
467+
): Promise<void> {
468+
try {
469+
await this.ig.entity.directThread(threadId).markItemSeen(itemId);
470+
} catch (error) {
471+
this.logger.error('Failed to mark item as seen', error);
472+
throw error;
473+
}
474+
}
475+
464476
public async markItemAsSeen(threadId: string, itemId: string): Promise<void> {
465477
if (this.realtimeStatus === 'connected' && this.realtime?.direct) {
466478
try {
467479
await this.realtime.direct.markAsSeen({threadId, itemId});
468-
return;
469480
} catch {
470481
this.logger.warn('MQTT mark as seen failed, falling back to API.');
471482
}
472483
}
473-
474-
// Fallback to API if MQTT not available, failed, or not ready
475-
try {
476-
await this.ig.entity.directThread(threadId).markItemSeen(itemId);
477-
} catch (error) {
478-
this.logger.error('Failed to mark item as seen', error);
479-
throw error;
480-
}
481484
}
482485

483486
public async sendMessage(threadId: string, text: string): Promise<void> {

instagram-ts/source/mocks/mock-client.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,25 @@ class MockClient extends EventEmitter {
244244
console.log(`Mock: Unsent message ${messageId} from thread ${threadId}`);
245245
}
246246

247+
async markThreadAsSeen(threadId: string): Promise<void> {
248+
// Simulate marking a thread as seen
249+
await new Promise(resolve => {
250+
setTimeout(resolve, 50);
251+
});
252+
console.log(`Mock: Marked thread ${threadId} as seen`);
253+
}
254+
255+
async markItemAsSeen(threadId: string, itemId: string): Promise<void> {
256+
// Simulate marking a message as seen
257+
await new Promise(resolve => {
258+
setTimeout(resolve, 50);
259+
});
260+
console.log(`Mock: Marked item ${itemId} as seen in thread ${threadId}`);
261+
}
262+
247263
async getCurrentUser(): Promise<User | undefined> {
248264
return {
249-
pk: 'current_user',
265+
pk: 'current_user_id',
250266
username: 'mock_user',
251267
fullName: 'Mock User',
252268
profilePicUrl: 'https://via.placeholder.com/150',

instagram-ts/source/ui/views/chat-view.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ export default function ChatView() {
365365
const lastMessage = messages.at(-1);
366366

367367
if (lastMessage?.id) {
368-
await client.markItemAsSeen(thread.id, lastMessage.id);
368+
await client.markThreadAsSeen(thread.id, lastMessage.id);
369369
}
370370
} catch (error) {
371371
setChatState(previous => ({
@@ -510,11 +510,11 @@ export default function ChatView() {
510510
<Text>Loading messages...</Text>
511511
</Box>
512512
)}
513-
chatState.recipientAlreadyRead && (
514-
<Box>
515-
<Text dimColor>Seen just now</Text>
516-
</Box>
517-
)
513+
{chatState.recipientAlreadyRead && (
514+
<Box>
515+
<Text dimColor>Seen just now</Text>
516+
</Box>
517+
)}
518518
<Box flexShrink={0} flexDirection="column">
519519
{systemMessage && (
520520
<Box marginTop={1}>

instagram-ts/test.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import test, {type ExecutionContext} from 'ava';
33
import {render} from 'ink-testing-library';
44
import Index from './source/commands/index.js';
55
import {AppMock} from './source/app.mock.js';
6+
import {mockThreads, mockMessages} from './source/mocks/mock-data.js';
7+
8+
const delay = async (ms: number): Promise<void> => {
9+
return new Promise(resolve => {
10+
setTimeout(resolve, ms);
11+
});
12+
};
613

714
test('sanity check', (t: ExecutionContext) => {
815
const {lastFrame} = render(<Index />);
@@ -21,3 +28,28 @@ test('renders feed view', (t: ExecutionContext) => {
2128

2229
t.not(lastFrame(), undefined);
2330
});
31+
32+
test('chat view displays messages when thread is selected', async (t: ExecutionContext) => {
33+
const {lastFrame, stdin} = render(<AppMock view="chat" />);
34+
35+
await delay(500);
36+
37+
// Verify threads are displayed
38+
let output = lastFrame();
39+
t.truthy(output, 'Frame should render threads');
40+
t.true(
41+
output!.includes(mockThreads[0]!.title),
42+
'Thread should be visible before selection',
43+
);
44+
45+
// Select first thread by pressing Enter
46+
stdin.write('\r');
47+
48+
await delay(500);
49+
50+
output = lastFrame();
51+
t.truthy(output, 'Frame should render after thread selection');
52+
const firstMessage = mockMessages[0]!;
53+
const messageText = firstMessage.itemType === 'text' ? firstMessage.text : '';
54+
t.true(output!.includes(messageText), 'First message should be visible');
55+
});

0 commit comments

Comments
 (0)