@jackwener/opencli 1.7.3 → 1.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +81 -59
  2. package/README.zh-CN.md +93 -67
  3. package/cli-manifest.json +5015 -2975
  4. package/clis/antigravity/serve.js +71 -25
  5. package/clis/baidu-scholar/search.js +87 -0
  6. package/clis/baidu-scholar/search.test.js +23 -0
  7. package/clis/bilibili/favorite.js +18 -13
  8. package/clis/binance/depth.js +3 -4
  9. package/clis/boss/utils.js +2 -3
  10. package/clis/chatgpt-app/ax.js +6 -3
  11. package/clis/deepseek/ask.js +74 -0
  12. package/clis/deepseek/history.js +25 -0
  13. package/clis/deepseek/new.js +20 -0
  14. package/clis/deepseek/read.js +22 -0
  15. package/clis/deepseek/status.js +24 -0
  16. package/clis/deepseek/utils.js +208 -0
  17. package/clis/douban/search.js +1 -0
  18. package/clis/douban/search.test.js +11 -0
  19. package/clis/douban/subject.js +20 -93
  20. package/clis/douban/subject.test.js +11 -0
  21. package/clis/douban/utils.js +250 -8
  22. package/clis/douban/utils.test.js +179 -4
  23. package/clis/doubao/utils.js +319 -130
  24. package/clis/doubao/utils.test.js +241 -2
  25. package/clis/eastmoney/_secid.js +78 -0
  26. package/clis/eastmoney/announcement.js +52 -0
  27. package/clis/eastmoney/convertible.js +73 -0
  28. package/clis/eastmoney/etf.js +65 -0
  29. package/clis/eastmoney/holders.js +78 -0
  30. package/clis/eastmoney/hot-rank.js +50 -0
  31. package/clis/eastmoney/hot-rank.test.js +59 -0
  32. package/clis/eastmoney/index-board.js +96 -0
  33. package/clis/eastmoney/kline.js +87 -0
  34. package/clis/eastmoney/kuaixun.js +54 -0
  35. package/clis/eastmoney/longhu.js +67 -0
  36. package/clis/eastmoney/money-flow.js +78 -0
  37. package/clis/eastmoney/northbound.js +57 -0
  38. package/clis/eastmoney/quote.js +107 -0
  39. package/clis/eastmoney/rank.js +94 -0
  40. package/clis/eastmoney/sectors.js +76 -0
  41. package/clis/google-scholar/search.js +58 -0
  42. package/clis/google-scholar/search.test.js +23 -0
  43. package/clis/gov-law/commands.test.js +39 -0
  44. package/clis/gov-law/recent.js +22 -0
  45. package/clis/gov-law/search.js +41 -0
  46. package/clis/gov-law/shared.js +51 -0
  47. package/clis/gov-policy/commands.test.js +27 -0
  48. package/clis/gov-policy/recent.js +47 -0
  49. package/clis/gov-policy/search.js +48 -0
  50. package/clis/grok/image.test.ts +107 -0
  51. package/clis/grok/image.ts +356 -0
  52. package/clis/nowcoder/companies.js +23 -0
  53. package/clis/nowcoder/creators.js +27 -0
  54. package/clis/nowcoder/detail.js +61 -0
  55. package/clis/nowcoder/experience.js +36 -0
  56. package/clis/nowcoder/hot.js +24 -0
  57. package/clis/nowcoder/jobs.js +21 -0
  58. package/clis/nowcoder/notifications.js +29 -0
  59. package/clis/nowcoder/papers.js +40 -0
  60. package/clis/nowcoder/practice.js +37 -0
  61. package/clis/nowcoder/recommend.js +30 -0
  62. package/clis/nowcoder/referral.js +39 -0
  63. package/clis/nowcoder/salary.js +40 -0
  64. package/clis/nowcoder/search.js +49 -0
  65. package/clis/nowcoder/suggest.js +33 -0
  66. package/clis/nowcoder/topics.js +27 -0
  67. package/clis/nowcoder/trending.js +25 -0
  68. package/clis/tdx/hot-rank.js +47 -0
  69. package/clis/tdx/hot-rank.test.js +59 -0
  70. package/clis/ths/hot-rank.js +49 -0
  71. package/clis/ths/hot-rank.test.js +64 -0
  72. package/clis/twitter/bookmarks.js +2 -1
  73. package/clis/twitter/list-add.js +337 -0
  74. package/clis/twitter/list-add.test.js +15 -0
  75. package/clis/twitter/list-remove.js +297 -0
  76. package/clis/twitter/list-remove.test.js +14 -0
  77. package/clis/twitter/list-tweets.js +185 -0
  78. package/clis/twitter/list-tweets.test.js +108 -0
  79. package/clis/twitter/lists.js +134 -47
  80. package/clis/twitter/lists.test.js +105 -38
  81. package/clis/uiverse/_shared.js +368 -0
  82. package/clis/uiverse/_shared.test.js +55 -0
  83. package/clis/uiverse/code.js +47 -0
  84. package/clis/uiverse/preview.js +71 -0
  85. package/clis/wanfang/search.js +66 -0
  86. package/clis/wanfang/search.test.js +23 -0
  87. package/clis/web/read.js +1 -1
  88. package/clis/weixin/download.js +3 -2
  89. package/clis/xiaohongshu/comments.js +2 -2
  90. package/clis/xiaohongshu/comments.test.js +46 -25
  91. package/clis/xiaohongshu/download.js +6 -7
  92. package/clis/xiaohongshu/download.test.js +17 -5
  93. package/clis/xiaohongshu/note-helpers.js +46 -12
  94. package/clis/xiaohongshu/note.js +3 -5
  95. package/clis/xiaohongshu/note.test.js +52 -25
  96. package/clis/xiaohongshu/publish.js +149 -28
  97. package/clis/xiaohongshu/publish.test.js +319 -6
  98. package/clis/xiaoyuzhou/auth.js +303 -0
  99. package/clis/xiaoyuzhou/auth.test.js +124 -0
  100. package/clis/xiaoyuzhou/download.js +53 -0
  101. package/clis/xiaoyuzhou/download.test.js +135 -0
  102. package/clis/xiaoyuzhou/episode.js +9 -4
  103. package/clis/xiaoyuzhou/podcast-episodes.js +15 -11
  104. package/clis/xiaoyuzhou/podcast.js +9 -4
  105. package/clis/xiaoyuzhou/transcript.js +76 -0
  106. package/clis/xiaoyuzhou/transcript.test.js +195 -0
  107. package/clis/xiaoyuzhou/utils.js +0 -40
  108. package/clis/xiaoyuzhou/utils.test.js +15 -75
  109. package/clis/youtube/feed.js +120 -0
  110. package/clis/youtube/history.js +118 -0
  111. package/clis/youtube/like.js +62 -0
  112. package/clis/youtube/playlist.js +97 -0
  113. package/clis/youtube/subscribe.js +71 -0
  114. package/clis/youtube/subscriptions.js +57 -0
  115. package/clis/youtube/unlike.js +62 -0
  116. package/clis/youtube/unsubscribe.js +71 -0
  117. package/clis/youtube/utils.js +122 -0
  118. package/clis/youtube/utils.test.js +32 -1
  119. package/clis/youtube/watch-later.js +76 -0
  120. package/clis/zsxq/dynamics.js +1 -1
  121. package/clis/zsxq/utils.js +6 -3
  122. package/clis/zsxq/utils.test.js +31 -0
  123. package/dist/src/browser/base-page.d.ts +1 -1
  124. package/dist/src/browser/base-page.js +25 -5
  125. package/dist/src/browser/bridge.d.ts +3 -0
  126. package/dist/src/browser/bridge.js +52 -15
  127. package/dist/src/browser/cdp.js +2 -1
  128. package/dist/src/browser/daemon-client.d.ts +7 -4
  129. package/dist/src/browser/daemon-client.js +6 -1
  130. package/dist/src/browser/daemon-client.test.js +40 -1
  131. package/dist/src/browser/dom-snapshot.js +20 -3
  132. package/dist/src/browser/page.d.ts +18 -5
  133. package/dist/src/browser/page.js +96 -15
  134. package/dist/src/browser/page.test.js +158 -1
  135. package/dist/src/browser/target-errors.d.ts +23 -0
  136. package/dist/src/browser/target-errors.js +29 -0
  137. package/dist/src/browser/target-errors.test.js +61 -0
  138. package/dist/src/browser/target-resolver.d.ts +57 -0
  139. package/dist/src/browser/target-resolver.js +298 -0
  140. package/dist/src/browser/target-resolver.test.js +43 -0
  141. package/dist/src/browser.test.js +38 -1
  142. package/dist/src/cli.js +272 -187
  143. package/dist/src/cli.test.js +167 -90
  144. package/dist/src/commanderAdapter.d.ts +0 -1
  145. package/dist/src/commanderAdapter.js +2 -16
  146. package/dist/src/commanderAdapter.test.js +1 -1
  147. package/dist/src/commands/daemon.d.ts +4 -2
  148. package/dist/src/commands/daemon.js +22 -2
  149. package/dist/src/commands/daemon.test.js +65 -2
  150. package/dist/src/completion-shared.js +2 -5
  151. package/dist/src/daemon.js +10 -0
  152. package/dist/src/doctor.d.ts +1 -0
  153. package/dist/src/doctor.js +32 -9
  154. package/dist/src/doctor.test.js +28 -12
  155. package/dist/src/download/article-download.d.ts +1 -0
  156. package/dist/src/download/article-download.js +3 -0
  157. package/dist/src/download/article-download.test.js +39 -0
  158. package/dist/src/external-clis.yaml +2 -2
  159. package/dist/src/logger.d.ts +2 -2
  160. package/dist/src/logger.js +3 -3
  161. package/dist/src/output.js +1 -5
  162. package/dist/src/output.test.js +0 -21
  163. package/dist/src/pipeline/steps/transform.js +1 -1
  164. package/dist/src/pipeline/template.d.ts +1 -0
  165. package/dist/src/pipeline/template.js +11 -3
  166. package/dist/src/pipeline/template.test.js +3 -0
  167. package/dist/src/pipeline/transform.test.js +14 -0
  168. package/dist/src/plugin.d.ts +8 -9
  169. package/dist/src/plugin.js +24 -28
  170. package/dist/src/plugin.test.js +16 -60
  171. package/dist/src/registry.d.ts +1 -0
  172. package/dist/src/registry.js +3 -2
  173. package/dist/src/registry.test.js +22 -0
  174. package/dist/src/types.d.ts +15 -6
  175. package/package.json +1 -1
  176. package/clis/twitter/lists-parser.js +0 -77
  177. package/clis/twitter/lists.d.ts +0 -5
  178. package/dist/src/cascade.d.ts +0 -46
  179. package/dist/src/cascade.js +0 -135
  180. package/dist/src/explore.d.ts +0 -99
  181. package/dist/src/explore.js +0 -402
  182. package/dist/src/generate-verified.d.ts +0 -105
  183. package/dist/src/generate-verified.js +0 -696
  184. package/dist/src/generate-verified.test.js +0 -925
  185. package/dist/src/generate.d.ts +0 -46
  186. package/dist/src/generate.js +0 -117
  187. package/dist/src/record.d.ts +0 -96
  188. package/dist/src/record.js +0 -657
  189. package/dist/src/record.test.js +0 -293
  190. package/dist/src/skill-generate.d.ts +0 -30
  191. package/dist/src/skill-generate.js +0 -75
  192. package/dist/src/skill-generate.test.js +0 -173
  193. package/dist/src/synthesize.d.ts +0 -97
  194. package/dist/src/synthesize.js +0 -208
  195. /package/dist/src/{generate-verified.test.d.ts → browser/target-errors.test.d.ts} +0 -0
  196. /package/dist/src/{record.test.d.ts → browser/target-resolver.test.d.ts} +0 -0
  197. /package/dist/src/{skill-generate.test.d.ts → download/article-download.test.d.ts} +0 -0
