@acedatacloud/skills 2026.720.1 → 2026.720.3
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.
- package/package.json +1 -1
- package/skills/personal-wechat/scripts/personal_wechat.py +1 -0
- package/skills/personal-wechat/tests/test_personal_wechat.py +25 -0
- package/skills/xiaohongshu/SKILL.md +8 -0
- package/skills/xiaohongshu/references/browse.md +9 -6
- package/skills/xiaohongshu/references/interactions.md +6 -6
- package/skills/xiaohongshu/references/login.md +10 -8
- package/skills/xiaohongshu/references/mcp-parity.md +49 -0
- package/skills/xiaohongshu/references/publish.md +10 -8
- package/skills/xiaohongshu/references/reconciliation.md +8 -0
- package/skills/xiaohongshu/tests/test_browser_contract.py +55 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acedatacloud/skills",
|
|
3
|
-
"version": "2026.720.
|
|
3
|
+
"version": "2026.720.3",
|
|
4
4
|
"description": "Agent Skills for AceDataCloud AI services — music, image, video generation, LLM chat, web search. Compatible with Claude Code, GitHub Copilot, Gemini CLI, OpenAI Codex, and 30+ AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
SCRIPT = Path(__file__).parents[1] / "scripts" / "personal_wechat.py"
|
|
10
|
+
SPEC = importlib.util.spec_from_file_location("personal_wechat_skill_script", SCRIPT)
|
|
11
|
+
assert SPEC and SPEC.loader
|
|
12
|
+
sys.path.insert(0, str(SCRIPT.parent))
|
|
13
|
+
personal_wechat = importlib.util.module_from_spec(SPEC)
|
|
14
|
+
SPEC.loader.exec_module(personal_wechat)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_wait_task_returns_successful_result() -> None:
|
|
18
|
+
with patch.object(
|
|
19
|
+
personal_wechat,
|
|
20
|
+
"request",
|
|
21
|
+
return_value={"status": "succeeded", "result": {"sent": True}},
|
|
22
|
+
):
|
|
23
|
+
result = personal_wechat.wait_task("task-1", timeout=0.1)
|
|
24
|
+
|
|
25
|
+
assert result == {"sent": True}
|
|
@@ -21,12 +21,19 @@ execution:
|
|
|
21
21
|
- tabs
|
|
22
22
|
- snapshot
|
|
23
23
|
- screenshot
|
|
24
|
+
- element_info
|
|
24
25
|
- navigate
|
|
25
26
|
- click
|
|
26
27
|
- click_at
|
|
28
|
+
- hover
|
|
27
29
|
- form_input
|
|
30
|
+
- type_text
|
|
31
|
+
- select_option
|
|
32
|
+
- set_checked
|
|
28
33
|
- key
|
|
29
34
|
- scroll
|
|
35
|
+
- scroll_to
|
|
36
|
+
- wait_for
|
|
30
37
|
- file_upload
|
|
31
38
|
license: Apache-2.0
|
|
32
39
|
metadata:
|
|
@@ -61,6 +68,7 @@ Read only the reference needed for the current request:
|
|
|
61
68
|
| Image, video, long article, schedule, original, visibility, products | [publish](./references/publish.md) |
|
|
62
69
|
| Like, favorite, comment, reply | [interactions](./references/interactions.md) |
|
|
63
70
|
| Any uncertain write result or interrupted workflow | [reconciliation](./references/reconciliation.md) |
|
|
71
|
+
| Feature parity, route contracts, and selector diagnostics | [MCP parity](./references/mcp-parity.md) |
|
|
64
72
|
|
|
65
73
|
For publish/search validation and feed-card parsing, use the shipped stdlib-only contract helper:
|
|
66
74
|
|
|
@@ -15,24 +15,27 @@ Use `parse-feed-snapshot` when a machine-checked card list is useful. Preserve `
|
|
|
15
15
|
|
|
16
16
|
## Recommendations
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Navigate to `https://www.xiaohongshu.com/` (or the attached recommendation page), then wait in 300 ms bounded intervals for feed cards to hydrate, for at most 8 seconds. Read the attached page. Scroll in bounded steps and read after each step. Return only the requested number of notes with title, author state, visible engagement, and canonical URL. Stop when enough results are collected, the page repeats, a warning appears, the 8-second hydration window expires without cards, or the user limit is reached.
|
|
19
19
|
|
|
20
20
|
## Search and filters
|
|
21
21
|
|
|
22
22
|
1. Normalize `{keyword, filters}` with `normalize-filters` before interacting. Supported filters are sort, note type, publish time, search scope, and location.
|
|
23
|
-
2.
|
|
24
|
-
3.
|
|
25
|
-
4.
|
|
23
|
+
2. Navigate to `https://www.xiaohongshu.com/search_result?keyword=<encoded>&source=web_explore_feed`, or use the visible search control when already attached there. Never invent a query token.
|
|
24
|
+
3. Wait for visible results. To filter, hover the visible `筛选` control, wait for the panel, then choose exact labels one group at a time in this order: sort, note type, publish time, search scope, location. Use the normalized labels from `normalize-filters` rather than positional guesses.
|
|
25
|
+
4. After every selection, wait for the panel/result state to settle and verify the exact selected label before continuing. If the hover panel closes, reacquire it; never click a stale option ref.
|
|
26
|
+
5. Return bounded cards. Never invent query tokens, counts, or hidden IDs.
|
|
26
27
|
|
|
27
28
|
## Detail and comments
|
|
28
29
|
|
|
29
|
-
Open a note from its fresh result ref or same-origin canonical URL.
|
|
30
|
+
Open a note from its fresh result ref or same-origin canonical URL. Prefer clicking the fresh feed link so any required page token remains browser-local. Retry navigation at most three times with a short bounded delay, then stop. Read visible text, media labels, author, engagement, and the first visible comment batch.
|
|
31
|
+
|
|
32
|
+
For more comments/replies, first scroll to the comment area. In each bounded round: expand at most three visible `展开 N 条回复` controls, read the count, scroll the last visible comment into view, then scroll about 70% of one viewport. Stop at the requested count, visible end marker, no-comment state, 20 stagnant rounds, warning, or caller limit. Never copy the upstream 500-attempt default into chat automation.
|
|
30
33
|
|
|
31
34
|
Pass the final semantic snapshot to `parse-note-snapshot --note-url <canonical-url>`. Preserve missing, ambiguous, and truncated states instead of filling absent fields. Only nodes with an explicit `comment` role are returned as structured comments; generic list items are never assumed to be comments.
|
|
32
35
|
|
|
33
36
|
## Profile
|
|
34
37
|
|
|
35
|
-
Open the fresh author link from a result/detail page. Return visible profile text, followers/following/engagement totals, and bounded recent notes. Do not expose unrelated private account data.
|
|
38
|
+
Open the fresh author link from a result/detail page. For the current account, use the sidebar `我` profile channel rather than fabricating an ID. Return visible profile text, followers/following/engagement totals, and bounded recent notes. Profile notes can be grouped/lazy-loaded; flatten only visibly observed note batches. Do not expose unrelated private account data.
|
|
36
39
|
|
|
37
40
|
Pass the final semantic snapshot to `parse-profile-snapshot --profile-url <canonical-url>` before reporting structured profile data. `visible_metrics` contains explicitly labeled profile metrics. Preserve `visible_counts` separately as unlabeled page counters; never reinterpret them as followers, following, likes, or favorites.
|
|
38
41
|
|
|
@@ -6,22 +6,22 @@ Always open and read the exact target note first. Derive it from the user's URL
|
|
|
6
6
|
|
|
7
7
|
1. Read the target control's visible label and checked/pressed/selected state.
|
|
8
8
|
2. If the current state already matches the explicit request, no-op and report it.
|
|
9
|
-
3. Otherwise click once,
|
|
10
|
-
4. If state
|
|
9
|
+
3. Otherwise click once, poll the fresh state every 500 ms for at most 4 seconds, and confirm the exact target state.
|
|
10
|
+
4. If the state is readable and clearly unchanged, one retry is allowed because the action is reversible; never exceed two total clicks. If state cannot be read, do not retry.
|
|
11
11
|
|
|
12
12
|
## Comment
|
|
13
13
|
|
|
14
14
|
1. Draft the exact comment and show the target note plus full text.
|
|
15
15
|
2. Obtain explicit chat confirmation.
|
|
16
|
-
3. Open the visible
|
|
16
|
+
3. Open the visible comment placeholder, then fill the visible contenteditable comment input and read the draft back.
|
|
17
17
|
4. If the target or exact text differs, stop.
|
|
18
|
-
5. Click
|
|
18
|
+
5. Click the visible submit button once after the confirmed preview. Poll the visible comments for the exact text every 300 ms for at most 4 seconds; absence is an unknown/failed result, not success.
|
|
19
19
|
|
|
20
20
|
## Reply
|
|
21
21
|
|
|
22
|
-
1. Locate the exact visible target comment and author
|
|
22
|
+
1. Locate the exact visible target comment and author. Prefer an exact comment ID when visible; otherwise match the explicitly confirmed user. Expand/scroll in bounded steps, stop at the end marker, and never search more than 100 rounds.
|
|
23
23
|
2. Show the target and full reply preview; obtain explicit confirmation.
|
|
24
24
|
3. Open that comment's reply control, fill the reply, and read the visible target/text back.
|
|
25
|
-
4. Submit once, then
|
|
25
|
+
4. Submit once, then require the exact reply text to appear within 4 seconds before reporting success.
|
|
26
26
|
|
|
27
27
|
Comments and replies are public account actions. The attached exact-origin session does not replace explicit chat preview confirmation.
|
|
@@ -2,21 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## Status
|
|
4
4
|
|
|
5
|
-
1.
|
|
6
|
-
2.
|
|
7
|
-
3.
|
|
5
|
+
1. Navigate or attach `https://www.xiaohongshu.com/explore` and wait up to 30 seconds in bounded intervals.
|
|
6
|
+
2. Treat a visible sidebar profile channel (`我` / profile link) as signed in. Treat a visible login prompt or QR container as signed out. URL alone is not sufficient unless it visibly redirects to login.
|
|
7
|
+
3. Determine login only from visible signed-in controls, profile links, or an explicit login prompt. Do not claim cryptographic account attestation.
|
|
8
|
+
4. If `browser.snapshot` is unavailable on the dense page, use `browser.screenshot` for this status check. If neither proves the state, ask the user to inspect the tab.
|
|
8
9
|
|
|
9
10
|
## QR login
|
|
10
11
|
|
|
11
|
-
1. Open the visible login control with a fresh ref.
|
|
12
|
-
2. Read again.
|
|
13
|
-
3. The user scans locally.
|
|
14
|
-
4.
|
|
12
|
+
1. Open the visible login control with a fresh ref or screenshot-bound point.
|
|
13
|
+
2. Read again. The upstream page contract renders the QR under the login container; call `browser.screenshot` and present the visible image, never the QR payload or session token.
|
|
14
|
+
3. The user scans locally. Poll every 500 ms only through bounded `browser.wait_for`/fresh observations, with a maximum matching the visible QR expiry (never more than 5 minutes).
|
|
15
|
+
4. Success requires the visible sidebar profile channel to appear. A disappeared QR alone is not success.
|
|
16
|
+
5. On expiry, ask before reopening a fresh QR. Never loop indefinitely.
|
|
15
17
|
|
|
16
18
|
## Switch or sign out
|
|
17
19
|
|
|
18
20
|
1. Show the visible current-account context and ask for explicit confirmation.
|
|
19
|
-
2. Use visible logout/switch controls with fresh refs after chat confirmation.
|
|
21
|
+
2. Use visible logout/switch controls with fresh refs after chat confirmation. Do not copy the upstream Cookie-deletion shortcut; this Skill never clears or exports Cookies.
|
|
20
22
|
3. Let the user complete credentials, SMS, QR, or verification locally.
|
|
21
23
|
4. Read again and report only the visible resulting account state.
|
|
22
24
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Xiaohongshu MCP feature parity
|
|
2
|
+
|
|
3
|
+
This Skill benchmarks its business workflows against `xpzouying/xiaohongshu-mcp` commit
|
|
4
|
+
`a7d1f2f7f45e0b1c27de67c8f8a19131ba321725`. Reimplement the behavior through generic
|
|
5
|
+
`browser.*` capabilities; never copy its CDP runtime into the extension.
|
|
6
|
+
|
|
7
|
+
| Reference feature | Skill workflow |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `check_login_status` | [login status](./login.md#status) |
|
|
10
|
+
| `get_login_qrcode` | [QR login](./login.md#qr-login) |
|
|
11
|
+
| `publish_content` | [image publish](./publish.md#execute) |
|
|
12
|
+
| `publish_with_video` | [video publish](./publish.md#execute) |
|
|
13
|
+
| long-article pipeline | [long article steps](./publish.md#execute) |
|
|
14
|
+
| `list_feeds` | [recommendations](./browse.md#recommendations) |
|
|
15
|
+
| `search_feeds` + five filter groups | [search and filters](./browse.md#search-and-filters) |
|
|
16
|
+
| `get_feed_detail` + comment loading | [detail and comments](./browse.md#detail-and-comments) |
|
|
17
|
+
| `user_profile` / `get_me` | [profile](./browse.md#profile) |
|
|
18
|
+
| `post_comment_to_feed` | [comment](./interactions.md#comment) |
|
|
19
|
+
| `reply_comment_in_feed` | [reply](./interactions.md#reply) |
|
|
20
|
+
| `like_feed` / unlike | [like and favorite](./interactions.md#like-and-favorite) |
|
|
21
|
+
| `favorite_feed` / unfavorite | [like and favorite](./interactions.md#like-and-favorite) |
|
|
22
|
+
|
|
23
|
+
## Selector recognition hints
|
|
24
|
+
|
|
25
|
+
These are Xiaohongshu-specific diagnostics owned by this Skill. Use visible semantics first and reacquire
|
|
26
|
+
fresh refs after every transition.
|
|
27
|
+
|
|
28
|
+
- Creator mode tabs: `div.creator-tab`, exact text `上传图文`, `上传视频`, `写长文`.
|
|
29
|
+
- Upload input: `input.upload-input`, fallback single visible/associated `input[type=file]`.
|
|
30
|
+
- Image completion: `.img-preview-area .pr` count.
|
|
31
|
+
- Image/video title: placeholder containing `填写标题`, fallback visible title input.
|
|
32
|
+
- Long-title field: `textarea.d-text[placeholder="输入标题"]`.
|
|
33
|
+
- Body/editor: `div.tiptap.ProseMirror`, fallback visible `div.ProseMirror[contenteditable=true]`.
|
|
34
|
+
- Publish: enabled `xhs-publish-btn`, fallback visible `.publish-page-publish-btn button.bg-red`.
|
|
35
|
+
- Comment opener/input/submit: `div.input-box div.content-edit span`, `p.content-input`, `div.bottom button.submit`.
|
|
36
|
+
- Like/favorite: `.like-lottie`, `.collect-icon`; always verify resulting state.
|
|
37
|
+
|
|
38
|
+
Selectors are recognition hints, not permission to run arbitrary JavaScript or CSS queries. If generic
|
|
39
|
+
browser observations cannot identify a unique visible target, use a screenshot-bound action or stop.
|
|
40
|
+
|
|
41
|
+
## Deliberate non-parity
|
|
42
|
+
|
|
43
|
+
Do not import upstream behaviors that violate the local-browser security boundary:
|
|
44
|
+
|
|
45
|
+
- no Cookie deletion/export or account state reset;
|
|
46
|
+
- no arbitrary CDP/evaluate, remote debugging port, or headless profile;
|
|
47
|
+
- no local filesystem paths or direct URL downloads in `browser.file_upload`;
|
|
48
|
+
- no hidden `window.__INITIAL_STATE__` extraction; report only visible browser observations;
|
|
49
|
+
- no 500-round unattended comment crawling; all loops are bounded and user-request limited.
|
|
@@ -20,13 +20,15 @@ Show the exact normalized preview: post type, title, full body, tags, media name
|
|
|
20
20
|
## Execute
|
|
21
21
|
|
|
22
22
|
1. Ask the user to open `https://creator.xiaohongshu.com`, attach that tab, and locally verify the signed-in account.
|
|
23
|
-
2. Read the page and stop on warnings or unexpected account context.
|
|
24
|
-
3. Select
|
|
25
|
-
4.
|
|
26
|
-
5. Fill
|
|
27
|
-
6.
|
|
28
|
-
7.
|
|
29
|
-
8.
|
|
30
|
-
9.
|
|
23
|
+
2. Navigate to `https://creator.xiaohongshu.com/publish/publish?source=official`. Wait for load, then allow two seconds for creator widgets and one bounded DOM-settle interval. Read or screenshot the page and stop on warnings, login redirects, or unexpected account context.
|
|
24
|
+
3. Select mode by exact visible tab text: `上传图文`, `上传视频`, or `写长文`. Prefer a fresh semantic ref; if the tab is visually blocked by a popover, stop for user inspection instead of deleting page nodes. Verify the selected mode after clicking.
|
|
25
|
+
4. For image posts, upload one approved resource at a time and wait until the visible preview count reaches the submitted count before the next resource (up to 60 seconds per image). For video, wait until processing completes and Publish becomes enabled, up to 10 minutes. If resource resolution is unavailable, wait for the user to select local media and verify the same preview/processing state.
|
|
26
|
+
5. Fill the image/video title using the visible title textbox (recognition hints: placeholder containing `填写标题`, then the single visible title input fallback). Fill body in the visible TipTap/ProseMirror contenteditable editor. Use `browser.form_input` for replacement or focus with `browser.click`/`click_at` then `browser.type_text` for rich text. Read immediately after each field; stop if the exact normalized value is not visible.
|
|
27
|
+
6. Limit tags to the first 10 confirmed tags. Insert them one at a time, close any topic suggestion popover by focusing the title, and verify visible chips/text before continuing.
|
|
28
|
+
7. Configure options one at a time and verify each exact state: schedule (1 hour–14 days), visibility (`公开可见`, `仅自己可见`, `仅互关好友可见`), originality, and products. If originality was requested but cannot be confirmed, abort rather than publishing non-original. Bind a product only when the exact intended product is visibly selected; never accept a first fuzzy match silently.
|
|
29
|
+
8. For long article: choose `写长文` → `新的创作`; fill `输入标题` textarea and ProseMirror body; click `一键排版`; enumerate visible template names; select the confirmed template and verify its selected state; click `下一步`; then fill the separate publish-page description editor.
|
|
30
|
+
9. Before the final action, read or screenshot again and compare media count, title, full body, tags, options, products, and schedule with the confirmed preview. Stop on mismatch.
|
|
31
|
+
10. Locate Publish through two page generations: visible enabled `xhs-publish-btn` widget first, then visible legacy red Publish button. Reject `submit-disabled=true`, `disabled`, `aria-disabled=true`, or disabled styling. Click exactly once after the final confirmed chat preview.
|
|
32
|
+
11. Follow [reconciliation](./reconciliation.md). Immediate success requires leaving `/publish/publish` or a visible success destination within 15 seconds. Remaining on the form is not success. Return the canonical note URL when visible.
|
|
31
33
|
|
|
32
34
|
Never mix image/video media unless the visible current UI explicitly supports it. Bind products only when the account visibly exposes the feature and the exact selected products appear in the final preview.
|
|
@@ -12,4 +12,12 @@ Use this after timeout, disconnect, stale ref, navigation, an ambiguous result,
|
|
|
12
12
|
5. If `not_applied`, reversible actions may be attempted once from the verified state. Irreversible actions require a fresh preview and renewed chat confirmation.
|
|
13
13
|
6. If `unknown`, stop and ask the user to inspect the local tab. Never retry publish, schedule, comment, or reply while unknown.
|
|
14
14
|
|
|
15
|
+
Action-specific success signals benchmarked from the local-browser workflow:
|
|
16
|
+
|
|
17
|
+
- Image upload: preview count reaches the submitted image count; a file-input event alone is not success.
|
|
18
|
+
- Video upload: Publish becomes enabled after processing; file selection alone is not success.
|
|
19
|
+
- Publish/schedule: URL leaves `/publish/publish` or a visible success destination appears within 15 seconds.
|
|
20
|
+
- Comment/reply: the exact submitted text renders in the comments area within 4 seconds.
|
|
21
|
+
- Like/favorite: the visible/semantic state equals the requested boolean; click completion alone is not success.
|
|
22
|
+
|
|
15
23
|
Preserve the page on CAPTCHA, moderation, rate limit, account restriction, or unusual-activity warnings. Do not dismiss, solve, bypass, or retry around them.
|
|
@@ -12,6 +12,7 @@ REFERENCES = {
|
|
|
12
12
|
"publish.md",
|
|
13
13
|
"interactions.md",
|
|
14
14
|
"reconciliation.md",
|
|
15
|
+
"mcp-parity.md",
|
|
15
16
|
}
|
|
16
17
|
EXPECTED_ORIGINS = {
|
|
17
18
|
"https://www.xiaohongshu.com",
|
|
@@ -21,12 +22,19 @@ EXPECTED_CAPABILITIES = {
|
|
|
21
22
|
"tabs",
|
|
22
23
|
"snapshot",
|
|
23
24
|
"screenshot",
|
|
25
|
+
"element_info",
|
|
24
26
|
"navigate",
|
|
25
27
|
"click",
|
|
26
28
|
"click_at",
|
|
29
|
+
"hover",
|
|
27
30
|
"form_input",
|
|
31
|
+
"type_text",
|
|
32
|
+
"select_option",
|
|
33
|
+
"set_checked",
|
|
28
34
|
"key",
|
|
29
35
|
"scroll",
|
|
36
|
+
"scroll_to",
|
|
37
|
+
"wait_for",
|
|
30
38
|
"file_upload",
|
|
31
39
|
}
|
|
32
40
|
DEPLOYED_BROWSER_TOOLS = {
|
|
@@ -140,8 +148,8 @@ def test_browser_skill_matches_complete_local_runtime() -> None:
|
|
|
140
148
|
assert "ask the user to open `https://creator.xiaohongshu.com`" in text
|
|
141
149
|
assert "opaque resource ids" in text
|
|
142
150
|
assert "trusted_input" not in _nested_list(_frontmatter(SKILL.read_text(encoding="utf-8")), "capabilities")
|
|
143
|
-
assert "
|
|
144
|
-
assert "
|
|
151
|
+
assert not re.search(r"\bbrowser\.read_page\b", text)
|
|
152
|
+
assert not re.search(r"\bbrowser\.wait\b", text)
|
|
145
153
|
assert "local approval" not in text
|
|
146
154
|
assert "publish image, video, or long-article notes" in text
|
|
147
155
|
assert "long_article" in text
|
|
@@ -164,4 +172,48 @@ def test_browser_skill_matches_complete_local_runtime() -> None:
|
|
|
164
172
|
assert "content planning" in text
|
|
165
173
|
assert "reconciliation after uncertain browser writes" in text
|
|
166
174
|
assert "stop on warning" in text
|
|
167
|
-
assert "explicit confirmation" in text
|
|
175
|
+
assert "explicit confirmation" in text
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_upstream_mcp_feature_parity_and_skill_ownership() -> None:
|
|
179
|
+
text = "\n".join(
|
|
180
|
+
path.read_text(encoding="utf-8")
|
|
181
|
+
for path in [SKILL, *(SKILL_DIR / "references").glob("*.md")]
|
|
182
|
+
).casefold()
|
|
183
|
+
|
|
184
|
+
for feature in (
|
|
185
|
+
"check_login_status",
|
|
186
|
+
"get_login_qrcode",
|
|
187
|
+
"publish_content",
|
|
188
|
+
"publish_with_video",
|
|
189
|
+
"list_feeds",
|
|
190
|
+
"search_feeds",
|
|
191
|
+
"get_feed_detail",
|
|
192
|
+
"user_profile",
|
|
193
|
+
"get_me",
|
|
194
|
+
"post_comment_to_feed",
|
|
195
|
+
"reply_comment_in_feed",
|
|
196
|
+
"like_feed",
|
|
197
|
+
"favorite_feed",
|
|
198
|
+
):
|
|
199
|
+
assert feature in text
|
|
200
|
+
|
|
201
|
+
for invariant in (
|
|
202
|
+
"上传图文",
|
|
203
|
+
"上传视频",
|
|
204
|
+
"写长文",
|
|
205
|
+
"新的创作",
|
|
206
|
+
"一键排版",
|
|
207
|
+
"xhs-publish-btn",
|
|
208
|
+
"submit-disabled=true",
|
|
209
|
+
"img-preview-area",
|
|
210
|
+
"10 minutes",
|
|
211
|
+
"15 seconds",
|
|
212
|
+
"4 seconds",
|
|
213
|
+
"never exceed two total clicks",
|
|
214
|
+
):
|
|
215
|
+
assert invariant.casefold() in text
|
|
216
|
+
|
|
217
|
+
assert "a7d1f2f7f45e0b1c27de67c8f8a19131ba321725" in text
|
|
218
|
+
assert "no arbitrary cdp/evaluate" in text
|
|
219
|
+
assert "no cookie deletion/export" in text
|