/ clis / zhihu / like.test.js
like.test.js
 1  import { describe, expect, it, vi } from 'vitest';
 2  import { getRegistry } from '@jackwener/opencli/registry';
 3  import './like.js';
 4  describe('zhihu like', () => {
 5      it('rejects article pages where the like control is not uniquely anchored', async () => {
 6          const cmd = getRegistry().get('zhihu/like');
 7          expect(cmd?.func).toBeTypeOf('function');
 8          const page = {
 9              goto: vi.fn().mockResolvedValue(undefined),
10              evaluate: vi.fn().mockResolvedValue({ state: 'ambiguous_article_like' }),
11          };
12          await expect(cmd.func(page, { target: 'article:9', execute: true })).rejects.toMatchObject({
13              code: 'ACTION_NOT_AVAILABLE',
14          });
15      });
16      it('returns already_applied for an already-liked article target', async () => {
17          const cmd = getRegistry().get('zhihu/like');
18          const page = {
19              goto: vi.fn().mockResolvedValue(undefined),
20              evaluate: vi.fn().mockResolvedValue({ state: 'already_liked' }),
21          };
22          await expect(cmd.func(page, { target: 'article:9', execute: true })).resolves.toEqual([
23              expect.objectContaining({ outcome: 'already_applied', target_type: 'article', target: 'article:9' }),
24          ]);
25      });
26      it('anchors to the requested answer block before clicking like', async () => {
27          const cmd = getRegistry().get('zhihu/like');
28          const page = {
29              goto: vi.fn().mockResolvedValue(undefined),
30              evaluate: vi.fn().mockResolvedValue({ state: 'liked' }),
31          };
32          await expect(cmd.func(page, { target: 'answer:123:456', execute: true })).resolves.toEqual([
33              expect.objectContaining({ outcome: 'applied', target_type: 'answer', target: 'answer:123:456' }),
34          ]);
35          expect(page.goto).toHaveBeenCalledWith('https://www.zhihu.com/question/123/answer/456');
36          expect(page.evaluate).toHaveBeenCalledTimes(1);
37          expect(page.evaluate.mock.calls[0][0]).toContain('targetQuestionId');
38          expect(page.evaluate.mock.calls[0][0]).toContain('"123"');
39          expect(page.evaluate.mock.calls[0][0]).toContain('"456"');
40          expect(page.evaluate.mock.calls[0][0]).toContain("node.getAttribute('data-answerid')");
41          expect(page.evaluate.mock.calls[0][0]).toContain("node.getAttribute('data-zop-question-answer')");
42      });
43      it('rejects answer targets when the answer-level like control is not unique', async () => {
44          const cmd = getRegistry().get('zhihu/like');
45          const page = {
46              goto: vi.fn().mockResolvedValue(undefined),
47              evaluate: vi.fn().mockResolvedValue({ state: 'ambiguous_answer_like' }),
48          };
49          await expect(cmd.func(page, { target: 'answer:123:456', execute: true })).rejects.toMatchObject({
50              code: 'ACTION_NOT_AVAILABLE',
51          });
52      });
53      it('maps missing answer blocks to TARGET_NOT_FOUND', async () => {
54          const cmd = getRegistry().get('zhihu/like');
55          const page = {
56              goto: vi.fn().mockResolvedValue(undefined),
57              evaluate: vi.fn().mockResolvedValue({ state: 'wrong_answer' }),
58          };
59          await expect(cmd.func(page, { target: 'answer:123:456', execute: true })).rejects.toMatchObject({
60              code: 'TARGET_NOT_FOUND',
61          });
62          expect(page.evaluate.mock.calls[0][0]).toContain("if (!block) return { state: 'wrong_answer' }");
63      });
64  });