import { Builder, By, until, WebDriver, WebElement } from 'selenium-webdriver'; import * as chromedriver from 'chromedriver'; import chrome, { ServiceBuilder } from 'selenium-webdriver/chrome'; import * as fs from 'fs'; import * as path from 'path'; import { WebDriverUtils } from './utils'; import { ContactInfo } from './types'; export async function execSearch(driver: WebDriver, city: string): Promise { try { // Find the search input field const searchSelector = 'input[name="q"][placeholder="Places to go, things to do, hotels..."]'; await WebDriverUtils.waitForElement(driver, searchSelector, 10000); console.log("Search box found"); const searchInput = await driver.findElement(By.css(searchSelector)); // Clear any existing text and enter the city name await searchInput.clear(); await searchInput.sendKeys(city); // Submit the search (press Enter) await WebDriverUtils.wait(driver); await searchInput.sendKeys('\uE007'); // Unicode for Enter key await WebDriverUtils.wait(driver); // Wait 5 seconds before next city return true; } catch (e) { return false; } } export async function clickSeeAll(driver: WebDriver): Promise { try { const seeAllElement = await driver.wait( until.elementLocated(By.xpath("//span[contains(text(), 'See all')]")), 5000 // Waits up to 5 seconds ); await driver.wait(until.elementIsVisible(seeAllElement), 5000); await driver.wait(until.elementIsEnabled(seeAllElement), 5000); await seeAllElement.click(); return true; // Click succeeded } catch (error) { // Element not found or not clickable within the timeout return false; } } export async function getSeeAllUrl(driver: WebDriver): Promise { const xpath = `//h3[normalize-space(.)='Things to do']/ancestor::div[1]//a[starts-with(@href, '/Attractions')]`; try { const anchor = await driver.wait(until.elementLocated(By.xpath(xpath)), 5000); const url = await anchor.getAttribute('href'); console.log('Found Attractions URL:', url); return url; } catch (err) { console.warn('Could not find the Attractions link:', err); } return ""; } export async function gotoHome(driver: WebDriver): Promise { try { // Click on the Tripadvisor logo before searching for the city const logoSelector = 'img.XpHHt[alt="Tripadvisor"]'; const logo = await driver.findElement(By.css(logoSelector)); console.log('Found Tripadvisor logo. Clicking it...'); await logo.click(); return true; } catch (error) { // Element not found or not clickable within the timeout return false; } } export async function clickSeeAllAttractions(driver: WebDriver): Promise { const xpath = `//h3[starts-with(normalize-space(.), 'Things to do')]/parent::*[1]//a[starts-with(@href, '/Attractions') and .//span[normalize-space(.)='See all']]`; try { const anchorElement = await driver.wait(until.elementLocated(By.xpath(xpath)), 5000); await driver.wait(until.elementIsVisible(anchorElement), 5000); await driver.wait(until.elementIsEnabled(anchorElement), 5000); await anchorElement.click(); return true; } catch (error) { console.warn('Element not found or not clickable.', error); return false; } } export async function getSeeAllAttractionsUrl(driver: WebDriver): Promise { const xpath = `//h3[starts-with(normalize-space(.), 'Top Attractions in')]/parent::*[1]//a[starts-with(@href, '/Attractions') and .//span[normalize-space(.)='See all']]`; try { const anchorElement = await driver.wait(until.elementLocated(By.xpath(xpath)), 5000); await driver.wait(until.elementIsVisible(anchorElement), 5000); const href = await anchorElement.getAttribute('href'); return href; } catch (error) { console.warn('Element not found or href not retrievable.', error); return null; } } export async function clickMuseumsLink(driver: WebDriver): Promise { const xpath = `//a[.//*[normalize-space(.)='Museums']]`; try { const museumsLink = await driver.wait(until.elementLocated(By.xpath(xpath)), 5000); await driver.wait(until.elementIsVisible(museumsLink), 5000); await driver.wait(until.elementIsEnabled(museumsLink), 5000); await museumsLink.click(); return true; } catch (error) { console.warn('Museums link not found or not clickable.', error); return false; } } export async function clickTourismLink(driver: WebDriver): Promise { const xpath = `//a[starts-with(@href, '/Tourism')]`; try { const tourismLink = await driver.wait( until.elementLocated(By.xpath(xpath)), 5000 ); await driver.wait(until.elementIsVisible(tourismLink), 5000); await driver.wait(until.elementIsEnabled(tourismLink), 5000); await tourismLink.click(); return true; } catch (error) { console.warn('Tourism link not found or not clickable.', error); return false; } } export async function getMusiums(driver: WebDriver): Promise { const xpath = `//div//section[.//a[starts-with(@href, '/Attraction')] and .//h3]//a[starts-with(@href, '/Attraction') and .//img]`; try { const links: WebElement[] = await driver.findElements(By.xpath(xpath)); return links; } catch (error) { console.warn('Error clicking attraction links:', error); return []; } } export async function getWebsiteAndEmail(driver: WebDriver): Promise { const result: ContactInfo = { websiteUrl: null, email: null }; // XPath to find URL (starting with 'http' but not containing 'tripadvisor') const urlXPath = `//a[starts-with(@href, 'http') and not(contains(@href, 'tripadvisor'))]`; // XPath to find Email (starting with 'mailto:') const emailXPath = `//a[starts-with(@href, 'mailto:')]`; try { const urlElement = await driver.findElement(By.xpath(urlXPath)); result.websiteUrl = await urlElement.getAttribute('href'); } catch { console.warn('Website URL not found.'); } try { const emailElement = await driver.findElement(By.xpath(emailXPath)); const emailHref = await emailElement.getAttribute('href'); result.email = emailHref.replace('mailto:', '').trim(); } catch { console.warn('Email address not found.'); } return result; } export async function clickPagination(driver: WebDriver, pageNumber: number): Promise { const xpath = `//a[@aria-label='${pageNumber}']`; try { const pageElement = await driver.wait(until.elementLocated(By.xpath(xpath)), 5000); await driver.wait(until.elementIsVisible(pageElement), 5000); await driver.wait(until.elementIsEnabled(pageElement), 5000); await pageElement.click(); return true; } catch (error) { console.warn(`Error clicking page number ${pageNumber}:`, error); return false; } } export async function closeAllTabsExceptFirst(driver: WebDriver): Promise { const windowHandles = await driver.getAllWindowHandles(); if (windowHandles.length <= 1) { console.log('Only one tab open; nothing to close.'); return; } const originalHandle = windowHandles[0]; for (const handle of windowHandles) { if (handle !== originalHandle) { await driver.switchTo().window(handle); await driver.close(); console.log(`Closed tab: ${handle}`); } } await driver.switchTo().window(originalHandle); console.log(`Switched back to original tab: ${originalHandle}`); }