Files
FlowPilot/tests/background-platform-verify-codex2api.test.js
T
2026-05-21 07:21:34 +08:00

217 lines
8.1 KiB
JavaScript

const assert = require('node:assert/strict');
const fs = require('node:fs');
const test = require('node:test');
test('platform verify module supports codex2api protocol callback exchange', async () => {
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
const originalFetch = globalThis.fetch;
globalThis.fetch = async (url, options = {}) => {
assert.equal(url, 'http://localhost:8080/api/admin/oauth/exchange-code');
assert.equal(options.method, 'POST');
assert.equal(options.headers['X-Admin-Key'], 'admin-secret');
assert.deepStrictEqual(JSON.parse(options.body), {
session_id: 'session-123',
code: 'callback-code',
state: 'oauth-state',
});
return {
ok: true,
json: async () => ({
message: 'OAuth 账号 flow@example.com 添加成功',
id: 42,
email: 'flow@example.com',
plan_type: 'pro',
}),
};
};
try {
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
const completed = [];
const logs = [];
const executor = api.createStep10Executor({
addLog: async (message, level = 'info', options = {}) => {
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
},
chrome: {},
closeConflictingTabsForSource: async () => {},
completeNodeFromBackground: async (step, payload) => {
completed.push({ step, payload });
},
ensureContentScriptReadyOnTab: async () => {},
getPanelMode: () => 'codex2api',
getTabId: async () => 0,
isLocalhostOAuthCallbackUrl: (value) => String(value || '').includes('/auth/callback?code='),
isTabAlive: async () => false,
normalizeCodex2ApiUrl: () => 'http://localhost:8080/admin/accounts',
normalizeSub2ApiUrl: (value) => value,
rememberSourceLastUrl: async () => {},
reuseOrCreateTab: async () => 0,
sendToContentScript: async () => ({}),
sendToContentScriptResilient: async () => ({}),
shouldBypassStep9ForLocalCpa: () => false,
SUB2API_STEP9_RESPONSE_TIMEOUT_MS: 120000,
});
await executor.executeStep10({
panelMode: 'codex2api',
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
codex2apiUrl: 'http://localhost:8080/admin/accounts',
codex2apiAdminKey: 'admin-secret',
codex2apiSessionId: 'session-123',
codex2apiOAuthState: 'oauth-state',
});
assert.deepStrictEqual(logs, [
{ message: '正在向 Codex2API 提交回调并创建账号...', level: 'info', step: 10, stepKey: 'platform-verify' },
{ message: 'OAuth 账号 flow@example.com 添加成功', level: 'ok', step: 10, stepKey: 'platform-verify' },
]);
assert.deepStrictEqual(completed, [
{
step: 'platform-verify',
payload: {
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
verifiedStatus: 'OAuth 账号 flow@example.com 添加成功',
},
},
]);
} finally {
globalThis.fetch = originalFetch;
}
});
test('platform verify retries transient SUB2API oauth/token exchange errors before succeeding', async () => {
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
const logs = [];
const attempts = [];
let callCount = 0;
let contentScriptCalled = false;
const executor = api.createStep10Executor({
addLog: async (message, level = 'info') => {
logs.push({ message, level });
},
chrome: {
tabs: {
update: async () => {},
},
},
closeConflictingTabsForSource: async () => {},
completeNodeFromBackground: async () => {},
ensureContentScriptReadyOnTab: async () => {},
getPanelMode: () => 'sub2api',
getTabId: async () => 12,
isLocalhostOAuthCallbackUrl: (value) => String(value || '').includes('/auth/callback?code='),
isTabAlive: async () => true,
normalizeCodex2ApiUrl: (value) => value,
normalizeSub2ApiUrl: () => 'https://sub2api.example.com/admin/accounts',
rememberSourceLastUrl: async () => {},
reuseOrCreateTab: async () => 12,
sendToContentScript: async () => {
contentScriptCalled = true;
return {};
},
createSub2ApiApi: () => ({
submitOpenAiCallback: async () => {
attempts.push('direct-api');
callCount += 1;
if (callCount === 1) {
throw new Error('request failed: Post "https://auth.openai.com/oauth/token": unexpected EOF');
}
return {
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
verifiedStatus: 'SUB2API 已创建账号 #11',
};
},
}),
sendToContentScriptResilient: async () => ({}),
shouldBypassStep9ForLocalCpa: () => false,
SUB2API_STEP9_RESPONSE_TIMEOUT_MS: 120000,
});
await executor.executeStep10({
panelMode: 'sub2api',
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
sub2apiUrl: 'https://sub2api.example.com/admin/accounts',
sub2apiEmail: 'flow@example.com',
sub2apiPassword: 'secret',
sub2apiSessionId: 'session-123',
sub2apiOAuthState: 'oauth-state',
});
assert.equal(callCount, 2);
assert.equal(contentScriptCalled, false);
assert.deepStrictEqual(attempts, ['direct-api', 'direct-api']);
assert.equal(
logs.some((entry) => /临时网络波动/.test(entry.message) && entry.level === 'warn'),
true
);
});
test('platform verify retries transient SUB2API token_exchange_user_error before succeeding', async () => {
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
const logs = [];
let callCount = 0;
let contentScriptCalled = false;
const executor = api.createStep10Executor({
addLog: async (message, level = 'info') => {
logs.push({ message, level });
},
chrome: {
tabs: {
update: async () => {},
},
},
closeConflictingTabsForSource: async () => {},
completeNodeFromBackground: async () => {},
ensureContentScriptReadyOnTab: async () => {},
getPanelMode: () => 'sub2api',
getTabId: async () => 12,
isLocalhostOAuthCallbackUrl: (value) => String(value || '').includes('/auth/callback?code='),
isTabAlive: async () => true,
normalizeCodex2ApiUrl: (value) => value,
normalizeSub2ApiUrl: () => 'https://sub2api.example.com/admin/accounts',
rememberSourceLastUrl: async () => {},
reuseOrCreateTab: async () => 12,
sendToContentScript: async () => {
contentScriptCalled = true;
return { ok: true };
},
createSub2ApiApi: () => ({
submitOpenAiCallback: async () => {
callCount += 1;
if (callCount === 1) {
throw new Error('token exchange failed: status 400, body: { "error": { "message": "Invalid request. Please try again later.", "type": "invalid_request_error", "param": null, "code": "token_exchange_user_error" } }');
}
return {
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
verifiedStatus: 'SUB2API 已创建账号 #11',
};
},
}),
sendToContentScriptResilient: async () => ({}),
shouldBypassStep9ForLocalCpa: () => false,
SUB2API_STEP9_RESPONSE_TIMEOUT_MS: 120000,
});
await executor.executeStep10({
panelMode: 'sub2api',
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
sub2apiUrl: 'https://sub2api.example.com/admin/accounts',
sub2apiEmail: 'flow@example.com',
sub2apiPassword: 'secret',
sub2apiSessionId: 'session-123',
sub2apiOAuthState: 'oauth-state',
});
assert.equal(callCount, 2);
assert.equal(contentScriptCalled, false);
assert.equal(
logs.some((entry) => /临时网络波动/.test(entry.message) && entry.level === 'warn'),
true
);
});