返回 Social Auto Upload
test_sau_browser_cli.py
根目录 / tests / test_sau_browser_cli.py
1 import asyncio
2 import tempfile
3 import unittest
4 from argparse import Namespace
5 from pathlib import Path
6 from unittest.mock import AsyncMock, patch
7
8 import sau_cli
9
10
11 class BrowserCliParserTests(unittest.TestCase):
12 def test_build_parser_accepts_xiaohongshu_login(self):
13 parser = sau_cli.build_parser()
14 args = parser.parse_args(["xiaohongshu", "login", "--account", "creator"])
15 self.assertEqual(args.platform, "xiaohongshu")
16 self.assertEqual(args.action, "login")
17
18 def test_douyin_upload_video_accepts_desc(self):
19 with tempfile.TemporaryDirectory() as tmp_dir:
20 video_path = Path(tmp_dir) / "demo.mp4"
21 video_path.write_bytes(b"video")
22
23 parser = sau_cli.build_parser()
24 args = parser.parse_args(
25 [
26 "douyin",
27 "upload-video",
28 "--account",
29 "creator",
30 "--file",
31 str(video_path),
32 "--title",
33 "标题",
34 "--desc",
35 "视频简介",
36 ]
37 )
38
39 self.assertEqual(args.desc, "视频简介")
40
41 def test_douyin_upload_video_accepts_dual_thumbnail_aspects(self):
42 with tempfile.TemporaryDirectory() as tmp_dir:
43 video_path = Path(tmp_dir) / "demo.mp4"
44 landscape_path = Path(tmp_dir) / "landscape.png"
45 portrait_path = Path(tmp_dir) / "portrait.png"
46 video_path.write_bytes(b"video")
47 landscape_path.write_bytes(b"image")
48 portrait_path.write_bytes(b"image")
49
50 parser = sau_cli.build_parser()
51 args = parser.parse_args(
52 [
53 "douyin",
54 "upload-video",
55 "--account",
56 "creator",
57 "--file",
58 str(video_path),
59 "--title",
60 "标题",
61 "--thumbnail-landscape",
62 str(landscape_path),
63 "--thumbnail-portrait",
64 str(portrait_path),
65 ]
66 )
67
68 self.assertEqual(args.thumbnail_landscape, landscape_path)
69 self.assertEqual(args.thumbnail_portrait, portrait_path)
70
71 def test_douyin_upload_video_accepts_explicit_declaration(self):
72 with tempfile.TemporaryDirectory() as tmp_dir:
73 video_path = Path(tmp_dir) / "demo.mp4"
74 video_path.write_bytes(b"video")
75 parser = sau_cli.build_parser()
76 args = parser.parse_args([
77 "douyin", "upload-video", "--account", "creator",
78 "--file", str(video_path), "--title", "标题",
79 "--declaration", "已确认声明原文",
80 ])
81 self.assertEqual(args.declaration, "已确认声明原文")
82
83 def test_douyin_upload_video_has_no_implicit_declaration(self):
84 with tempfile.TemporaryDirectory() as tmp_dir:
85 video_path = Path(tmp_dir) / "demo.mp4"
86 video_path.write_bytes(b"video")
87 args = sau_cli.build_parser().parse_args([
88 "douyin", "upload-video", "--account", "creator",
89 "--file", str(video_path), "--title", "标题",
90 ])
91 self.assertIsNone(args.declaration)
92
93 def test_douyin_request_legacy_positional_runtime_flags_keep_their_meaning(self):
94 request = sau_cli.DouyinVideoUploadRequest(
95 "creator", Path("demo.mp4"), "标题", "简介", [], 0,
96 None, None, None, "", "", "scheduled", False, False,
97 )
98 self.assertEqual(request.publish_strategy, "scheduled")
99 self.assertFalse(request.debug)
100 self.assertFalse(request.headless)
101 self.assertIsNone(request.declaration)
102
103 def test_tencent_upload_video_accepts_dual_thumbnail_aspects(self):
104 with tempfile.TemporaryDirectory() as tmp_dir:
105 video_path = Path(tmp_dir) / "demo.mp4"
106 landscape_path = Path(tmp_dir) / "landscape.png"
107 portrait_path = Path(tmp_dir) / "portrait.png"
108 video_path.write_bytes(b"video")
109 landscape_path.write_bytes(b"image")
110 portrait_path.write_bytes(b"image")
111
112 parser = sau_cli.build_parser()
113 args = parser.parse_args(
114 [
115 "tencent",
116 "upload-video",
117 "--account",
118 "creator",
119 "--file",
120 str(video_path),
121 "--title",
122 "标题",
123 "--thumbnail-landscape",
124 str(landscape_path),
125 "--thumbnail-portrait",
126 str(portrait_path),
127 ]
128 )
129
130 self.assertEqual(args.thumbnail_landscape, landscape_path)
131 self.assertEqual(args.thumbnail_portrait, portrait_path)
132
133 def test_kuaishou_upload_note_accepts_title_and_note(self):
134 with tempfile.TemporaryDirectory() as tmp_dir:
135 image_path = Path(tmp_dir) / "1.png"
136 image_path.write_bytes(b"image")
137
138 parser = sau_cli.build_parser()
139 args = parser.parse_args(
140 [
141 "kuaishou",
142 "upload-note",
143 "--account",
144 "creator",
145 "--images",
146 str(image_path),
147 "--title",
148 "图文标题",
149 "--note",
150 "图文正文",
151 ]
152 )
153
154 self.assertEqual(args.title, "图文标题")
155 self.assertEqual(args.note, "图文正文")
156
157 def test_xiaohongshu_upload_video_defaults_to_headless(self):
158 with tempfile.TemporaryDirectory() as tmp_dir:
159 video_path = Path(tmp_dir) / "demo.mp4"
160 video_path.write_bytes(b"video")
161
162 parser = sau_cli.build_parser()
163 args = parser.parse_args(
164 [
165 "xiaohongshu",
166 "upload-video",
167 "--account",
168 "creator",
169 "--file",
170 str(video_path),
171 "--title",
172 "视频标题",
173 ]
174 )
175
176 self.assertTrue(args.headless)
177
178 def test_xiaohongshu_upload_note_accepts_headed(self):
179 with tempfile.TemporaryDirectory() as tmp_dir:
180 image_path = Path(tmp_dir) / "1.png"
181 image_path.write_bytes(b"image")
182
183 parser = sau_cli.build_parser()
184 args = parser.parse_args(
185 [
186 "xiaohongshu",
187 "upload-note",
188 "--account",
189 "creator",
190 "--images",
191 str(image_path),
192 "--title",
193 "图文标题",
194 "--note",
195 "图文正文",
196 "--headed",
197 ]
198 )
199
200 self.assertFalse(args.headless)
201
202
203 class BrowserCliDispatchTests(unittest.TestCase):
204 def test_dispatch_xiaohongshu_check_prints_valid(self):
205 args = Namespace(platform="xiaohongshu", action="check", account="creator")
206 with patch("sau_cli.check_xiaohongshu_account", new=AsyncMock(return_value=True)):
207 code = asyncio.run(sau_cli.dispatch(args))
208 self.assertEqual(code, 0)
209
210 def test_dispatch_douyin_upload_note_uses_new_request_fields(self):
211 args = Namespace(
212 platform="douyin",
213 action="upload-note",
214 account="creator",
215 images=[Path("1.png")],
216 title="图文标题",
217 note="图文正文",
218 tags="测试,图文",
219 schedule=0,
220 debug=False,
221 headless=True,
222 )
223 with patch("sau_cli.upload_note", new=AsyncMock()) as mock_upload:
224 asyncio.run(sau_cli.dispatch(args))
225
226 request = mock_upload.await_args.args[0]
227 self.assertEqual(request.title, "图文标题")
228 self.assertEqual(request.note, "图文正文")
229
230 def test_dispatch_douyin_upload_video_uses_dual_thumbnail_request_fields(self):
231 args = Namespace(
232 platform="douyin",
233 action="upload-video",
234 account="creator",
235 file=Path("demo.mp4"),
236 title="视频标题",
237 desc="视频简介",
238 tags="测试,视频",
239 schedule=0,
240 thumbnail=None,
241 thumbnail_landscape=Path("landscape.png"),
242 thumbnail_portrait=Path("portrait.png"),
243 product_link="",
244 product_title="",
245 declaration="已确认声明原文",
246 debug=False,
247 headless=True,
248 )
249 with patch("sau_cli.upload_video", new=AsyncMock()) as mock_upload:
250 asyncio.run(sau_cli.dispatch(args))
251
252 request = mock_upload.await_args.args[0]
253 self.assertEqual(request.thumbnail_landscape_file, Path("landscape.png"))
254 self.assertEqual(request.thumbnail_portrait_file, Path("portrait.png"))
255 self.assertEqual(request.declaration, "已确认声明原文")
256
257 def test_dispatch_tencent_upload_video_uses_dual_thumbnail_request_fields(self):
258 args = Namespace(
259 platform="tencent",
260 action="upload-video",
261 account="creator",
262 file=Path("demo.mp4"),
263 title="视频标题",
264 desc="视频简介",
265 tags="测试,视频",
266 schedule=0,
267 thumbnail=None,
268 thumbnail_landscape=Path("landscape.png"),
269 thumbnail_portrait=Path("portrait.png"),
270 short_title=None,
271 category=None,
272 draft=False,
273 debug=False,
274 headless=True,
275 )
276 with patch("sau_cli.upload_tencent_video", new=AsyncMock()) as mock_upload:
277 asyncio.run(sau_cli.dispatch(args))
278
279 request = mock_upload.await_args.args[0]
280 self.assertEqual(request.thumbnail_landscape_file, Path("landscape.png"))
281 self.assertEqual(request.thumbnail_portrait_file, Path("portrait.png"))
282
283 def test_dispatch_xiaohongshu_upload_video_uses_headed_request(self):
284 args = Namespace(
285 platform="xiaohongshu",
286 action="upload-video",
287 account="creator",
288 file=Path("demo.mp4"),
289 title="视频标题",
290 desc="视频简介",
291 tags="测试,视频",
292 schedule=0,
293 thumbnail=None,
294 debug=False,
295 headless=False,
296 )
297 with patch("sau_cli.upload_xiaohongshu_video", new=AsyncMock()) as mock_upload:
298 asyncio.run(sau_cli.dispatch(args))
299
300 request = mock_upload.await_args.args[0]
301 self.assertEqual(request.title, "视频标题")
302 self.assertEqual(request.description, "视频简介")
303 self.assertFalse(request.headless)
304
305 def test_dispatch_xiaohongshu_upload_note_uses_headless_request(self):
306 args = Namespace(
307 platform="xiaohongshu",
308 action="upload-note",
309 account="creator",
310 images=[Path("1.png"), Path("2.png")],
311 title="图文标题",
312 note="图文正文",
313 tags="测试,图文",
314 schedule=0,
315 debug=False,
316 headless=True,
317 )
318 with patch("sau_cli.upload_xiaohongshu_note", new=AsyncMock()) as mock_upload:
319 asyncio.run(sau_cli.dispatch(args))
320
321 request = mock_upload.await_args.args[0]
322 self.assertEqual(request.title, "图文标题")
323 self.assertEqual(request.note, "图文正文")
324 self.assertTrue(request.headless)
325 self.assertEqual(len(request.image_files), 2)
326
327
328 if __name__ == "__main__":
329 unittest.main()
330
330 lines PYTHON