Fix PayPal hosted checkout flow
This commit is contained in:
@@ -127,6 +127,35 @@ return { shouldReportReadyForFrame };
|
||||
assert.equal(api.shouldReportReadyForFrame('unknown-source', true), false);
|
||||
});
|
||||
|
||||
test('simulateClick logs the button text captured before click side effects', () => {
|
||||
const bundle = [extractFunction('simulateClick')].join('\n');
|
||||
const logs = [];
|
||||
const consoleMessages = [];
|
||||
const api = new Function('logs', 'console', 'location', `
|
||||
function throwIfStopped() {}
|
||||
const LOG_PREFIX = '[test]';
|
||||
function log(message) { logs.push(message); }
|
||||
${bundle}
|
||||
return { simulateClick };
|
||||
`)(logs, { log: (...args) => consoleMessages.push(args.join(' ')) }, { pathname: '/checkout' });
|
||||
|
||||
const button = {
|
||||
tagName: 'BUTTON',
|
||||
textContent: '订阅',
|
||||
getAttribute: () => '',
|
||||
click() {
|
||||
this.textContent = '正在处理';
|
||||
},
|
||||
};
|
||||
|
||||
api.simulateClick(button);
|
||||
|
||||
assert.equal(button.textContent, '正在处理');
|
||||
assert.equal(logs.at(-1), '已点击(click) [BUTTON] "订阅"');
|
||||
assert.match(consoleMessages.at(-1), /BUTTON 订阅/);
|
||||
assert.doesNotMatch(logs.at(-1), /正在处理/);
|
||||
});
|
||||
|
||||
test('getRuntimeScriptSource follows injected source overrides after utils is already loaded', () => {
|
||||
const bundle = [extractFunction('getRuntimeScriptSource')].join('\n');
|
||||
const api = new Function('window', 'SCRIPT_SOURCE', `
|
||||
|
||||
@@ -494,6 +494,66 @@ test('PayPal no-card binding OpenAI checkout node submits hosted page and comple
|
||||
});
|
||||
});
|
||||
|
||||
test('PayPal hosted email node completes when Next navigation drops the content response', async () => {
|
||||
const events = [];
|
||||
let currentUrl = 'https://www.paypal.com/checkoutweb/pay?token=EC-test';
|
||||
const executor = api.createPlusCheckoutCreateExecutor({
|
||||
addLog: async (message, level = 'info', options = {}) => events.push({ type: 'log', message, level, options }),
|
||||
chrome: {
|
||||
tabs: {
|
||||
get: async (tabId) => ({ id: tabId, url: currentUrl, status: 'complete' }),
|
||||
},
|
||||
},
|
||||
completeNodeFromBackground: async (step, payload) => events.push({ type: 'complete', step, payload }),
|
||||
ensureContentScriptReadyOnTabUntilStopped: async (source, tabId, options) => events.push({ type: 'ready', source, tabId, options }),
|
||||
getState: async () => ({
|
||||
hostedCheckoutPhoneNumber: '(415) 555-1234',
|
||||
}),
|
||||
registerTab: async (source, tabId) => events.push({ type: 'register', source, tabId }),
|
||||
sendTabMessageUntilStopped: async (tabId, source, message) => {
|
||||
events.push({ type: 'tab-message', tabId, source, message });
|
||||
if (message.type === 'PAYPAL_RUN_HOSTED_CHECKOUT_STEP') {
|
||||
currentUrl = 'https://www.paypal.com/checkoutweb/signup?ba_token=BA-test&token=EC-test';
|
||||
return new Promise(() => {});
|
||||
}
|
||||
if (message.type === 'PAYPAL_HOSTED_GET_STATE') {
|
||||
return {
|
||||
hostedStage: currentUrl.includes('/signup')
|
||||
? 'guest_checkout'
|
||||
: 'pay_login',
|
||||
};
|
||||
}
|
||||
throw new Error(`unexpected message type ${message.type}`);
|
||||
},
|
||||
setState: async (payload) => events.push({ type: 'set-state', payload }),
|
||||
sleepWithStop: async (ms) => events.push({ type: 'sleep', ms }),
|
||||
waitForTabCompleteUntilStopped: async () => events.push({ type: 'tab-complete' }),
|
||||
});
|
||||
|
||||
await executor.executePayPalHostedEmail({
|
||||
plusCheckoutTabId: 85661333,
|
||||
plusHostedCheckoutGuestProfile: {
|
||||
email: 'guest@example.com',
|
||||
phone: '4155551234',
|
||||
address: { street: '1 Main St', city: 'New York', state: 'New York', zip: '10001' },
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(currentUrl.includes('/signup'), true);
|
||||
assert.equal(
|
||||
events.some((event) => event.type === 'complete' && event.step === 'paypal-hosted-email'),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
events.some((event) => event.type === 'log' && /已检测到 PayPal 进入后续页面(guest_checkout)/.test(event.message)),
|
||||
true
|
||||
);
|
||||
assert.equal(
|
||||
events.some((event) => event.type === 'tab-message' && event.message.type === 'PAYPAL_RUN_HOSTED_CHECKOUT_STEP'),
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test('Plus checkout content routes billing operations through the operation delay gate', async () => {
|
||||
const { checkoutEvents, send } = createCheckoutContentHarness();
|
||||
|
||||
|
||||
@@ -222,7 +222,6 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
|
||||
'fill-profile',
|
||||
'plus-checkout-create',
|
||||
'paypal-hosted-email',
|
||||
'paypal-hosted-verification',
|
||||
'paypal-hosted-card',
|
||||
'paypal-hosted-create-account',
|
||||
'paypal-hosted-review',
|
||||
@@ -236,9 +235,10 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
|
||||
assert.equal(hostedSteps.some((step) => step.key === 'paypal-approve'), false);
|
||||
assert.equal(hostedSteps.some((step) => step.key === 'plus-checkout-return'), false);
|
||||
assert.equal(hostedSteps.some((step) => step.key === 'paypal-hosted-openai-checkout'), false);
|
||||
assert.equal(hostedSteps.some((step) => step.key === 'paypal-hosted-verification'), false);
|
||||
assert.equal(hostedSteps.find((step) => step.key === 'paypal-hosted-card')?.title, '无卡直绑填写 PayPal 资料');
|
||||
assert.deepStrictEqual(api.getStepIds({ plusModeEnabled: true, plusPaymentMethod: 'paypal-hosted' }), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
|
||||
assert.equal(api.getLastStepId({ plusModeEnabled: true, plusPaymentMethod: 'paypal-hosted' }), 15);
|
||||
assert.deepStrictEqual(api.getStepIds({ plusModeEnabled: true, plusPaymentMethod: 'paypal-hosted' }), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]);
|
||||
assert.equal(api.getLastStepId({ plusModeEnabled: true, plusPaymentMethod: 'paypal-hosted' }), 14);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
goPaySteps.map((step) => step.key),
|
||||
@@ -316,7 +316,7 @@ test('Plus session strategy swaps the OAuth tail for a single SUB2API import nod
|
||||
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||
},
|
||||
previousNodeId: 'paypal-hosted-review',
|
||||
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||
},
|
||||
{
|
||||
label: 'gopay',
|
||||
@@ -407,7 +407,7 @@ test('Plus session strategy swaps the OAuth tail for a single CPA import node',
|
||||
plusAccountAccessStrategy: 'cpa_codex_session',
|
||||
},
|
||||
previousNodeId: 'paypal-hosted-review',
|
||||
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||
},
|
||||
{
|
||||
label: 'gopay',
|
||||
|
||||
Reference in New Issue
Block a user