The suite uses the Page Object Model (POM) pattern to separate page-specific selectors from test logic.
BasePage
Shared by all pages:
| Method | Description |
|---|
goto(path) | Navigates, waits for domcontentloaded, asserts HTTP < 400 |
assertNavVisible() | Checks for <nav> or <header> (lenient) |
assertFooterVisible() | Checks for <footer> (lenient) |
assertHasContent() | Body must have >100 characters |
HomePage
| Method | Description |
|---|
assertNavigationLinks() | Links to scopes and /chat/ (accepts aliases) |
ScopePage
| Method | Description |
|---|
assertAllStateLinksPresent() | All 27 states have matching links |
getStateLinkCount() | Raw count of scope-related links |
StatePage
| Method | Description |
|---|
assertStateNameInTitle(stateName) | Title contains state name |
assertCityLinksPresent() | At least one city link exists |
assertBreadcrumbOrHeading(scopeName, stateName) | Body mentions scope or state |
CityPage
| Method | Description |
|---|
assertTitleContainsCityAndState(citySlug, stateSlug) | Handles Portuguese accent normalization |
assertHasContentBody() | Content > 200 characters |
assertSchemaOrgPresent() | application/ld+json contains @context |
TopicPage
| Method | Description |
|---|
assertHeadingHierarchy() | At least one h1 and one h2 |
assertArticleLikeStructure() | Page has main, article, or valid body |
SpecialPage
| Method | Description |
|---|
assertChatWidgetLoads() | Input/textarea/contenteditable visible |
assertContactFormPresent() | Form with ≥2 inputs and submit button |
assertDirectoryListing() | List/grid container visible |