@@ -1,6 +1,16 @@
1
1
  import vm from 'node:vm';
2
2
  import { describe, expect, it, vi } from 'vitest';
3
- import { getDoubanPhotoExtension, inferDoubanSearchResultType, loadDoubanSubjectPhotos, normalizeDoubanSubjectId, promoteDoubanPhotoUrl, resolveDoubanPhotoAssetUrl, searchDouban, } from './utils.js';
3
+ import {
4
+ getDoubanPhotoExtension,
5
+ inferDoubanSearchResultType,
6
+ loadDoubanSubjectDetail,
7
+ loadDoubanSubjectPhotos,
8
+ normalizeDoubanBookSubject,
9
+ normalizeDoubanSubjectId,
10
+ promoteDoubanPhotoUrl,
11
+ resolveDoubanPhotoAssetUrl,
12
+ searchDouban,
13
+ } from './utils.js';
4
14
 
5
15
  function createFakeNode(text = '', attrs = {}) {
6
16
  return {
@@ -10,18 +20,22 @@ function createFakeNode(text = '', attrs = {}) {
10
20
  },
11
21
  };
12
22
  }
23
+
13
24
  function createFakeSearchItem({ title, url, rating, abstract, cover }) {
14
25
  return {
15
26
  querySelector(selector) {
16
- if (selector === '.title-text, .title a, a[title]') {
27
+ if (selector === '.title-text, .title a, .title h3 a, h3 a, a[title]') {
17
28
  return createFakeNode(title, { href: url, title });
18
29
  }
19
30
  if (selector === '.rating_nums') {
20
31
  return createFakeNode(rating);
21
32
  }
22
- if (selector === '.meta.abstract, .meta, .abstract, p') {
33
+ if (selector === '.meta.abstract, .meta, .abstract, .subject-abstract, p') {
23
34
  return createFakeNode(abstract);
24
35
  }
36
+ if (selector === 'a[href*="/subject/"]') {
37
+ return createFakeNode('', { href: url });
38
+ }
25
39
  if (selector === 'img') {
26
40
  return createFakeNode('', { src: cover });
27
41
  }
@@ -29,11 +43,15 @@ function createFakeSearchItem({ title, url, rating, abstract, cover }) {
29
43
  },
30
44
  };
31
45
  }
46
+
32
47
  async function runSearchEvaluate(script, rawItems, domItems) {
33
48
  const document = {
34
49
  querySelector(selector) {
35
50
  if (selector === '.item-root .title-text, .item-root .title a') {
36
- return domItems[0]?.querySelector('.title-text, .title a, a[title]') || null;
51
+ return domItems[0]?.querySelector('.title-text, .title a, .title h3 a, h3 a, a[title]') || null;
52
+ }
53
+ if (selector === '.item-root .title-text, .item-root .title a, .result-list .result-item h3 a') {
54
+ return domItems[0]?.querySelector('.title-text, .title a, .title h3 a, h3 a, a[title]') || null;
37
55
  }
38
56
  return null;
39
57
  },
@@ -41,9 +59,13 @@ async function runSearchEvaluate(script, rawItems, domItems) {
41
59
  if (selector === '.item-root') {
42
60
  return domItems;
43
61
  }
62
+ if (selector === '.item-root, .result-list .result-item') {
63
+ return domItems;
64
+ }
44
65
  return [];
45
66
  },
46
67
  };
68
+
47
69
  return vm.runInNewContext(script, {
48
70
  Map,
49
71
  Promise,
@@ -59,20 +81,25 @@ async function runSearchEvaluate(script, rawItems, domItems) {
59
81
  },
60
82
  });
61
83
  }
84
+
62
85
  describe('douban utils', () => {
63
86
  it('normalizes valid subject ids', () => {
64
87
  expect(normalizeDoubanSubjectId(' 30382501 ')).toBe('30382501');
65
88
  });
89
+
66
90
  it('rejects invalid subject ids', () => {
67
91
  expect(() => normalizeDoubanSubjectId('tt30382501')).toThrow('Invalid Douban subject ID');
68
92
  });
93
+
69
94
  it('promotes thumbnail urls to large photo urls', () => {
70
95
  expect(promoteDoubanPhotoUrl('https://img1.doubanio.com/view/photo/m/public/p2913450214.webp')).toBe('https://img1.doubanio.com/view/photo/l/public/p2913450214.webp');
71
96
  expect(promoteDoubanPhotoUrl('https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2578474613.jpg')).toBe('https://img9.doubanio.com/view/photo/l/public/p2578474613.jpg');
72
97
  });
98
+
73
99
  it('rejects non-http photo urls during promotion', () => {
74
100
  expect(promoteDoubanPhotoUrl('data:image/gif;base64,abc')).toBe('');
75
101
  });
102
+
76
103
  it('prefers lazy-loaded photo urls over data placeholders', () => {
77
104
  expect(resolveDoubanPhotoAssetUrl([
78
105
  '',
@@ -80,9 +107,11 @@ describe('douban utils', () => {
80
107
  'data:image/gif;base64,abc',
81
108
  ], 'https://movie.douban.com/subject/30382501/photos?type=Rb')).toBe('https://img1.doubanio.com/view/photo/m/public/p2913450214.webp');
82
109
  });
110
+
83
111
  it('drops unsupported non-http photo urls when no real image url exists', () => {
84
112
  expect(resolveDoubanPhotoAssetUrl(['data:image/gif;base64,abc', 'blob:https://movie.douban.com/example'], 'https://movie.douban.com/subject/30382501/photos?type=Rb')).toBe('');
85
113
  });
114
+
86
115
  it('removes the default photo cap when scanning for an exact photo id', async () => {
87
116
  const evaluate = vi.fn()
88
117
  .mockResolvedValueOnce({ blocked: false, title: 'Some Movie', href: 'https://movie.douban.com/subject/30382501/photos?type=Rb' })
@@ -116,10 +145,12 @@ describe('douban utils', () => {
116
145
  expect(scanScript).toContain(`const limit = ${Number.MAX_SAFE_INTEGER};`);
117
146
  expect(scanScript).toContain('for (let pageIndex = 0; photos.length < limit; pageIndex += 1)');
118
147
  });
148
+
119
149
  it('keeps image extensions when download urls contain query params', () => {
120
150
  expect(getDoubanPhotoExtension('https://img1.doubanio.com/view/photo/l/public/p2913450214.webp?foo=1')).toBe('.webp');
121
151
  expect(getDoubanPhotoExtension('https://img1.doubanio.com/view/photo/l/public/p2913450214.jpeg')).toBe('.jpeg');
122
152
  });
153
+
123
154
  it('maps tv series results to tvshow in searchDouban output', async () => {
124
155
  const domItems = [
125
156
  createFakeSearchItem({
@@ -161,7 +192,149 @@ describe('douban utils', () => {
161
192
  { id: '36289423', type: 'movie', title: '射雕英雄传:侠之大者‎ (2025)' },
162
193
  ]);
163
194
  });
195
+
196
+ it('normalizes douban book subject raw data into structured fields', () => {
197
+ const normalized = normalizeDoubanBookSubject({
198
+ id: '2567698',
199
+ title: '小狗钱钱',
200
+ subtitle: '让孩子和家长共同成长的财商童话',
201
+ originalTitle: 'Ein Hund namens Money',
202
+ infoText: `
203
+ 作者: [德] 博多·舍费尔
204
+ 出版社: 南海出版公司
205
+ 副标题: 让孩子和家长共同成长的财商童话
206
+ 原作名: Ein Hund namens Money
207
+ 译者: 王钟欣 / 余茜
208
+ 出版年: 2014-1-1
209
+ 页数: 208
210
+ 定价: 26.00元
211
+ 装帧: 平装
212
+ 丛书: 新经典文库·爱心树童书
213
+ ISBN: 9787544270871
214
+ `,
215
+ rating: '8.9',
216
+ ratingCount: '12345',
217
+ summary: '理财启蒙故事',
218
+ cover: 'https://img9.doubanio.com/view/subject/l/public/s29618581.jpg',
219
+ url: 'https://book.douban.com/subject/2567698/',
220
+ });
221
+ expect(normalized).toMatchObject({
222
+ id: '2567698',
223
+ type: 'book',
224
+ title: '小狗钱钱',
225
+ subtitle: '让孩子和家长共同成长的财商童话',
226
+ originalTitle: 'Ein Hund namens Money',
227
+ authors: ['[德] 博多·舍费尔'],
228
+ translators: ['王钟欣', '余茜'],
229
+ publisher: '南海出版公司',
230
+ publishDate: '2014-1-1',
231
+ publishYear: '2014',
232
+ pageCount: 208,
233
+ binding: '平装',
234
+ price: '26.00元',
235
+ series: '新经典文库·爱心树童书',
236
+ isbn13: '9787544270871',
237
+ rating: 8.9,
238
+ ratingCount: 12345,
239
+ summary: '理财启蒙故事',
240
+ cover: 'https://img9.doubanio.com/view/subject/l/public/s29618581.jpg',
241
+ url: 'https://book.douban.com/subject/2567698/',
242
+ });
243
+ });
244
+
245
+ it('loads book subject details from book.douban.com when type=book', async () => {
246
+ const page = {
247
+ goto: vi.fn().mockResolvedValue(undefined),
248
+ wait: vi.fn().mockResolvedValue(undefined),
249
+ evaluate: vi.fn()
250
+ .mockResolvedValueOnce({ blocked: false, title: '小狗钱钱 (豆瓣)', href: 'https://book.douban.com/subject/2567698/' })
251
+ .mockResolvedValueOnce({
252
+ id: '2567698',
253
+ title: '小狗钱钱',
254
+ subtitle: '',
255
+ originalTitle: '',
256
+ infoText: `
257
+ 作者: [德] 博多·舍费尔
258
+ 出版社: 南海出版公司
259
+ 出版年: 2014-1-1
260
+ ISBN: 9787544270871
261
+ `,
262
+ rating: '8.9',
263
+ ratingCount: '12345',
264
+ summary: '理财启蒙故事',
265
+ cover: 'https://img9.doubanio.com/view/subject/l/public/s29618581.jpg',
266
+ url: 'https://book.douban.com/subject/2567698/',
267
+ }),
268
+ };
269
+ const detail = await loadDoubanSubjectDetail(page, '2567698', 'book');
270
+ expect(page.goto).toHaveBeenCalledWith('https://book.douban.com/subject/2567698/', {
271
+ waitUntil: 'load',
272
+ settleMs: 1500,
273
+ });
274
+ expect(page.wait).toHaveBeenCalledWith({ selector: 'h1 span, #info', timeout: 8 });
275
+ expect(detail).toMatchObject({
276
+ id: '2567698',
277
+ type: 'book',
278
+ title: '小狗钱钱',
279
+ authors: ['[德] 博多·舍费尔'],
280
+ publisher: '南海出版公司',
281
+ isbn13: '9787544270871',
282
+ rating: 8.9,
283
+ ratingCount: 12345,
284
+ url: 'https://book.douban.com/subject/2567698/',
285
+ });
286
+ });
287
+
288
+ it('retries transient detached navigation errors when loading douban search results', async () => {
289
+ const page = {
290
+ goto: vi.fn()
291
+ .mockRejectedValueOnce(new Error('Detached while handling command'))
292
+ .mockResolvedValueOnce(undefined),
293
+ wait: vi.fn().mockResolvedValue(undefined),
294
+ evaluate: vi.fn()
295
+ .mockResolvedValueOnce({
296
+ blocked: false,
297
+ title: '经济学思维 - 豆瓣搜索',
298
+ href: 'https://search.douban.com/book/subject_search?search_text=%E7%BB%8F%E6%B5%8E%E5%AD%A6%E6%80%9D%E7%BB%B4&cat=1001',
299
+ })
300
+ .mockResolvedValueOnce([
301
+ {
302
+ rank: 1,
303
+ id: '26895402',
304
+ type: 'book',
305
+ title: '经济学思维',
306
+ rating: 7.9,
307
+ abstract: '李子畅 / 中信出版社 / 2016-7',
308
+ url: 'https://book.douban.com/subject/26895402/',
309
+ cover: 'https://img1.doubanio.com/view/subject/m/public/s29000000.jpg',
310
+ },
311
+ ]),
312
+ };
313
+ const results = await searchDouban(page, 'book', '经济学思维', 3);
314
+ expect(page.goto).toHaveBeenNthCalledWith(1, 'https://search.douban.com/book/subject_search?search_text=%E7%BB%8F%E6%B5%8E%E5%AD%A6%E6%80%9D%E7%BB%B4&cat=1001', {
315
+ waitUntil: 'load',
316
+ settleMs: 1500,
317
+ });
318
+ expect(page.goto).toHaveBeenCalledTimes(2);
319
+ expect(page.wait).toHaveBeenCalledWith({
320
+ selector: '.item-root .title-text, .item-root .title a, .result-list .result-item h3 a',
321
+ timeout: 8,
322
+ });
323
+ expect(results).toEqual([
324
+ {
325
+ rank: 1,
326
+ id: '26895402',
327
+ type: 'book',
328
+ title: '经济学思维',
329
+ rating: 7.9,
330
+ abstract: '李子畅 / 中信出版社 / 2016-7',
331
+ url: 'https://book.douban.com/subject/26895402/',
332
+ cover: 'https://img1.doubanio.com/view/subject/m/public/s29000000.jpg',
333
+ },
334
+ ]);
335
+ });
164
336
  });
337
+
165
338
  describe('inferDoubanSearchResultType', () => {
166
339
  it('returns tvshow for movie search results marked as TV', () => {
167
340
  expect(inferDoubanSearchResultType('movie', {
@@ -169,12 +342,14 @@ describe('inferDoubanSearchResultType', () => {
169
342
  labels: [{ text: '剧集' }],
170
343
  })).toBe('tvshow');
171
344
  });
345
+
172
346
  it('returns movie when a movie search result has no TV signal', () => {
173
347
  expect(inferDoubanSearchResultType('movie', {
174
348
  moreUrl: "onclick=\"moreurl(this,{is_tv:'0'})\"",
175
349
  labels: [{ text: '可播放' }],
176
350
  })).toBe('movie');
177
351
  });
352
+
178
353
  it('preserves non-movie search types', () => {
179
354
  expect(inferDoubanSearchResultType('book', {
180
355
  moreUrl: '',