fix: keep GPC card mode during plus billing
This commit is contained in:
@@ -1396,6 +1396,69 @@ function FindProxyForURL(url, host) {
|
|||||||
}
|
}
|
||||||
await waitForTabCompleteUntilStopped(tabId);
|
await waitForTabCompleteUntilStopped(tabId);
|
||||||
await sleepWithStop(800);
|
await sleepWithStop(800);
|
||||||
|
|
||||||
|
const ensureCardMode = async () => {
|
||||||
|
const results = await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
func: () => {
|
||||||
|
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
||||||
|
const isVisible = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const style = window.getComputedStyle ? window.getComputedStyle(element) : null;
|
||||||
|
if (style && (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const rect = typeof element.getBoundingClientRect === 'function' ? element.getBoundingClientRect() : null;
|
||||||
|
return !rect || rect.width > 0 || rect.height > 0;
|
||||||
|
};
|
||||||
|
const hasActiveMarker = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const markerText = [
|
||||||
|
element.className,
|
||||||
|
element.getAttribute?.('class'),
|
||||||
|
element.getAttribute?.('aria-selected'),
|
||||||
|
element.getAttribute?.('aria-pressed'),
|
||||||
|
element.getAttribute?.('data-state'),
|
||||||
|
element.getAttribute?.('data-active'),
|
||||||
|
].join(' ');
|
||||||
|
return /\b(active|selected|current|checked|on|true)\b/i.test(markerText);
|
||||||
|
};
|
||||||
|
const candidates = Array.from(document.querySelectorAll('button, [role="button"], .design-mode-card, .mode-card, [class*="mode"]'));
|
||||||
|
const cardModeButton = candidates.find((element) => /卡密充值/.test(textOf(element)));
|
||||||
|
const freeModeButton = candidates.find((element) => /免费充值/.test(textOf(element)));
|
||||||
|
const visibleCardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'))
|
||||||
|
.filter(isVisible);
|
||||||
|
const isCardModeActive = Boolean(cardModeButton && hasActiveMarker(cardModeButton))
|
||||||
|
|| (visibleCardInputs.length > 0 && !(freeModeButton && hasActiveMarker(freeModeButton)));
|
||||||
|
if (cardModeButton && !isCardModeActive) {
|
||||||
|
cardModeButton.scrollIntoView?.({ block: 'center', inline: 'center' });
|
||||||
|
cardModeButton.click?.();
|
||||||
|
return {
|
||||||
|
hasCardMode: true,
|
||||||
|
clickedCardMode: true,
|
||||||
|
isCardModeActive: false,
|
||||||
|
activeModeText: textOf(cardModeButton),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
hasCardMode: Boolean(cardModeButton),
|
||||||
|
clickedCardMode: false,
|
||||||
|
isCardModeActive,
|
||||||
|
activeModeText: textOf(isCardModeActive ? cardModeButton : freeModeButton),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return results?.[0]?.result || {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const modeResult = await ensureCardMode();
|
||||||
|
if (!modeResult.hasCardMode) {
|
||||||
|
throw new Error('步骤 6:未找到 GPC“卡密充值”模式入口。');
|
||||||
|
}
|
||||||
|
if (modeResult.clickedCardMode) {
|
||||||
|
await sleepWithStop(600);
|
||||||
|
}
|
||||||
|
|
||||||
const results = await chrome.scripting.executeScript({
|
const results = await chrome.scripting.executeScript({
|
||||||
target: { tabId },
|
target: { tabId },
|
||||||
func: (rawCardKey, rawSessionJson) => {
|
func: (rawCardKey, rawSessionJson) => {
|
||||||
@@ -1416,17 +1479,21 @@ function FindProxyForURL(url, host) {
|
|||||||
element.dispatchEvent?.(new Event('change', { bubbles: true }));
|
element.dispatchEvent?.(new Event('change', { bubbles: true }));
|
||||||
element.blur?.();
|
element.blur?.();
|
||||||
};
|
};
|
||||||
const clickElement = (element) => {
|
const hasActiveMarker = (element) => {
|
||||||
element.scrollIntoView?.({ block: 'center', inline: 'center' });
|
if (!element) return false;
|
||||||
element.click?.();
|
const markerText = [
|
||||||
|
element.className,
|
||||||
|
element.getAttribute?.('class'),
|
||||||
|
element.getAttribute?.('aria-selected'),
|
||||||
|
element.getAttribute?.('aria-pressed'),
|
||||||
|
element.getAttribute?.('data-state'),
|
||||||
|
element.getAttribute?.('data-active'),
|
||||||
|
].join(' ');
|
||||||
|
return /\b(active|selected|current|checked|on|true)\b/i.test(markerText);
|
||||||
};
|
};
|
||||||
const modeButtons = Array.from(document.querySelectorAll('button, [role="button"], .design-mode-card, .mode-card'));
|
const modeButtons = Array.from(document.querySelectorAll('button, [role="button"], .design-mode-card, .mode-card'));
|
||||||
const cardModeButton = modeButtons.find((element) => /卡密充值/.test(textOf(element)));
|
const cardModeButton = modeButtons.find((element) => /卡密充值/.test(textOf(element)));
|
||||||
if (cardModeButton && !/\bactive\b/i.test(String(cardModeButton.className || ''))) {
|
const freeModeButton = modeButtons.find((element) => /免费充值/.test(textOf(element)));
|
||||||
clickElement(cardModeButton);
|
|
||||||
} else if (cardModeButton) {
|
|
||||||
clickElement(cardModeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
const compactCardKey = String(rawCardKey || '').trim().replace(/\s+/g, '');
|
const compactCardKey = String(rawCardKey || '').trim().replace(/\s+/g, '');
|
||||||
const explicitSegments = compactCardKey.includes('-') || compactCardKey.includes('_')
|
const explicitSegments = compactCardKey.includes('-') || compactCardKey.includes('_')
|
||||||
@@ -1437,11 +1504,14 @@ function FindProxyForURL(url, host) {
|
|||||||
: (compactCardKey.match(/.{1,8}/g) || []);
|
: (compactCardKey.match(/.{1,8}/g) || []);
|
||||||
const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'))
|
const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'))
|
||||||
.filter(isVisible);
|
.filter(isVisible);
|
||||||
|
const isCardModeActive = Boolean(cardModeButton && hasActiveMarker(cardModeButton))
|
||||||
|
|| (cardInputs.length > 0 && !(freeModeButton && hasActiveMarker(freeModeButton)));
|
||||||
cardInputs.forEach((input, index) => {
|
cardInputs.forEach((input, index) => {
|
||||||
dispatchInput(input, cardSegments[index] || '');
|
dispatchInput(input, cardSegments[index] || '');
|
||||||
});
|
});
|
||||||
|
let fallbackInput = null;
|
||||||
if (!cardInputs.length) {
|
if (!cardInputs.length) {
|
||||||
const fallbackInput = Array.from(document.querySelectorAll('input')).find((input) => /卡密|card/i.test([
|
fallbackInput = Array.from(document.querySelectorAll('input')).find((input) => /卡密|card/i.test([
|
||||||
input.placeholder,
|
input.placeholder,
|
||||||
input.name,
|
input.name,
|
||||||
input.id,
|
input.id,
|
||||||
@@ -1468,10 +1538,12 @@ function FindProxyForURL(url, host) {
|
|||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
cardInputCount: cardInputs.length,
|
cardInputCount: cardInputs.length,
|
||||||
|
cardFallbackFilled: Boolean(fallbackInput),
|
||||||
cardSegments: cardSegments.map((segment) => segment ? segment.length : 0),
|
cardSegments: cardSegments.map((segment) => segment ? segment.length : 0),
|
||||||
|
isCardModeActive,
|
||||||
sessionLength: String(sessionTextarea.value || '').length,
|
sessionLength: String(sessionTextarea.value || '').length,
|
||||||
startButtonText: textOf(startButton),
|
startButtonText: textOf(startButton),
|
||||||
activeModeText: textOf(cardModeButton),
|
activeModeText: textOf(isCardModeActive ? cardModeButton : freeModeButton),
|
||||||
url: location.href,
|
url: location.href,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -1481,6 +1553,9 @@ function FindProxyForURL(url, host) {
|
|||||||
if (!result?.ok) {
|
if (!result?.ok) {
|
||||||
throw new Error('步骤 6:GPC 页面准备失败。');
|
throw new Error('步骤 6:GPC 页面准备失败。');
|
||||||
}
|
}
|
||||||
|
if (!result.isCardModeActive || (!result.cardInputCount && !result.cardFallbackFilled)) {
|
||||||
|
throw new Error('步骤 6:GPC 页面未进入卡密充值模式,无法填写卡密。');
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,14 +197,41 @@
|
|||||||
target: { tabId },
|
target: { tabId },
|
||||||
func: () => {
|
func: () => {
|
||||||
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
||||||
|
const isVisible = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const style = window.getComputedStyle ? window.getComputedStyle(element) : null;
|
||||||
|
if (style && (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const rect = typeof element.getBoundingClientRect === 'function' ? element.getBoundingClientRect() : null;
|
||||||
|
return !rect || rect.width > 0 || rect.height > 0;
|
||||||
|
};
|
||||||
|
const hasActiveMarker = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const markerText = [
|
||||||
|
element.className,
|
||||||
|
element.getAttribute?.('class'),
|
||||||
|
element.getAttribute?.('aria-selected'),
|
||||||
|
element.getAttribute?.('aria-pressed'),
|
||||||
|
element.getAttribute?.('data-state'),
|
||||||
|
element.getAttribute?.('data-active'),
|
||||||
|
].join(' ');
|
||||||
|
return /\b(active|selected|current|checked|on|true)\b/i.test(markerText);
|
||||||
|
};
|
||||||
const buttons = Array.from(document.querySelectorAll('button, [role="button"]'));
|
const buttons = Array.from(document.querySelectorAll('button, [role="button"]'));
|
||||||
const startButton = buttons.find((button) => /开始\s*Plus\s*充值|任务进行中/.test(textOf(button)))
|
const startButton = buttons.find((button) => /开始\s*Plus\s*充值|任务进行中/.test(textOf(button)))
|
||||||
|| buttons.find((button) => /开始|任务/.test(textOf(button)));
|
|| buttons.find((button) => /开始|任务/.test(textOf(button)));
|
||||||
|
const modeButtons = Array.from(document.querySelectorAll('button, [role="button"], .design-mode-card, .mode-card, [class*="mode"]'));
|
||||||
|
const cardModeButton = modeButtons.find((element) => /卡密充值/.test(textOf(element)));
|
||||||
|
const freeModeButton = modeButtons.find((element) => /免费充值/.test(textOf(element)));
|
||||||
const bodyText = String(document.body?.innerText || document.documentElement?.innerText || '').replace(/\r/g, '');
|
const bodyText = String(document.body?.innerText || document.documentElement?.innerText || '').replace(/\r/g, '');
|
||||||
const logNodes = Array.from(document.querySelectorAll('[class*="log"], [id*="log"], .design-log, .logs, pre, code'));
|
const logNodes = Array.from(document.querySelectorAll('[class*="log"], [id*="log"], .design-log, .logs, pre, code'));
|
||||||
const logText = logNodes.map(textOf).filter(Boolean).join('\n') || bodyText;
|
const logText = logNodes.map(textOf).filter(Boolean).join('\n') || bodyText;
|
||||||
const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'));
|
const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'))
|
||||||
|
.filter(isVisible);
|
||||||
const sessionTextarea = document.querySelector('textarea.design-session-input') || document.querySelector('textarea');
|
const sessionTextarea = document.querySelector('textarea.design-session-input') || document.querySelector('textarea');
|
||||||
|
const isCardModeActive = Boolean(cardModeButton && hasActiveMarker(cardModeButton))
|
||||||
|
|| (cardInputs.length > 0 && !(freeModeButton && hasActiveMarker(freeModeButton)));
|
||||||
return {
|
return {
|
||||||
url: location.href,
|
url: location.href,
|
||||||
readyState: document.readyState,
|
readyState: document.readyState,
|
||||||
@@ -217,6 +244,74 @@
|
|||||||
hasStartButton: Boolean(startButton),
|
hasStartButton: Boolean(startButton),
|
||||||
cardKeyValue: cardInputs.map((input) => String(input.value || '')).join('-'),
|
cardKeyValue: cardInputs.map((input) => String(input.value || '')).join('-'),
|
||||||
sessionLength: String(sessionTextarea?.value || '').length,
|
sessionLength: String(sessionTextarea?.value || '').length,
|
||||||
|
hasCardMode: Boolean(cardModeButton),
|
||||||
|
hasFreeMode: Boolean(freeModeButton),
|
||||||
|
isCardModeActive,
|
||||||
|
activeModeText: textOf(isCardModeActive ? cardModeButton : freeModeButton),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return results?.[0]?.result || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureGpcCardMode(tabId) {
|
||||||
|
if (!chrome?.scripting?.executeScript) {
|
||||||
|
throw new Error('步骤 7:当前运行环境不支持脚本注入,无法切换 GPC 卡密充值模式。');
|
||||||
|
}
|
||||||
|
const results = await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
func: () => {
|
||||||
|
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
||||||
|
const isVisible = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const style = window.getComputedStyle ? window.getComputedStyle(element) : null;
|
||||||
|
if (style && (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const rect = typeof element.getBoundingClientRect === 'function' ? element.getBoundingClientRect() : null;
|
||||||
|
return !rect || rect.width > 0 || rect.height > 0;
|
||||||
|
};
|
||||||
|
const hasActiveMarker = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const markerText = [
|
||||||
|
element.className,
|
||||||
|
element.getAttribute?.('class'),
|
||||||
|
element.getAttribute?.('aria-selected'),
|
||||||
|
element.getAttribute?.('aria-pressed'),
|
||||||
|
element.getAttribute?.('data-state'),
|
||||||
|
element.getAttribute?.('data-active'),
|
||||||
|
].join(' ');
|
||||||
|
return /\b(active|selected|current|checked|on|true)\b/i.test(markerText);
|
||||||
|
};
|
||||||
|
const candidates = Array.from(document.querySelectorAll('button, [role="button"], .design-mode-card, .mode-card, [class*="mode"]'));
|
||||||
|
const cardModeButton = candidates.find((element) => /卡密充值/.test(textOf(element)));
|
||||||
|
const freeModeButton = candidates.find((element) => /免费充值/.test(textOf(element)));
|
||||||
|
const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]'))
|
||||||
|
.filter(isVisible);
|
||||||
|
const isCardModeActive = Boolean(cardModeButton && hasActiveMarker(cardModeButton))
|
||||||
|
|| (cardInputs.length > 0 && !(freeModeButton && hasActiveMarker(freeModeButton)));
|
||||||
|
if (!cardModeButton) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
reason: 'missing-card-mode',
|
||||||
|
activeModeText: textOf(freeModeButton),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (isCardModeActive) {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
clicked: false,
|
||||||
|
isCardModeActive: true,
|
||||||
|
activeModeText: textOf(cardModeButton),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
cardModeButton.scrollIntoView?.({ block: 'center', inline: 'center' });
|
||||||
|
cardModeButton.click?.();
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
clicked: true,
|
||||||
|
isCardModeActive: false,
|
||||||
|
activeModeText: textOf(cardModeButton),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -231,7 +326,16 @@
|
|||||||
target: { tabId },
|
target: { tabId },
|
||||||
func: () => {
|
func: () => {
|
||||||
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
const textOf = (element) => String(element?.innerText || element?.textContent || element?.value || '').replace(/\s+/g, ' ').trim();
|
||||||
const buttons = Array.from(document.querySelectorAll('button, [role="button"]'));
|
const isVisible = (element) => {
|
||||||
|
if (!element) return false;
|
||||||
|
const style = window.getComputedStyle ? window.getComputedStyle(element) : null;
|
||||||
|
if (style && (style.display === 'none' || style.visibility === 'hidden' || Number(style.opacity) === 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const rect = typeof element.getBoundingClientRect === 'function' ? element.getBoundingClientRect() : null;
|
||||||
|
return !rect || rect.width > 0 || rect.height > 0;
|
||||||
|
};
|
||||||
|
const buttons = Array.from(document.querySelectorAll('button, [role="button"]')).filter(isVisible);
|
||||||
const button = buttons.find((candidate) => /开始\s*Plus\s*充值/.test(textOf(candidate)));
|
const button = buttons.find((candidate) => /开始\s*Plus\s*充值/.test(textOf(candidate)));
|
||||||
if (!button) {
|
if (!button) {
|
||||||
return {
|
return {
|
||||||
@@ -261,9 +365,7 @@
|
|||||||
async function executeGpcHelperBilling(state = {}) {
|
async function executeGpcHelperBilling(state = {}) {
|
||||||
const tabId = await getGpcPortalTabId(state);
|
const tabId = await getGpcPortalTabId(state);
|
||||||
if (chrome?.tabs?.update) {
|
if (chrome?.tabs?.update) {
|
||||||
await chrome.tabs.update(tabId, { url: GPC_PORTAL_URL, active: true }).catch(() => (
|
await chrome.tabs.update(tabId, { active: true }).catch(() => {});
|
||||||
chrome.tabs.update(tabId, { active: true }).catch(() => {})
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
await addLog('步骤 7:正在等待 GPC 页面加载完成...', 'info');
|
await addLog('步骤 7:正在等待 GPC 页面加载完成...', 'info');
|
||||||
await waitForTabCompleteUntilStopped(tabId);
|
await waitForTabCompleteUntilStopped(tabId);
|
||||||
@@ -311,6 +413,23 @@
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pageState.isCardModeActive) {
|
||||||
|
const modeResult = await ensureGpcCardMode(tabId);
|
||||||
|
if (!modeResult.ok) {
|
||||||
|
throw new Error('GPC_PAGE_FLOW_ENDED::步骤 7:未找到 GPC“卡密充值”模式入口,无法启动 Plus 充值。');
|
||||||
|
}
|
||||||
|
await addLog(
|
||||||
|
modeResult.clicked
|
||||||
|
? '步骤 7:已切换到 GPC 卡密充值模式,准备启动。'
|
||||||
|
: '步骤 7:GPC 卡密充值模式已就绪。',
|
||||||
|
'info'
|
||||||
|
);
|
||||||
|
if (modeResult.clicked) {
|
||||||
|
await sleepWithStop(800);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (/开始\s*Plus\s*充值/.test(buttonText) && !pageState.startButtonDisabled) {
|
if (/开始\s*Plus\s*充值/.test(buttonText) && !pageState.startButtonDisabled) {
|
||||||
if (startAttempts >= GPC_PAGE_MAX_START_ATTEMPTS) {
|
if (startAttempts >= GPC_PAGE_MAX_START_ATTEMPTS) {
|
||||||
throw new Error(`GPC_PAGE_FLOW_ENDED::步骤 7:GPC 页面已尝试启动 ${startAttempts} 次仍未显示订阅完成。`);
|
throw new Error(`GPC_PAGE_FLOW_ENDED::步骤 7:GPC 页面已尝试启动 ${startAttempts} 次仍未显示订阅完成。`);
|
||||||
|
|||||||
@@ -903,10 +903,23 @@ test('Plus checkout billing reports when the payment iframe exists but cannot re
|
|||||||
function createGpcPageHarness(states) {
|
function createGpcPageHarness(states) {
|
||||||
const pageStates = Array.isArray(states) ? [...states] : [];
|
const pageStates = Array.isArray(states) ? [...states] : [];
|
||||||
const clicks = [];
|
const clicks = [];
|
||||||
|
const modeClicks = [];
|
||||||
return {
|
return {
|
||||||
clicks,
|
clicks,
|
||||||
|
modeClicks,
|
||||||
run(details) {
|
run(details) {
|
||||||
const source = String(details.func || '');
|
const source = String(details.func || '');
|
||||||
|
if (source.includes('cardModeButton.click')) {
|
||||||
|
modeClicks.push({ target: details.target?.tabId });
|
||||||
|
return [{
|
||||||
|
result: {
|
||||||
|
ok: true,
|
||||||
|
clicked: true,
|
||||||
|
isCardModeActive: false,
|
||||||
|
activeModeText: '卡密充值 使用付费卡密扣次充值',
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
}
|
||||||
if (source.includes('button.click')) {
|
if (source.includes('button.click')) {
|
||||||
clicks.push({ target: details.target?.tabId });
|
clicks.push({ target: details.target?.tabId });
|
||||||
return [{ result: { clicked: true, buttonText: '开始 Plus 充值' } }];
|
return [{ result: { clicked: true, buttonText: '开始 Plus 充值' } }];
|
||||||
@@ -925,6 +938,10 @@ function createGpcPageHarness(states) {
|
|||||||
hasStartButton: true,
|
hasStartButton: true,
|
||||||
cardKeyValue: 'AAAA1111-BBBB2222-CCCC3333',
|
cardKeyValue: 'AAAA1111-BBBB2222-CCCC3333',
|
||||||
sessionLength: 256,
|
sessionLength: 256,
|
||||||
|
hasCardMode: state.hasCardMode !== false,
|
||||||
|
hasFreeMode: true,
|
||||||
|
isCardModeActive: state.isCardModeActive !== false,
|
||||||
|
activeModeText: state.isCardModeActive === false ? '免费充值' : '卡密充值 使用付费卡密扣次充值',
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
},
|
},
|
||||||
@@ -1005,6 +1022,26 @@ test('GPC billing clicks start and completes after page log shows subscription d
|
|||||||
assert.equal(events.states.some((state) => state.gpcPageStatus === 'completed'), true);
|
assert.equal(events.states.some((state) => state.gpcPageStatus === 'completed'), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('GPC billing keeps prepared page, switches card mode, and clicks start instead of reloading home', async () => {
|
||||||
|
const { events, executor, pageHarness } = createGpcPageExecutorHarness([
|
||||||
|
{ startButtonText: '停止当前任务', logText: '免费充值任务进行中', isCardModeActive: false },
|
||||||
|
{ startButtonText: '开始 Plus 充值', logText: 'SYSTEM 页面已就绪', isCardModeActive: true },
|
||||||
|
{ startButtonText: '任务进行中', logText: '开始处理任务', isCardModeActive: true },
|
||||||
|
{ startButtonText: '开始 Plus 充值', logText: '订阅完成', hasSubscriptionDone: true, isCardModeActive: true },
|
||||||
|
]);
|
||||||
|
|
||||||
|
await executor.executePlusCheckoutBilling({
|
||||||
|
plusPaymentMethod: 'gpc-helper',
|
||||||
|
plusCheckoutSource: 'gpc-helper',
|
||||||
|
plusCheckoutTabId: 77,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(pageHarness.modeClicks.length, 1);
|
||||||
|
assert.equal(pageHarness.clicks.length, 1);
|
||||||
|
assert.equal(events.updates.some((event) => event.payload?.url === 'https://gpc.qlhazycoder.top/'), false);
|
||||||
|
assert.equal(events.completed.length, 1);
|
||||||
|
});
|
||||||
|
|
||||||
test('GPC billing restarts when start button returns without subscription done', async () => {
|
test('GPC billing restarts when start button returns without subscription done', async () => {
|
||||||
const { events, executor, pageHarness } = createGpcPageExecutorHarness([
|
const { events, executor, pageHarness } = createGpcPageExecutorHarness([
|
||||||
{ startButtonText: '开始 Plus 充值', logText: 'SYSTEM 页面已就绪' },
|
{ startButtonText: '开始 Plus 充值', logText: 'SYSTEM 页面已就绪' },
|
||||||
|
|||||||
@@ -873,6 +873,7 @@ function createFakeGpcPrepareDom() {
|
|||||||
scrollIntoView() {},
|
scrollIntoView() {},
|
||||||
click() {
|
click() {
|
||||||
this.clicked = true;
|
this.clicked = true;
|
||||||
|
this.onClick?.();
|
||||||
},
|
},
|
||||||
dispatchEvent(event) {
|
dispatchEvent(event) {
|
||||||
dispatches.push({ element: this, type: event?.type || '' });
|
dispatches.push({ element: this, type: event?.type || '' });
|
||||||
@@ -886,6 +887,11 @@ function createFakeGpcPrepareDom() {
|
|||||||
|
|
||||||
const freeButton = createElement({ tagName: 'BUTTON', text: '免费充值' });
|
const freeButton = createElement({ tagName: 'BUTTON', text: '免费充值' });
|
||||||
const cardModeButton = createElement({ tagName: 'BUTTON', text: '卡密充值 使用付费卡密扣次充值' });
|
const cardModeButton = createElement({ tagName: 'BUTTON', text: '卡密充值 使用付费卡密扣次充值' });
|
||||||
|
freeButton.className = 'active';
|
||||||
|
cardModeButton.onClick = () => {
|
||||||
|
freeButton.className = '';
|
||||||
|
cardModeButton.className = 'active';
|
||||||
|
};
|
||||||
const startButton = createElement({ tagName: 'BUTTON', text: '开始 Plus 充值' });
|
const startButton = createElement({ tagName: 'BUTTON', text: '开始 Plus 充值' });
|
||||||
const cardInputs = [
|
const cardInputs = [
|
||||||
createElement({ tagName: 'INPUT', placeholder: 'XXXXXXXX', className: 'card-key-seg' }),
|
createElement({ tagName: 'INPUT', placeholder: 'XXXXXXXX', className: 'card-key-seg' }),
|
||||||
@@ -1004,7 +1010,7 @@ test('GPC checkout prepare opens page, fills segmented card key, and writes full
|
|||||||
includeSession: true,
|
includeSession: true,
|
||||||
includeAccessToken: true,
|
includeAccessToken: true,
|
||||||
});
|
});
|
||||||
const executeEvent = events.find((event) => event.type === 'execute-script');
|
const executeEvent = events.find((event) => event.type === 'execute-script' && Array.isArray(event.args));
|
||||||
assert.equal(executeEvent.target.tabId, 77);
|
assert.equal(executeEvent.target.tabId, 77);
|
||||||
assert.equal(executeEvent.args[1], JSON.stringify(session));
|
assert.equal(executeEvent.args[1], JSON.stringify(session));
|
||||||
const statePayload = events.find((event) => event.type === 'set-state')?.payload || {};
|
const statePayload = events.find((event) => event.type === 'set-state')?.payload || {};
|
||||||
|
|||||||
Reference in New Issue
Block a user