Archived
邮件契约:账号入参按 kind 分两形、视图只回 secretBound、入站 / 出站 / 探测 schema
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TM4kUBvekALu9qqmp7D3wr
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
/** 邮件契约 —— 账号入参按 kind 分两形,默认值与视图不带密文 */
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
mailAccountInputSchema,
|
||||
mailAccountViewSchema,
|
||||
mailSendInputSchema,
|
||||
MAIL_ACCOUNT_KINDS,
|
||||
} from '../mail.ts';
|
||||
|
||||
describe('mailAccountInputSchema', () => {
|
||||
it('imap-smtp:只给地址与名字,腾讯的服务器 / 端口 / TLS / 文件夹全部有默认值', () => {
|
||||
const parsed = mailAccountInputSchema.parse({ kind: 'imap-smtp', name: '销售信箱', address: 'sales@we.com' });
|
||||
expect(parsed.kind).toBe('imap-smtp');
|
||||
if (parsed.kind !== 'imap-smtp') throw new Error('unreachable');
|
||||
expect(parsed.settings).toEqual({
|
||||
imapHost: 'imap.exmail.qq.com',
|
||||
imapPort: 993,
|
||||
imapTls: true,
|
||||
smtpHost: 'smtp.exmail.qq.com',
|
||||
smtpPort: 465,
|
||||
smtpTls: true,
|
||||
folder: 'INBOX',
|
||||
});
|
||||
expect(parsed.enabled).toBe(true);
|
||||
expect(parsed.isDefault).toBe(false);
|
||||
expect(parsed.pollIntervalSec).toBe(30);
|
||||
expect(parsed.channelId).toBeNull();
|
||||
expect(parsed.backfillFrom).toBeNull();
|
||||
expect(parsed.secret).toBeUndefined();
|
||||
});
|
||||
|
||||
it('wecom:corpId 必填,地址不由人填(探测回填)', () => {
|
||||
const parsed = mailAccountInputSchema.parse({ kind: 'wecom', name: '应用邮箱', settings: { corpId: 'ww123' } });
|
||||
if (parsed.kind !== 'wecom') throw new Error('unreachable');
|
||||
expect(parsed.settings.apiBase).toBe('https://qyapi.weixin.qq.com');
|
||||
expect('address' in parsed).toBe(false);
|
||||
expect(mailAccountInputSchema.safeParse({ kind: 'wecom', name: 'x', settings: {} }).success).toBe(false);
|
||||
});
|
||||
|
||||
it('轮询间隔下限 10 秒;地址必须是邮箱;kind 只认两种', () => {
|
||||
expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'a@b.c', pollIntervalSec: 5 }).success).toBe(false);
|
||||
expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'not-mail' }).success).toBe(false);
|
||||
expect(mailAccountInputSchema.safeParse({ kind: 'pop3', name: 'a' }).success).toBe(false);
|
||||
expect(MAIL_ACCOUNT_KINDS).toEqual(['imap-smtp', 'wecom']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mailAccountViewSchema', () => {
|
||||
it('视图只有 secretBound,没有任何密文 / 密码字段', () => {
|
||||
const keys = Object.keys(mailAccountViewSchema.options[0]!.shape);
|
||||
expect(keys).toContain('secretBound');
|
||||
expect(keys.some((k) => /cipher|password|secret$/i.test(k))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mailSendInputSchema', () => {
|
||||
it('收件人至少一个、主题必填;附件默认空数组;requestedBy 必带 kind', () => {
|
||||
const ok = mailSendInputSchema.safeParse({ to: ['a@b.c'], subject: 'hi', text: 'x', requestedBy: { kind: 'ops' } });
|
||||
expect(ok.success).toBe(true);
|
||||
if (ok.success) expect(ok.data.attachments).toEqual([]);
|
||||
expect(mailSendInputSchema.safeParse({ to: [], subject: 'hi', text: 'x', requestedBy: { kind: 'ops' } }).success).toBe(false);
|
||||
expect(mailSendInputSchema.safeParse({ to: ['a@b.c'], subject: 'hi', text: 'x' }).success).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user