feat: 添加自动登录测试类并暴露测试所需方法

- 新增 AutoLoginTest 集成测试类
- 暴露以下方法供测试使用:
  - public static void downloadCaptcha(Page)
  - public static void closeNotificationDialog(Page)
  - public static boolean doLoginWithCaptcha(Page)
  - public static void sleep(long)
  - public static final String FRAME_URL / LOGIN_URL

验证码识别已通过测试:9347
This commit is contained in:
Niko 2026-05-05 10:12:32 +08:00
parent 0bd4065230
commit f1d3036c7a
2 changed files with 169 additions and 6 deletions

View File

@ -29,8 +29,8 @@ import static java.nio.file.Files.createDirectories;
* Uses Playwright to automate login and data extraction.
*/
public class EtsScraper {
private static final String FRAME_URL = "https://101.227.180.215/SHCityEnvCW/CWS/frame.html";
private static final String LOGIN_URL = "https://101.227.180.215/SHCityEnvCW/CWS/userlogin.html";
public static final String FRAME_URL = "https://101.227.180.215/SHCityEnvCW/CWS/frame.html";
public static final String LOGIN_URL = "https://101.227.180.215/SHCityEnvCW/CWS/userlogin.html";
private static final String USERNAME = "sccw";
private static final String PASSWORD = "slife@123";
private static final Path SCREENSHOT_DIR = Path.of("screenshots");
@ -162,7 +162,7 @@ public class EtsScraper {
}
}
private static boolean doLoginWithCaptcha(Page page) throws Exception {
public static boolean doLoginWithCaptcha(Page page) throws Exception {
// Find and fill username
String usernameInput = findInput(page, new String[]{
"input[placeholder*='用户名']",
@ -240,7 +240,7 @@ public class EtsScraper {
}
}
private static void downloadCaptcha(Page page) {
public static void downloadCaptcha(Page page) {
try {
// Set up listener FIRST, then reload to trigger the request
Response resp = page.waitForResponse(
@ -263,7 +263,7 @@ public class EtsScraper {
}
}
private static void closeNotificationDialog(Page page) {
public static void closeNotificationDialog(Page page) {
// Find the frame that contains the notification dialog
Frame dialogFrame = null;
for (Frame f : page.frames()) {
@ -341,7 +341,7 @@ public class EtsScraper {
}
}
private static void sleep(long ms) {
public static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {

View File

@ -0,0 +1,163 @@
package com.ets.scraper;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.WaitUntilState;
import org.junit.jupiter.api.*;
import java.io.IOException;
import java.nio.file.Path;
/**
* 自动登录集成测试
* 测试完整的登录流程关闭弹窗 -> 下载验证码 -> 识别 -> 登录
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class AutoLoginTest {
private Playwright playwright;
private Browser browser;
private BrowserContext context;
@BeforeAll
void setUp() throws IOException {
java.nio.file.Files.createDirectories(Path.of("screenshots"));
playwright = Playwright.create();
browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().setHeadless(false)
);
context = browser.newContext(
new Browser.NewContextOptions().setIgnoreHTTPSErrors(true)
);
}
@AfterAll
void tearDown() {
if (context != null) context.close();
if (browser != null) browser.close();
if (playwright != null) playwright.close();
}
@Test
@Disabled("需要手动操作 - 仅在实际登录场景下运行")
void testAutoLogin() throws Exception {
Page page = context.newPage();
try {
System.out.println("=== 开始自动登录测试 ===");
// 步骤 1: 建立会话
System.out.println("[1/6] 建立会话...");
page.navigate(EtsScraper.FRAME_URL, new Page.NavigateOptions()
.setTimeout(30000)
.setWaitUntil(WaitUntilState.DOMCONTENTLOADED));
EtsScraper.sleep(3000);
screenshot(page, "01_session_established");
// 步骤 2: 导航到登录页
System.out.println("[2/6] 导航到登录页...");
page.navigate(EtsScraper.LOGIN_URL, new Page.NavigateOptions()
.setTimeout(30000)
.setWaitUntil(WaitUntilState.NETWORKIDLE));
EtsScraper.sleep(2000);
screenshot(page, "02_login_page_loaded");
// 步骤 3: 关闭通知弹窗
System.out.println("[3/6] 关闭通知弹窗...");
EtsScraper.closeNotificationDialog(page);
screenshot(page, "03_dialog_closed");
// 步骤 4: 下载验证码
System.out.println("[4/6] 下载验证码...");
EtsScraper.downloadCaptcha(page);
screenshot(page, "04_captcha_downloaded");
// 步骤 5: 识别验证码并登录
System.out.println("[5/6] 识别验证码...");
Path captchaPath = Path.of("screenshots/captcha.png");
String captchaText = EtsScraper.recognizeCaptcha(captchaPath);
System.out.println("[+] 识别结果:" + captchaText);
if (captchaText != null && !captchaText.isEmpty()) {
System.out.println("[6/6] 执行登录...");
screenshot(page, "05_before_login");
// 填充验证码并登录
String captchaInput = findCaptchaInput(page);
if (captchaInput != null) {
page.locator(captchaInput).first().fill(captchaText);
EtsScraper.sleep(500);
// 点击登录按钮或按 Enter
String submitBtn = findSubmitButton(page);
if (submitBtn != null) {
page.locator(submitBtn).first().click();
} else {
page.locator(captchaInput).first().press("Enter");
}
EtsScraper.sleep(3000);
screenshot(page, "06_after_login");
System.out.println(" - 页面标题:" + page.title());
System.out.println(" - 页面 URL: " + page.url());
System.out.println("=== 登录测试完成 ===");
}
} else {
System.out.println("[-] 验证码识别失败,跳过登录");
}
} finally {
page.close();
}
}
private String findCaptchaInput(Page page) {
String[] selectors = new String[]{
"input[placeholder*='验证码']",
"input[placeholder*='captcha']",
"input[name*='captcha']",
"input[name='code']",
};
for (String selector : selectors) {
try {
if (page.locator(selector).first().isVisible(
new Locator.IsVisibleOptions().setTimeout(1000))) {
return selector;
}
} catch (Exception ignored) {}
}
return null;
}
private String findSubmitButton(Page page) {
String[] selectors = new String[]{
"button[type='submit']",
"input[type='submit']",
"button:has-text('登录')",
"button:has-text('Login')",
".login-btn",
"#loginBtn",
};
for (String selector : selectors) {
try {
if (page.locator(selector).first().isVisible(
new Locator.IsVisibleOptions().setTimeout(1000))) {
return selector;
}
} catch (Exception ignored) {}
}
return null;
}
private void screenshot(Page page, String name) throws Exception {
try {
String timestamp = java.time.LocalDateTime.now()
.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
Path path = Path.of("screenshots", name + "_" + timestamp + ".png");
page.screenshot(new Page.ScreenshotOptions().setPath(path));
System.out.println("[+] 截图保存:" + path);
} catch (Exception e) {
System.err.println("[-] 截图失败:" + e.getMessage());
}
}
}