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:
parent
0bd4065230
commit
f1d3036c7a
@ -29,8 +29,8 @@ import static java.nio.file.Files.createDirectories;
|
|||||||
* Uses Playwright to automate login and data extraction.
|
* Uses Playwright to automate login and data extraction.
|
||||||
*/
|
*/
|
||||||
public class EtsScraper {
|
public class EtsScraper {
|
||||||
private static final String FRAME_URL = "https://101.227.180.215/SHCityEnvCW/CWS/frame.html";
|
public 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 LOGIN_URL = "https://101.227.180.215/SHCityEnvCW/CWS/userlogin.html";
|
||||||
private static final String USERNAME = "sccw";
|
private static final String USERNAME = "sccw";
|
||||||
private static final String PASSWORD = "slife@123";
|
private static final String PASSWORD = "slife@123";
|
||||||
private static final Path SCREENSHOT_DIR = Path.of("screenshots");
|
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
|
// Find and fill username
|
||||||
String usernameInput = findInput(page, new String[]{
|
String usernameInput = findInput(page, new String[]{
|
||||||
"input[placeholder*='用户名']",
|
"input[placeholder*='用户名']",
|
||||||
@ -240,7 +240,7 @@ public class EtsScraper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void downloadCaptcha(Page page) {
|
public static void downloadCaptcha(Page page) {
|
||||||
try {
|
try {
|
||||||
// Set up listener FIRST, then reload to trigger the request
|
// Set up listener FIRST, then reload to trigger the request
|
||||||
Response resp = page.waitForResponse(
|
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
|
// Find the frame that contains the notification dialog
|
||||||
Frame dialogFrame = null;
|
Frame dialogFrame = null;
|
||||||
for (Frame f : page.frames()) {
|
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 {
|
try {
|
||||||
Thread.sleep(ms);
|
Thread.sleep(ms);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|||||||
163
src/test/java/com/ets/scraper/AutoLoginTest.java
Normal file
163
src/test/java/com/ets/scraper/AutoLoginTest.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user