mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-17 02:30:45 +08:00
feat(weixin): show typing indicator during turns
This commit is contained in:
parent
ad3c08ace3
commit
cb34e3f8de
10 changed files with 948 additions and 200 deletions
|
|
@ -208,6 +208,103 @@ test('sendText emits the iLink message envelope without reflecting the token in
|
|||
assert.doesNotMatch(calls[0].init.body, /host-only-token/);
|
||||
});
|
||||
|
||||
test('getConfig requests a typing ticket for the current Weixin conversation', async () => {
|
||||
const calls = [];
|
||||
const api = createWeixinApi({
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url: url.toString(), init });
|
||||
return jsonResponse({ ret: 0, typing_ticket: 'typing-ticket' });
|
||||
},
|
||||
});
|
||||
|
||||
const config = await api.getConfig({
|
||||
baseUrl: 'https://ilinkai.weixin.qq.com',
|
||||
token: 'host-only-token',
|
||||
toUserId: 'wx-user',
|
||||
contextToken: 'message-context',
|
||||
});
|
||||
|
||||
assert.deepEqual(config, { typingTicket: 'typing-ticket' });
|
||||
assert.match(calls[0].url, /\/ilink\/bot\/getconfig$/);
|
||||
assert.equal(calls[0].init.headers.Authorization, 'Bearer host-only-token');
|
||||
const body = JSON.parse(calls[0].init.body);
|
||||
assert.equal(body.ilink_user_id, 'wx-user');
|
||||
assert.equal(body.context_token, 'message-context');
|
||||
assert.equal(body.base_info.channel_version, '2.4.6');
|
||||
assert.doesNotMatch(calls[0].init.body, /host-only-token/);
|
||||
});
|
||||
|
||||
test('sendTyping sends start and cancel states with the cached ticket', async () => {
|
||||
const calls = [];
|
||||
const api = createWeixinApi({
|
||||
fetchImpl: async (url, init) => {
|
||||
calls.push({ url: url.toString(), init });
|
||||
return jsonResponse({ ret: 0 });
|
||||
},
|
||||
});
|
||||
|
||||
for (const status of [1, 2]) {
|
||||
await api.sendTyping({
|
||||
baseUrl: 'https://ilinkai.weixin.qq.com',
|
||||
token: 'host-only-token',
|
||||
toUserId: 'wx-user',
|
||||
typingTicket: 'typing-ticket',
|
||||
status,
|
||||
});
|
||||
}
|
||||
|
||||
assert.deepEqual(calls.map(({ url, init }) => {
|
||||
const body = JSON.parse(init.body);
|
||||
return {
|
||||
path: new URL(url).pathname,
|
||||
user: body.ilink_user_id,
|
||||
ticket: body.typing_ticket,
|
||||
status: body.status,
|
||||
tokenInBody: init.body.includes('host-only-token'),
|
||||
};
|
||||
}), [
|
||||
{
|
||||
path: '/ilink/bot/sendtyping',
|
||||
user: 'wx-user',
|
||||
ticket: 'typing-ticket',
|
||||
status: 1,
|
||||
tokenInBody: false,
|
||||
},
|
||||
{
|
||||
path: '/ilink/bot/sendtyping',
|
||||
user: 'wx-user',
|
||||
ticket: 'typing-ticket',
|
||||
status: 2,
|
||||
tokenInBody: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('typing endpoints reject non-zero iLink return codes', async () => {
|
||||
const api = createWeixinApi({
|
||||
fetchImpl: async () => jsonResponse({ ret: -2, errmsg: 'rejected' }),
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
api.getConfig({
|
||||
baseUrl: 'https://ilinkai.weixin.qq.com',
|
||||
token: 'host-only-token',
|
||||
toUserId: 'wx-user',
|
||||
}),
|
||||
(error) => error instanceof WeixinApiError && error.code === 'config-rejected',
|
||||
);
|
||||
await assert.rejects(
|
||||
api.sendTyping({
|
||||
baseUrl: 'https://ilinkai.weixin.qq.com',
|
||||
token: 'host-only-token',
|
||||
toUserId: 'wx-user',
|
||||
typingTicket: 'typing-ticket',
|
||||
status: 1,
|
||||
}),
|
||||
(error) => error instanceof WeixinApiError && error.code === 'typing-rejected',
|
||||
);
|
||||
});
|
||||
|
||||
test('sendFile uses the iLink 2.4.6 encrypted CDN flow and sends a native file item', async () => {
|
||||
const calls = [];
|
||||
const api = createWeixinApi({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue