initial commit

This commit is contained in:
Ken Yasue
2025-03-23 20:32:57 +01:00
parent c2e18462be
commit 4b42f7bf3a
14 changed files with 1884 additions and 132 deletions

196
src/lib/UIActions.ts Normal file
View File

@ -0,0 +1,196 @@
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(2);
await searchInput.sendKeys('\uE007'); // Unicode for Enter key
await WebDriverUtils.wait(5); // 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 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 = `//h2[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);
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 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}`);
}