132 lines
3.2 KiB
JavaScript
132 lines
3.2 KiB
JavaScript
/**
|
|
* Navigation Manager
|
|
*
|
|
* Handles page navigation with error handling, retries, and logging
|
|
*/
|
|
|
|
class NavigationManager {
|
|
constructor(coreParser) {
|
|
this.coreParser = coreParser;
|
|
}
|
|
|
|
/**
|
|
* Navigate to URL with comprehensive error handling
|
|
*/
|
|
async navigateTo(url, options = {}) {
|
|
const {
|
|
pageId = "default",
|
|
waitUntil = "domcontentloaded",
|
|
retries = 1,
|
|
retryDelay = 2000,
|
|
timeout = this.coreParser.config.timeout,
|
|
} = options;
|
|
|
|
const page = this.coreParser.getPage(pageId);
|
|
if (!page) {
|
|
throw new Error(`Page with ID '${pageId}' not found`);
|
|
}
|
|
|
|
let lastError;
|
|
|
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
try {
|
|
console.log(
|
|
`🌐 Navigating to: ${url} (attempt ${attempt + 1}/${retries + 1})`
|
|
);
|
|
|
|
await page.goto(url, {
|
|
waitUntil,
|
|
timeout,
|
|
});
|
|
|
|
console.log(`✅ Navigation successful: ${url}`);
|
|
return true;
|
|
} catch (error) {
|
|
lastError = error;
|
|
console.warn(
|
|
`⚠️ Navigation attempt ${attempt + 1} failed: ${error.message}`
|
|
);
|
|
|
|
if (attempt < retries) {
|
|
console.log(`🔄 Retrying in ${retryDelay}ms...`);
|
|
await this.delay(retryDelay);
|
|
}
|
|
}
|
|
}
|
|
|
|
// All attempts failed
|
|
const errorMessage = `Navigation failed after ${retries + 1} attempts: ${
|
|
lastError.message
|
|
}`;
|
|
console.error(`❌ ${errorMessage}`);
|
|
throw new Error(errorMessage);
|
|
}
|
|
|
|
/**
|
|
* Navigate and wait for specific selector
|
|
*/
|
|
async navigateAndWaitFor(url, selector, options = {}) {
|
|
await this.navigateTo(url, options);
|
|
|
|
const { pageId = "default", timeout = this.coreParser.config.timeout } =
|
|
options;
|
|
const page = this.coreParser.getPage(pageId);
|
|
|
|
try {
|
|
await page.waitForSelector(selector, { timeout });
|
|
console.log(`✅ Selector found: ${selector}`);
|
|
return true;
|
|
} catch (error) {
|
|
console.warn(`⚠️ Selector not found: ${selector} - ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if current page has specific content
|
|
*/
|
|
async hasContent(content, options = {}) {
|
|
const { pageId = "default", timeout = 5000 } = options;
|
|
const page = this.coreParser.getPage(pageId);
|
|
|
|
try {
|
|
await page.waitForFunction(
|
|
(text) => document.body.innerText.includes(text),
|
|
content,
|
|
{ timeout }
|
|
);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Utility delay function
|
|
*/
|
|
async delay(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
/**
|
|
* Get current page URL
|
|
*/
|
|
getCurrentUrl(pageId = "default") {
|
|
const page = this.coreParser.getPage(pageId);
|
|
return page ? page.url() : null;
|
|
}
|
|
|
|
/**
|
|
* Take screenshot for debugging
|
|
*/
|
|
async screenshot(filepath, pageId = "default") {
|
|
const page = this.coreParser.getPage(pageId);
|
|
if (page) {
|
|
await page.screenshot({ path: filepath });
|
|
console.log(`📸 Screenshot saved: ${filepath}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = NavigationManager;
|