feat: add smsbower phone fill tool with rotation
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
function load(extra = {}) {
|
||||
const sandbox = {
|
||||
chrome: {
|
||||
action: { onClicked: { addListener() {} } },
|
||||
tabs: { async sendMessage() {} },
|
||||
scripting: { async executeScript() {} },
|
||||
runtime: { onMessage: { addListener() {} } },
|
||||
storage: { local: { async get() { return {}; }, async set() {} } }
|
||||
},
|
||||
fetch: async () => { throw new Error('not mocked'); },
|
||||
URL,
|
||||
console,
|
||||
Date,
|
||||
Number,
|
||||
String,
|
||||
Object,
|
||||
Array,
|
||||
RegExp,
|
||||
Math,
|
||||
JSON,
|
||||
Set,
|
||||
...extra,
|
||||
};
|
||||
const fn = new Function('globalThis', 'self', `with (globalThis) { ${source}; return { collectPriceEntries, filterPriceEntries, normalizeActivation, extractVerificationCode, isPhoneNumberUsedError, isPhoneNumberDeliveryRefusedError, getPhoneReplacementReleaseAction, fetchNextPhone, normalizeSettings }; }`);
|
||||
return fn(sandbox, sandbox);
|
||||
}
|
||||
test('collectPriceEntries parses keyed price inventory', () => {
|
||||
const api = load();
|
||||
const entries = api.collectPriceEntries({ 6: { dr: { '0.12': { count: 3 }, '0.20': { count: 0 } } } });
|
||||
assert.deepEqual(entries.filter((x) => x.inStock).map((x) => x.cost), [0.12]);
|
||||
});
|
||||
test('filterPriceEntries respects min and max', () => {
|
||||
const api = load();
|
||||
const entries = [{ cost: 0.05, inStock: true }, { cost: 0.15, inStock: true }, { cost: 0.3, inStock: true }];
|
||||
assert.deepEqual(api.filterPriceEntries(entries, { minPrice: '0.1', maxPrice: '0.2' }).map((x) => x.cost), [0.15]);
|
||||
});
|
||||
test('normalizeActivation parses ACCESS_NUMBER response', () => {
|
||||
const api = load();
|
||||
const activation = api.normalizeActivation('ACCESS_NUMBER:12345:628123456789', { countryId: 6, countryLabel: 'Indonesia' });
|
||||
assert.equal(activation.activationId, '12345');
|
||||
assert.equal(activation.phoneNumber, '628123456789');
|
||||
assert.equal(activation.countryLabel, 'Indonesia');
|
||||
});
|
||||
test('extractVerificationCode parses STATUS_OK response', () => {
|
||||
const api = load();
|
||||
assert.equal(api.extractVerificationCode('STATUS_OK: Your code is 654321'), '654321');
|
||||
assert.equal(api.extractVerificationCode('STATUS_OK:987654'), '987654');
|
||||
});
|
||||
test('FlowPilot-style phone failure classifiers choose release action', () => {
|
||||
const api = load();
|
||||
assert.equal(api.isPhoneNumberUsedError('该电话已被使用,请换一个号码'), true);
|
||||
assert.equal(api.isPhoneNumberDeliveryRefusedError('无法向此电话号码发送验证码'), true);
|
||||
assert.equal(api.getPhoneReplacementReleaseAction('phone_number_used'), 'ban');
|
||||
assert.equal(api.getPhoneReplacementReleaseAction('phone_delivery_refused'), 'cancel');
|
||||
});
|
||||
test('fetchNextPhone releases previous activation then acquires replacement', async () => {
|
||||
const requests = [];
|
||||
const stored = {
|
||||
apiKey: 'demo-key',
|
||||
baseUrl: 'https://smsbower.app/stubs/handler_api.php',
|
||||
serviceCode: 'dr',
|
||||
minPrice: '0.1',
|
||||
maxPrice: '0.3',
|
||||
countries: [{ id: 6, label: 'Indonesia' }],
|
||||
activeActivation: { activationId: 'old-activation', phoneNumber: '628111', countryId: 6 },
|
||||
};
|
||||
const api = load({
|
||||
chrome: {
|
||||
action: { onClicked: { addListener() {} } },
|
||||
tabs: { async sendMessage() {} },
|
||||
scripting: { async executeScript() {} },
|
||||
runtime: { onMessage: { addListener() {} } },
|
||||
storage: { local: { async get() { return stored; }, async set(update) { Object.assign(stored, update); } } }
|
||||
},
|
||||
fetch: async (url) => {
|
||||
const parsed = new URL(url);
|
||||
const action = parsed.searchParams.get('action');
|
||||
requests.push([action, parsed.searchParams.get('id'), parsed.searchParams.get('status'), parsed.searchParams.get('country')]);
|
||||
if (action === 'setStatus') return new Response('ACCESS_CANCEL', { status: 200 });
|
||||
if (action === 'getPricesV3') return new Response(JSON.stringify({ 6: { dr: { '0.2': { count: 2 } } } }), { status: 200 });
|
||||
if (action === 'getNumberV2') return new Response(JSON.stringify({ activationId: 'new-activation', phoneNumber: '628222', countryCode: 6 }), { status: 200 });
|
||||
throw new Error(`unexpected ${url}`);
|
||||
},
|
||||
Response,
|
||||
});
|
||||
const result = await api.fetchNextPhone({ reason: 'phone_number_used', releaseAction: 'ban' });
|
||||
assert.equal(result.activation.activationId, 'new-activation');
|
||||
assert.equal(result.releasePrevious.releaseAction, 'ban');
|
||||
assert.equal(stored.activeActivation.previousActivationId, 'old-activation');
|
||||
assert.deepEqual(requests, [
|
||||
['setStatus', 'old-activation', '8', null],
|
||||
['getPricesV3', null, null, '6'],
|
||||
['getNumberV2', null, null, '6'],
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user