fix: align Hotmail API integration with current dev
- merge the latest dev changes into PR #69 before continuing the review flow - keep Microsoft API mode while preserving mailbox-by-mailbox polling and verification filters - update the Hotmail side panel copy and helper coverage for the repaired API path
This commit is contained in:
@@ -5,9 +5,10 @@ const {
|
||||
extractVerificationCodeFromMessages,
|
||||
fetchMicrosoftMailboxMessages,
|
||||
fetchMicrosoftVerificationCode,
|
||||
normalizeMailboxId,
|
||||
} = require('../microsoft-email.js');
|
||||
|
||||
test('extractVerificationCodeFromMessages 只命中过滤时间后的 OpenAI 微软邮件', () => {
|
||||
test('extractVerificationCodeFromMessages 支持显式过滤条件并跳过排除的验证码', () => {
|
||||
const result = extractVerificationCodeFromMessages([
|
||||
{
|
||||
From: { EmailAddress: { Address: 'noreply@openai.com' } },
|
||||
@@ -32,6 +33,9 @@ test('extractVerificationCodeFromMessages 只命中过滤时间后的 OpenAI 微
|
||||
},
|
||||
], {
|
||||
filterAfterTimestamp: Date.UTC(2026, 3, 14, 9, 30, 0),
|
||||
senderFilters: ['openai'],
|
||||
subjectFilters: ['verification'],
|
||||
excludeCodes: ['112233'],
|
||||
});
|
||||
|
||||
assert.deepEqual(result, {
|
||||
@@ -40,14 +44,46 @@ test('extractVerificationCodeFromMessages 只命中过滤时间后的 OpenAI 微
|
||||
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('fetchMicrosoftMailboxMessages 使用 refresh token 拉取微软邮箱列表并返回新 token', async () => {
|
||||
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 () => ({
|
||||
@@ -57,16 +93,17 @@ test('fetchMicrosoftMailboxMessages 使用 refresh token 拉取微软邮箱列
|
||||
};
|
||||
}
|
||||
|
||||
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',
|
||||
from: { emailAddress: { address: 'noreply@openai.com' } },
|
||||
subject: 'OpenAI verification',
|
||||
bodyPreview: 'Use 445566 to continue',
|
||||
receivedDateTime: '2026-04-14T10:06:00.000Z',
|
||||
id: 'mail-1',
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -76,18 +113,25 @@ test('fetchMicrosoftMailboxMessages 使用 refresh token 拉取微软邮箱列
|
||||
const result = await fetchMicrosoftMailboxMessages({
|
||||
clientId: 'client-1',
|
||||
refreshToken: 'refresh-token-1',
|
||||
mailbox: 'Junk',
|
||||
top: 5,
|
||||
fetchImpl,
|
||||
});
|
||||
|
||||
assert.equal(requests.length, 2);
|
||||
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 会重试直到命中最新验证码', async () => {
|
||||
let messageRequestCount = 0;
|
||||
test('fetchMicrosoftVerificationCode 会按邮箱夹轮询并在 Junk 中命中最新验证码', async () => {
|
||||
const mailboxRequests = {
|
||||
inbox: 0,
|
||||
junkemail: 0,
|
||||
};
|
||||
const logs = [];
|
||||
const fetchImpl = async (url) => {
|
||||
if (String(url).includes('/oauth2/v2.0/token')) {
|
||||
@@ -100,8 +144,9 @@ test('fetchMicrosoftVerificationCode 会重试直到命中最新验证码', asyn
|
||||
};
|
||||
}
|
||||
|
||||
messageRequestCount += 1;
|
||||
if (messageRequestCount === 1) {
|
||||
const urlString = String(url);
|
||||
if (urlString.includes('/mailFolders/inbox/messages')) {
|
||||
mailboxRequests.inbox += 1;
|
||||
return {
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
@@ -116,11 +161,28 @@ test('fetchMicrosoftVerificationCode 会重试直到命中最新验证码', asyn
|
||||
};
|
||||
}
|
||||
|
||||
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: 'noreply@openai.com' } },
|
||||
from: { emailAddress: { address: 'account-security@openai.com' } },
|
||||
Subject: 'Your verification code',
|
||||
BodyPreview: '667788',
|
||||
ReceivedDateTime: '2026-04-14T10:10:00.000Z',
|
||||
@@ -135,13 +197,19 @@ test('fetchMicrosoftVerificationCode 会重试直到命中最新验证码', asyn
|
||||
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);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user