comments.test.js
1 import { beforeEach, describe, expect, it, vi } from 'vitest'; 2 const { mockApiGet } = vi.hoisted(() => ({ 3 mockApiGet: vi.fn(), 4 })); 5 vi.mock('./utils.js', async (importOriginal) => ({ 6 ...(await importOriginal()), 7 apiGet: mockApiGet, 8 })); 9 import { getRegistry } from '@jackwener/opencli/registry'; 10 import './comments.js'; 11 describe('bilibili comments', () => { 12 const command = getRegistry().get('bilibili/comments'); 13 beforeEach(() => { 14 mockApiGet.mockReset(); 15 }); 16 it('resolves bvid to aid and fetches replies', async () => { 17 mockApiGet 18 .mockResolvedValueOnce({ data: { aid: 12345 } }) // view endpoint 19 .mockResolvedValueOnce({ 20 data: { 21 replies: [ 22 { 23 member: { uname: 'Alice' }, 24 content: { message: 'Great video!' }, 25 like: 42, 26 rcount: 3, 27 ctime: 1700000000, 28 }, 29 ], 30 }, 31 }); 32 const result = await command.func({}, { bvid: 'BV1WtAGzYEBm', limit: 5 }); 33 expect(mockApiGet).toHaveBeenNthCalledWith(1, {}, '/x/web-interface/view', { params: { bvid: 'BV1WtAGzYEBm' } }); 34 expect(mockApiGet).toHaveBeenNthCalledWith(2, {}, '/x/v2/reply/main', { 35 params: { oid: 12345, type: 1, mode: 3, ps: 5 }, 36 signed: true, 37 }); 38 expect(result).toEqual([ 39 { 40 rank: 1, 41 author: 'Alice', 42 text: 'Great video!', 43 likes: 42, 44 replies: 3, 45 time: new Date(1700000000 * 1000).toISOString().slice(0, 16).replace('T', ' '), 46 }, 47 ]); 48 }); 49 it('throws when aid cannot be resolved', async () => { 50 mockApiGet.mockResolvedValueOnce({ data: {} }); // no aid 51 await expect(command.func({}, { bvid: 'BVinvalid123', limit: 5 })).rejects.toThrow('Cannot resolve aid for bvid: BVinvalid123'); 52 }); 53 it('returns empty array when replies is missing', async () => { 54 mockApiGet 55 .mockResolvedValueOnce({ data: { aid: 99 } }) 56 .mockResolvedValueOnce({ data: {} }); // no replies key 57 const result = await command.func({}, { bvid: 'BV1xxx', limit: 5 }); 58 expect(result).toEqual([]); 59 }); 60 it('caps limit at 50', async () => { 61 mockApiGet 62 .mockResolvedValueOnce({ data: { aid: 1 } }) 63 .mockResolvedValueOnce({ data: { replies: [] } }); 64 await command.func({}, { bvid: 'BV1xxx', limit: 999 }); 65 expect(mockApiGet).toHaveBeenNthCalledWith(2, {}, '/x/v2/reply/main', { 66 params: { oid: 1, type: 1, mode: 3, ps: 50 }, 67 signed: true, 68 }); 69 }); 70 it('collapses newlines in comment text', async () => { 71 mockApiGet 72 .mockResolvedValueOnce({ data: { aid: 1 } }) 73 .mockResolvedValueOnce({ 74 data: { 75 replies: [ 76 { member: { uname: 'Bob' }, content: { message: 'line1\nline2\nline3' }, like: 0, rcount: 0, ctime: 0 }, 77 ], 78 }, 79 }); 80 const result = (await command.func({}, { bvid: 'BV1xxx', limit: 5 })); 81 expect(result[0].text).toBe('line1 line2 line3'); 82 }); 83 });