修正手机接码价格区间与最低价逻辑
This commit is contained in:
@@ -163,6 +163,8 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
autoStepDelaySeconds: null,
|
||||
gopayHelperApiUrl: 'https://gpc.qlhazycoder.top',
|
||||
mailProvider: '163',
|
||||
heroSmsMinPrice: '',
|
||||
fiveSimMinPrice: '',
|
||||
};
|
||||
function normalizePanelMode(value) { return value === 'sub2api' ? 'sub2api' : (value === 'codex2api' ? 'codex2api' : 'cpa'); }
|
||||
function normalizeLocalCpaStep9Mode(value) { return value === 'bypass' ? 'bypass' : 'submit'; }
|
||||
@@ -241,6 +243,8 @@ return {
|
||||
assert.equal(api.normalizePersistentSettingValue('phoneCodeTimeoutWindows', '3'), 3);
|
||||
assert.equal(api.normalizePersistentSettingValue('phoneCodePollIntervalSeconds', '6'), 6);
|
||||
assert.equal(api.normalizePersistentSettingValue('phoneCodePollMaxRounds', '18'), 18);
|
||||
assert.equal(api.normalizePersistentSettingValue('heroSmsMinPrice', '0.123456'), '0.1235');
|
||||
assert.equal(api.normalizePersistentSettingValue('heroSmsMinPrice', '0'), '');
|
||||
assert.equal(api.normalizePersistentSettingValue('heroSmsMaxPrice', '0.123456'), '0.1235');
|
||||
assert.equal(api.normalizePersistentSettingValue('heroSmsMaxPrice', '0'), '');
|
||||
assert.equal(api.normalizePersistentSettingValue('heroSmsPreferredPrice', '0.051234'), '0.0512');
|
||||
@@ -259,6 +263,8 @@ return {
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimCountryLabel', ''), '越南 (Vietnam)');
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimMaxPrice', '9.87654'), '9.8765');
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimMaxPrice', '-1'), '');
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimMinPrice', '9.87654'), '9.8765');
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimMinPrice', '-1'), '');
|
||||
assert.equal(api.normalizePersistentSettingValue('fiveSimOperator', ''), 'any');
|
||||
assert.deepStrictEqual(
|
||||
api.normalizePersistentSettingValue('fiveSimCountryFallback', [{ id: 'usa', label: 'USA' }, 'thailand:Thailand']),
|
||||
@@ -326,6 +332,12 @@ return {
|
||||
[1, 6]
|
||||
);
|
||||
assert.equal(api.normalizePersistentSettingValue('nexSmsServiceCode', ' OT! '), 'ot');
|
||||
const rangePayload = api.buildPersistentSettingsPayload({
|
||||
heroSmsMinPrice: '0.023456',
|
||||
fiveSimMinPrice: '0.0789',
|
||||
});
|
||||
assert.equal(rangePayload.heroSmsMinPrice, '0.0235');
|
||||
assert.equal(rangePayload.fiveSimMinPrice, '0.0789');
|
||||
assert.deepStrictEqual(
|
||||
api.normalizePersistentSettingValue('phonePreferredActivation', {
|
||||
provider: 'nexsms',
|
||||
|
||||
@@ -1747,6 +1747,129 @@ test('phone verification helper climbs price tiers when NO_NUMBERS is returned a
|
||||
]);
|
||||
});
|
||||
|
||||
test('phone verification helper filters HeroSMS tiers by minimum price and ignores out-of-range preferred tier', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async (url) => {
|
||||
const parsedUrl = new URL(url);
|
||||
requests.push(parsedUrl);
|
||||
const action = parsedUrl.searchParams.get('action');
|
||||
const maxPrice = parsedUrl.searchParams.get('maxPrice');
|
||||
if (action === 'getPrices') {
|
||||
return {
|
||||
ok: true,
|
||||
text: async () => JSON.stringify({
|
||||
52: {
|
||||
dr: {
|
||||
low: { cost: 0.04, count: 100 },
|
||||
high: { cost: 0.09, count: 100 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (action === 'getNumber' && maxPrice === '0.09') {
|
||||
return {
|
||||
ok: true,
|
||||
text: async () => 'ACCESS_NUMBER:989899:66951112223',
|
||||
};
|
||||
}
|
||||
throw new Error(`Unexpected HeroSMS action: ${action} @ ${maxPrice || 'no-price'}`);
|
||||
},
|
||||
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
const activation = await helpers.requestPhoneActivation({
|
||||
heroSmsApiKey: 'demo-key',
|
||||
heroSmsMinPrice: '0.06',
|
||||
heroSmsPreferredPrice: '0.04',
|
||||
});
|
||||
|
||||
assert.equal(activation.activationId, '989899');
|
||||
const actions = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('maxPrice') || ''}`);
|
||||
assert.deepStrictEqual(actions, [
|
||||
'getPrices:',
|
||||
'getNumber:0.09',
|
||||
]);
|
||||
});
|
||||
|
||||
test('phone verification helper rejects HeroSMS WRONG_MAX_PRICE below configured minimum price', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async (url) => {
|
||||
const parsedUrl = new URL(url);
|
||||
requests.push(parsedUrl);
|
||||
const action = parsedUrl.searchParams.get('action');
|
||||
if (action === 'getPrices') {
|
||||
return {
|
||||
ok: true,
|
||||
text: async () => buildHeroSmsPricesPayload({ cost: 0.08 }),
|
||||
};
|
||||
}
|
||||
if (action === 'getNumber' || action === 'getNumberV2') {
|
||||
return {
|
||||
ok: false,
|
||||
text: async () => 'WRONG_MAX_PRICE:0.05',
|
||||
};
|
||||
}
|
||||
throw new Error(`Unexpected HeroSMS action: ${action}`);
|
||||
},
|
||||
getState: async () => ({ heroSmsApiKey: 'demo-key', heroSmsMinPrice: '0.07' }),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
helpers.requestPhoneActivation({ heroSmsApiKey: 'demo-key', heroSmsMinPrice: '0.07' }),
|
||||
/below configured minPrice=0\.07/i
|
||||
);
|
||||
|
||||
const actions = requests.map((requestUrl) => `${requestUrl.searchParams.get('action')}:${requestUrl.searchParams.get('maxPrice') || ''}`);
|
||||
assert.deepStrictEqual(actions, [
|
||||
'getPrices:',
|
||||
'getNumber:0.08',
|
||||
'getNumberV2:0.08',
|
||||
]);
|
||||
assert.equal(actions.some((entry) => entry.endsWith(':0.05')), false);
|
||||
});
|
||||
|
||||
test('phone verification helper rejects reversed price range before fetching prices', async () => {
|
||||
let fetchCalled = false;
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async () => {
|
||||
fetchCalled = true;
|
||||
throw new Error('fetch should not run for an invalid range');
|
||||
},
|
||||
getState: async () => ({ heroSmsApiKey: 'demo-key' }),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
helpers.requestPhoneActivation({
|
||||
heroSmsApiKey: 'demo-key',
|
||||
heroSmsMinPrice: '0.2',
|
||||
heroSmsMaxPrice: '0.1',
|
||||
}),
|
||||
/price range is invalid/i
|
||||
);
|
||||
assert.equal(fetchCalled, false);
|
||||
});
|
||||
|
||||
test('phone verification helper stops when WRONG_MAX_PRICE exceeds configured max price limit', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
@@ -2153,10 +2276,81 @@ test('phone verification helper rejects 5sim maxPrice with custom operator befor
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
}),
|
||||
/maxPrice only works when operator is "any"/
|
||||
);
|
||||
assert.deepStrictEqual(requests, []);
|
||||
});
|
||||
|
||||
);
|
||||
assert.deepStrictEqual(requests, []);
|
||||
});
|
||||
|
||||
test('phone verification helper keeps 5sim maxPrice independent from HeroSMS maxPrice', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async (url) => {
|
||||
const parsedUrl = new URL(url);
|
||||
requests.push(parsedUrl);
|
||||
if (parsedUrl.pathname === '/v1/guest/prices') {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
openai: {
|
||||
thailand: {
|
||||
any: {
|
||||
low: { cost: 0.08, count: 2 },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (parsedUrl.pathname === '/v1/user/buy/activation/thailand/any/openai') {
|
||||
if (parsedUrl.searchParams.get('maxPrice') === '0.08') {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
id: 900010,
|
||||
phone: '+66951112235',
|
||||
country: 'thailand',
|
||||
country_name: 'Thailand',
|
||||
product: 'openai',
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
throw new Error(`Unexpected 5sim request: ${parsedUrl.pathname}${parsedUrl.search}`);
|
||||
},
|
||||
getState: async () => ({
|
||||
phoneSmsProvider: '5sim',
|
||||
fiveSimApiKey: 'five-token',
|
||||
fiveSimCountryOrder: ['thailand'],
|
||||
fiveSimOperator: 'any',
|
||||
fiveSimProduct: 'openai',
|
||||
heroSmsMaxPrice: '0.06',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
}),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
const activation = await helpers.requestPhoneActivation({
|
||||
phoneSmsProvider: '5sim',
|
||||
fiveSimApiKey: 'five-token',
|
||||
fiveSimCountryOrder: ['thailand'],
|
||||
fiveSimOperator: 'any',
|
||||
fiveSimProduct: 'openai',
|
||||
heroSmsMaxPrice: '0.06',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
});
|
||||
|
||||
assert.equal(activation.phoneNumber, '+66951112235');
|
||||
const buyRequests = requests.filter((entry) => entry.pathname === '/v1/user/buy/activation/thailand/any/openai');
|
||||
assert.equal(buyRequests.length, 1);
|
||||
assert.equal(buyRequests[0].searchParams.get('maxPrice'), '0.08');
|
||||
});
|
||||
|
||||
test('phone verification helper honors price-priority ordering for 5sim countries', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
@@ -2324,6 +2518,80 @@ test('phone verification helper tries multiple 5sim price tiers within the same
|
||||
assert.equal(buyRequests[1].includes('maxPrice=0.08'), true);
|
||||
});
|
||||
|
||||
test('phone verification helper filters 5sim tiers by minimum price before buying', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async (url) => {
|
||||
const parsedUrl = new URL(url);
|
||||
requests.push(parsedUrl.pathname + parsedUrl.search);
|
||||
if (parsedUrl.pathname === '/v1/guest/prices') {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
openai: {
|
||||
thailand: {
|
||||
any: {
|
||||
low: { cost: 0.05, count: 3 },
|
||||
high: { cost: 0.08, count: 2 },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
if (parsedUrl.pathname === '/v1/user/buy/activation/thailand/any/openai') {
|
||||
const maxPrice = parsedUrl.searchParams.get('maxPrice');
|
||||
if (maxPrice === '0.08') {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
id: 800002,
|
||||
phone: '+66951112234',
|
||||
country: 'thailand',
|
||||
country_name: 'Thailand',
|
||||
product: 'openai',
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
throw new Error(`Unexpected 5sim request: ${parsedUrl.pathname}${parsedUrl.search}`);
|
||||
},
|
||||
getState: async () => ({
|
||||
phoneSmsProvider: '5sim',
|
||||
fiveSimApiKey: 'five-token',
|
||||
fiveSimCountryOrder: ['thailand'],
|
||||
fiveSimOperator: 'any',
|
||||
fiveSimProduct: 'openai',
|
||||
fiveSimMinPrice: '0.07',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
}),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
const activation = await helpers.requestPhoneActivation({
|
||||
phoneSmsProvider: '5sim',
|
||||
fiveSimApiKey: 'five-token',
|
||||
fiveSimCountryOrder: ['thailand'],
|
||||
fiveSimOperator: 'any',
|
||||
fiveSimProduct: 'openai',
|
||||
fiveSimMinPrice: '0.07',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
});
|
||||
|
||||
assert.equal(activation.phoneNumber, '+66951112234');
|
||||
const buyRequests = requests.filter((entry) => entry.startsWith('/v1/user/buy/activation/thailand/any/openai'));
|
||||
assert.equal(buyRequests.length, 1);
|
||||
assert.equal(buyRequests[0].includes('maxPrice=0.08'), true);
|
||||
assert.equal(buyRequests[0].includes('maxPrice=0.05'), false);
|
||||
});
|
||||
|
||||
test('phone verification helper polls and parses 5sim verification codes', async () => {
|
||||
let checkCount = 0;
|
||||
const statusUpdates = [];
|
||||
@@ -2661,6 +2929,96 @@ test('phone verification helper acquires a number from NexSMS with ordered fallb
|
||||
assert.equal(requests[3].body?.countryId, 6);
|
||||
});
|
||||
|
||||
test('phone verification helper filters NexSMS tiers by minimum price before purchase', async () => {
|
||||
const requests = [];
|
||||
const helpers = api.createPhoneVerificationHelpers({
|
||||
addLog: async () => {},
|
||||
ensureStep8SignupPageReady: async () => {},
|
||||
fetchImpl: async (url, options = {}) => {
|
||||
const parsedUrl = new URL(url);
|
||||
const method = String(options?.method || 'GET').toUpperCase();
|
||||
const body = options?.body ? JSON.parse(options.body) : null;
|
||||
requests.push({
|
||||
pathname: parsedUrl.pathname,
|
||||
search: parsedUrl.searchParams,
|
||||
method,
|
||||
body,
|
||||
});
|
||||
|
||||
if (parsedUrl.pathname === '/api/getCountryByService') {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
code: 0,
|
||||
data: {
|
||||
countryId: 6,
|
||||
countryName: 'Indonesia',
|
||||
minPrice: 0.03,
|
||||
priceMap: { '0.03': 4, '0.08': 2 },
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (parsedUrl.pathname === '/api/order/purchase') {
|
||||
if (body?.price === 0.08) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
text: async () => JSON.stringify({
|
||||
code: 0,
|
||||
data: {
|
||||
countryId: 6,
|
||||
countryName: 'Indonesia',
|
||||
serviceCode: 'ot',
|
||||
phoneNumbers: ['+6281234567891'],
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected NexSMS request: ${parsedUrl.pathname}`);
|
||||
},
|
||||
getState: async () => ({
|
||||
phoneSmsProvider: 'nexsms',
|
||||
nexSmsApiKey: 'nex-key',
|
||||
nexSmsCountryOrder: [6],
|
||||
nexSmsServiceCode: 'ot',
|
||||
heroSmsMinPrice: '0.05',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
}),
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setState: async () => {},
|
||||
sleepWithStop: async () => {},
|
||||
throwIfStopped: () => {},
|
||||
});
|
||||
|
||||
const activation = await helpers.requestPhoneActivation({
|
||||
phoneSmsProvider: 'nexsms',
|
||||
nexSmsApiKey: 'nex-key',
|
||||
nexSmsCountryOrder: [6],
|
||||
nexSmsServiceCode: 'ot',
|
||||
heroSmsMinPrice: '0.05',
|
||||
heroSmsActivationRetryRounds: 1,
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(activation, {
|
||||
activationId: '+6281234567891',
|
||||
phoneNumber: '+6281234567891',
|
||||
provider: 'nexsms',
|
||||
serviceCode: 'ot',
|
||||
countryId: 6,
|
||||
countryLabel: 'Indonesia',
|
||||
successfulUses: 0,
|
||||
maxUses: 1,
|
||||
});
|
||||
const purchaseRequests = requests.filter((entry) => entry.pathname === '/api/order/purchase');
|
||||
assert.equal(purchaseRequests.length, 1);
|
||||
assert.equal(purchaseRequests[0].body?.price, 0.08);
|
||||
});
|
||||
|
||||
test('phone verification helper polls and parses NexSMS verification codes', async () => {
|
||||
let pollCount = 0;
|
||||
const statusUpdates = [];
|
||||
@@ -7463,6 +7821,7 @@ test('phone verification helper logs no-supply diagnostics with consecutive stre
|
||||
heroSmsCountryId: 52,
|
||||
heroSmsCountryLabel: 'Thailand',
|
||||
heroSmsCountryFallback: [],
|
||||
heroSmsMinPrice: '0.04',
|
||||
heroSmsMaxPrice: '0.06',
|
||||
currentPhoneActivation: null,
|
||||
reusablePhoneActivation: null,
|
||||
@@ -7525,6 +7884,14 @@ test('phone verification helper logs no-supply diagnostics with consecutive stre
|
||||
assert.equal(diagnosticsLogs.every((entry) => entry.options?.stepKey === 'phone-verification'), true);
|
||||
assert.equal(diagnosticsLogs.some((entry) => entry.message.includes('无号连续失败 1 次')), true);
|
||||
assert.equal(diagnosticsLogs.some((entry) => entry.message.includes('无号连续失败 2 次')), true);
|
||||
assert.equal(
|
||||
diagnosticsLogs.some((entry) => entry.message.includes('priceRange=0.04~0.06')),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
diagnosticsLogs.some((entry) => entry.message.includes('minPrice=0.04')),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
diagnosticsLogs.some((entry) => entry.message.includes('maxPrice=0.06')),
|
||||
true
|
||||
|
||||
@@ -98,6 +98,7 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
|
||||
assert.doesNotMatch(html, /id="select-hero-sms-country-fallback"/);
|
||||
assert.match(html, /id="row-hero-sms-api-key"/);
|
||||
assert.match(html, /id="row-hero-sms-max-price"/);
|
||||
assert.match(html, /id="input-hero-sms-min-price"/);
|
||||
assert.match(html, /id="btn-phone-sms-balance"/);
|
||||
assert.match(html, /id="display-phone-sms-balance"/);
|
||||
assert.match(html, /id="row-five-sim-operator"/);
|
||||
@@ -756,6 +757,8 @@ let latestState = {
|
||||
mail2925UseAccountPool: false,
|
||||
currentMail2925AccountId: '',
|
||||
fiveSimCountryOrder: ['thailand', 'england'],
|
||||
heroSmsMinPrice: '0.0444',
|
||||
fiveSimMinPrice: '0.3333',
|
||||
};
|
||||
let cloudflareDomainEditMode = false;
|
||||
let cloudflareTempEmailDomainEditMode = false;
|
||||
@@ -820,6 +823,7 @@ function getSelectedPhonePreferredActivation() {
|
||||
};
|
||||
}
|
||||
const inputHeroSmsMaxPrice = { value: '0.12' };
|
||||
const inputHeroSmsMinPrice = { value: '0.03' };
|
||||
const inputHeroSmsPreferredPrice = { value: '0.0512' };
|
||||
const inputPhoneReplacementLimit = { value: '5' };
|
||||
const inputPhoneCodeWaitSeconds = { value: '75' };
|
||||
@@ -900,6 +904,7 @@ ${extractFunction('normalizeFiveSimOperator')}
|
||||
${extractFunction('normalizeFiveSimMaxPriceValue')}
|
||||
${extractFunction('normalizeFiveSimCountryFallbackList')}
|
||||
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
||||
${extractFunction('normalizeHeroSmsMaxPriceValue')}
|
||||
${extractFunction('normalizePhoneVerificationReplacementLimit')}
|
||||
${extractFunction('normalizePhoneCodeWaitSecondsValue')}
|
||||
@@ -948,6 +953,7 @@ return { collectSettingsPayload };
|
||||
assert.equal(payload.freePhoneReuseEnabled, true);
|
||||
assert.equal(payload.freePhoneReuseAutoEnabled, true);
|
||||
assert.equal(payload.heroSmsAcquirePriority, 'price');
|
||||
assert.equal(payload.heroSmsMinPrice, '0.03');
|
||||
assert.equal(payload.heroSmsMaxPrice, '0.12');
|
||||
assert.equal(payload.heroSmsPreferredPrice, '0.0512');
|
||||
assert.deepStrictEqual(payload.phonePreferredActivation, {
|
||||
@@ -969,6 +975,7 @@ return { collectSettingsPayload };
|
||||
assert.deepStrictEqual(payload.heroSmsCountryFallback, [{ id: 16, label: 'United Kingdom' }]);
|
||||
assert.equal(payload.fiveSimApiKey, 'five-sim-key');
|
||||
assert.equal(payload.fiveSimCountryId, 'vietnam');
|
||||
assert.equal(payload.fiveSimMinPrice, '0.3333');
|
||||
});
|
||||
|
||||
test('switchPhoneSmsProvider saves API keys independently when the select value has already changed', async () => {
|
||||
@@ -977,7 +984,9 @@ let latestState = {
|
||||
phoneSmsProvider: 'hero-sms',
|
||||
heroSmsApiKey: 'hero-old',
|
||||
fiveSimApiKey: 'five-old',
|
||||
heroSmsMinPrice: '0.04',
|
||||
heroSmsMaxPrice: '0.11',
|
||||
fiveSimMinPrice: '0.88',
|
||||
fiveSimMaxPrice: '12',
|
||||
heroSmsCountryId: 52,
|
||||
heroSmsCountryLabel: 'Thailand',
|
||||
@@ -998,6 +1007,7 @@ const FIVE_SIM_SUPPORTED_COUNTRY_ID_SET = new Set(['indonesia', 'thailand', 'vie
|
||||
const HERO_SMS_SUPPORTED_COUNTRY_ID_SET = new Set(['6', '52', '10']);
|
||||
const selectPhoneSmsProvider = { value: 'hero-sms', dataset: { activeProvider: 'hero-sms' } };
|
||||
const inputHeroSmsApiKey = { value: 'hero-live' };
|
||||
const inputHeroSmsMinPrice = { value: '0.03' };
|
||||
const inputHeroSmsMaxPrice = { value: '0.22' };
|
||||
const inputFiveSimOperator = { value: 'any' };
|
||||
const displayHeroSmsPriceTiers = { textContent: '' };
|
||||
@@ -1015,6 +1025,7 @@ ${extractFunction('normalizeFiveSimCountryLabel')}
|
||||
${extractFunction('normalizeFiveSimOperator')}
|
||||
${extractFunction('normalizeFiveSimMaxPriceValue')}
|
||||
${extractFunction('normalizeHeroSmsMaxPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
||||
${extractFunction('normalizeHeroSmsCountryId')}
|
||||
${extractFunction('normalizeHeroSmsCountryLabel')}
|
||||
@@ -1042,6 +1053,7 @@ ${extractFunction('switchPhoneSmsProvider')}
|
||||
return {
|
||||
selectPhoneSmsProvider,
|
||||
inputHeroSmsApiKey,
|
||||
inputHeroSmsMinPrice,
|
||||
get latestState() { return latestState; },
|
||||
get savedPayload() { return savedPayload; },
|
||||
switchPhoneSmsProvider,
|
||||
@@ -1055,7 +1067,10 @@ return {
|
||||
assert.equal(api.latestState.phoneSmsProvider, '5sim');
|
||||
assert.equal(api.latestState.heroSmsApiKey, 'hero-live');
|
||||
assert.equal(api.latestState.fiveSimApiKey, 'five-old');
|
||||
assert.equal(api.latestState.heroSmsMinPrice, '0.03');
|
||||
assert.equal(api.latestState.fiveSimMinPrice, '0.88');
|
||||
assert.equal(api.inputHeroSmsApiKey.value, 'five-old');
|
||||
assert.equal(api.inputHeroSmsMinPrice.value, '0.88');
|
||||
assert.equal(api.selectPhoneSmsProvider.dataset.activeProvider, '5sim');
|
||||
|
||||
api.inputHeroSmsApiKey.value = 'five-live';
|
||||
@@ -1065,10 +1080,15 @@ return {
|
||||
assert.equal(api.latestState.phoneSmsProvider, 'hero-sms');
|
||||
assert.equal(api.latestState.heroSmsApiKey, 'hero-live');
|
||||
assert.equal(api.latestState.fiveSimApiKey, 'five-live');
|
||||
assert.equal(api.latestState.heroSmsMinPrice, '0.03');
|
||||
assert.equal(api.latestState.fiveSimMinPrice, '0.88');
|
||||
assert.equal(api.inputHeroSmsApiKey.value, 'hero-live');
|
||||
assert.equal(api.inputHeroSmsMinPrice.value, '0.03');
|
||||
assert.equal(api.selectPhoneSmsProvider.dataset.activeProvider, 'hero-sms');
|
||||
assert.equal(api.savedPayload.heroSmsApiKey, 'hero-live');
|
||||
assert.equal(api.savedPayload.fiveSimApiKey, 'five-live');
|
||||
assert.equal(api.savedPayload.heroSmsMinPrice, '0.03');
|
||||
assert.equal(api.savedPayload.fiveSimMinPrice, '0.88');
|
||||
});
|
||||
|
||||
test('formatPhoneSmsPriceEntriesSummary treats HeroSMS physicalCount=0 as out of stock even when count is positive', () => {
|
||||
@@ -1107,6 +1127,7 @@ const DEFAULT_FIVE_SIM_PRODUCT = 'openai';
|
||||
const FIVE_SIM_SUPPORTED_COUNTRY_ID_SET = new Set(['indonesia', 'thailand', 'vietnam']);
|
||||
const HERO_SMS_SUPPORTED_COUNTRY_ID_SET = new Set(['6', '52', '10']);
|
||||
const inputHeroSmsMaxPrice = { value: '' };
|
||||
const inputHeroSmsMinPrice = { value: '0.1' };
|
||||
const inputHeroSmsApiKey = { value: '' };
|
||||
const inputFiveSimOperator = { value: 'any' };
|
||||
const inputFiveSimProduct = { value: 'openai' };
|
||||
@@ -1126,6 +1147,7 @@ ${extractFunction('normalizeFiveSimCountryCode')}
|
||||
${extractFunction('normalizeFiveSimProductValue')}
|
||||
${extractFunction('normalizeFiveSimOperator')}
|
||||
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
||||
${extractFunction('normalizeFiveSimMaxPriceValue')}
|
||||
${extractFunction('normalizeHeroSmsMaxPriceValue')}
|
||||
${extractFunction('normalizeHeroSmsPriceForPreview')}
|
||||
@@ -1135,6 +1157,12 @@ ${extractFunction('collectHeroSmsPriceEntriesForPreview')}
|
||||
${extractFunction('formatPhoneSmsPriceEntriesSummary')}
|
||||
${extractFunction('describeHeroSmsPreviewPayload')}
|
||||
${extractFunction('summarizeHeroSmsPreviewError')}
|
||||
${extractFunction('resolvePhoneSmsPricePreviewRange')}
|
||||
${extractFunction('isPhoneSmsPriceWithinPreviewRange')}
|
||||
${extractFunction('filterPhoneSmsPriceEntriesForPreviewRange')}
|
||||
${extractFunction('filterPhoneSmsPriceValuesForPreviewRange')}
|
||||
${extractFunction('formatPhoneSmsPriceRangePreviewText')}
|
||||
${extractFunction('buildPhoneSmsPriceRangePreviewMessage')}
|
||||
${extractFunction('formatPriceTiersForPreview')}
|
||||
${extractFunction('formatPriceTiersWithZeroStockForPreview')}
|
||||
function normalizeHeroSmsFetchErrorMessage(error) { return error?.message || String(error); }
|
||||
@@ -1193,7 +1221,7 @@ return {
|
||||
|
||||
assert.equal(
|
||||
api.displayHeroSmsPriceTiers.textContent,
|
||||
'5sim:\n越南 (Vietnam): 最低 0.1282;档位:0.0769(x0), 0.1282(x4608)'
|
||||
'5sim:\n越南 (Vietnam): 区间内最低 0.1282;档位:0.1282(x4608)'
|
||||
);
|
||||
assert.equal(api.rowHeroSmsPriceTiers.style.display, '');
|
||||
assert.deepStrictEqual(
|
||||
@@ -1211,4 +1239,12 @@ test('hero sms max price input does not auto-save partial typing states', () =>
|
||||
sidepanelSource,
|
||||
/inputHeroSmsMaxPrice\?\.\s*addEventListener\('input',\s*\(\)\s*=>\s*\{\s*markSettingsDirty\(true\);\s*scheduleSettingsAutoSave\(\);/
|
||||
);
|
||||
assert.match(
|
||||
sidepanelSource,
|
||||
/inputHeroSmsMinPrice\?\.\s*addEventListener\('input',\s*\(\)\s*=>\s*\{\s*markSettingsDirty\(true\);\s*\}\);/
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
sidepanelSource,
|
||||
/inputHeroSmsMinPrice\?\.\s*addEventListener\('input',\s*\(\)\s*=>\s*\{\s*markSettingsDirty\(true\);\s*scheduleSettingsAutoSave\(\);/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user