fix(flow): harden proxy phone and checkout recovery paths
This commit is contained in:
@@ -50,6 +50,20 @@ function createIdAddressSeed() {
|
||||
};
|
||||
}
|
||||
|
||||
function createKrAddressSeed() {
|
||||
return {
|
||||
countryCode: 'KR',
|
||||
query: 'Seoul Jung-gu',
|
||||
suggestionIndex: 1,
|
||||
fallback: {
|
||||
address1: 'Sejong-daero 110',
|
||||
city: 'Jung-gu',
|
||||
region: 'Seoul',
|
||||
postalCode: '04524',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createSuccessfulBillingResult() {
|
||||
return {
|
||||
countryText: 'Germany',
|
||||
@@ -68,6 +82,7 @@ function createExecutorHarness({
|
||||
fetchImpl = null,
|
||||
getAddressSeedForCountry = () => createAddressSeed(),
|
||||
markCurrentRegistrationAccountUsed = async () => {},
|
||||
probeIpProxyExit = null,
|
||||
submitRedirectUrl = 'https://www.paypal.com/checkoutnow',
|
||||
}) {
|
||||
const api = loadPlusCheckoutBillingModule();
|
||||
@@ -149,6 +164,7 @@ function createExecutorHarness({
|
||||
assert.equal(matcher(submitRedirectUrl), true);
|
||||
return { id: tabId, url: submitRedirectUrl };
|
||||
},
|
||||
...(typeof probeIpProxyExit === 'function' ? { probeIpProxyExit } : {}),
|
||||
});
|
||||
|
||||
return { checkoutTab, events, executor };
|
||||
@@ -240,7 +256,7 @@ test('Plus checkout billing sends the billing command to the iframe that contain
|
||||
assert.equal(events.completed[0].step, 7);
|
||||
});
|
||||
|
||||
test('Plus checkout billing forces Indonesia address for GoPay even when page country differs', async () => {
|
||||
test('Plus checkout billing uses proxy exit country for GoPay address when available', async () => {
|
||||
const requestedCountries = [];
|
||||
const fetchRequests = [];
|
||||
const { events, executor } = createExecutorHarness({
|
||||
@@ -263,7 +279,17 @@ test('Plus checkout billing forces Indonesia address for GoPay even when page co
|
||||
},
|
||||
getAddressSeedForCountry: (countryValue) => {
|
||||
requestedCountries.push(countryValue);
|
||||
return countryValue === 'ID' ? createIdAddressSeed() : createAddressSeed();
|
||||
return countryValue === 'JP' ? {
|
||||
countryCode: 'JP',
|
||||
query: 'Tokyo Marunouchi',
|
||||
suggestionIndex: 1,
|
||||
fallback: {
|
||||
address1: 'Marunouchi 1-1',
|
||||
city: 'Chiyoda-ku',
|
||||
region: 'Tokyo',
|
||||
postalCode: '100-0005',
|
||||
},
|
||||
} : createIdAddressSeed();
|
||||
},
|
||||
fetchImpl: async (url, init) => {
|
||||
fetchRequests.push({ url, init });
|
||||
@@ -273,10 +299,11 @@ test('Plus checkout billing forces Indonesia address for GoPay even when page co
|
||||
json: async () => ({
|
||||
status: 'ok',
|
||||
address: {
|
||||
Address: 'Jl. M.H. Thamrin No. 10',
|
||||
City: 'Jakarta',
|
||||
State: 'DKI Jakarta',
|
||||
Zip_Code: '10310',
|
||||
Address: 'トウキョウト, チヨダク, マルノウチ, 1-1',
|
||||
Trans_Address: 'Marunouchi 1-1, Chiyoda-ku, Tokyo',
|
||||
City: 'Tokyo',
|
||||
State: 'Tokyo',
|
||||
Zip_Code: '100-0005',
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -284,17 +311,206 @@ test('Plus checkout billing forces Indonesia address for GoPay even when page co
|
||||
submitRedirectUrl: 'https://app.midtrans.com/snap/v4/redirection/session#/gopay-tokenization/linking',
|
||||
});
|
||||
|
||||
await executor.executePlusCheckoutBilling({ plusPaymentMethod: 'gopay', plusCheckoutCountry: 'US' });
|
||||
await executor.executePlusCheckoutBilling({
|
||||
plusPaymentMethod: 'gopay',
|
||||
plusCheckoutCountry: 'ID',
|
||||
ipProxyAppliedExitRegion: 'JP',
|
||||
});
|
||||
|
||||
const fillMessage = events.messages.find((entry) => entry.message.type === 'PLUS_CHECKOUT_FILL_BILLING_ADDRESS');
|
||||
assert.equal(requestedCountries[0], 'ID');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.countryCode, 'ID');
|
||||
assert.equal(requestedCountries[0], 'JP');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.countryCode, 'JP');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.source, 'meiguodizhi');
|
||||
assert.deepEqual(JSON.parse(fetchRequests[0].init.body), {
|
||||
city: 'Jakarta',
|
||||
path: '/id-address',
|
||||
city: 'Chiyoda-ku',
|
||||
path: '/jp-address',
|
||||
method: 'refresh',
|
||||
});
|
||||
assert.equal(events.logs.some((entry) => /GoPay 账单地址将按当前代理出口地区 JP/.test(entry.message)), true);
|
||||
});
|
||||
|
||||
test('Plus checkout billing refreshes stale GoPay proxy country before filling address', async () => {
|
||||
const requestedCountries = [];
|
||||
const probeCalls = [];
|
||||
const { events, executor } = createExecutorHarness({
|
||||
frames: [
|
||||
{ frameId: 0, url: 'https://chatgpt.com/checkout/openai_llc/cs_test' },
|
||||
{ frameId: 7, url: 'https://js.stripe.com/v3/elements-inner-payment.html' },
|
||||
{ frameId: 8, url: 'https://js.stripe.com/v3/elements-inner-address.html' },
|
||||
],
|
||||
stateByFrame: {
|
||||
0: { hasPayPal: false, hasGoPay: false, paypalCandidates: [], gopayCandidates: [], hasSubscribeButton: true },
|
||||
7: { hasPayPal: false, hasGoPay: true, gopayCandidates: [{ tag: 'button', text: 'GoPay' }] },
|
||||
8: {
|
||||
hasPayPal: false,
|
||||
hasGoPay: false,
|
||||
paypalCandidates: [],
|
||||
gopayCandidates: [],
|
||||
billingFieldsVisible: true,
|
||||
countryText: 'Indonesia',
|
||||
},
|
||||
},
|
||||
getAddressSeedForCountry: (countryValue) => {
|
||||
requestedCountries.push(countryValue);
|
||||
return countryValue === 'JP' ? {
|
||||
countryCode: 'JP',
|
||||
query: 'Tokyo Chiyoda-ku',
|
||||
suggestionIndex: 1,
|
||||
fallback: {
|
||||
address1: 'Marunouchi 1-1',
|
||||
city: 'Chiyoda-ku',
|
||||
region: 'Tokyo',
|
||||
postalCode: '100-0005',
|
||||
},
|
||||
} : createKrAddressSeed();
|
||||
},
|
||||
fetchImpl: async () => ({
|
||||
ok: false,
|
||||
status: 503,
|
||||
json: async () => ({ status: 'error' }),
|
||||
}),
|
||||
probeIpProxyExit: async (options) => {
|
||||
probeCalls.push(options);
|
||||
return {
|
||||
proxyRouting: {
|
||||
exitRegion: 'JP',
|
||||
exitIp: '203.0.113.8',
|
||||
exitSource: 'page_context',
|
||||
exitEndpoint: 'https://ipinfo.io/json',
|
||||
},
|
||||
};
|
||||
},
|
||||
submitRedirectUrl: 'https://app.midtrans.com/snap/v4/redirection/session#/gopay-tokenization/linking',
|
||||
});
|
||||
|
||||
await executor.executePlusCheckoutBilling({
|
||||
plusPaymentMethod: 'gopay',
|
||||
plusCheckoutCountry: 'ID',
|
||||
ipProxyAppliedExitRegion: 'KR',
|
||||
});
|
||||
|
||||
const fillMessage = events.messages.find((entry) => entry.message.type === 'PLUS_CHECKOUT_FILL_BILLING_ADDRESS');
|
||||
assert.equal(probeCalls.length, 1);
|
||||
assert.equal(probeCalls[0].detectWhenDisabled, true);
|
||||
assert.equal(requestedCountries[0], 'JP');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.countryCode, 'JP');
|
||||
assert.equal(events.logs.some((entry) => entry.message.includes('当前代理出口复测结果:JP / 203.0.113.8')), true);
|
||||
assert.equal(events.logs.some((entry) => /GoPay 账单地址将按当前代理出口地区 JP/.test(entry.message)), true);
|
||||
assert.equal(events.logs.some((entry) => /GoPay 账单地址将按当前代理出口地区 KR/.test(entry.message)), false);
|
||||
});
|
||||
|
||||
test('Plus checkout billing refuses to reuse stale GoPay proxy country when refresh has no region', async () => {
|
||||
const requestedCountries = [];
|
||||
const { events, executor } = createExecutorHarness({
|
||||
frames: [
|
||||
{ frameId: 0, url: 'https://chatgpt.com/checkout/openai_llc/cs_test' },
|
||||
{ frameId: 7, url: 'https://js.stripe.com/v3/elements-inner-payment.html' },
|
||||
{ frameId: 8, url: 'https://js.stripe.com/v3/elements-inner-address.html' },
|
||||
],
|
||||
stateByFrame: {
|
||||
0: { hasPayPal: false, hasGoPay: false, paypalCandidates: [], gopayCandidates: [], hasSubscribeButton: true },
|
||||
7: { hasPayPal: false, hasGoPay: true, gopayCandidates: [{ tag: 'button', text: 'GoPay' }] },
|
||||
8: {
|
||||
hasPayPal: false,
|
||||
hasGoPay: false,
|
||||
paypalCandidates: [],
|
||||
gopayCandidates: [],
|
||||
billingFieldsVisible: true,
|
||||
countryText: 'Indonesia',
|
||||
},
|
||||
},
|
||||
getAddressSeedForCountry: (countryValue) => {
|
||||
requestedCountries.push(countryValue);
|
||||
return createKrAddressSeed();
|
||||
},
|
||||
probeIpProxyExit: async () => ({
|
||||
proxyRouting: {
|
||||
reason: 'disabled_probe_only',
|
||||
exitIp: '203.0.113.9',
|
||||
exitRegion: '',
|
||||
exitError: 'missing_region',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
() => executor.executePlusCheckoutBilling({
|
||||
plusPaymentMethod: 'gopay',
|
||||
plusCheckoutCountry: 'ID',
|
||||
ipProxyAppliedExitRegion: 'KR',
|
||||
}),
|
||||
/本次复测没有拿到国家码/
|
||||
);
|
||||
|
||||
assert.equal(requestedCountries.length, 0);
|
||||
assert.equal(events.logs.some((entry) => /已清空旧出口地区 KR/.test(entry.message)), true);
|
||||
assert.equal(events.logs.some((entry) => /GoPay 账单地址将按当前代理出口地区 KR/.test(entry.message)), false);
|
||||
});
|
||||
|
||||
test('Plus checkout billing normalizes legacy Korean postal code for GoPay address', async () => {
|
||||
const requestedCountries = [];
|
||||
const fetchRequests = [];
|
||||
const { events, executor } = createExecutorHarness({
|
||||
frames: [
|
||||
{ frameId: 0, url: 'https://chatgpt.com/checkout/openai_llc/cs_test' },
|
||||
{ frameId: 7, url: 'https://js.stripe.com/v3/elements-inner-payment.html' },
|
||||
{ frameId: 8, url: 'https://js.stripe.com/v3/elements-inner-address.html' },
|
||||
],
|
||||
stateByFrame: {
|
||||
0: { hasPayPal: false, hasGoPay: false, paypalCandidates: [], gopayCandidates: [], hasSubscribeButton: true },
|
||||
7: { hasPayPal: false, hasGoPay: true, gopayCandidates: [{ tag: 'button', text: 'GoPay' }] },
|
||||
8: {
|
||||
hasPayPal: false,
|
||||
hasGoPay: false,
|
||||
paypalCandidates: [],
|
||||
gopayCandidates: [],
|
||||
billingFieldsVisible: true,
|
||||
countryText: 'United States',
|
||||
},
|
||||
},
|
||||
getAddressSeedForCountry: (countryValue) => {
|
||||
requestedCountries.push(countryValue);
|
||||
return countryValue === 'KR' ? createKrAddressSeed() : createIdAddressSeed();
|
||||
},
|
||||
fetchImpl: async (url, init) => {
|
||||
fetchRequests.push({ url, init });
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
status: 'ok',
|
||||
address: {
|
||||
Address: '서울특별시 중구 세종대로 110',
|
||||
Trans_Address: 'Sejong-daero 110, Jung-gu, Seoul',
|
||||
City: 'Jung-gu',
|
||||
State: 'Seoul',
|
||||
Zip_Code: '150-300',
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
submitRedirectUrl: 'https://app.midtrans.com/snap/v4/redirection/session#/gopay-tokenization/linking',
|
||||
});
|
||||
|
||||
await executor.executePlusCheckoutBilling({
|
||||
plusPaymentMethod: 'gopay',
|
||||
plusCheckoutCountry: 'ID',
|
||||
ipProxyAppliedExitRegion: 'KR',
|
||||
});
|
||||
|
||||
const fillMessage = events.messages.find((entry) => entry.message.type === 'PLUS_CHECKOUT_FILL_BILLING_ADDRESS');
|
||||
assert.equal(requestedCountries[0], 'KR');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.countryCode, 'KR');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.source, 'meiguodizhi');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.fallback.address1, 'Sejong-daero 110, Jung-gu, Seoul');
|
||||
assert.equal(fillMessage.message.payload.addressSeed.fallback.postalCode, '04524');
|
||||
assert.match(fillMessage.message.payload.addressSeed.fallback.postalCode, /^\d{5}$/);
|
||||
assert.deepEqual(JSON.parse(fetchRequests[0].init.body), {
|
||||
city: 'Jung-gu',
|
||||
path: '/kr-address',
|
||||
method: 'refresh',
|
||||
});
|
||||
assert.equal(events.logs.some((entry) => /GoPay 账单地址将按当前代理出口地区 KR/.test(entry.message)), true);
|
||||
});
|
||||
|
||||
test('Plus checkout billing selects GoPay and waits for a GoPay redirect', async () => {
|
||||
|
||||
Reference in New Issue
Block a user