chainlesschain 0.162.20 → 0.162.26
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 +2 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-Buh_mYlF.js → AIOps-DEhhAYYj.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Dc7c0bZf.js → ActionButton-DEyfUz5F.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CR9TWfM-.js → Analytics-D1rjS61W.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-DVfanUep.js → AppLayout-CptFJPy6.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BxojBqRe.js → Audit-BG6KQUHY.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CGkreaK9.js → Backup-D2ikQT54.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B-Q2ZGfz.js → BaseInput-BG_d8yMt.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Dd_VC5Av.js → Chat-CcHmGkLY.js} +1 -1
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B64kZfRH.js → ChatBubbleRenderer-DIXrOHbn.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-NYBD1rCW.js → Checkbox-Bx2h6vT3.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B3Kqhgv1.js → Codegen-o14zzfuK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-2A3Bg2GC.js → Col-HlZjxy7V.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C84SkDEJ.js → Community-DXxMflr2.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Crv3pyZJ.js → Compact-DbswbBjd.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-D4qasxoY.js → Compliance-C7Q4Da2p.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bfbvysw-.js → Cowork-BLImywOe.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-Dkjyiekd.js → Cron-DpXu1G4m.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-DbJm9Kjd.js → Crosschain-C4qokeJu.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C2HI6acG.js → DID-C0BjPiij.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-BXMY7QVP.js → Dashboard-CsfDXwPl.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DcOykpfh.js → Dropdown-CiwMUKrx.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Doo52F2M.js → EmailListRenderer-DX7xfm5a.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-cHubZT6U.js → Federation-CA4Ibsg0.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B5OVlspi.js → FormItemContext-DvM0lU-7.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-OgA46PJq.js → GenericCardRenderer-REjsnTHA.js} +1 -1
- package/src/assets/web-panel/assets/{Git-_OKH_JOq.js → Git-ZhnSDQGH.js} +1 -1
- package/src/assets/web-panel/assets/{Governance-CTByBwSV.js → Governance-BL8iUV_g.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-C0nqgySA.js → Inference-BONrgLk-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CWW4ZIqH.js → KnowledgeGraph-q9SAz7h7.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DrwqUltr.js → Logs-eHfEFnEZ.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-LJMRx-dm.js → Marketplace-DzwuVedm.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-F_EjC8j3.js → McpTools-BRoLIeq5.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-VonDem9-.js → Memory-DjvAa1Ce.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-CUWxIrfb.js → MobileBridge-CGTanjsT.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CGOo70lk.js → MobileProjects-cTccXHwN.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CqUquFbQ.js → Mtc-CNUe29wS.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-CRVusaip.js → MtcAudit-COk24mdH.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-B0o8Mv8T.js → Multisig-CFq2j0BU.js} +1 -1
- package/src/assets/web-panel/assets/{NLProgramming-CxQINUhu.js → NLProgramming-dfRr-FGW.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-B6Q_apFW.js → Notes-iM4aoXiw.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-DO-lgp6x.js → NotificationSettings-CeVJ-942.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DxoBoMtz.js → OrderTableRenderer-zQ5jvUZI.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DqJ_KawH.js → Organization-CTSWyMGT.js} +1 -1
- package/src/assets/web-panel/assets/{Overflow-Cg4iKODM.js → Overflow---n60sAp.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-n5GPMrwC.js → P2P-BCQurpAB.js} +1 -1
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BdZI0EJs.js → PdhVaultBrowser-C5L1qAc0.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-BjtwAIGb.js → Permissions-I8sgLLE5.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-CEUfFRCj.js +2 -0
- package/src/assets/web-panel/assets/{PersonalDataHub-D0ncF92t.css → PersonalDataHub-CO9-IYDY.css} +1 -1
- package/src/assets/web-panel/assets/{Pipeline-BZe2-Flj.js → Pipeline-BTBjJaRd.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-OJqMon4c.js → Privacy-aCs44rpW.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dw-5SMG1.js → ProjectInit-DZ2iIlbN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-DxqW44cV.js → ProjectSettings-oYUtNgHP.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-CPOqs2ec.js → Projects-FonFg0ie.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-hBfwscEl.js → Providers-CRmOuabY.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DA3WFFAr.js → QuickAsk-BHd6UZ1A.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DMpz3URg.js → Recommend-BkzGGuq-.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-6-z56FwC.js → Reputation-Do7cPr9u.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CL1Y6SfW.js → Row-D_sR3MmD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BIHU2bMf.js → RssFeed-pWSbZ06l.js} +1 -1
- package/src/assets/web-panel/assets/{Search-CRAfuEX-.js → Search-BTL71JSs.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CVya3gvH.js → Security-8lbNoqY6.js} +1 -1
- package/src/assets/web-panel/assets/{Services-Cxv7_umF.js → Services-yr3QVduo.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-D_GvsCtv.js → Skeleton-DdnY1ZTz.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DyiEpcvf.js → Skills-fk24WY3D.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-wiglQzXV.js → Sla-bOXRT7wR.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CLtovaa5.js → SpeechSettings-DjonFUbP.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BOgVef1O.js → SyncSettings-C-7HTl6d.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-Ik8AX7-J.js → Tasks-DDohfzFT.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CireiINW.js → Templates-C8PI_WTt.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-t7jF9NkQ.js → Tenant-CIvbeRkn.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Btq_O951.js → Terminal-BuIPGugj.js} +1 -1
- package/src/assets/web-panel/assets/{TimelineRenderer-hC_Piiwy.js → TimelineRenderer-BefCbTxN.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BTIqA2J1.js → Tokens-gGAeez46.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dzv2gJpK.js → Trigger-C_86E2v7.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B13QpWOh.js → Trust-Beg23C1W.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CFj3UF4G.js → UkeySign--sGSaISg.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CGMOGTQb.js → VideoEditing-DIsnY6D_.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BkCJ573Y.js → Wallet-a7ECYY0i.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-C8dCrmGH.js → WebAuthn-CsVpkUE8.js} +1 -1
- package/src/assets/web-panel/assets/{WorkflowEditor-CclfhxwH.js → WorkflowEditor-BOJ4WTgl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CW_X_A9l.js → chat-ezCR5ZZX.js} +1 -1
- package/src/assets/web-panel/assets/{colors-6GtheJb2.js → colors-DSUEQ7GR.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-tz7dJapw.js → compact-item-D4w3DGj_.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CbiGcRCw.js → createContext-B_hvu-NR.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-bmNFD3PH.js → hasIn-FY775Vpc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxHmNJ8S.js → index-1ki6aTIz.js} +1 -1
- package/src/assets/web-panel/assets/{index-UId2JAY6.js → index-B3lbDu2b.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM4slfDH.js → index-B9LXVosT.js} +1 -1
- package/src/assets/web-panel/assets/{index-b7sSMzkC.js → index-BGdchdRx.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFdfLxVt.js → index-BGrm33US.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9sJpsz3.js → index-BHPD-_s2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6GgMo1k.js → index-BMnGj-Ui.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2P1c5yD.js → index-BSp1hSN8.js} +1 -1
- package/src/assets/web-panel/assets/{index-S9g45I5s.js → index-BaZmrJ6j.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cb33JbDx.js → index-BnvLdkR8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQ7aJ-8s.js → index-BzME19Nh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeoJYTHX.js → index-C0wDzrUK.js} +3 -3
- package/src/assets/web-panel/assets/{index-CBNnbQxM.js → index-CAa3LSKI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLk3xgD2.js → index-CE3vDzJj.js} +1 -1
- package/src/assets/web-panel/assets/{index-De0xvTEv.js → index-CLp4V3Tb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKP-AZD3.js → index-CNUQnJsg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzIQ0u4e.js → index-CSbCIyga.js} +1 -1
- package/src/assets/web-panel/assets/{index-UjxsY00y.js → index-CUNYcWEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgLF_zD1.js → index-CV-F9a_X.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5zlrlPd.js → index-CcvzscCg.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3UH6whC.js → index-CdzLJsac.js} +1 -1
- package/src/assets/web-panel/assets/{index-CU0MeCwH.js → index-Cug_yoee.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxdLksCx.js → index-CxMArAIk.js} +1 -1
- package/src/assets/web-panel/assets/index-CzkEIn_T.js +1 -0
- package/src/assets/web-panel/assets/index-D2PcvXPP.js +1 -0
- package/src/assets/web-panel/assets/{index-DMGJqZ-o.js → index-D6yJ0RMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaYfMM7r.js → index-DM77-xyl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CV9aPPYM.js → index-DfU6zsU8.js} +1 -1
- package/src/assets/web-panel/assets/{index-l2VM-W36.js → index-DqsQUPY7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DK7ee5hC.js → index-DqxLCUYa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaK59dFw.js → index-DtztktoP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs5KWviO.js → index-Dz8-7APi.js} +1 -1
- package/src/assets/web-panel/assets/{index-Da2RUdcb.js → index-Enin7rzK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYIwY9zQ.js → index-S6A76pR1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvWXdCxl.js → index-ZGJo2fz1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj1N1idV.js → index-d0HXotWE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTnIkosg.js → index-gAtp_KkQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-zP_o4yKV.js → index-mlTTTHla.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxCPkuTG.js → index-wWVM6ENX.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTGwT0NA.js → initDefaultProps-BoLcNBz9.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BheHkG8e.js → motion-ouRvP3eO.js} +1 -1
- package/src/assets/web-panel/assets/{move-BkMMNkAw.js → move-BBITvaOV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B9zmSFf6.js → omit-D8Yxdvbb.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CFNBcA5Z.js → pickAttrs-BIUy7mER.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B4mvrUYw.js → placementArrow-CrNWpNSF.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BJqsSjxJ.js → responsiveObserve-aHLPN464.js} +1 -1
- package/src/assets/web-panel/assets/{slide-Cj78MXSi.js → slide-2qNtePjk.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Bk6ChXAV.js → statusUtils-FAF3iR3R.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B_YDSNYf.js → styleChecker-BNFTkrbl.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-q90prOQL.js → useFlexGapSupport-BgdPlW7E.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BtpFJ9kI.js → useFs-q1QvAh3f.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C3qhf1sQ.js → usePersonalDataHub-DEZ6cY8C.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bz2j0JiG.js → vnode-vp6H-NL_.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CzaEtel2.js → zoom-UatfJMw4.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-bilibili-adb-sync.test.js +350 -0
- package/src/commands/__tests__/hub-douyin-adb-sync.test.js +199 -0
- package/src/commands/__tests__/hub-kuaishou-adb-sync.test.js +161 -0
- package/src/commands/__tests__/hub-toutiao-adb-sync.test.js +158 -0
- package/src/commands/__tests__/hub-weibo-adb-sync.test.js +163 -0
- package/src/commands/__tests__/hub-xhs-adb-sync.test.js +155 -0
- package/src/commands/hub.js +883 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +84 -0
- package/src/lib/host-adb-bridge.js +77 -1
- package/src/lib/personal-data-hub-wiring.js +471 -12
- package/src/assets/web-panel/assets/PersonalDataHub-Bsf3Wh6n.js +0 -1
- package/src/assets/web-panel/assets/index-BFkZAdio.js +0 -1
- package/src/assets/web-panel/assets/index-BhgINPAH.js +0 -1
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1c — cc hub bilibili-adb-sync CLI command unit tests.
|
|
3
|
+
*
|
|
4
|
+
* Same _getHub test-seam pattern as hub-wechat.test.js: we synthesize a
|
|
5
|
+
* tiny fake hub whose `bilibiliAdbSync` method returns canned `{ok, ...}`
|
|
6
|
+
* shapes matching the real wiring contract.
|
|
7
|
+
*
|
|
8
|
+
* What we cover:
|
|
9
|
+
* - Happy path (status=ok, all 4 counts) — human + JSON output
|
|
10
|
+
* - Each typed failure reason emits the right inline tip + exit code 1
|
|
11
|
+
* - Limits options are parsed + forwarded
|
|
12
|
+
* - stagingDir / displayName forward
|
|
13
|
+
* - Partial-result diagnostic (lastErrorCode) renders the warning line
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from "vitest";
|
|
17
|
+
|
|
18
|
+
import { _internal } from "../hub.js";
|
|
19
|
+
|
|
20
|
+
let logSpy, errSpy;
|
|
21
|
+
let prevExitCode;
|
|
22
|
+
|
|
23
|
+
function fakeHub(syncResult) {
|
|
24
|
+
return {
|
|
25
|
+
bilibiliAdbSync: vi.fn(async (_opts) => syncResult),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const HAPPY_RESULT = {
|
|
30
|
+
ok: true,
|
|
31
|
+
report: {
|
|
32
|
+
adapter: "social-bilibili",
|
|
33
|
+
status: "ok",
|
|
34
|
+
rawCount: 42,
|
|
35
|
+
entityCounts: { events: 42, persons: 0, places: 0, items: 0, topics: 0 },
|
|
36
|
+
bilibili: {
|
|
37
|
+
uid: 1234567890,
|
|
38
|
+
eventCounts: {
|
|
39
|
+
history: 30,
|
|
40
|
+
favourite: 5,
|
|
41
|
+
dynamic: 2,
|
|
42
|
+
follow: 5,
|
|
43
|
+
total: 42,
|
|
44
|
+
},
|
|
45
|
+
lastErrorCode: 0,
|
|
46
|
+
lastErrorMessage: null,
|
|
47
|
+
cookieDiagnostic: { cookieCount: 5, hadEncrypted: false },
|
|
48
|
+
cleanupFailed: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
55
|
+
errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
56
|
+
prevExitCode = process.exitCode;
|
|
57
|
+
process.exitCode = 0;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
logSpy.mockRestore();
|
|
62
|
+
errSpy.mockRestore();
|
|
63
|
+
process.exitCode = prevExitCode;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("cc hub bilibili-adb-sync — happy path", () => {
|
|
67
|
+
it("prints human-readable summary by default", async () => {
|
|
68
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
69
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
70
|
+
expect(hub.bilibiliAdbSync).toHaveBeenCalledOnce();
|
|
71
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
72
|
+
expect(out).toMatch(/bilibili-adb-sync succeeded/);
|
|
73
|
+
expect(out).toMatch(/uid:.*1234567890/);
|
|
74
|
+
expect(out).toMatch(/history:\s+30/);
|
|
75
|
+
expect(out).toMatch(/favourite:\s+5/);
|
|
76
|
+
expect(out).toMatch(/dynamic:\s+2/);
|
|
77
|
+
expect(out).toMatch(/follow:\s+5/);
|
|
78
|
+
expect(out).toMatch(/total:\s+42/);
|
|
79
|
+
expect(out).toMatch(/status:\s+ok/);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("prints JSON when --json", async () => {
|
|
83
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
84
|
+
await _internal.cmdBilibiliAdbSync({
|
|
85
|
+
_getHub: async () => hub,
|
|
86
|
+
json: true,
|
|
87
|
+
});
|
|
88
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
89
|
+
const parsed = JSON.parse(out);
|
|
90
|
+
expect(parsed.ok).toBe(true);
|
|
91
|
+
expect(parsed.report.bilibili.uid).toBe(1234567890);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("renders partial-result warning when lastErrorCode != 0", async () => {
|
|
95
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
96
|
+
result.report.bilibili.lastErrorCode = -412;
|
|
97
|
+
result.report.bilibili.lastErrorMessage = "anti-spider";
|
|
98
|
+
const hub = fakeHub(result);
|
|
99
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
100
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
101
|
+
expect(out).toMatch(/partial.*lastErrorCode=-412.*anti-spider/);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("renders cleanup-failed note when reported", async () => {
|
|
105
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
106
|
+
result.report.bilibili.cleanupFailed = true;
|
|
107
|
+
const hub = fakeHub(result);
|
|
108
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
109
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
110
|
+
expect(out).toMatch(/staging file cleanup failed/);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("cc hub bilibili-adb-sync — failure reasons", () => {
|
|
115
|
+
it("BRIDGE_UNAVAILABLE → exit 1 + install-platform-tools tip", async () => {
|
|
116
|
+
const hub = fakeHub({
|
|
117
|
+
ok: false,
|
|
118
|
+
reason: "BRIDGE_UNAVAILABLE",
|
|
119
|
+
message: "adb not found",
|
|
120
|
+
});
|
|
121
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
122
|
+
expect(process.exitCode).toBe(1);
|
|
123
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
124
|
+
expect(out).toMatch(/bilibili-adb-sync failed.*BRIDGE_UNAVAILABLE/);
|
|
125
|
+
expect(out).toMatch(/Install Android Platform Tools/);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("BILIBILI_NO_ROOT → exit 1 + root-required tip", async () => {
|
|
129
|
+
const hub = fakeHub({
|
|
130
|
+
ok: false,
|
|
131
|
+
reason: "BILIBILI_NO_ROOT",
|
|
132
|
+
message: "su returned uid=2000",
|
|
133
|
+
});
|
|
134
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
135
|
+
expect(process.exitCode).toBe(1);
|
|
136
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
137
|
+
expect(out).toMatch(/BILIBILI_NO_ROOT/);
|
|
138
|
+
expect(out).toMatch(/root \+ Magisk required/);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN → install-and-relog tip", async () => {
|
|
142
|
+
const hub = fakeHub({
|
|
143
|
+
ok: false,
|
|
144
|
+
reason: "BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN",
|
|
145
|
+
message: "Cookies path not found",
|
|
146
|
+
});
|
|
147
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
148
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
149
|
+
expect(out).toMatch(/Install Bilibili App on the phone/);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("BILIBILI_COOKIES_INCOMPLETE → relog tip", async () => {
|
|
153
|
+
const hub = fakeHub({
|
|
154
|
+
ok: false,
|
|
155
|
+
reason: "BILIBILI_COOKIES_INCOMPLETE",
|
|
156
|
+
message: "missing buvid3",
|
|
157
|
+
});
|
|
158
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
159
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
160
|
+
expect(out).toMatch(/Cookie file is missing required fields/);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("unknown reason → generic failure message + exit 1", async () => {
|
|
164
|
+
const hub = fakeHub({
|
|
165
|
+
ok: false,
|
|
166
|
+
reason: "SYNC_FAILED",
|
|
167
|
+
message: "vault write failed",
|
|
168
|
+
});
|
|
169
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
170
|
+
expect(process.exitCode).toBe(1);
|
|
171
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
172
|
+
expect(out).toMatch(/SYNC_FAILED/);
|
|
173
|
+
expect(out).toMatch(/vault write failed/);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("--json on failure outputs full result", async () => {
|
|
177
|
+
const hub = fakeHub({
|
|
178
|
+
ok: false,
|
|
179
|
+
reason: "BILIBILI_NO_ROOT",
|
|
180
|
+
message: "su returned 2000",
|
|
181
|
+
});
|
|
182
|
+
await _internal.cmdBilibiliAdbSync({
|
|
183
|
+
_getHub: async () => hub,
|
|
184
|
+
json: true,
|
|
185
|
+
});
|
|
186
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
187
|
+
const parsed = JSON.parse(out);
|
|
188
|
+
expect(parsed.ok).toBe(false);
|
|
189
|
+
expect(parsed.reason).toBe("BILIBILI_NO_ROOT");
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("cc hub bilibili-adb-sync — options forwarding", () => {
|
|
194
|
+
it("limit-* options become hub.limits object", async () => {
|
|
195
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
196
|
+
await _internal.cmdBilibiliAdbSync({
|
|
197
|
+
_getHub: async () => hub,
|
|
198
|
+
limitHistory: "50",
|
|
199
|
+
limitFavourite: "10",
|
|
200
|
+
limitDynamic: "20",
|
|
201
|
+
limitFollow: "30",
|
|
202
|
+
});
|
|
203
|
+
const callArg = hub.bilibiliAdbSync.mock.calls[0][0];
|
|
204
|
+
expect(callArg.limits).toEqual({
|
|
205
|
+
history: 50,
|
|
206
|
+
favourite: 10,
|
|
207
|
+
dynamic: 20,
|
|
208
|
+
follow: 30,
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("no limit options → limits is undefined", async () => {
|
|
213
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
214
|
+
await _internal.cmdBilibiliAdbSync({ _getHub: async () => hub });
|
|
215
|
+
const callArg = hub.bilibiliAdbSync.mock.calls[0][0];
|
|
216
|
+
expect(callArg.limits).toBeUndefined();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("displayName + stagingDir are forwarded", async () => {
|
|
220
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
221
|
+
await _internal.cmdBilibiliAdbSync({
|
|
222
|
+
_getHub: async () => hub,
|
|
223
|
+
displayName: "alice",
|
|
224
|
+
stagingDir: "/tmp/custom-staging",
|
|
225
|
+
});
|
|
226
|
+
const callArg = hub.bilibiliAdbSync.mock.calls[0][0];
|
|
227
|
+
expect(callArg.displayName).toBe("alice");
|
|
228
|
+
expect(callArg.stagingDir).toBe("/tmp/custom-staging");
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
describe("cc hub bilibili-adb-sync — _internal export", () => {
|
|
233
|
+
it("cmdBilibiliAdbSync is exported", () => {
|
|
234
|
+
expect(typeof _internal.cmdBilibiliAdbSync).toBe("function");
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// ─── Phase 1e — cc hub bilibili-adb-doctor ──────────────────────────────
|
|
239
|
+
|
|
240
|
+
const DOCTOR_HAPPY = {
|
|
241
|
+
ok: true,
|
|
242
|
+
uid: 1234567890,
|
|
243
|
+
extractedAt: 1716383021000,
|
|
244
|
+
cookieDiagnostic: { cookieCount: 5, hadEncrypted: false },
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
function fakeDoctorHub(result) {
|
|
248
|
+
return { bilibiliAdbDoctor: vi.fn(async () => result) };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
describe("cc hub bilibili-adb-doctor — happy path", () => {
|
|
252
|
+
it("prints ready summary on success", async () => {
|
|
253
|
+
const hub = fakeDoctorHub(DOCTOR_HAPPY);
|
|
254
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
255
|
+
expect(hub.bilibiliAdbDoctor).toHaveBeenCalledOnce();
|
|
256
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
257
|
+
expect(out).toMatch(/env ready to sync/);
|
|
258
|
+
expect(out).toMatch(/uid:.*1234567890/);
|
|
259
|
+
expect(out).toMatch(/cookies found:.*5/);
|
|
260
|
+
expect(out).toMatch(/Next: run.*bilibili-adb-sync/);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("renders encrypted-rows warning when present", async () => {
|
|
264
|
+
const result = JSON.parse(JSON.stringify(DOCTOR_HAPPY));
|
|
265
|
+
result.cookieDiagnostic.hadEncrypted = true;
|
|
266
|
+
const hub = fakeDoctorHub(result);
|
|
267
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
268
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
269
|
+
expect(out).toMatch(/encrypted rows/);
|
|
270
|
+
expect(out).toMatch(/Android-Keystore-wrapped/);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("--json outputs raw result", async () => {
|
|
274
|
+
const hub = fakeDoctorHub(DOCTOR_HAPPY);
|
|
275
|
+
await _internal.cmdBilibiliAdbDoctor({
|
|
276
|
+
_getHub: async () => hub,
|
|
277
|
+
json: true,
|
|
278
|
+
});
|
|
279
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
280
|
+
const parsed = JSON.parse(out);
|
|
281
|
+
expect(parsed.ok).toBe(true);
|
|
282
|
+
expect(parsed.uid).toBe(1234567890);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe("cc hub bilibili-adb-doctor — failure reasons", () => {
|
|
287
|
+
it("BRIDGE_UNAVAILABLE → exit 1 + install tip", async () => {
|
|
288
|
+
const hub = fakeDoctorHub({
|
|
289
|
+
ok: false,
|
|
290
|
+
reason: "BRIDGE_UNAVAILABLE",
|
|
291
|
+
message: "adb not found",
|
|
292
|
+
});
|
|
293
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
294
|
+
expect(process.exitCode).toBe(1);
|
|
295
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
296
|
+
expect(out).toMatch(/BRIDGE_UNAVAILABLE/);
|
|
297
|
+
expect(out).toMatch(/install Android Platform Tools/);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("BILIBILI_NO_ROOT → exit 1 + Magisk tip", async () => {
|
|
301
|
+
const hub = fakeDoctorHub({
|
|
302
|
+
ok: false,
|
|
303
|
+
reason: "BILIBILI_NO_ROOT",
|
|
304
|
+
message: "uid=2000",
|
|
305
|
+
});
|
|
306
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
307
|
+
expect(process.exitCode).toBe(1);
|
|
308
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
309
|
+
expect(out).toMatch(/Magisk root/);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN → install+login tip", async () => {
|
|
313
|
+
const hub = fakeDoctorHub({
|
|
314
|
+
ok: false,
|
|
315
|
+
reason: "BILIBILI_NOT_INSTALLED_OR_NEVER_LOGGED_IN",
|
|
316
|
+
message: "Cookies file missing",
|
|
317
|
+
});
|
|
318
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
319
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
320
|
+
expect(out).toMatch(/install Bilibili App.*log in/);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("BILIBILI_COOKIES_INCOMPLETE → relog tip", async () => {
|
|
324
|
+
const hub = fakeDoctorHub({
|
|
325
|
+
ok: false,
|
|
326
|
+
reason: "BILIBILI_COOKIES_INCOMPLETE",
|
|
327
|
+
message: "missing buvid3",
|
|
328
|
+
});
|
|
329
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
330
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
331
|
+
expect(out).toMatch(/relog on the Bilibili App/);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("BILIBILI_COOKIES_TRUNCATED → USB-replug tip", async () => {
|
|
335
|
+
const hub = fakeDoctorHub({
|
|
336
|
+
ok: false,
|
|
337
|
+
reason: "BILIBILI_COOKIES_TRUNCATED",
|
|
338
|
+
message: "decoded 50 bytes",
|
|
339
|
+
});
|
|
340
|
+
await _internal.cmdBilibiliAdbDoctor({ _getHub: async () => hub });
|
|
341
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
342
|
+
expect(out).toMatch(/unplug \+ replug USB/);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe("cc hub bilibili-adb-doctor — _internal export", () => {
|
|
347
|
+
it("cmdBilibiliAdbDoctor is exported", () => {
|
|
348
|
+
expect(typeof _internal.cmdBilibiliAdbDoctor).toBe("function");
|
|
349
|
+
});
|
|
350
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2a — cc hub douyin-adb-sync CLI command unit tests.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors hub-bilibili-adb-sync.test.js. Synthesizes a fake hub whose
|
|
5
|
+
* `douyinAdbSync` returns canned `{ok, ...}` shapes matching the wiring
|
|
6
|
+
* contract.
|
|
7
|
+
*
|
|
8
|
+
* Covers:
|
|
9
|
+
* - Happy path: human + JSON
|
|
10
|
+
* - 5 typed failure reasons each emit the right inline tip + exit 1
|
|
11
|
+
* - Parser diagnostic warnings (msg / SIMPLE_USER missing)
|
|
12
|
+
* - Options forwarding (uid / limit-messages / limit-contacts / staging-dir / display-name)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
16
|
+
|
|
17
|
+
import { _internal } from "../hub.js";
|
|
18
|
+
|
|
19
|
+
let logSpy, errSpy;
|
|
20
|
+
let prevExitCode;
|
|
21
|
+
|
|
22
|
+
function fakeHub(syncResult) {
|
|
23
|
+
return {
|
|
24
|
+
douyinAdbSync: vi.fn(async (_opts) => syncResult),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const HAPPY_RESULT = {
|
|
29
|
+
ok: true,
|
|
30
|
+
report: {
|
|
31
|
+
adapter: "social-douyin",
|
|
32
|
+
status: "ok",
|
|
33
|
+
rawCount: 12,
|
|
34
|
+
entityCounts: { events: 12, persons: 0, places: 0, items: 0, topics: 0 },
|
|
35
|
+
douyin: {
|
|
36
|
+
uid: "1234567890123456789",
|
|
37
|
+
eventCounts: { message: 10, contact: 2, total: 12 },
|
|
38
|
+
parserDiagnostic: {
|
|
39
|
+
hadMsgTable: true,
|
|
40
|
+
hadSimpleUserTable: true,
|
|
41
|
+
messageCount: 10,
|
|
42
|
+
contactCount: 2,
|
|
43
|
+
},
|
|
44
|
+
cleanupFailed: false,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
51
|
+
errSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
52
|
+
prevExitCode = process.exitCode;
|
|
53
|
+
process.exitCode = 0;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
logSpy.mockRestore();
|
|
58
|
+
errSpy.mockRestore();
|
|
59
|
+
process.exitCode = prevExitCode;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("cc hub douyin-adb-sync — happy path", () => {
|
|
63
|
+
it("prints human-readable summary by default", async () => {
|
|
64
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
65
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
66
|
+
expect(hub.douyinAdbSync).toHaveBeenCalledOnce();
|
|
67
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
68
|
+
expect(out).toMatch(/douyin-adb-sync succeeded/);
|
|
69
|
+
expect(out).toMatch(/uid:.*1234567890123456789/);
|
|
70
|
+
expect(out).toMatch(/messages:\s+10/);
|
|
71
|
+
expect(out).toMatch(/contacts:\s+2/);
|
|
72
|
+
expect(out).toMatch(/total:\s+12/);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("--json outputs raw result", async () => {
|
|
76
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
77
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub, json: true });
|
|
78
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
79
|
+
const parsed = JSON.parse(out);
|
|
80
|
+
expect(parsed.ok).toBe(true);
|
|
81
|
+
expect(parsed.report.douyin.uid).toBe("1234567890123456789");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("renders missing-msg-table warning", async () => {
|
|
85
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
86
|
+
result.report.douyin.parserDiagnostic.hadMsgTable = false;
|
|
87
|
+
const hub = fakeHub(result);
|
|
88
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
89
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
90
|
+
expect(out).toMatch(/msg table not found/);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("renders missing-SIMPLE_USER warning", async () => {
|
|
94
|
+
const result = JSON.parse(JSON.stringify(HAPPY_RESULT));
|
|
95
|
+
result.report.douyin.parserDiagnostic.hadSimpleUserTable = false;
|
|
96
|
+
const hub = fakeHub(result);
|
|
97
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
98
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
99
|
+
expect(out).toMatch(/SIMPLE_USER table not found/);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("cc hub douyin-adb-sync — failure reasons", () => {
|
|
104
|
+
it("BRIDGE_UNAVAILABLE → exit 1 + install tip", async () => {
|
|
105
|
+
const hub = fakeHub({
|
|
106
|
+
ok: false,
|
|
107
|
+
reason: "BRIDGE_UNAVAILABLE",
|
|
108
|
+
message: "adb not found",
|
|
109
|
+
});
|
|
110
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
111
|
+
expect(process.exitCode).toBe(1);
|
|
112
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
113
|
+
expect(out).toMatch(/Install Android Platform Tools/);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("DOUYIN_NO_ROOT → exit 1 + Magisk tip", async () => {
|
|
117
|
+
const hub = fakeHub({
|
|
118
|
+
ok: false,
|
|
119
|
+
reason: "DOUYIN_NO_ROOT",
|
|
120
|
+
message: "uid=2000",
|
|
121
|
+
});
|
|
122
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
123
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
124
|
+
expect(out).toMatch(/Magisk root/);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("DOUYIN_NOT_INSTALLED → install tip", async () => {
|
|
128
|
+
const hub = fakeHub({
|
|
129
|
+
ok: false,
|
|
130
|
+
reason: "DOUYIN_NOT_INSTALLED",
|
|
131
|
+
message: "dir missing",
|
|
132
|
+
});
|
|
133
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
134
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
135
|
+
expect(out).toMatch(/Install Douyin App on the phone/);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("DOUYIN_NO_IM_DB → login+open-chat tip", async () => {
|
|
139
|
+
const hub = fakeHub({
|
|
140
|
+
ok: false,
|
|
141
|
+
reason: "DOUYIN_NO_IM_DB",
|
|
142
|
+
message: "no <uid>_im.db",
|
|
143
|
+
});
|
|
144
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
145
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
146
|
+
expect(out).toMatch(/Log in to Douyin App.*open any chat thread/);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("DOUYIN_MULTIPLE_USERS → --uid tip", async () => {
|
|
150
|
+
const hub = fakeHub({
|
|
151
|
+
ok: false,
|
|
152
|
+
reason: "DOUYIN_MULTIPLE_USERS",
|
|
153
|
+
message: "multiple",
|
|
154
|
+
});
|
|
155
|
+
await _internal.cmdDouyinAdbSync({ _getHub: async () => hub });
|
|
156
|
+
const out = logSpy.mock.calls.map((c) => c.join(" ")).join("\n");
|
|
157
|
+
expect(out).toMatch(/--uid <19-digit>/);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("cc hub douyin-adb-sync — options forwarding", () => {
|
|
162
|
+
it("forwards --uid", async () => {
|
|
163
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
164
|
+
await _internal.cmdDouyinAdbSync({
|
|
165
|
+
_getHub: async () => hub,
|
|
166
|
+
uid: "1234567890123456789",
|
|
167
|
+
});
|
|
168
|
+
expect(hub.douyinAdbSync.mock.calls[0][0].uid).toBe("1234567890123456789");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("forwards limit-messages + limit-contacts → limits object", async () => {
|
|
172
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
173
|
+
await _internal.cmdDouyinAdbSync({
|
|
174
|
+
_getHub: async () => hub,
|
|
175
|
+
limitMessages: "500",
|
|
176
|
+
limitContacts: "100",
|
|
177
|
+
});
|
|
178
|
+
const arg = hub.douyinAdbSync.mock.calls[0][0];
|
|
179
|
+
expect(arg.limits).toEqual({ messages: 500, contacts: 100 });
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("forwards display-name + staging-dir", async () => {
|
|
183
|
+
const hub = fakeHub(HAPPY_RESULT);
|
|
184
|
+
await _internal.cmdDouyinAdbSync({
|
|
185
|
+
_getHub: async () => hub,
|
|
186
|
+
displayName: "alice",
|
|
187
|
+
stagingDir: "/tmp/x",
|
|
188
|
+
});
|
|
189
|
+
const arg = hub.douyinAdbSync.mock.calls[0][0];
|
|
190
|
+
expect(arg.displayName).toBe("alice");
|
|
191
|
+
expect(arg.stagingDir).toBe("/tmp/x");
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe("cc hub douyin-adb-sync — _internal export", () => {
|
|
196
|
+
it("cmdDouyinAdbSync is exported", () => {
|
|
197
|
+
expect(typeof _internal.cmdDouyinAdbSync).toBe("function");
|
|
198
|
+
});
|
|
199
|
+
});
|