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,179 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { getQzoneFeedDetail, getQzoneShareArk } from '../../src/web/qzone-public';
|
||||
import { RequestUtil, getBknFromCookie } from '../../src/web/request-util';
|
||||
|
||||
const cookies = { p_skey: 'fixture', uin: 'o20002' };
|
||||
// Synthetic post: author 10001, Unix time 1700000000, sequence word 1.
|
||||
const tid = '1127000000f1536501000000';
|
||||
const ugcId = 'CLcCEJFOGIDiz6oGIgAqADIBMEIYMTEyNzAwMDAwMGYxNTM2NTAxMDAwMDAw';
|
||||
const feed = {
|
||||
cell_common: { domain_type: 1, union_id: { feed_id: tid, ugc_id: ugcId }, operate_mask: 0 },
|
||||
cell_summary: { summary: 'Fixture post' },
|
||||
cell_pic: { pics: [{ url: 'https://example.com/one.png' }, { future_image: true }] },
|
||||
cell_video: { opaque_video: 'preserved' },
|
||||
cell_comment: { comments: [{ id: '9007199254740993', unknown: true }] },
|
||||
cell_operation: {
|
||||
share_outside: {
|
||||
share_access_resource: { busi_id: 'qzone_feed', resource_id: 'resource' },
|
||||
},
|
||||
},
|
||||
cell_feed_transfer: 'original-transfer',
|
||||
cell_future: { nested: [null, '18446744073709551615', { preserved: true }] },
|
||||
};
|
||||
const detail = {
|
||||
feed: { feed },
|
||||
attach_info: 'opaque-comment-continuation',
|
||||
contribute_bar: null,
|
||||
future_detail_field: { preserved: true },
|
||||
};
|
||||
|
||||
afterEach(() => vi.restoreAllMocks());
|
||||
|
||||
describe('Qzone feed detail by tid', () => {
|
||||
it.each([tid, tid.toUpperCase()])(
|
||||
'requests the personal-space detail with the encoded identity (%s)',
|
||||
async (input) => {
|
||||
const request = vi
|
||||
.spyOn(RequestUtil, 'HttpGetJson')
|
||||
.mockResolvedValue({ retcode: 0, data: detail });
|
||||
const result = await getQzoneFeedDetail(cookies, input);
|
||||
|
||||
expect(result).toEqual({ ...detail, feed });
|
||||
expect(result.feed).toBe(feed);
|
||||
expect(request).toHaveBeenCalledExactlyOnceWith(
|
||||
`https://h5.qzone.qq.com/http2rpc/gotrpc/v1/trpc.qzone.feeds_reader.FeedsReader/GetFeedDetail?g_tk=${getBknFromCookie(cookies)}`,
|
||||
'POST',
|
||||
{
|
||||
union_id: { feed_id: tid, ugc_id: ugcId, adv_id: null },
|
||||
feed_action_domain_type: 1,
|
||||
from_page: 1,
|
||||
},
|
||||
expect.objectContaining({
|
||||
Cookie: 'p_skey=fixture; uin=o20002',
|
||||
'Content-Type': 'application/json',
|
||||
'x-oidb': JSON.stringify({
|
||||
uint32_command: '0x97b1',
|
||||
uint32_service_type: '1',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it('keeps the author and time unsigned and emits the explicit empty identity fields', async () => {
|
||||
const highTid = 'ffffffffffffffff01000000';
|
||||
const request = vi.spyOn(RequestUtil, 'HttpGetJson').mockResolvedValue({
|
||||
retcode: 0,
|
||||
data: { feed: { feed: { cell_common: { union_id: { feed_id: highTid } } } } },
|
||||
});
|
||||
|
||||
await getQzoneFeedDetail(cookies, highTid);
|
||||
const body = request.mock.calls[0]![2] as { union_id: { ugc_id: string } };
|
||||
// Independent wire vector: app 311; two uint32-max values encoded as
|
||||
// positive int64; present empty strings in fields 4 and 5; field 8 tid.
|
||||
expect(Buffer.from(body.union_id.ugc_id, 'base64').toString('hex')).toBe(
|
||||
'08b70210ffffffff0f18ffffffff0f22002a003201304218' +
|
||||
'666666666666666666666666666666663031303030303030',
|
||||
);
|
||||
});
|
||||
|
||||
it.each([undefined, null, ''])(
|
||||
'preserves an empty or absent upstream comment cursor (%s)',
|
||||
async (attach_info) => {
|
||||
const request = vi.spyOn(RequestUtil, 'HttpGetJson').mockResolvedValue({
|
||||
retcode: 0,
|
||||
data: { ...detail, attach_info },
|
||||
});
|
||||
|
||||
expect((await getQzoneFeedDetail(cookies, tid)).attach_info).toBe(attach_info ?? null);
|
||||
expect(request).toHaveBeenCalledOnce();
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['', 'T1', 'g'.repeat(24), 'a'.repeat(23), 'a'.repeat(25), `${tid}\n`, ` ${tid}`])(
|
||||
'rejects unsupported or malformed post IDs before requesting (%j)',
|
||||
async (input) => {
|
||||
const request = vi.spyOn(RequestUtil, 'HttpGetJson');
|
||||
|
||||
await expect(getQzoneFeedDetail(cookies, input)).rejects.toThrow('24 位十六进制');
|
||||
expect(request).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{},
|
||||
{ feed: null },
|
||||
{ feed: [] },
|
||||
{ feed: { feed: [] } },
|
||||
{ feed: { feed: {} } },
|
||||
{ feed: { feed: { cell_common: { union_id: { feed_id: 'other' } } } } },
|
||||
{ ...detail, attach_info: {} },
|
||||
])('rejects incomplete, mismatched or malformed details (%#)', async (data) => {
|
||||
const request = vi
|
||||
.spyOn(RequestUtil, 'HttpGetJson')
|
||||
.mockResolvedValue({ retcode: 0, data });
|
||||
|
||||
await expect(getQzoneFeedDetail(cookies, tid)).rejects.toThrow('GetFeedDetail');
|
||||
expect(request).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('propagates access and transport failures without a second request', async () => {
|
||||
const request = vi
|
||||
.spyOn(RequestUtil, 'HttpGetJson')
|
||||
.mockResolvedValueOnce({ retcode: 10023, message: '无权限访问' })
|
||||
.mockRejectedValueOnce(new Error('network down'));
|
||||
|
||||
await expect(getQzoneFeedDetail(cookies, tid)).rejects.toThrow('10023 无权限访问');
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
await expect(getQzoneFeedDetail(cookies, tid)).rejects.toThrow('network down');
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('passes the returned feed straight to card generation without rebuilding sharing data', async () => {
|
||||
const ark = '{ "app": "com.tencent.tuwen.lua", "fixture": true }';
|
||||
const request = vi
|
||||
.spyOn(RequestUtil, 'HttpGetJson')
|
||||
.mockResolvedValueOnce({ retcode: 0, data: detail })
|
||||
.mockResolvedValueOnce({ retcode: 0, data: { template_data: ark } });
|
||||
const result = await getQzoneFeedDetail(cookies, tid);
|
||||
|
||||
await expect(getQzoneShareArk(cookies, result.feed)).resolves.toEqual({
|
||||
ark,
|
||||
requires_confirmation: false,
|
||||
notice: null,
|
||||
});
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
expect(request).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.stringContaining('/trpc.qq.share.Service/CreateShare?g_tk='),
|
||||
'POST',
|
||||
{
|
||||
info: {
|
||||
busi_id: 'qzone_feed',
|
||||
resource_id: 'resource',
|
||||
template: 'ark_busi_select',
|
||||
busi_data: 'original-transfer',
|
||||
plat: 1,
|
||||
target: 3,
|
||||
},
|
||||
},
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
it('can read a share-restricted feed while preserving the share refusal', async () => {
|
||||
const restrictedFeed = {
|
||||
...feed,
|
||||
cell_common: { ...feed.cell_common, operate_mask: 1 << 17 },
|
||||
};
|
||||
const request = vi.spyOn(RequestUtil, 'HttpGetJson').mockResolvedValue({
|
||||
retcode: 0,
|
||||
data: { feed: { feed: restrictedFeed } },
|
||||
});
|
||||
const result = await getQzoneFeedDetail(cookies, tid);
|
||||
|
||||
expect(result.feed).toBe(restrictedFeed);
|
||||
await expect(getQzoneShareArk(cookies, result.feed)).rejects.toThrow('不支持分享');
|
||||
expect(request).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user