Files
FlowPilot/tests/microsoft-email.test.js
2026-05-13 06:35:43 +08:00

246 lines
7.3 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const {
extractVerificationCodeFromMessages,
fetchMicrosoftMailboxMessages,
fetchMicrosoftVerificationCode,
normalizeMailboxId,
} = require('../microsoft-email.js');
test('extractVerificationCodeFromMessages 支持显式过滤条件并跳过排除的验证码', () => {
const result = extractVerificationCodeFromMessages([
{
From: { EmailAddress: { Address: 'noreply@openai.com' } },
Subject: 'Your code is 112233',
BodyPreview: '112233',
ReceivedDateTime: '2026-04-14T09:00:00.000Z',
Id: 'too-old',
},
{
From: { EmailAddress: { Address: 'alerts@example.com' } },
Subject: 'Your code is 223344',
BodyPreview: '223344',
ReceivedDateTime: '2026-04-14T10:00:00.000Z',
Id: 'wrong-sender',
},
{
From: { EmailAddress: { Address: 'account-security@openai.com' } },
Subject: 'OpenAI verification',
BodyPreview: 'Use 334455 to continue',
ReceivedDateTime: '2026-04-14T10:05:00.000Z',
Id: 'matched',
},
], {
filterAfterTimestamp: Date.UTC(2026, 3, 14, 9, 30, 0),
senderFilters: ['openai'],
subjectFilters: ['verification'],
excludeCodes: ['112233'],
});
assert.deepEqual(result, {
code: '334455',
emailTimestamp: Date.UTC(2026, 3, 14, 10, 5, 0),
messageId: 'matched',
sender: 'account-security@openai.com',
subject: 'OpenAI verification',
mailbox: 'INBOX',
message: {
mailbox: 'INBOX',
from: {
emailAddress: {
address: 'account-security@openai.com',
name: '',
},
},
subject: 'OpenAI verification',
receivedDateTime: '2026-04-14T10:05:00.000Z',
bodyPreview: 'Use 334455 to continue',
body: {
content: '',
},
id: 'matched',
},
});
});
test('extractVerificationCodeFromMessages supports keyword hints and runtime code patterns without OpenAI-specific fallback', () => {
const result = extractVerificationCodeFromMessages([
{
From: { EmailAddress: { Address: 'alerts@example.com' } },
Subject: 'Security center',
BodyPreview: 'Use pin A-551199 to continue',
ReceivedDateTime: '2026-04-14T10:07:00.000Z',
Id: 'mail-1',
},
{
From: { EmailAddress: { Address: 'news@example.com' } },
Subject: 'Newsletter',
BodyPreview: 'pin A-000000',
ReceivedDateTime: '2026-04-14T10:06:00.000Z',
Id: 'mail-2',
},
], {
filterAfterTimestamp: 0,
senderFilters: [],
subjectFilters: [],
requiredKeywords: ['security'],
codePatterns: [{ source: 'pin\\s+A-(\\d{6})', flags: 'i' }],
excludeCodes: [],
});
assert.equal(result.code, '551199');
assert.equal(result.messageId, 'mail-1');
assert.equal(result.sender, 'alerts@example.com');
});
test('normalizeMailboxId 将 Junk 归一为微软邮箱夹 ID', () => {
assert.equal(normalizeMailboxId('INBOX'), 'inbox');
assert.equal(normalizeMailboxId('junk'), 'junkemail');
assert.equal(normalizeMailboxId('Junk Email'), 'junkemail');
});
test('fetchMicrosoftMailboxMessages 会回退到可用的 token 策略并保留邮箱夹信息', async () => {
const requests = [];
const fetchImpl = async (url, options = {}) => {
requests.push({ url, options });
if (String(url).includes('/oauth2/v2.0/token')) {
const params = new URLSearchParams(String(options.body || ''));
if (String(url).includes('/common/') && params.get('scope')?.includes('Mail.Read')) {
return {
ok: false,
status: 400,
statusText: 'Bad Request',
text: async () => JSON.stringify({ error_description: 'common delegated failed' }),
};
}
return {
ok: true,
json: async () => ({
access_token: 'access-token-1',
refresh_token: 'refresh-token-next',
}),
};
}
assert.match(String(url), /graph\.microsoft\.com\/v1\.0\/me\/mailFolders\/junkemail\/messages/);
return {
ok: true,
json: async () => ({
value: [
{
from: { emailAddress: { address: 'noreply@openai.com' } },
subject: 'OpenAI verification',
bodyPreview: 'Use 445566 to continue',
receivedDateTime: '2026-04-14T10:06:00.000Z',
id: 'mail-1',
},
],
}),
};
};
const result = await fetchMicrosoftMailboxMessages({
clientId: 'client-1',
refreshToken: 'refresh-token-1',
mailbox: 'Junk',
top: 5,
fetchImpl,
});
assert.equal(requests.length, 3);
assert.equal(result.nextRefreshToken, 'refresh-token-next');
assert.equal(result.tokenStrategy, 'entra-consumers-delegated');
assert.equal(result.transport, 'graph');
assert.equal(result.messages.length, 1);
assert.equal(result.messages[0].id, 'mail-1');
assert.equal(result.messages[0].mailbox, 'Junk');
});
test('fetchMicrosoftVerificationCode 会按邮箱夹轮询并在 Junk 中命中最新验证码', async () => {
const mailboxRequests = {
inbox: 0,
junkemail: 0,
};
const logs = [];
const fetchImpl = async (url) => {
if (String(url).includes('/oauth2/v2.0/token')) {
return {
ok: true,
json: async () => ({
access_token: 'access-token-2',
refresh_token: 'refresh-token-next-2',
}),
};
}
const urlString = String(url);
if (urlString.includes('/mailFolders/inbox/messages')) {
mailboxRequests.inbox += 1;
return {
ok: true,
json: async () => ({
value: [{
From: { EmailAddress: { Address: 'alerts@example.com' } },
Subject: 'Nothing useful',
BodyPreview: 'No code',
ReceivedDateTime: '2026-04-14T10:00:00.000Z',
Id: 'mail-ignore',
}],
}),
};
}
assert.match(urlString, /mailFolders\/junkemail\/messages/);
mailboxRequests.junkemail += 1;
if (mailboxRequests.junkemail === 1) {
return {
ok: true,
json: async () => ({
value: [{
from: { emailAddress: { address: 'no-reply@example.com' } },
subject: 'Nothing useful',
bodyPreview: 'Still no code',
receivedDateTime: '2026-04-14T10:05:00.000Z',
id: 'mail-ignore-2',
}],
}),
};
}
return {
ok: true,
json: async () => ({
value: [{
from: { emailAddress: { address: 'account-security@openai.com' } },
Subject: 'Your verification code',
BodyPreview: '667788',
ReceivedDateTime: '2026-04-14T10:10:00.000Z',
Id: 'mail-hit',
}],
}),
};
};
const result = await fetchMicrosoftVerificationCode({
token: 'refresh-token-2',
clientId: 'client-2',
maxRetries: 2,
retryDelayMs: 0,
mailboxes: ['INBOX', 'Junk'],
fetchImpl,
log: (message) => logs.push(message),
filterAfterTimestamp: Date.UTC(2026, 3, 14, 9, 0, 0),
senderFilters: ['openai'],
subjectFilters: ['verification'],
});
assert.equal(result.code, '667788');
assert.equal(result.messageId, 'mail-hit');
assert.equal(result.nextRefreshToken, 'refresh-token-next-2');
assert.equal(result.mailbox, 'Junk');
assert.equal(mailboxRequests.inbox, 2);
assert.equal(mailboxRequests.junkemail, 2);
assert.equal(logs.some((message) => /retrying/i.test(message)), true);
});