/ tests / e2e / browser-auth.test.ts
browser-auth.test.ts
  1  /**
  2   * E2E tests for login-required browser commands.
  3   * These commands REQUIRE authentication (cookie/session).
  4   * In CI (headless, no login), they should fail gracefully — NOT crash.
  5   *
  6   * These tests verify the error handling path, not the data extraction.
  7   */
  8  
  9  import { describe, it } from 'vitest';
 10  import { expectGracefulAuthFailure } from './browser-auth-helpers.js';
 11  
 12  describe('login-required commands — graceful failure', () => {
 13  
 14    // ── bilibili (requires cookie session) ──
 15    it('bilibili me fails gracefully without login', async () => {
 16      await expectGracefulAuthFailure(['bilibili', 'me', '-f', 'json']);
 17    }, 60_000);
 18  
 19    it('bilibili dynamic fails gracefully without login', async () => {
 20      await expectGracefulAuthFailure(['bilibili', 'dynamic', '--limit', '3', '-f', 'json']);
 21    }, 60_000);
 22  
 23    it('bilibili favorite fails gracefully without login', async () => {
 24      await expectGracefulAuthFailure(['bilibili', 'favorite', '--limit', '3', '-f', 'json']);
 25    }, 60_000);
 26  
 27    it('bilibili history fails gracefully without login', async () => {
 28      await expectGracefulAuthFailure(['bilibili', 'history', '--limit', '3', '-f', 'json']);
 29    }, 60_000);
 30  
 31    it('bilibili following fails gracefully without login', async () => {
 32      await expectGracefulAuthFailure(['bilibili', 'following', '--limit', '3', '-f', 'json']);
 33    }, 60_000);
 34  
 35    // ── twitter (requires login) ──
 36    it('twitter bookmarks fails gracefully without login', async () => {
 37      await expectGracefulAuthFailure(['twitter', 'bookmarks', '--limit', '3', '-f', 'json']);
 38    }, 60_000);
 39  
 40    it('twitter timeline fails gracefully without login', async () => {
 41      await expectGracefulAuthFailure(['twitter', 'timeline', '--limit', '3', '-f', 'json']);
 42    }, 60_000);
 43  
 44    it('twitter notifications fails gracefully without login', async () => {
 45      await expectGracefulAuthFailure(['twitter', 'notifications', '--limit', '3', '-f', 'json']);
 46    }, 60_000);
 47  
 48    // ── v2ex (requires login) ──
 49    it('v2ex me fails gracefully without login', async () => {
 50      await expectGracefulAuthFailure(['v2ex', 'me', '-f', 'json']);
 51    }, 60_000);
 52  
 53    it('v2ex notifications fails gracefully without login', async () => {
 54      await expectGracefulAuthFailure(['v2ex', 'notifications', '--limit', '3', '-f', 'json']);
 55    }, 60_000);
 56  
 57    // ── xueqiu (requires login) ──
 58    it('xueqiu feed fails gracefully without login', async () => {
 59      await expectGracefulAuthFailure(['xueqiu', 'feed', '--limit', '3', '-f', 'json']);
 60    }, 60_000);
 61  
 62    it('xueqiu watchlist fails gracefully without login', async () => {
 63      await expectGracefulAuthFailure(['xueqiu', 'watchlist', '-f', 'json']);
 64    }, 60_000);
 65  
 66    it('xueqiu comments fails gracefully without login', async () => {
 67      await expectGracefulAuthFailure(['xueqiu', 'comments', 'SH600519', '--limit', '3', '-f', 'json'], 'xueqiu comments');
 68    }, 60_000);
 69  
 70    // ── linux-do (requires login — all endpoints need authentication) ──
 71    it('linux-do feed fails gracefully without login', async () => {
 72      await expectGracefulAuthFailure(['linux-do', 'feed', '--limit', '3', '-f', 'json']);
 73    }, 60_000);
 74  
 75    it('linux-do categories fails gracefully without login', async () => {
 76      await expectGracefulAuthFailure(['linux-do', 'categories', '--limit', '3', '-f', 'json']);
 77    }, 60_000);
 78  
 79    it('linux-do tags fails gracefully without login', async () => {
 80      await expectGracefulAuthFailure(['linux-do', 'tags', '--limit', '3', '-f', 'json']);
 81    }, 60_000);
 82  
 83    it('linux-do topic fails gracefully without login', async () => {
 84      await expectGracefulAuthFailure(['linux-do', 'topic', '1', '-f', 'json']);
 85    }, 60_000);
 86  
 87    it('linux-do topic-content fails gracefully without login', async () => {
 88      await expectGracefulAuthFailure(['linux-do', 'topic-content', '1', '-f', 'json']);
 89    }, 60_000);
 90  
 91    it('linux-do search fails gracefully without login', async () => {
 92      await expectGracefulAuthFailure(['linux-do', 'search', 'test', '--limit', '3', '-f', 'json']);
 93    }, 60_000);
 94  
 95    it('linux-do user-topics fails gracefully without login', async () => {
 96      await expectGracefulAuthFailure(['linux-do', 'user-topics', 'test', '--limit', '3', '-f', 'json']);
 97    }, 60_000);
 98  
 99    it('linux-do user-posts fails gracefully without login', async () => {
100      await expectGracefulAuthFailure(['linux-do', 'user-posts', 'test', '--limit', '3', '-f', 'json']);
101    }, 60_000);
102  
103    // ── xiaohongshu (requires login) ──
104    it('xiaohongshu feed fails gracefully without login', async () => {
105      await expectGracefulAuthFailure(['xiaohongshu', 'feed', '--limit', '3', '-f', 'json']);
106    }, 60_000);
107  
108    it('xiaohongshu notifications fails gracefully without login', async () => {
109      await expectGracefulAuthFailure(['xiaohongshu', 'notifications', '--limit', '3', '-f', 'json']);
110    }, 60_000);
111  
112    // ── yuanbao (requires login) ──
113    it('yuanbao new fails gracefully without login', async () => {
114      await expectGracefulAuthFailure(['yuanbao', 'new', '-f', 'json']);
115    }, 60_000);
116  
117    it('yuanbao ask fails gracefully without login', async () => {
118      await expectGracefulAuthFailure(['yuanbao', 'ask', '你好', '-f', 'json']);
119    }, 60_000);
120  
121    // ── pixiv (requires login) ──
122    it('pixiv ranking fails gracefully without login', async () => {
123      await expectGracefulAuthFailure(['pixiv', 'ranking', '--limit', '3', '-f', 'json']);
124    }, 60_000);
125  
126    it('pixiv search fails gracefully without login', async () => {
127      await expectGracefulAuthFailure(['pixiv', 'search', '初音ミク', '--limit', '3', '-f', 'json']);
128    }, 60_000);
129  
130    it('pixiv user fails gracefully without login', async () => {
131      await expectGracefulAuthFailure(['pixiv', 'user', '11', '-f', 'json']);
132    }, 60_000);
133  
134    it('pixiv illusts fails gracefully without login', async () => {
135      await expectGracefulAuthFailure(['pixiv', 'illusts', '11', '--limit', '3', '-f', 'json']);
136    }, 60_000);
137  
138    it('pixiv detail fails gracefully without login', async () => {
139      await expectGracefulAuthFailure(['pixiv', 'detail', '123456', '-f', 'json']);
140    }, 60_000);
141  
142    it('pixiv download fails gracefully without login', async () => {
143      await expectGracefulAuthFailure(['pixiv', 'download', '123456', '--output', '/tmp/pixiv-e2e-test', '-f', 'json']);
144    }, 60_000);
145  
146    // ── yollomi (requires login session) ──
147    it('yollomi generate fails gracefully without login', async () => {
148      await expectGracefulAuthFailure(['yollomi', 'generate', 'a cute cat', '--no-download', '-f', 'json']);
149    }, 60_000);
150  
151    it('yollomi video fails gracefully without login', async () => {
152      await expectGracefulAuthFailure(['yollomi', 'video', 'a sunset over the ocean', '--no-download', '-f', 'json']);
153    }, 60_000);
154  
155    // ── quark (requires cookie session) ──
156    it('quark ls fails gracefully without login', async () => {
157      await expectGracefulAuthFailure(['quark', 'ls', '-f', 'json']);
158    }, 60_000);
159  
160    it('quark mkdir fails gracefully without login', async () => {
161      await expectGracefulAuthFailure(['quark', 'mkdir', 'test', '-f', 'json']);
162    }, 60_000);
163  
164    it('quark mv fails gracefully without login', async () => {
165      await expectGracefulAuthFailure(['quark', 'mv', 'fakefid', '--to-fid', '0', '-f', 'json']);
166    }, 60_000);
167  
168    it('quark rename fails gracefully without login', async () => {
169      await expectGracefulAuthFailure(['quark', 'rename', 'fakefid', '--name', 'new-name', '-f', 'json']);
170    }, 60_000);
171  
172    it('quark rm fails gracefully without login', async () => {
173      await expectGracefulAuthFailure(['quark', 'rm', 'fakefid', '-f', 'json']);
174    }, 60_000);
175  
176    it('quark save fails gracefully without login', async () => {
177      await expectGracefulAuthFailure(['quark', 'save', 'https://pan.quark.cn/s/abc123', '--to-fid', '0', '-f', 'json']);
178    }, 60_000);
179  
180    it('quark share-tree fails gracefully without login', async () => {
181      await expectGracefulAuthFailure(['quark', 'share-tree', 'https://pan.quark.cn/s/abc123', '-f', 'json']);
182    }, 60_000);
183  });