Add configurable SUB2API account priority
This commit is contained in:
@@ -116,3 +116,49 @@ test('panel bridge can request cpa oauth url via management api', async () => {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test('panel bridge forwards SUB2API account priority when requesting oauth url', async () => {
|
||||
const source = fs.readFileSync('background/panel-bridge.js', 'utf8');
|
||||
const sentMessages = [];
|
||||
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundPanelBridge;`)({});
|
||||
const bridge = api.createPanelBridge({
|
||||
addLog: async () => {},
|
||||
chrome: {
|
||||
tabs: {
|
||||
create: async () => ({ id: 72 }),
|
||||
},
|
||||
},
|
||||
closeConflictingTabsForSource: async () => {},
|
||||
ensureContentScriptReadyOnTab: async () => {},
|
||||
getPanelMode: () => 'sub2api',
|
||||
normalizeCodex2ApiUrl: (value) => value,
|
||||
normalizeSub2ApiUrl: (value) => value,
|
||||
rememberSourceLastUrl: async () => {},
|
||||
sendToContentScript: async (sourceName, message, options) => {
|
||||
sentMessages.push({ sourceName, message, options });
|
||||
return {
|
||||
oauthUrl: 'https://auth.openai.com/authorize?state=oauth-state',
|
||||
sub2apiSessionId: 'session-123',
|
||||
sub2apiOAuthState: 'oauth-state',
|
||||
};
|
||||
},
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
waitForTabUrlFamily: async () => ({ id: 72 }),
|
||||
DEFAULT_SUB2API_GROUP_NAME: 'codex',
|
||||
SUB2API_STEP1_RESPONSE_TIMEOUT_MS: 90000,
|
||||
});
|
||||
|
||||
await bridge.requestOAuthUrlFromPanel({
|
||||
panelMode: 'sub2api',
|
||||
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||
sub2apiEmail: 'admin@example.com',
|
||||
sub2apiPassword: 'secret',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiAccountPriority: 3,
|
||||
}, { logLabel: '步骤 7' });
|
||||
|
||||
assert.equal(sentMessages.length, 1);
|
||||
assert.equal(sentMessages[0].sourceName, 'sub2api-panel');
|
||||
assert.equal(sentMessages[0].message.payload.sub2apiAccountPriority, 3);
|
||||
});
|
||||
|
||||
@@ -272,3 +272,34 @@ test('platform verify module sends Plus visible step 13 to SUB2API panel', async
|
||||
assert.equal(sentMessages[0].message.step, 13);
|
||||
});
|
||||
|
||||
test('platform verify module forwards SUB2API account priority to panel', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const sentMessages = [];
|
||||
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
|
||||
const { deps } = createDeps({
|
||||
getPanelMode: () => 'sub2api',
|
||||
getTabId: async () => 91,
|
||||
isTabAlive: async () => true,
|
||||
sendToContentScript: async (sourceName, message, options) => {
|
||||
sentMessages.push({ sourceName, message, options });
|
||||
return { ok: true };
|
||||
},
|
||||
});
|
||||
const executor = api.createStep10Executor(deps);
|
||||
|
||||
await executor.executeStep10({
|
||||
panelMode: 'sub2api',
|
||||
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
|
||||
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||
sub2apiEmail: 'admin@example.com',
|
||||
sub2apiPassword: 'secret',
|
||||
sub2apiSessionId: 'session-1',
|
||||
sub2apiOAuthState: 'oauth-state',
|
||||
sub2apiAccountPriority: 2,
|
||||
});
|
||||
|
||||
assert.equal(sentMessages.length, 1);
|
||||
assert.equal(sentMessages[0].sourceName, 'sub2api-panel');
|
||||
assert.equal(sentMessages[0].message.payload.sub2apiAccountPriority, 2);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const html = fs.readFileSync('sidepanel/sidepanel.html', 'utf8');
|
||||
const source = fs.readFileSync('sidepanel/sidepanel.js', 'utf8');
|
||||
|
||||
test('sidepanel exposes SUB2API account priority below group setting', () => {
|
||||
assert.match(html, /id="row-sub2api-account-priority"/);
|
||||
assert.match(html, /id="input-sub2api-account-priority"/);
|
||||
assert.match(html, /<span class="data-label">优先级<\/span>/);
|
||||
const inputTag = html.match(/<input[^>]*id="input-sub2api-account-priority"[^>]*>/)?.[0] || '';
|
||||
assert.match(inputTag, /type="number"/);
|
||||
assert.match(inputTag, /min="1"/);
|
||||
assert.match(inputTag, /step="1"/);
|
||||
assert.ok(
|
||||
html.indexOf('id="row-sub2api-account-priority"') > html.indexOf('id="row-sub2api-group"'),
|
||||
'priority row should be placed below the SUB2API group row'
|
||||
);
|
||||
assert.ok(
|
||||
html.indexOf('id="row-sub2api-account-priority"') < html.indexOf('id="row-sub2api-default-proxy"'),
|
||||
'priority row should remain above the SUB2API default proxy row'
|
||||
);
|
||||
});
|
||||
|
||||
test('sidepanel persists and locks SUB2API account priority setting', () => {
|
||||
assert.match(
|
||||
source,
|
||||
/const rowSub2ApiAccountPriority = document\.getElementById\('row-sub2api-account-priority'\);/
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/const inputSub2ApiAccountPriority = document\.getElementById\('input-sub2api-account-priority'\);/
|
||||
);
|
||||
assert.match(source, /function normalizeSub2ApiAccountPriorityValue\(/);
|
||||
assert.match(source, /const sub2apiAccountPriorityNormalizer = typeof normalizeSub2ApiAccountPriorityValue === 'function'/);
|
||||
assert.match(source, /sub2apiAccountPriority: sub2apiAccountPriorityNormalizer\(/);
|
||||
assert.match(
|
||||
source,
|
||||
/inputSub2ApiAccountPriority\.value = String\(normalizeSub2ApiAccountPriorityValue\(state\?\.sub2apiAccountPriority\)\);/
|
||||
);
|
||||
assert.match(source, /rowSub2ApiAccountPriority\.style\.display = useSub2Api \? '' : 'none';/);
|
||||
assert.match(source, /inputSub2ApiAccountPriority\.disabled = locked;/);
|
||||
assert.match(
|
||||
source,
|
||||
/inputSub2ApiAccountPriority\.addEventListener\('input', \(\) => \{[\s\S]*scheduleSettingsAutoSave\(\);[\s\S]*\}\);/
|
||||
);
|
||||
assert.match(
|
||||
source,
|
||||
/inputSub2ApiAccountPriority\.addEventListener\('blur', \(\) => \{[\s\S]*saveSettings\(\{ silent: true \}\)/
|
||||
);
|
||||
});
|
||||
@@ -277,3 +277,49 @@ test('SUB2API step 10 omits proxy_id when no proxy is configured', async () => {
|
||||
assert.equal(Object.hasOwn(exchangeCall.body, 'proxy_id'), false);
|
||||
assert.equal(Object.hasOwn(createCall.body, 'proxy_id'), false);
|
||||
});
|
||||
|
||||
test('SUB2API step 10 creates account with configured account priority', async () => {
|
||||
const fetchCalls = [];
|
||||
const context = createSub2ApiPanelContext(fetchCalls);
|
||||
|
||||
await vm.runInContext(`
|
||||
step9_submitOpenAiCallback({
|
||||
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
|
||||
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||
sub2apiEmail: 'admin@example.com',
|
||||
sub2apiPassword: 'secret',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiSessionId: 'session-1',
|
||||
sub2apiOAuthState: 'oauth-state',
|
||||
sub2apiGroupId: 5,
|
||||
sub2apiAccountPriority: 3
|
||||
})
|
||||
`, context);
|
||||
|
||||
const createCall = fetchCalls.find((call) => call.path === '/api/v1/admin/accounts');
|
||||
assert.equal(createCall.body.priority, 3);
|
||||
});
|
||||
|
||||
test('SUB2API account priority must be an integer greater than or equal to 1', async () => {
|
||||
const fetchCalls = [];
|
||||
const context = createSub2ApiPanelContext(fetchCalls);
|
||||
|
||||
await assert.rejects(
|
||||
() => vm.runInContext(`
|
||||
step9_submitOpenAiCallback({
|
||||
localhostUrl: 'http://localhost:1455/auth/callback?code=callback-code&state=oauth-state',
|
||||
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||
sub2apiEmail: 'admin@example.com',
|
||||
sub2apiPassword: 'secret',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiSessionId: 'session-1',
|
||||
sub2apiOAuthState: 'oauth-state',
|
||||
sub2apiGroupId: 5,
|
||||
sub2apiAccountPriority: 0
|
||||
})
|
||||
`, context),
|
||||
/SUB2API 账号优先级必须是大于等于 1 的整数/
|
||||
);
|
||||
|
||||
assert.equal(fetchCalls.some((call) => call.path === '/api/v1/admin/accounts'), false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user