mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-18 01:38:03 +00:00
## Summary Switch the meta title separator sitewide from an em dash (—) to a spaced hyphen ( - ), the follow-up to #13480 tracked as FE-1233, based on the Screaming Frog crawl that flagged the em dash titles. ## Changes - **What**: Replaced the em dash separator with a hyphen in every page meta title, in both `en` and `zh-CN`. Covers ~44 inline page titles, the shared title keys in `i18n/translations.ts` (`cloudNodes.meta.title`, `mcp.meta.title`, `affiliate-terms.page.title`, `enterprise-msa.page.title`, `affiliate.page.title`, `launches.page.title`), and the dynamic `customers`, `demos`, and `supported-models` `... - Comfy` suffixes. `BaseLayout` reuses each page title for `og:title`, `twitter:title`, and the JSON-LD `name`, so those inherit the change from a single source per page. - Updated the e2e title assertions to match. `launches` asserts via `t()` so it follows the translation change automatically. ## Review Focus - **Scope is titles only.** The crawl and this ticket are about meta titles. Description / body copy em dashes are left untouched, they are marketing copy, which we keep em-dashed per the comms-only styling decision. A full JSON-LD audit across all 57 routes confirms every `name`/title field is now em-dash-free. - **zh-CN cloud-nodes title keeps its Chinese double dash `——`** (`自定义节点包合集——开箱即用`). That is correct CJK punctuation, a dash break, not a brand/Latin separator, so the Latin-script separator concern does not apply. Its e2e assertion is left as `——` to match. - No visual change: titles are `<head>` metadata, not rendered UI, so there is nothing to screenshot on the page. Rendered `<title>` output was verified on the dev server across inline, `t()`-based, zh-CN, dynamic, and 404 routes, and `og:`/`twitter:` inheritance was confirmed. Ref: FE-1233
144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
import { expect } from '@playwright/test'
|
|
|
|
import { test } from './fixtures/blockExternalMedia'
|
|
|
|
test.describe('Cloud page @smoke', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/cloud')
|
|
})
|
|
|
|
test('has correct title', async ({ page }) => {
|
|
await expect(page).toHaveTitle('Comfy Cloud - AI in the Cloud')
|
|
})
|
|
|
|
test('HeroSection heading and subtitle are visible', async ({ page }) => {
|
|
await expect(
|
|
page.getByRole('heading', { name: /The full power of/i, level: 1 })
|
|
).toBeVisible()
|
|
await expect(
|
|
page.getByText(/The easiest way to start with ComfyUI/)
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('HeroSection has CTA button linking to cloud', async ({ page }) => {
|
|
const cta = page.getByRole('link', { name: /TRY COMFY CLOUD FOR FREE/i })
|
|
await expect(cta).toBeVisible()
|
|
})
|
|
|
|
test('ReasonSection heading and reasons are visible', async ({ page }) => {
|
|
await expect(
|
|
page.getByRole('heading', { name: /Why.*professionals.*choose/i })
|
|
).toBeVisible()
|
|
|
|
for (const title of [
|
|
'Powerful GPUs',
|
|
'All models',
|
|
'More control',
|
|
'Community workflows'
|
|
]) {
|
|
await expect(page.getByText(title).first()).toBeVisible()
|
|
}
|
|
})
|
|
|
|
test('AIModelsSection heading and 6 model cards are visible', async ({
|
|
page
|
|
}) => {
|
|
const heading = page.getByRole('heading', { name: /leading AI models/i })
|
|
await expect(heading).toBeVisible()
|
|
|
|
const section = heading.locator('xpath=ancestor::section')
|
|
const grid = section.locator('.grid')
|
|
const modelCards = grid.locator('a[href="https://comfy.org/workflows"]')
|
|
await expect(modelCards).toHaveCount(6)
|
|
})
|
|
|
|
test('AIModelsSection CTA links to workflows', async ({ page }) => {
|
|
const cta = page.getByRole('link', {
|
|
name: /EXPLORE WORKFLOWS/i
|
|
})
|
|
await expect(cta.first()).toBeVisible()
|
|
await expect(cta.first()).toHaveAttribute(
|
|
'href',
|
|
'https://comfy.org/workflows'
|
|
)
|
|
})
|
|
|
|
test('AudienceSection heading and cards are visible', async ({ page }) => {
|
|
await expect(page.getByText(/creators/i).first()).toBeVisible()
|
|
|
|
for (const label of ['CREATORS', 'TEAMS & STUDIOS']) {
|
|
await expect(page.getByText(label).first()).toBeVisible()
|
|
}
|
|
})
|
|
|
|
test('PricingSection heading and CTA are visible', async ({ page }) => {
|
|
await expect(page.getByText(/Simple, credit-based pricing/)).toBeVisible()
|
|
|
|
const cta = page.getByRole('link', { name: /SEE PRICING PLANS/i })
|
|
await expect(cta).toBeVisible()
|
|
await expect(cta).toHaveAttribute('href', '/cloud/pricing')
|
|
})
|
|
|
|
test('ProductCardsSection has 3 product cards', async ({ page }) => {
|
|
const section = page.locator('section', {
|
|
has: page.getByRole('heading', { name: /The AI creation/ })
|
|
})
|
|
const cards = section.locator('a[href]')
|
|
await expect(cards).toHaveCount(3)
|
|
})
|
|
|
|
test('FAQSection heading is visible with 15 items', async ({ page }) => {
|
|
await expect(page.getByRole('heading', { name: /FAQ/i })).toBeVisible()
|
|
|
|
const faqButtons = page.locator('button[aria-controls^="faq-panel-"]')
|
|
await expect(faqButtons).toHaveCount(15)
|
|
})
|
|
})
|
|
|
|
test.describe('Cloud FAQ accordion @interaction', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/cloud')
|
|
})
|
|
|
|
test('all FAQs are collapsed by default', async ({ page }) => {
|
|
await expect(
|
|
page.getByText(/Comfy Cloud is a version of ComfyUI/i)
|
|
).toBeHidden()
|
|
})
|
|
|
|
test('clicking a collapsed FAQ expands it', async ({ page }) => {
|
|
const firstQuestion = page.getByRole('button', {
|
|
name: /What is Comfy Cloud/i
|
|
})
|
|
await firstQuestion.scrollIntoViewIfNeeded()
|
|
// Gate: wait for Vue hydration to bind aria-expanded
|
|
await expect(firstQuestion).toHaveAttribute('aria-expanded', 'false')
|
|
await firstQuestion.click()
|
|
|
|
await expect(
|
|
page.getByText(/Comfy Cloud is a version of ComfyUI/i)
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('clicking an expanded FAQ collapses it again', async ({ page }) => {
|
|
const firstQuestion = page.getByRole('button', {
|
|
name: /What is Comfy Cloud/i
|
|
})
|
|
await firstQuestion.scrollIntoViewIfNeeded()
|
|
// Gate: wait for Vue hydration to bind aria-expanded
|
|
await expect(firstQuestion).toHaveAttribute('aria-expanded', 'false')
|
|
|
|
await firstQuestion.click()
|
|
await expect(firstQuestion).toHaveAttribute('aria-expanded', 'true')
|
|
await expect(
|
|
page.getByText(/Comfy Cloud is a version of ComfyUI/i)
|
|
).toBeVisible()
|
|
|
|
await firstQuestion.click()
|
|
await expect(firstQuestion).toHaveAttribute('aria-expanded', 'false')
|
|
await expect(
|
|
page.getByText(/Comfy Cloud is a version of ComfyUI/i)
|
|
).toBeHidden()
|
|
})
|
|
})
|