linkedout/core-parser/navigation.js

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;