@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
- package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
- package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
- package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
- package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
- package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
- package/tests/cypress/e2e/_docs/README.md +215 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
- package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
- package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
- package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
- package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
- package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
- package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
- package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
- package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
- package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
- package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
- package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
- package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
- package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
- package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
- package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
- package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
- package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
- package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
- package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
- package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
- package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
- package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
- package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
- package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
- package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
- package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
- package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
- package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
- package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
- package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
- package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
- package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
- package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
- package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
- package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
- package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
- package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
- package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
- package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
- package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
- package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
- package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
- package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
- package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
- package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
- package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
- package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
- package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
- package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
- package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
- package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
- package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
- package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
- package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
- package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
- package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
- package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
- package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
- package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
- package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
- package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
- package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
- package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
- package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
- package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
- package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
- package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
- package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
- package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
- package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
- package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
- package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
- package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
- package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
- package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
- package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
- package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
- package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
- package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
- package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
- package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
- package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
- package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
- package/tests/cypress/fixtures/blocks.json +218 -0
- package/tests/cypress/fixtures/entities.json +78 -0
- package/tests/cypress/fixtures/page-builder.json +21 -0
- package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
- package/tests/cypress/src/components/CustomersPOM.ts +439 -0
- package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
- package/tests/cypress/src/components/EntityForm.ts +375 -0
- package/tests/cypress/src/components/EntityList.ts +389 -0
- package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
- package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
- package/tests/cypress/src/components/PostsListPOM.ts +223 -0
- package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
- package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
- package/tests/cypress/src/components/TasksPOM.ts +272 -0
- package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
- package/tests/cypress/src/components/index.ts +21 -0
- package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
- package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
- package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
- package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
- package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
- package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
- package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
- package/tests/cypress/src/controllers/index.js +25 -0
- package/tests/cypress/src/core/AuthPOM.ts +450 -0
- package/tests/cypress/src/core/BasePOM.ts +86 -0
- package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
- package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
- package/tests/cypress/src/core/index.ts +14 -0
- package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
- package/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/tests/cypress/src/entities/PostsPOM.ts +137 -0
- package/tests/cypress/src/entities/TasksPOM.ts +176 -0
- package/tests/cypress/src/entities/index.ts +14 -0
- package/tests/cypress/src/features/BillingPOM.ts +385 -0
- package/tests/cypress/src/features/DashboardPOM.ts +245 -0
- package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
- package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
- package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
- package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
- package/tests/cypress/src/features/SettingsPOM.ts +362 -0
- package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
- package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
- package/tests/cypress/src/features/index.ts +28 -0
- package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
- package/tests/cypress/src/index.ts +101 -0
- package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
- package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
- package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
- package/tests/cypress/src/pages/dashboard/index.js +6 -0
- package/tests/cypress/src/pages/index.js +5 -0
- package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
- package/tests/cypress/src/pages/public/LandingPage.js +69 -0
- package/tests/cypress/src/pages/public/PricingPage.js +33 -0
- package/tests/cypress/src/pages/public/index.js +6 -0
- package/tests/cypress/src/selectors.ts +46 -0
- package/tests/cypress/src/session-helpers.ts +500 -0
- package/tests/cypress/support/doc-commands.ts +260 -0
- package/tests/cypress.config.ts +150 -0
- package/tests/jest/components/post-header.test.tsx +377 -0
- package/tests/jest/config/role-config.test.ts +529 -0
- package/tests/jest/jest.config.ts +81 -0
- package/tests/jest/langchain/COVERAGE.md +372 -0
- package/tests/jest/langchain/guardrails.test.ts +465 -0
- package/tests/jest/langchain/streaming.test.ts +367 -0
- package/tests/jest/langchain/token-tracker.test.ts +455 -0
- package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
- package/tests/jest/langchain/tracer.test.ts +823 -0
- package/tests/jest/user-roles/role-helpers.test.ts +432 -0
- package/tests/jest/validation/categories.test.ts +429 -0
- package/tests/jest/validation/posts.test.ts +546 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Page POM
|
|
3
|
+
*
|
|
4
|
+
* Page Object Model for testing public page rendering.
|
|
5
|
+
* Validates that pages created with the Block Editor render correctly
|
|
6
|
+
* on the public-facing site.
|
|
7
|
+
*
|
|
8
|
+
* Convention: block-{slug} for rendered blocks
|
|
9
|
+
* Based on data-cy attributes added to block components.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { cySelector } from '../selectors'
|
|
13
|
+
|
|
14
|
+
export interface PageData {
|
|
15
|
+
slug: string
|
|
16
|
+
locale?: 'en' | 'es'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class PublicPagePOM {
|
|
20
|
+
// ============================================
|
|
21
|
+
// SELECTORS - Navbar (using centralized cySelector)
|
|
22
|
+
// ============================================
|
|
23
|
+
|
|
24
|
+
static get navbarSelectors() {
|
|
25
|
+
return {
|
|
26
|
+
container: cySelector('public.navbar.container'),
|
|
27
|
+
logo: cySelector('public.navbar.logo'),
|
|
28
|
+
loginButton: cySelector('public.navbar.loginButton'),
|
|
29
|
+
signupButton: cySelector('public.navbar.signupButton'),
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ============================================
|
|
34
|
+
// SELECTORS - Footer (using centralized cySelector)
|
|
35
|
+
// ============================================
|
|
36
|
+
|
|
37
|
+
static get footerSelectors() {
|
|
38
|
+
return {
|
|
39
|
+
container: cySelector('public.footer.container'),
|
|
40
|
+
logo: cySelector('public.footer.logo'),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ============================================
|
|
45
|
+
// SELECTORS - Page Container
|
|
46
|
+
// ============================================
|
|
47
|
+
|
|
48
|
+
static get pageSelectors() {
|
|
49
|
+
return {
|
|
50
|
+
// Page wrapper (from PageRenderer)
|
|
51
|
+
page: '[data-page-id]',
|
|
52
|
+
pageById: (id: string) => `[data-page-id="${id}"]`,
|
|
53
|
+
pageBySlug: (slug: string) => `[data-page-slug="${slug}"]`,
|
|
54
|
+
|
|
55
|
+
// Generic block wrapper
|
|
56
|
+
blockWrapper: '[data-block-id]',
|
|
57
|
+
blockById: (id: string) => `[data-block-id="${id}"]`,
|
|
58
|
+
blockBySlug: (slug: string) => `[data-block-slug="${slug}"]`,
|
|
59
|
+
|
|
60
|
+
// Empty page state
|
|
61
|
+
emptyPage: '[data-cy="page-empty"]',
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// SELECTORS - Block Components
|
|
67
|
+
// ============================================
|
|
68
|
+
|
|
69
|
+
static get blockSelectors() {
|
|
70
|
+
return {
|
|
71
|
+
// Core blocks (from contents/themes/default/blocks/)
|
|
72
|
+
hero: '[data-cy="block-hero"]',
|
|
73
|
+
ctaSection: '[data-cy="block-cta-section"]',
|
|
74
|
+
featuresGrid: '[data-cy="block-features-grid"]',
|
|
75
|
+
testimonials: '[data-cy="block-testimonials"]',
|
|
76
|
+
textContent: '[data-cy="block-text-content"]',
|
|
77
|
+
benefits: '[data-cy="block-benefits"]',
|
|
78
|
+
|
|
79
|
+
// Generic block selector
|
|
80
|
+
block: (slug: string) => `[data-cy="block-${slug}"]`,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================
|
|
85
|
+
// SELECTORS - Block Internal Elements
|
|
86
|
+
// ============================================
|
|
87
|
+
|
|
88
|
+
static get heroElements() {
|
|
89
|
+
return {
|
|
90
|
+
section: '[data-cy="block-hero"]',
|
|
91
|
+
title: '[data-cy="block-hero"] h1',
|
|
92
|
+
subtitle: '[data-cy="block-hero"] p',
|
|
93
|
+
ctaButton: '[data-cy="block-hero"] a[href]',
|
|
94
|
+
backgroundImage: '[data-cy="block-hero"] img',
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static get ctaElements() {
|
|
99
|
+
return {
|
|
100
|
+
section: '[data-cy="block-cta-section"]',
|
|
101
|
+
title: '[data-cy="block-cta-section"] h2',
|
|
102
|
+
description: '[data-cy="block-cta-section"] p',
|
|
103
|
+
primaryButton: '[data-cy="block-cta-section"] a:first-of-type',
|
|
104
|
+
secondaryButton: '[data-cy="block-cta-section"] a:last-of-type',
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static get featuresElements() {
|
|
109
|
+
return {
|
|
110
|
+
section: '[data-cy="block-features-grid"]',
|
|
111
|
+
title: '[data-cy="block-features-grid"] h2',
|
|
112
|
+
featureItem: '[data-cy="block-features-grid"] [class*="feature"]',
|
|
113
|
+
featureIcon: '[data-cy="block-features-grid"] svg',
|
|
114
|
+
featureTitle: '[data-cy="block-features-grid"] h3',
|
|
115
|
+
featureDescription: '[data-cy="block-features-grid"] p',
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static get testimonialsElements() {
|
|
120
|
+
return {
|
|
121
|
+
section: '[data-cy="block-testimonials"]',
|
|
122
|
+
title: '[data-cy="block-testimonials"] h2',
|
|
123
|
+
testimonialItem: '[data-cy="block-testimonials"] [class*="testimonial"]',
|
|
124
|
+
quote: '[data-cy="block-testimonials"] blockquote, [data-cy="block-testimonials"] p',
|
|
125
|
+
authorName: '[data-cy="block-testimonials"] [class*="author"]',
|
|
126
|
+
authorAvatar: '[data-cy="block-testimonials"] img',
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
static get textContentElements() {
|
|
131
|
+
return {
|
|
132
|
+
section: '[data-cy="block-text-content"]',
|
|
133
|
+
content: '[data-cy="block-text-content"] [class*="prose"], [data-cy="block-text-content"] div',
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static get benefitsElements() {
|
|
138
|
+
return {
|
|
139
|
+
section: '[data-cy="block-benefits"]',
|
|
140
|
+
title: '[data-cy="block-benefits"] h2',
|
|
141
|
+
benefitItem: '[data-cy="block-benefits"] [class*="benefit"]',
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ============================================
|
|
146
|
+
// NAVIGATION
|
|
147
|
+
// ============================================
|
|
148
|
+
|
|
149
|
+
static visit(slug: string, locale?: string) {
|
|
150
|
+
const path = locale && locale !== 'en' ? `/${locale}/${slug}` : `/${slug}`
|
|
151
|
+
cy.visit(path)
|
|
152
|
+
return this
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static visitEnglish(slug: string) {
|
|
156
|
+
cy.visit(`/${slug}`)
|
|
157
|
+
return this
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static visitSpanish(slug: string) {
|
|
161
|
+
cy.visit(`/es/${slug}`)
|
|
162
|
+
return this
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ============================================
|
|
166
|
+
// WAIT METHODS
|
|
167
|
+
// ============================================
|
|
168
|
+
|
|
169
|
+
static waitForPageLoad() {
|
|
170
|
+
cy.get(this.pageSelectors.page, { timeout: 15000 }).should('exist')
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static waitForBlockLoad(slug: string) {
|
|
175
|
+
cy.get(this.blockSelectors.block(slug), { timeout: 10000 }).should('be.visible')
|
|
176
|
+
return this
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static waitForHeroLoad() {
|
|
180
|
+
cy.get(this.blockSelectors.hero, { timeout: 10000 }).should('be.visible')
|
|
181
|
+
return this
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ============================================
|
|
185
|
+
// INTERACTIONS
|
|
186
|
+
// ============================================
|
|
187
|
+
|
|
188
|
+
static clickHeroCta() {
|
|
189
|
+
cy.get(this.heroElements.ctaButton).first().click()
|
|
190
|
+
return this
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
static clickCtaPrimaryButton() {
|
|
194
|
+
cy.get(this.ctaElements.primaryButton).click()
|
|
195
|
+
return this
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static clickCtaSecondaryButton() {
|
|
199
|
+
cy.get(this.ctaElements.secondaryButton).click()
|
|
200
|
+
return this
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ============================================
|
|
204
|
+
// ASSERTIONS - Page Level
|
|
205
|
+
// ============================================
|
|
206
|
+
|
|
207
|
+
static assertPageExists() {
|
|
208
|
+
cy.get(this.pageSelectors.page).should('exist')
|
|
209
|
+
return this
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static assertPageHasSlug(slug: string) {
|
|
213
|
+
cy.get(this.pageSelectors.pageBySlug(slug)).should('exist')
|
|
214
|
+
return this
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static assertPageNotFound() {
|
|
218
|
+
cy.contains('404').should('exist')
|
|
219
|
+
return this
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static assertPageEmpty() {
|
|
223
|
+
cy.get(this.pageSelectors.emptyPage).should('be.visible')
|
|
224
|
+
return this
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static assertBlockCount(count: number) {
|
|
228
|
+
cy.get(this.pageSelectors.blockWrapper).should('have.length', count)
|
|
229
|
+
return this
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ============================================
|
|
233
|
+
// ASSERTIONS - Block Visibility
|
|
234
|
+
// ============================================
|
|
235
|
+
|
|
236
|
+
static assertHeroVisible() {
|
|
237
|
+
cy.get(this.blockSelectors.hero).should('be.visible')
|
|
238
|
+
return this
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
static assertCtaVisible() {
|
|
242
|
+
cy.get(this.blockSelectors.ctaSection).should('be.visible')
|
|
243
|
+
return this
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static assertFeaturesVisible() {
|
|
247
|
+
cy.get(this.blockSelectors.featuresGrid).should('be.visible')
|
|
248
|
+
return this
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
static assertTestimonialsVisible() {
|
|
252
|
+
cy.get(this.blockSelectors.testimonials).should('be.visible')
|
|
253
|
+
return this
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static assertTextContentVisible() {
|
|
257
|
+
cy.get(this.blockSelectors.textContent).should('be.visible')
|
|
258
|
+
return this
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static assertBenefitsVisible() {
|
|
262
|
+
cy.get(this.blockSelectors.benefits).should('be.visible')
|
|
263
|
+
return this
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static assertBlockVisible(slug: string) {
|
|
267
|
+
cy.get(this.blockSelectors.block(slug)).should('be.visible')
|
|
268
|
+
return this
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static assertBlockNotVisible(slug: string) {
|
|
272
|
+
cy.get(this.blockSelectors.block(slug)).should('not.exist')
|
|
273
|
+
return this
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ============================================
|
|
277
|
+
// ASSERTIONS - Hero Block Content
|
|
278
|
+
// ============================================
|
|
279
|
+
|
|
280
|
+
static assertHeroTitle(title: string) {
|
|
281
|
+
cy.get(this.heroElements.title).should('contain.text', title)
|
|
282
|
+
return this
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static assertHeroSubtitle(subtitle: string) {
|
|
286
|
+
cy.get(this.heroElements.subtitle).should('contain.text', subtitle)
|
|
287
|
+
return this
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
static assertHeroCtaText(text: string) {
|
|
291
|
+
cy.get(this.heroElements.ctaButton).should('contain.text', text)
|
|
292
|
+
return this
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
static assertHeroCtaLink(href: string) {
|
|
296
|
+
cy.get(this.heroElements.ctaButton).should('have.attr', 'href', href)
|
|
297
|
+
return this
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static assertHeroHasBackgroundImage() {
|
|
301
|
+
cy.get(this.heroElements.backgroundImage).should('exist')
|
|
302
|
+
return this
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ============================================
|
|
306
|
+
// ASSERTIONS - CTA Block Content
|
|
307
|
+
// ============================================
|
|
308
|
+
|
|
309
|
+
static assertCtaTitle(title: string) {
|
|
310
|
+
cy.get(this.ctaElements.title).should('contain.text', title)
|
|
311
|
+
return this
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
static assertCtaDescription(description: string) {
|
|
315
|
+
cy.get(this.ctaElements.description).should('contain.text', description)
|
|
316
|
+
return this
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
static assertCtaPrimaryButtonText(text: string) {
|
|
320
|
+
cy.get(this.ctaElements.primaryButton).should('contain.text', text)
|
|
321
|
+
return this
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ============================================
|
|
325
|
+
// ASSERTIONS - Features Block Content
|
|
326
|
+
// ============================================
|
|
327
|
+
|
|
328
|
+
static assertFeaturesTitle(title: string) {
|
|
329
|
+
cy.get(this.featuresElements.title).should('contain.text', title)
|
|
330
|
+
return this
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static assertFeatureCount(count: number) {
|
|
334
|
+
cy.get(this.featuresElements.featureItem).should('have.length', count)
|
|
335
|
+
return this
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
static assertFeatureHasTitle(index: number, title: string) {
|
|
339
|
+
cy.get(this.featuresElements.featureTitle).eq(index).should('contain.text', title)
|
|
340
|
+
return this
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ============================================
|
|
344
|
+
// ASSERTIONS - Testimonials Block Content
|
|
345
|
+
// ============================================
|
|
346
|
+
|
|
347
|
+
static assertTestimonialsTitle(title: string) {
|
|
348
|
+
cy.get(this.testimonialsElements.title).should('contain.text', title)
|
|
349
|
+
return this
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
static assertTestimonialCount(count: number) {
|
|
353
|
+
cy.get(this.testimonialsElements.testimonialItem).should('have.length', count)
|
|
354
|
+
return this
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ============================================
|
|
358
|
+
// ASSERTIONS - Text Content Block
|
|
359
|
+
// ============================================
|
|
360
|
+
|
|
361
|
+
static assertTextContentContains(text: string) {
|
|
362
|
+
cy.get(this.textContentElements.content).should('contain.text', text)
|
|
363
|
+
return this
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ============================================
|
|
367
|
+
// ASSERTIONS - SEO & Metadata
|
|
368
|
+
// ============================================
|
|
369
|
+
|
|
370
|
+
static assertMetaTitle(title: string) {
|
|
371
|
+
cy.title().should('contain', title)
|
|
372
|
+
return this
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static assertMetaDescription(description: string) {
|
|
376
|
+
cy.get('meta[name="description"]').should('have.attr', 'content').and('contain', description)
|
|
377
|
+
return this
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
static assertOgTitle(title: string) {
|
|
381
|
+
cy.get('meta[property="og:title"]').should('have.attr', 'content').and('contain', title)
|
|
382
|
+
return this
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
static assertOgDescription(description: string) {
|
|
386
|
+
cy.get('meta[property="og:description"]').should('have.attr', 'content').and('contain', description)
|
|
387
|
+
return this
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
static assertCanonicalUrl(url: string) {
|
|
391
|
+
cy.get('link[rel="canonical"]').should('have.attr', 'href').and('contain', url)
|
|
392
|
+
return this
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// ============================================
|
|
396
|
+
// COMPLETE VALIDATION WORKFLOWS
|
|
397
|
+
// ============================================
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Validate a complete page with expected blocks
|
|
401
|
+
*/
|
|
402
|
+
static validatePage(slug: string, expectedBlocks: string[]) {
|
|
403
|
+
this.visit(slug)
|
|
404
|
+
this.waitForPageLoad()
|
|
405
|
+
this.assertPageHasSlug(slug)
|
|
406
|
+
this.assertBlockCount(expectedBlocks.length)
|
|
407
|
+
|
|
408
|
+
expectedBlocks.forEach((blockSlug) => {
|
|
409
|
+
this.assertBlockVisible(blockSlug)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
return this
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Validate hero block has all expected content
|
|
417
|
+
*/
|
|
418
|
+
static validateHeroBlock(expectedContent: { title?: string; subtitle?: string; ctaText?: string; ctaLink?: string }) {
|
|
419
|
+
this.assertHeroVisible()
|
|
420
|
+
|
|
421
|
+
if (expectedContent.title) this.assertHeroTitle(expectedContent.title)
|
|
422
|
+
if (expectedContent.subtitle) this.assertHeroSubtitle(expectedContent.subtitle)
|
|
423
|
+
if (expectedContent.ctaText) this.assertHeroCtaText(expectedContent.ctaText)
|
|
424
|
+
if (expectedContent.ctaLink) this.assertHeroCtaLink(expectedContent.ctaLink)
|
|
425
|
+
|
|
426
|
+
return this
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Validate page SEO metadata
|
|
431
|
+
*/
|
|
432
|
+
static validateSeo(expected: { title?: string; description?: string }) {
|
|
433
|
+
if (expected.title) {
|
|
434
|
+
this.assertMetaTitle(expected.title)
|
|
435
|
+
this.assertOgTitle(expected.title)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (expected.description) {
|
|
439
|
+
this.assertMetaDescription(expected.description)
|
|
440
|
+
this.assertOgDescription(expected.description)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return this
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export default PublicPagePOM
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Post POM
|
|
3
|
+
*
|
|
4
|
+
* Page Object Model for public post display pages (/blog/[slug]).
|
|
5
|
+
* Covers post rendering, blocks, categories, and SEO verification.
|
|
6
|
+
*
|
|
7
|
+
* Convention: post-{component}-{element}
|
|
8
|
+
* Based on selectors documented in tests.md
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export class PublicPostPOM {
|
|
12
|
+
// ============================================
|
|
13
|
+
// SELECTORS - Public Post
|
|
14
|
+
// ============================================
|
|
15
|
+
|
|
16
|
+
static get postSelectors() {
|
|
17
|
+
return {
|
|
18
|
+
content: '[data-cy="post-content"]',
|
|
19
|
+
header: '[data-cy="post-header"]',
|
|
20
|
+
title: '[data-cy="post-title"]',
|
|
21
|
+
excerpt: '[data-cy="post-excerpt"]',
|
|
22
|
+
featuredImage: '[data-cy="post-featured-image-display"]',
|
|
23
|
+
categoriesDisplay: '[data-cy="post-categories-display"]',
|
|
24
|
+
categoryBadge: (name: string) => `[data-cy="post-categories-display"] :contains("${name}")`,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ============================================
|
|
29
|
+
// NAVIGATION
|
|
30
|
+
// ============================================
|
|
31
|
+
|
|
32
|
+
static visit(slug: string, options?: Partial<Cypress.VisitOptions>) {
|
|
33
|
+
cy.visit(`/blog/${slug}`, options)
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================
|
|
38
|
+
// WAIT METHODS
|
|
39
|
+
// ============================================
|
|
40
|
+
|
|
41
|
+
static waitForPostLoad() {
|
|
42
|
+
cy.get(this.postSelectors.content, { timeout: 15000 }).should('be.visible')
|
|
43
|
+
return this
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ============================================
|
|
47
|
+
// ASSERTIONS
|
|
48
|
+
// ============================================
|
|
49
|
+
|
|
50
|
+
static assertPostVisible() {
|
|
51
|
+
cy.get(this.postSelectors.content).should('be.visible')
|
|
52
|
+
return this
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static assertHeaderVisible() {
|
|
56
|
+
cy.get(this.postSelectors.header).should('be.visible')
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static assertTitle(title: string) {
|
|
61
|
+
cy.get(this.postSelectors.title).should('contain', title)
|
|
62
|
+
return this
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static assertExcerpt(excerpt: string) {
|
|
66
|
+
cy.get(this.postSelectors.excerpt).should('contain', excerpt)
|
|
67
|
+
return this
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static assertFeaturedImageVisible() {
|
|
71
|
+
cy.get(this.postSelectors.featuredImage).should('be.visible')
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static assertCategoryVisible(categoryName: string) {
|
|
76
|
+
cy.get(this.postSelectors.categoriesDisplay).should('contain', categoryName)
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static assertCategoryBadgeColor(categoryName: string, color: string) {
|
|
81
|
+
// Check that category badge has the expected color in its styling
|
|
82
|
+
cy.get(this.postSelectors.categoryBadge(categoryName))
|
|
83
|
+
.should('exist')
|
|
84
|
+
.and('have.attr', 'style')
|
|
85
|
+
.and('include', color)
|
|
86
|
+
return this
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static assertBlockRendered(blockType: string) {
|
|
90
|
+
// Check for block rendering (blocks typically have a wrapper with block-specific data)
|
|
91
|
+
cy.get(this.postSelectors.content).within(() => {
|
|
92
|
+
cy.contains(blockType, { matchCase: false }).should('exist')
|
|
93
|
+
})
|
|
94
|
+
return this
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static assert404() {
|
|
98
|
+
cy.contains('404').should('be.visible')
|
|
99
|
+
return this
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static assertUnpublishedNotAccessible() {
|
|
103
|
+
// Should redirect to 404 or show error
|
|
104
|
+
cy.url().should('match', /404|not-found/)
|
|
105
|
+
return this
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================
|
|
109
|
+
// SEO VERIFICATION
|
|
110
|
+
// ============================================
|
|
111
|
+
|
|
112
|
+
static assertMetaTitle(title: string) {
|
|
113
|
+
cy.get('head title').should('contain', title)
|
|
114
|
+
return this
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static assertMetaDescription(description: string) {
|
|
118
|
+
cy.get('head meta[name="description"]')
|
|
119
|
+
.should('have.attr', 'content')
|
|
120
|
+
.and('include', description)
|
|
121
|
+
return this
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static assertOgImage(imageUrl: string) {
|
|
125
|
+
cy.get('head meta[property="og:image"]')
|
|
126
|
+
.should('have.attr', 'content')
|
|
127
|
+
.and('include', imageUrl)
|
|
128
|
+
return this
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static assertNoIndex() {
|
|
132
|
+
cy.get('head meta[name="robots"]')
|
|
133
|
+
.should('have.attr', 'content')
|
|
134
|
+
.and('include', 'noindex')
|
|
135
|
+
return this
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static assertNoFollow() {
|
|
139
|
+
cy.get('head meta[name="robots"]')
|
|
140
|
+
.should('have.attr', 'content')
|
|
141
|
+
.and('include', 'nofollow')
|
|
142
|
+
return this
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default PublicPostPOM
|