fix(myTischtennis): refine CAPTCHA readiness checks and improve interaction flow
- Introduced a new mechanism to detect CAPTCHA readiness before form submission, enhancing login reliability. - Adjusted timeout settings for CAPTCHA field checks to optimize performance during login attempts. - Added diagnostic logging for better visibility into CAPTCHA state changes and interaction outcomes.
This commit is contained in:
@@ -401,6 +401,7 @@ class MyTischtennisClient {
|
||||
}
|
||||
const captchaHost = page.locator('private-captcha').first();
|
||||
const hasCaptchaHost = (await captchaHost.count()) > 0;
|
||||
let captchaReadyDetected = !hasCaptchaHost;
|
||||
if (hasCaptchaHost) {
|
||||
try {
|
||||
await page.waitForTimeout(1200);
|
||||
@@ -433,7 +434,31 @@ class MyTischtennisClient {
|
||||
});
|
||||
console.log('[myTischtennisClient.playwright] evaluate interaction result:', interaction);
|
||||
|
||||
// Wait for a visual captcha state change in Shadow DOM (not only hidden fields).
|
||||
// Wait until hidden captcha fields are populated by site scripts.
|
||||
try {
|
||||
await page.waitForFunction(() => {
|
||||
const captchaField = document.querySelector('input[name="captcha"]');
|
||||
const clickedField = document.querySelector('input[name="captcha_clicked"]');
|
||||
const captchaValue = (captchaField && captchaField.value ? captchaField.value.trim() : '');
|
||||
const clickedValue = (clickedField && clickedField.value ? clickedField.value.toLowerCase() : '');
|
||||
return captchaValue.length > 80 && (clickedValue === 'true' || clickedValue === '1');
|
||||
}, { timeout: 20000 });
|
||||
const captchaState = await page.evaluate(() => {
|
||||
const captchaField = document.querySelector('input[name="captcha"]');
|
||||
const clickedField = document.querySelector('input[name="captcha_clicked"]');
|
||||
return {
|
||||
captchaLen: captchaField?.value?.length || 0,
|
||||
captchaClicked: clickedField?.value || null
|
||||
};
|
||||
});
|
||||
console.log('[myTischtennisClient.playwright] Captcha value ready:', captchaState);
|
||||
captchaReadyDetected = true;
|
||||
} catch (_waitErr) {
|
||||
// Keep going; some flows still succeed without explicit hidden field update.
|
||||
console.warn('[myTischtennisClient.playwright] Captcha value not ready in time');
|
||||
}
|
||||
|
||||
// Optional diagnostic only: visual state change should never block submit.
|
||||
try {
|
||||
await page.waitForFunction((beforeState) => {
|
||||
const host = document.querySelector('private-captcha');
|
||||
@@ -455,57 +480,11 @@ class MyTischtennisClient {
|
||||
|| current.checkboxChecked !== !!beforeState?.checkboxChecked
|
||||
|| current.checkboxAriaChecked !== (beforeState?.checkboxAriaChecked || '');
|
||||
|
||||
const positiveSignals = [
|
||||
current.hostClass,
|
||||
current.hostDataState,
|
||||
current.checkboxClass,
|
||||
String(current.checkboxAriaChecked)
|
||||
].join(' ').toLowerCase();
|
||||
|
||||
return visualChanged && (
|
||||
current.checkboxChecked
|
||||
|| current.checkboxAriaChecked === 'true'
|
||||
|| /success|solved|verified|checked|active|complete|done/.test(positiveSignals)
|
||||
);
|
||||
}, captchaVisualStateBefore, { timeout: 30000 });
|
||||
|
||||
const captchaVisualStateAfter = await page.evaluate(() => {
|
||||
const host = document.querySelector('private-captcha');
|
||||
const checkbox = host?.shadowRoot?.querySelector('#pc-checkbox');
|
||||
return {
|
||||
hostClass: host?.className || null,
|
||||
hostDataState: host?.getAttribute?.('data-state') || null,
|
||||
checkboxClass: checkbox?.className || null,
|
||||
checkboxChecked: !!checkbox?.checked,
|
||||
checkboxAriaChecked: checkbox?.getAttribute?.('aria-checked') || null
|
||||
};
|
||||
});
|
||||
console.log('[myTischtennisClient.playwright] Captcha visual state changed:', captchaVisualStateAfter);
|
||||
return visualChanged;
|
||||
}, captchaVisualStateBefore, { timeout: 1500 });
|
||||
console.log('[myTischtennisClient.playwright] Captcha visual state changed');
|
||||
} catch (_visualWaitErr) {
|
||||
console.warn('[myTischtennisClient.playwright] Captcha visual state did not change in time');
|
||||
}
|
||||
|
||||
// Wait until hidden captcha fields are populated by site scripts.
|
||||
try {
|
||||
await page.waitForFunction(() => {
|
||||
const captchaField = document.querySelector('input[name="captcha"]');
|
||||
const clickedField = document.querySelector('input[name="captcha_clicked"]');
|
||||
const captchaValue = (captchaField && captchaField.value ? captchaField.value.trim() : '');
|
||||
const clickedValue = (clickedField && clickedField.value ? clickedField.value.toLowerCase() : '');
|
||||
return captchaValue.length > 80 && (clickedValue === 'true' || clickedValue === '1');
|
||||
}, { timeout: 30000 });
|
||||
const captchaState = await page.evaluate(() => {
|
||||
const captchaField = document.querySelector('input[name="captcha"]');
|
||||
const clickedField = document.querySelector('input[name="captcha_clicked"]');
|
||||
return {
|
||||
captchaLen: captchaField?.value?.length || 0,
|
||||
captchaClicked: clickedField?.value || null
|
||||
};
|
||||
});
|
||||
console.log('[myTischtennisClient.playwright] Captcha value ready:', captchaState);
|
||||
} catch (_waitErr) {
|
||||
// Keep going; some flows still succeed without explicit hidden field update.
|
||||
console.warn('[myTischtennisClient.playwright] Captcha value not ready in time');
|
||||
// no-op: widget often keeps "ready" class despite solved token
|
||||
}
|
||||
} catch (captchaError) {
|
||||
console.warn('[myTischtennisClient.playwright] Captcha interaction warning:', captchaError?.message || captchaError);
|
||||
@@ -529,6 +508,7 @@ class MyTischtennisClient {
|
||||
const clickedValue = (clickedField && clickedField.value ? clickedField.value.toLowerCase() : '');
|
||||
return captchaValue.length > 80 && (clickedValue === 'true' || clickedValue === '1');
|
||||
});
|
||||
captchaReadyDetected = captchaReadyDetected || isCaptchaReadyNow;
|
||||
|
||||
if (!isCaptchaReadyNow) {
|
||||
try {
|
||||
@@ -538,7 +518,8 @@ class MyTischtennisClient {
|
||||
const captchaValue = (captchaField && captchaField.value ? captchaField.value.trim() : '');
|
||||
const clickedValue = (clickedField && clickedField.value ? clickedField.value.toLowerCase() : '');
|
||||
return captchaValue.length > 80 && (clickedValue === 'true' || clickedValue === '1');
|
||||
}, { timeout: 45000 });
|
||||
}, { timeout: 12000 });
|
||||
captchaReadyDetected = true;
|
||||
} catch (_captchaNotReadyErr) {
|
||||
return {
|
||||
success: false,
|
||||
@@ -548,6 +529,13 @@ class MyTischtennisClient {
|
||||
}
|
||||
}
|
||||
|
||||
// Human-like pause only after captcha was actually solved (2-6s).
|
||||
if (captchaReadyDetected) {
|
||||
const postCaptchaDelayMs = 2000 + Math.floor(Math.random() * 4001);
|
||||
await page.waitForTimeout(postCaptchaDelayMs);
|
||||
console.log('[myTischtennisClient.playwright] Waited after solved captcha:', postCaptchaDelayMs);
|
||||
}
|
||||
|
||||
// Submit form
|
||||
const submitButton = page.locator('button[type="submit"], input[type="submit"]').first();
|
||||
if (await submitButton.count()) {
|
||||
|
||||
Reference in New Issue
Block a user