SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run
This commit is contained in:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,214 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import * as qzonePublic from '@snowluma/protocol/web/qzone-public';
|
||||
import { QzoneApi } from '../../src/bridge/apis/qzone';
|
||||
import { mockApiHub, mockBridge } from './_helpers';
|
||||
|
||||
const cookies = { p_skey: 'PSK' };
|
||||
const feed = {
|
||||
cell_common: { union_id: { feed_id: 'opaque-id' } },
|
||||
cell_feed_transfer: { future: true },
|
||||
};
|
||||
const comment = { id: 'comment-id', user: { uid: 'commenter' }, unknown: [1, 2] };
|
||||
const reply = { id: 'reply-id', user: { uid: 'recipient' } };
|
||||
const content = [{ type: 0, content: 'text', future: { enabled: true } }];
|
||||
const user = { uin: '10001', uid: 'self-uid', nick: 'self-nick' };
|
||||
const result = { feeds: [], has_more: false, next_cursor: null, unknown: { preserved: true } };
|
||||
|
||||
function makeApi() {
|
||||
const getCookies = vi.fn().mockResolvedValue(cookies);
|
||||
const bridge = mockBridge({ apis: { ...mockApiHub(), web: { getCookies } } as never });
|
||||
return { api: new QzoneApi(bridge as never), bridge, getCookies };
|
||||
}
|
||||
|
||||
const cases = [
|
||||
{
|
||||
method: 'getQzoneHomeFeeds',
|
||||
invoke: (api: QzoneApi) => api.getHomeFeeds(20002, 'cursor'),
|
||||
args: [cookies, '10001', '20002', 'cursor'],
|
||||
},
|
||||
{
|
||||
method: 'getQzonePublicCapabilities',
|
||||
invoke: (api: QzoneApi) => api.getPublicCapabilities(),
|
||||
args: [cookies, '10001'],
|
||||
},
|
||||
{
|
||||
method: 'getQzonePublicFeeds',
|
||||
invoke: (api: QzoneApi) => api.getPublicFeeds('cursor'),
|
||||
args: [cookies, '10001', 'cursor'],
|
||||
},
|
||||
{
|
||||
method: 'getQzonePublicFeedDetail',
|
||||
invoke: (api: QzoneApi) => api.getPublicFeedDetail(feed),
|
||||
args: [cookies, feed],
|
||||
},
|
||||
{
|
||||
method: 'getQzonePublicComments',
|
||||
invoke: (api: QzoneApi) => api.getPublicComments(feed, 'cursor'),
|
||||
args: [cookies, feed, 'cursor'],
|
||||
},
|
||||
{
|
||||
method: 'getQzonePublicReplies',
|
||||
invoke: (api: QzoneApi) => api.getPublicReplies(feed, comment, 'cursor', 5),
|
||||
args: [cookies, feed, comment, 'cursor', 5],
|
||||
},
|
||||
{
|
||||
method: 'setQzonePublicUpvote',
|
||||
invoke: (api: QzoneApi) => api.setPublicUpvote(feed, false),
|
||||
args: [cookies, feed, false],
|
||||
},
|
||||
{
|
||||
method: 'setQzonePublicLike',
|
||||
invoke: (api: QzoneApi) => api.setPublicLike(feed, false),
|
||||
args: [cookies, feed, false],
|
||||
},
|
||||
{
|
||||
method: 'setQzonePublicCommentLike',
|
||||
invoke: (api: QzoneApi) => api.setPublicCommentLike(feed, comment, false, reply),
|
||||
args: [cookies, feed, comment, false, reply],
|
||||
},
|
||||
{
|
||||
method: 'commentQzonePublicFeed',
|
||||
invoke: (api: QzoneApi) => api.commentPublicFeed(feed, content),
|
||||
args: [cookies, feed, user, content],
|
||||
},
|
||||
{
|
||||
method: 'replyQzonePublicFeed',
|
||||
invoke: (api: QzoneApi) => api.replyPublicFeed(feed, comment, content, reply),
|
||||
args: [cookies, feed, user, comment, content, reply],
|
||||
},
|
||||
{
|
||||
method: 'deleteQzonePublicComment',
|
||||
invoke: (api: QzoneApi) => api.deletePublicComment(feed, comment),
|
||||
args: [cookies, feed, comment],
|
||||
},
|
||||
{
|
||||
method: 'deleteQzonePublicReply',
|
||||
invoke: (api: QzoneApi) => api.deletePublicReply(feed, comment, reply),
|
||||
args: [cookies, feed, comment, reply],
|
||||
},
|
||||
{
|
||||
method: 'setQzonePublicFollow',
|
||||
invoke: (api: QzoneApi) => api.setPublicFollow(feed, false),
|
||||
args: [cookies, feed, false],
|
||||
},
|
||||
{
|
||||
method: 'forwardQzonePublicFeed',
|
||||
invoke: (api: QzoneApi) => api.forwardPublicFeed(feed, 'reason'),
|
||||
args: [cookies, feed, 'reason'],
|
||||
},
|
||||
] as const;
|
||||
|
||||
describe('apis/qzone public', () => {
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
it('reads a post by tid using current-account credentials', async () => {
|
||||
const { api, getCookies } = makeApi();
|
||||
const tid = '1127000000f1536501000000';
|
||||
const detail = { feed, attach_info: 'comments-next' };
|
||||
const request = vi.spyOn(qzonePublic, 'getQzoneFeedDetail').mockResolvedValue(detail);
|
||||
|
||||
expect(await api.getFeedDetail(tid)).toBe(detail);
|
||||
expect(getCookies).toHaveBeenCalledExactlyOnceWith('qzone.qq.com');
|
||||
expect(request).toHaveBeenCalledExactlyOnceWith(cookies, tid);
|
||||
});
|
||||
|
||||
it('propagates feed detail and cookie failures without replay', async () => {
|
||||
const { api, getCookies } = makeApi();
|
||||
const request = vi
|
||||
.spyOn(qzonePublic, 'getQzoneFeedDetail')
|
||||
.mockRejectedValue(new Error('denied'));
|
||||
|
||||
await expect(api.getFeedDetail('1127000000f1536501000000')).rejects.toThrow('denied');
|
||||
getCookies.mockRejectedValueOnce(new Error('cookie failure'));
|
||||
await expect(api.getFeedDetail('1127000000f1536501000000')).rejects.toThrow(
|
||||
'cookie failure',
|
||||
);
|
||||
expect(request).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('generates a share card with the account cookies and preserves its notice', async () => {
|
||||
const { api, getCookies } = makeApi();
|
||||
const card = { ark: '{}', requires_confirmation: true, notice: '所有人可见' };
|
||||
const request = vi.spyOn(qzonePublic, 'getQzoneShareArk').mockResolvedValue(card);
|
||||
expect(await api.getShareArk(feed)).toBe(card);
|
||||
expect(getCookies).toHaveBeenCalledWith('qzone.qq.com');
|
||||
expect(request).toHaveBeenCalledExactlyOnceWith(cookies, feed);
|
||||
request.mockRejectedValueOnce(new Error('share denied'));
|
||||
await expect(api.getShareArk(feed)).rejects.toThrow('share denied');
|
||||
});
|
||||
|
||||
it.each(cases)(
|
||||
'$method uses current-account cookies and preserves upstream objects',
|
||||
async ({ method, invoke, args }) => {
|
||||
const { api, getCookies } = makeApi();
|
||||
const request = vi.spyOn(qzonePublic, method).mockResolvedValue(result);
|
||||
|
||||
expect(await invoke(api)).toBe(result);
|
||||
expect(getCookies).toHaveBeenCalledWith('qzone.qq.com');
|
||||
expect(request).toHaveBeenCalledExactlyOnceWith(...args);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(cases)(
|
||||
'$method propagates cookie and upstream failures without replay',
|
||||
async ({ method, invoke }) => {
|
||||
const { api, getCookies } = makeApi();
|
||||
const request = vi
|
||||
.spyOn(qzonePublic, method)
|
||||
.mockRejectedValue(new Error('upstream denied'));
|
||||
|
||||
await expect(invoke(api)).rejects.toThrow('upstream denied');
|
||||
getCookies.mockRejectedValueOnce(new Error('cookie failure'));
|
||||
await expect(invoke(api)).rejects.toThrow('cookie failure');
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
},
|
||||
);
|
||||
|
||||
it('keeps documented defaults and omits an optional reply target', async () => {
|
||||
const { api } = makeApi();
|
||||
const feeds = vi.spyOn(qzonePublic, 'getQzonePublicFeeds').mockResolvedValue(result);
|
||||
const replies = vi.spyOn(qzonePublic, 'getQzonePublicReplies').mockResolvedValue(result);
|
||||
const upvote = vi.spyOn(qzonePublic, 'setQzonePublicUpvote').mockResolvedValue(result);
|
||||
const like = vi.spyOn(qzonePublic, 'setQzonePublicLike').mockResolvedValue(result);
|
||||
const commentLike = vi
|
||||
.spyOn(qzonePublic, 'setQzonePublicCommentLike')
|
||||
.mockResolvedValue(result);
|
||||
const follow = vi.spyOn(qzonePublic, 'setQzonePublicFollow').mockResolvedValue(result);
|
||||
const forward = vi.spyOn(qzonePublic, 'forwardQzonePublicFeed').mockResolvedValue(result);
|
||||
const replyRequest = vi
|
||||
.spyOn(qzonePublic, 'replyQzonePublicFeed')
|
||||
.mockResolvedValue(result);
|
||||
|
||||
await api.getPublicFeeds();
|
||||
await api.getPublicReplies(feed, comment);
|
||||
await api.setPublicUpvote(feed);
|
||||
await api.setPublicLike(feed);
|
||||
await api.setPublicCommentLike(feed, comment);
|
||||
await api.setPublicFollow(feed);
|
||||
await api.forwardPublicFeed(feed);
|
||||
await api.replyPublicFeed(feed, comment, 'text');
|
||||
|
||||
expect(feeds).toHaveBeenCalledWith(cookies, '10001', undefined);
|
||||
expect(replies).toHaveBeenCalledWith(cookies, feed, comment, '', 20);
|
||||
expect(upvote).toHaveBeenCalledWith(cookies, feed, true);
|
||||
expect(like).toHaveBeenCalledWith(cookies, feed, true);
|
||||
expect(commentLike).toHaveBeenCalledWith(cookies, feed, comment, true, undefined);
|
||||
expect(follow).toHaveBeenCalledWith(cookies, feed, true);
|
||||
expect(forward).toHaveBeenCalledWith(cookies, feed, '');
|
||||
expect(replyRequest).toHaveBeenCalledWith(cookies, feed, user, comment, 'text', undefined);
|
||||
});
|
||||
|
||||
it('binds comment authors to the current account even when its uid is unavailable', async () => {
|
||||
const { api, bridge } = makeApi();
|
||||
Object.assign(bridge.identity, { selfUid: undefined });
|
||||
const request = vi.spyOn(qzonePublic, 'commentQzonePublicFeed').mockResolvedValue(result);
|
||||
|
||||
await api.commentPublicFeed(feed, 'text');
|
||||
expect(request).toHaveBeenCalledWith(
|
||||
cookies,
|
||||
feed,
|
||||
{ uin: '10001', uid: '', nick: 'self-nick' },
|
||||
'text',
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user