227 lines
7.8 KiB
TypeScript
227 lines
7.8 KiB
TypeScript
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<boolean> {
|
|
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<boolean> {
|
|
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<string> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
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<string | null> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
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<WebElement[]> {
|
|
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<ContactInfo> {
|
|
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<boolean> {
|
|
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<void> {
|
|
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}`);
|
|
} |