mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2253d05618
Remove the nested v3/ subdirectory by moving all active source code, tests, configs, and assets directly to the project root. Archive v2/ (dead code, 847MB) to v2-archive.tar.gz. Key changes: - Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/ - Move v3/tsconfig.json, v3/vitest.config.ts to root - Merge v3/package.json into root package.json (ESM, scripts, deps, exports) - Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/ - Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes - Fix all init installer path resolution (3-level-up → 2-level-up) - Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe" - Update settings.json ADR/DDD directories to docs/implementation/ - Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks) - Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces - Update 15 guidance shards: v3/src/ → src/ path references - Fix sync interfaces: remove v3/ and v2/ path references - Fix test path calculations (process.cwd() + '..' no longer needed) - Fix flaky perf test threshold (500ms → 1000ms for CI environments) - Fix complexity-analyzer test to match ADR-051 keyword-based eligibility Build passes, 17,901 tests pass, CLI and MCP bundles verified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
135 lines
4.1 KiB
TypeScript
135 lines
4.1 KiB
TypeScript
import { Page, Locator, expect } from '@playwright/test';
|
|
import { BasePage } from './BasePage';
|
|
|
|
/**
|
|
* Home Page Object Model
|
|
* Handles interactions with the Sauce Demo homepage
|
|
*
|
|
* Generated by: qe-queen-coordinator
|
|
*/
|
|
export class HomePage extends BasePage {
|
|
// Hero section
|
|
readonly heroSection: Locator;
|
|
readonly heroTitle: Locator;
|
|
readonly heroSubtitle: Locator;
|
|
|
|
// Featured products
|
|
readonly featuredProducts: Locator;
|
|
readonly productCards: Locator;
|
|
readonly productTitles: Locator;
|
|
readonly productPrices: Locator;
|
|
readonly productImages: Locator;
|
|
|
|
// Navigation links
|
|
readonly catalogLink: Locator;
|
|
readonly aboutUsLink: Locator;
|
|
readonly blogLink: Locator;
|
|
|
|
// Social links
|
|
readonly socialLinks: Locator;
|
|
readonly facebookLink: Locator;
|
|
readonly twitterLink: Locator;
|
|
readonly instagramLink: Locator;
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
|
|
// Hero section selectors
|
|
this.heroSection = page.locator('.hero, .banner, [data-hero]');
|
|
this.heroTitle = page.locator('.hero h1, .banner-title, [data-hero-title]');
|
|
this.heroSubtitle = page.locator('.hero p, .banner-subtitle');
|
|
|
|
// Product grid selectors - Shopify theme specific
|
|
this.featuredProducts = page.locator('.featured-products, .product-grid, [data-products]');
|
|
this.productCards = page.locator('.product-card, .grid-item, .product-item');
|
|
this.productTitles = page.locator('.product-card h3, .product-title, .product-card__title');
|
|
this.productPrices = page.locator('.product-price, .price, [data-price]');
|
|
this.productImages = page.locator('.product-card img, .product-image');
|
|
|
|
// Navigation
|
|
this.catalogLink = page.locator('[href="/collections/all"], a:text("Catalog")');
|
|
this.aboutUsLink = page.locator('[href*="about"], a:text("About")');
|
|
this.blogLink = page.locator('[href*="/blogs"], a:text("Blog")');
|
|
|
|
// Social links
|
|
this.socialLinks = page.locator('.social-links, .footer-social');
|
|
this.facebookLink = page.locator('[href*="facebook"]');
|
|
this.twitterLink = page.locator('[href*="twitter"]');
|
|
this.instagramLink = page.locator('[href*="instagram"]');
|
|
}
|
|
|
|
/**
|
|
* Navigate to homepage
|
|
*/
|
|
async navigate() {
|
|
await this.goto('/');
|
|
await this.waitForPageLoad();
|
|
}
|
|
|
|
/**
|
|
* Get all featured product names
|
|
*/
|
|
async getFeaturedProductNames(): Promise<string[]> {
|
|
const titles = await this.productTitles.allTextContents();
|
|
return titles.map(t => t.trim());
|
|
}
|
|
|
|
/**
|
|
* Get featured product count
|
|
*/
|
|
async getFeaturedProductCount(): Promise<number> {
|
|
return await this.productCards.count();
|
|
}
|
|
|
|
/**
|
|
* Click on a product by name
|
|
*/
|
|
async clickProduct(productName: string) {
|
|
const product = this.page.locator(`.product-card:has-text("${productName}"), .product-item:has-text("${productName}")`);
|
|
await product.click();
|
|
await this.page.waitForURL('**/products/**');
|
|
}
|
|
|
|
/**
|
|
* Click on first product
|
|
*/
|
|
async clickFirstProduct() {
|
|
await this.productCards.first().click();
|
|
await this.page.waitForURL('**/products/**');
|
|
}
|
|
|
|
/**
|
|
* Navigate to catalog page
|
|
*/
|
|
async goToCatalog() {
|
|
await this.catalogLink.click();
|
|
await this.page.waitForURL('**/collections/**');
|
|
}
|
|
|
|
/**
|
|
* Verify homepage loaded correctly
|
|
*/
|
|
async verifyHomepageLoaded() {
|
|
await expect(this.page).toHaveTitle(/Sauce Demo/i);
|
|
await expect(this.featuredProducts.or(this.productCards.first())).toBeVisible();
|
|
}
|
|
|
|
/**
|
|
* Get product price by name
|
|
*/
|
|
async getProductPrice(productName: string): Promise<string> {
|
|
const productCard = this.page.locator(`.product-card:has-text("${productName}"), .product-item:has-text("${productName}")`);
|
|
const price = await productCard.locator('.price, .product-price, [data-price]').textContent();
|
|
return price?.trim() || '';
|
|
}
|
|
|
|
/**
|
|
* Check if social links are present
|
|
*/
|
|
async verifySocialLinks() {
|
|
await expect(this.facebookLink).toBeVisible();
|
|
await expect(this.twitterLink).toBeVisible();
|
|
await expect(this.instagramLink).toBeVisible();
|
|
}
|
|
}
|