Files
wehub-resource-sync 9b395f5cc3
Build Chrome Extension / build (push) Waiting to run
Trigger Website Rebuild (Docs Updated) / dispatch (push) Waiting to run
E2E Headed Chrome / e2e-headed (macos-15) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (ubuntu-latest) (push) Has been cancelled
E2E Headed Chrome / e2e-headed (windows-latest) (push) Has been cancelled
CI / build (macos-latest) (push) Has been cancelled
CI / build (ubuntu-latest) (push) Has been cancelled
CI / build (windows-latest) (push) Has been cancelled
CI / unit-test (push) Has been cancelled
CI / bun-test (push) Has been cancelled
CI / adapter-test (push) Has been cancelled
CI / smoke-test (macos-latest) (push) Has been cancelled
CI / smoke-test (ubuntu-latest) (push) Has been cancelled
Security Audit / audit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:48 +08:00

153 lines
6.0 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { getRegistry } from '@jackwener/opencli/registry';
import { CommandExecutionError } from '@jackwener/opencli/errors';
import './inbox.js';
const { parseConversations, threadUrl } = await import('./inbox.js').then((m) => m.__test__);
const SELF = 'urn:li:fsd_profile:SELF';
// Minimal normalized messaging payload mirroring LinkedIn's real response shape:
// a flat `included` entity array where conversations reference participants and
// messages by URN.
function fixture() {
return {
included: [
{
$type: 'com.linkedin.messenger.MessagingParticipant',
entityUrn: 'urn:li:msg_messagingParticipant:SELF',
hostIdentityUrn: SELF,
participantType: { member: { firstName: { text: 'Hanzi' }, lastName: { text: 'Li' } } },
},
{
$type: 'com.linkedin.messenger.MessagingParticipant',
entityUrn: 'urn:li:msg_messagingParticipant:P1',
hostIdentityUrn: 'urn:li:fsd_profile:P1',
participantType: { member: { firstName: { text: 'Olga' }, lastName: { text: 'Magere' } } },
},
{
$type: 'com.linkedin.messenger.MessagingParticipant',
entityUrn: 'urn:li:msg_messagingParticipant:ORG',
hostIdentityUrn: 'urn:li:fsd_company:99',
participantType: { organization: { name: { text: 'American Express' } } },
},
{ $type: 'com.linkedin.messenger.Message', entityUrn: 'urn:li:msg_message:M1', body: { text: 'hey, are you around this week?' } },
{ $type: 'com.linkedin.messenger.Message', entityUrn: 'urn:li:msg_message:M2', body: { text: 'Sponsored offer' } },
{
$type: 'com.linkedin.messenger.Conversation',
entityUrn: 'urn:li:msg_conversation:C1',
backendUrn: 'urn:li:messagingThread:2-aaa==',
unreadCount: 2,
read: false,
categories: ['INBOX', 'PRIMARY_INBOX'],
lastActivityAt: 2000,
'*conversationParticipants': ['urn:li:msg_messagingParticipant:P1', 'urn:li:msg_messagingParticipant:SELF'],
messages: { '*elements': ['urn:li:msg_message:M1'] },
title: null,
},
{
$type: 'com.linkedin.messenger.Conversation',
entityUrn: 'urn:li:msg_conversation:C2',
backendUrn: 'urn:li:messagingThread:2-bbb==',
unreadCount: 0,
read: true,
categories: ['INBOX', 'PRIMARY_INBOX', 'INMAIL'],
lastActivityAt: 3000,
'*conversationParticipants': ['urn:li:msg_messagingParticipant:ORG', 'urn:li:msg_messagingParticipant:SELF'],
messages: { '*elements': ['urn:li:msg_message:M2'] },
title: null,
},
{
$type: 'com.linkedin.messenger.Conversation',
entityUrn: 'urn:li:msg_conversation:C3',
backendUrn: 'urn:li:messagingThread:2-ccc==',
unreadCount: 0,
read: true,
categories: ['INBOX', 'PRIMARY_INBOX'],
lastActivityAt: 1000,
'*conversationParticipants': ['urn:li:msg_messagingParticipant:P1', 'urn:li:msg_messagingParticipant:SELF'],
messages: { '*elements': [] },
title: 'Cohort 2 group',
},
],
};
}
describe('linkedin inbox adapter', () => {
const command = getRegistry().get('linkedin/inbox');
it('registers the command with the expected shape', () => {
expect(command).toBeDefined();
expect(command.site).toBe('linkedin');
expect(command.name).toBe('inbox');
expect(command.domain).toBe('www.linkedin.com');
expect(command.strategy).toBe('cookie');
expect(command.browser).toBe(true);
expect(typeof command.func).toBe('function');
});
it('exposes channel-safe structured columns', () => {
expect(command.columns).toEqual(
expect.arrayContaining([
'thread_url',
'thread_id',
'person_name',
'last_message_preview',
'unread',
'counterparty_type',
'category',
'timestamp',
]),
);
});
it('builds a thread URL from a thread id', () => {
expect(threadUrl('2-aaa==')).toBe('https://www.linkedin.com/messaging/thread/2-aaa==/');
expect(threadUrl('')).toBe('');
});
it('parses conversations and sorts them by most recent activity', () => {
const rows = parseConversations(fixture(), SELF);
expect(rows).toHaveLength(3);
expect(rows.map((r) => r.thread_id)).toEqual(['2-bbb==', '2-aaa==', '2-ccc==']);
});
it('resolves the member counterparty, excludes the inbox owner, and reports unread state', () => {
const c1 = parseConversations(fixture(), SELF).find((r) => r.thread_id === '2-aaa==');
expect(c1.person_name).toBe('Olga Magere');
expect(c1.counterparty_type).toBe('member');
expect(c1.unread).toBe(true);
expect(c1.last_message_preview).toBe('hey, are you around this week?');
});
it('flags organization counterparties and read conversations', () => {
const c2 = parseConversations(fixture(), SELF).find((r) => r.thread_id === '2-bbb==');
expect(c2.person_name).toBe('American Express');
expect(c2.counterparty_type).toBe('organization');
expect(c2.unread).toBe(false);
expect(c2.category).toBe('INBOX,PRIMARY_INBOX,INMAIL');
});
it('uses the group title as the conversation name', () => {
const c3 = parseConversations(fixture(), SELF).find((r) => r.thread_id === '2-ccc==');
expect(c3.person_name).toBe('Cohort 2 group');
});
it('returns an empty array when a valid payload has no conversations', () => {
expect(parseConversations({ included: [] }, SELF)).toEqual([]);
});
it('fails typed when the normalized payload shape is malformed', () => {
expect(() => parseConversations({}, SELF)).toThrow(CommandExecutionError);
expect(() => parseConversations(null, SELF)).toThrow(CommandExecutionError);
const malformed = fixture();
malformed.included.push({
$type: 'com.linkedin.messenger.Conversation',
entityUrn: 'urn:li:msg_conversation:MALFORMED',
'*conversationParticipants': [],
messages: { '*elements': [] },
});
expect(() => parseConversations(malformed, SELF)).toThrow(CommandExecutionError);
});
});