@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,340 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Public Page Rendering Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests for public page rendering including block visibility,
|
|
7
|
+
* content validation, SEO metadata, and i18n support.
|
|
8
|
+
*
|
|
9
|
+
* Tags: @uat, @feat-pages, @public, @page-builder
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as allure from 'allure-cypress'
|
|
13
|
+
import { PublicPagePOM } from '../../../../src/components'
|
|
14
|
+
import pageBuilderFixtures from '../../../../fixtures/page-builder.json'
|
|
15
|
+
|
|
16
|
+
describe('Public Page Rendering', {
|
|
17
|
+
tags: ['@uat', '@feat-pages', '@public', '@page-builder']
|
|
18
|
+
}, () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
allure.epic('Page Builder')
|
|
21
|
+
allure.feature('Public Rendering')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// ============================================================
|
|
25
|
+
// Published Page Tests
|
|
26
|
+
// ============================================================
|
|
27
|
+
describe('Published Page Rendering', () => {
|
|
28
|
+
it('PB_PUBLIC_001: Should render published page with HTTP 200', { tags: '@smoke' }, () => {
|
|
29
|
+
allure.story('Page Rendering')
|
|
30
|
+
allure.severity('critical')
|
|
31
|
+
|
|
32
|
+
// Visit about-us page (exists from sample data)
|
|
33
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
34
|
+
|
|
35
|
+
// Visit the page directly - cy.visit() already validates the page loads successfully
|
|
36
|
+
PublicPagePOM.visit(slug)
|
|
37
|
+
PublicPagePOM.waitForPageLoad()
|
|
38
|
+
PublicPagePOM.assertPageExists()
|
|
39
|
+
|
|
40
|
+
// Verify page has correct slug attribute
|
|
41
|
+
cy.get(`[data-page-slug="${slug}"]`).should('exist')
|
|
42
|
+
|
|
43
|
+
cy.log('Published page rendered successfully')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('PB_PUBLIC_002: Should display Hero block with content', () => {
|
|
47
|
+
allure.story('Block Rendering')
|
|
48
|
+
|
|
49
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
50
|
+
|
|
51
|
+
PublicPagePOM.visit(slug)
|
|
52
|
+
PublicPagePOM.waitForPageLoad()
|
|
53
|
+
|
|
54
|
+
// Hero block should be visible
|
|
55
|
+
PublicPagePOM.assertHeroVisible()
|
|
56
|
+
|
|
57
|
+
// Verify hero has content
|
|
58
|
+
cy.get(PublicPagePOM.heroElements.title).should('exist')
|
|
59
|
+
|
|
60
|
+
cy.log('Hero block rendered with content')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('PB_PUBLIC_003: Should display Features Grid block', () => {
|
|
64
|
+
allure.story('Block Rendering')
|
|
65
|
+
|
|
66
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
67
|
+
|
|
68
|
+
PublicPagePOM.visit(slug)
|
|
69
|
+
PublicPagePOM.waitForPageLoad()
|
|
70
|
+
|
|
71
|
+
PublicPagePOM.assertFeaturesVisible()
|
|
72
|
+
|
|
73
|
+
cy.log('Features Grid block rendered')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('PB_PUBLIC_004: Should display CTA Section block', () => {
|
|
77
|
+
allure.story('Block Rendering')
|
|
78
|
+
|
|
79
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
80
|
+
|
|
81
|
+
PublicPagePOM.visit(slug)
|
|
82
|
+
PublicPagePOM.waitForPageLoad()
|
|
83
|
+
|
|
84
|
+
PublicPagePOM.assertCtaVisible()
|
|
85
|
+
|
|
86
|
+
cy.log('CTA Section block rendered')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('PB_PUBLIC_005: Should display Testimonials block', () => {
|
|
90
|
+
allure.story('Block Rendering')
|
|
91
|
+
|
|
92
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
93
|
+
|
|
94
|
+
PublicPagePOM.visit(slug)
|
|
95
|
+
PublicPagePOM.waitForPageLoad()
|
|
96
|
+
|
|
97
|
+
PublicPagePOM.assertTestimonialsVisible()
|
|
98
|
+
|
|
99
|
+
cy.log('Testimonials block rendered')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('PB_PUBLIC_006: Should display all expected blocks', () => {
|
|
103
|
+
allure.story('Block Rendering')
|
|
104
|
+
|
|
105
|
+
const { slug, expectedBlocks } = pageBuilderFixtures.existingPages.aboutUs
|
|
106
|
+
|
|
107
|
+
if (expectedBlocks) {
|
|
108
|
+
PublicPagePOM.validatePage(slug, expectedBlocks)
|
|
109
|
+
cy.log(`All ${expectedBlocks.length} expected blocks rendered`)
|
|
110
|
+
} else {
|
|
111
|
+
PublicPagePOM.visit(slug)
|
|
112
|
+
PublicPagePOM.waitForPageLoad()
|
|
113
|
+
cy.log('Page rendered (no specific blocks expected)')
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// ============================================================
|
|
119
|
+
// Draft Page Tests
|
|
120
|
+
// ============================================================
|
|
121
|
+
describe('Draft Page Handling', () => {
|
|
122
|
+
it('PB_PUBLIC_007: Should return 404 for draft page', () => {
|
|
123
|
+
allure.story('Access Control')
|
|
124
|
+
|
|
125
|
+
// Create a draft page via API
|
|
126
|
+
const timestamp = Date.now()
|
|
127
|
+
const draftSlug = `draft-test-${timestamp}`
|
|
128
|
+
|
|
129
|
+
cy.request({
|
|
130
|
+
method: 'POST',
|
|
131
|
+
url: '/api/v1/pages',
|
|
132
|
+
headers: {
|
|
133
|
+
'x-api-key': 'test_api_key_for_testing_purposes_only_not_a_real_secret_key_abc123',
|
|
134
|
+
'Content-Type': 'application/json'
|
|
135
|
+
},
|
|
136
|
+
body: {
|
|
137
|
+
title: `Draft Test ${timestamp}`,
|
|
138
|
+
slug: draftSlug,
|
|
139
|
+
locale: 'en',
|
|
140
|
+
published: false, // Draft
|
|
141
|
+
blocks: []
|
|
142
|
+
}
|
|
143
|
+
}).then((createResponse) => {
|
|
144
|
+
const pageId = createResponse.body.data.id
|
|
145
|
+
|
|
146
|
+
// Try to access draft page publicly
|
|
147
|
+
cy.request({
|
|
148
|
+
url: `/${draftSlug}`,
|
|
149
|
+
failOnStatusCode: false
|
|
150
|
+
}).then((response) => {
|
|
151
|
+
expect(response.status).to.eq(404)
|
|
152
|
+
cy.log('Draft page correctly returns 404')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
// Cleanup
|
|
156
|
+
cy.request({
|
|
157
|
+
method: 'DELETE',
|
|
158
|
+
url: `/api/v1/pages/${pageId}`,
|
|
159
|
+
headers: {
|
|
160
|
+
'x-api-key': 'test_api_key_for_testing_purposes_only_not_a_real_secret_key_abc123'
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// ============================================================
|
|
168
|
+
// SEO Metadata Tests
|
|
169
|
+
// ============================================================
|
|
170
|
+
describe('SEO Metadata', () => {
|
|
171
|
+
it('PB_PUBLIC_008: Should have correct meta title', () => {
|
|
172
|
+
allure.story('SEO')
|
|
173
|
+
|
|
174
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
175
|
+
|
|
176
|
+
PublicPagePOM.visit(slug)
|
|
177
|
+
PublicPagePOM.waitForPageLoad()
|
|
178
|
+
|
|
179
|
+
// Check page title exists
|
|
180
|
+
cy.title().should('not.be.empty')
|
|
181
|
+
|
|
182
|
+
cy.log('Meta title present')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('PB_PUBLIC_009: Should have meta description', () => {
|
|
186
|
+
allure.story('SEO')
|
|
187
|
+
|
|
188
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
189
|
+
|
|
190
|
+
PublicPagePOM.visit(slug)
|
|
191
|
+
PublicPagePOM.waitForPageLoad()
|
|
192
|
+
|
|
193
|
+
// Check meta description exists
|
|
194
|
+
cy.get('meta[name="description"]').should('exist')
|
|
195
|
+
|
|
196
|
+
cy.log('Meta description present')
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// ============================================================
|
|
201
|
+
// i18n Tests
|
|
202
|
+
// ============================================================
|
|
203
|
+
describe('Internationalization', () => {
|
|
204
|
+
it('PB_PUBLIC_010: Should render Spanish version of page', { tags: '@i18n' }, () => {
|
|
205
|
+
allure.story('i18n')
|
|
206
|
+
|
|
207
|
+
const spanishSlug = pageBuilderFixtures.existingPages.sobreNosotros?.slug
|
|
208
|
+
|
|
209
|
+
if (spanishSlug) {
|
|
210
|
+
// Try Spanish locale path
|
|
211
|
+
cy.request({
|
|
212
|
+
url: `/es/${spanishSlug}`,
|
|
213
|
+
failOnStatusCode: false
|
|
214
|
+
}).then((response) => {
|
|
215
|
+
if (response.status === 200) {
|
|
216
|
+
PublicPagePOM.visitSpanish(spanishSlug)
|
|
217
|
+
PublicPagePOM.waitForPageLoad()
|
|
218
|
+
PublicPagePOM.assertPageExists()
|
|
219
|
+
|
|
220
|
+
cy.log('Spanish page rendered successfully')
|
|
221
|
+
} else {
|
|
222
|
+
// Try without locale prefix (might be default locale)
|
|
223
|
+
cy.request({
|
|
224
|
+
url: `/${spanishSlug}`,
|
|
225
|
+
failOnStatusCode: false
|
|
226
|
+
}).then((altResponse) => {
|
|
227
|
+
expect(altResponse.status).to.eq(200)
|
|
228
|
+
cy.log('Spanish page rendered at root path')
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
} else {
|
|
233
|
+
cy.log('No Spanish page configured in fixtures - skipping')
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// ============================================================
|
|
239
|
+
// Block Interaction Tests
|
|
240
|
+
// ============================================================
|
|
241
|
+
describe('Block Interactions', () => {
|
|
242
|
+
it('PB_PUBLIC_011: Should have clickable CTA button', () => {
|
|
243
|
+
allure.story('Block Interactions')
|
|
244
|
+
|
|
245
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
246
|
+
|
|
247
|
+
PublicPagePOM.visit(slug)
|
|
248
|
+
PublicPagePOM.waitForPageLoad()
|
|
249
|
+
|
|
250
|
+
// Check if CTA section has clickable links
|
|
251
|
+
cy.get(PublicPagePOM.ctaElements.section).then(($section) => {
|
|
252
|
+
if ($section.length > 0) {
|
|
253
|
+
cy.get(PublicPagePOM.ctaElements.primaryButton).then(($btn) => {
|
|
254
|
+
if ($btn.length > 0) {
|
|
255
|
+
cy.wrap($btn).should('have.attr', 'href')
|
|
256
|
+
cy.log('CTA button is clickable with href')
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('PB_PUBLIC_012: Should have clickable Hero CTA', () => {
|
|
264
|
+
allure.story('Block Interactions')
|
|
265
|
+
|
|
266
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
267
|
+
|
|
268
|
+
PublicPagePOM.visit(slug)
|
|
269
|
+
PublicPagePOM.waitForPageLoad()
|
|
270
|
+
|
|
271
|
+
cy.get(PublicPagePOM.heroElements.ctaButton).then(($btn) => {
|
|
272
|
+
if ($btn.length > 0) {
|
|
273
|
+
cy.wrap($btn).should('have.attr', 'href')
|
|
274
|
+
cy.log('Hero CTA is clickable')
|
|
275
|
+
} else {
|
|
276
|
+
cy.log('Hero CTA not present on this page')
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// ============================================================
|
|
283
|
+
// Page Structure Tests
|
|
284
|
+
// ============================================================
|
|
285
|
+
describe('Page Structure', () => {
|
|
286
|
+
it('PB_PUBLIC_013: Should have correct page data attributes', () => {
|
|
287
|
+
allure.story('Page Structure')
|
|
288
|
+
|
|
289
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
290
|
+
|
|
291
|
+
PublicPagePOM.visit(slug)
|
|
292
|
+
PublicPagePOM.waitForPageLoad()
|
|
293
|
+
|
|
294
|
+
// Verify page has data attributes
|
|
295
|
+
cy.get('[data-page-id]').should('exist')
|
|
296
|
+
cy.get('[data-page-slug]').should('have.attr', 'data-page-slug', slug)
|
|
297
|
+
|
|
298
|
+
cy.log('Page data attributes correct')
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
it('PB_PUBLIC_014: Should have block data attributes', () => {
|
|
302
|
+
allure.story('Page Structure')
|
|
303
|
+
|
|
304
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
305
|
+
|
|
306
|
+
PublicPagePOM.visit(slug)
|
|
307
|
+
PublicPagePOM.waitForPageLoad()
|
|
308
|
+
|
|
309
|
+
// Verify blocks have data attributes
|
|
310
|
+
cy.get('[data-block-id]').should('have.length.at.least', 1)
|
|
311
|
+
cy.get('[data-block-slug]').should('have.length.at.least', 1)
|
|
312
|
+
|
|
313
|
+
cy.log('Block data attributes present')
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
// ============================================================
|
|
318
|
+
// Performance Tests
|
|
319
|
+
// ============================================================
|
|
320
|
+
describe('Performance', () => {
|
|
321
|
+
it('PB_PUBLIC_015: Should load page within reasonable time', () => {
|
|
322
|
+
allure.story('Performance')
|
|
323
|
+
|
|
324
|
+
const slug = pageBuilderFixtures.existingPages.aboutUs.slug
|
|
325
|
+
const startTime = Date.now()
|
|
326
|
+
|
|
327
|
+
PublicPagePOM.visit(slug)
|
|
328
|
+
PublicPagePOM.waitForPageLoad()
|
|
329
|
+
|
|
330
|
+
cy.then(() => {
|
|
331
|
+
const loadTime = Date.now() - startTime
|
|
332
|
+
|
|
333
|
+
// Page should load within 5 seconds
|
|
334
|
+
expect(loadTime).to.be.lessThan(5000)
|
|
335
|
+
|
|
336
|
+
cy.log(`Page loaded in ${loadTime}ms`)
|
|
337
|
+
})
|
|
338
|
+
})
|
|
339
|
+
})
|
|
340
|
+
})
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
feature: API-Aware Testing Pattern
|
|
3
|
+
priority: medium
|
|
4
|
+
tags: [posts, categories, api-aware, patterns, testing]
|
|
5
|
+
grepTags: [uat, feat-posts, api, patterns]
|
|
6
|
+
coverage: 3
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# API-Aware Testing Pattern - Demo
|
|
10
|
+
|
|
11
|
+
> Test suite demonstrating API-aware POM patterns for deterministic waits instead of arbitrary delays. Shows how to replace `cy.wait(ms)` with API intercepts for more reliable and faster tests.
|
|
12
|
+
|
|
13
|
+
## Background
|
|
14
|
+
|
|
15
|
+
```gherkin:en
|
|
16
|
+
Given I am logged in as Owner (owner@nextspark.dev)
|
|
17
|
+
And I have the ApiInterceptor utility available
|
|
18
|
+
And deterministic API waits replace arbitrary delays
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```gherkin:es
|
|
22
|
+
Given estoy logueado como Owner (owner@nextspark.dev)
|
|
23
|
+
And tengo la utilidad ApiInterceptor disponible
|
|
24
|
+
And las esperas deterministicas de API reemplazan delays arbitrarios
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## @test APIAWARE-001: Navigate with deterministic API wait
|
|
30
|
+
|
|
31
|
+
### Metadata
|
|
32
|
+
- **Priority:** High
|
|
33
|
+
- **Type:** Smoke
|
|
34
|
+
- **Tags:** navigation, api-wait, patterns
|
|
35
|
+
- **Grep:** `@smoke`
|
|
36
|
+
|
|
37
|
+
```gherkin:en
|
|
38
|
+
Scenario: Navigate with deterministic API wait
|
|
39
|
+
|
|
40
|
+
Given I am logged in as Owner
|
|
41
|
+
When I use the API-aware navigation method
|
|
42
|
+
Then the page should be visible
|
|
43
|
+
And at least 1 category row should exist
|
|
44
|
+
|
|
45
|
+
Note: This replaces the pattern:
|
|
46
|
+
visitCategoriesPage() + waitForPageLoad() + cy.wait(2000)
|
|
47
|
+
With:
|
|
48
|
+
visitWithApiWait()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```gherkin:es
|
|
52
|
+
Scenario: Navegar con espera deterministica de API
|
|
53
|
+
|
|
54
|
+
Given estoy logueado como Owner
|
|
55
|
+
When uso el metodo de navegacion consciente de API
|
|
56
|
+
Then la pagina deberia estar visible
|
|
57
|
+
And al menos 1 fila de categoria deberia existir
|
|
58
|
+
|
|
59
|
+
Nota: Esto reemplaza el patron:
|
|
60
|
+
visitCategoriesPage() + waitForPageLoad() + cy.wait(2000)
|
|
61
|
+
Con:
|
|
62
|
+
visitWithApiWait()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Expected Results
|
|
66
|
+
- Navigation completes with API wait
|
|
67
|
+
- Page loads with data from API response
|
|
68
|
+
- No arbitrary delays needed
|
|
69
|
+
- Test is faster and more reliable
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## @test APIAWARE-002: Create category with deterministic waits
|
|
74
|
+
|
|
75
|
+
### Metadata
|
|
76
|
+
- **Priority:** High
|
|
77
|
+
- **Type:** Regression
|
|
78
|
+
- **Tags:** crud, create, api-wait
|
|
79
|
+
|
|
80
|
+
```gherkin:en
|
|
81
|
+
Scenario: Create category with deterministic waits
|
|
82
|
+
|
|
83
|
+
Given I am logged in as Owner
|
|
84
|
+
And I have navigated with API wait
|
|
85
|
+
When I create a category using the API-aware method
|
|
86
|
+
Then the category should appear in the list
|
|
87
|
+
|
|
88
|
+
Note: This replaces the pattern:
|
|
89
|
+
createCategory() + cy.wait(2000)
|
|
90
|
+
With:
|
|
91
|
+
createCategoryWithApiWait()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```gherkin:es
|
|
95
|
+
Scenario: Crear categoria con esperas deterministicas
|
|
96
|
+
|
|
97
|
+
Given estoy logueado como Owner
|
|
98
|
+
And he navegado con espera de API
|
|
99
|
+
When creo una categoria usando el metodo consciente de API
|
|
100
|
+
Then la categoria deberia aparecer en la lista
|
|
101
|
+
|
|
102
|
+
Nota: Esto reemplaza el patron:
|
|
103
|
+
createCategory() + cy.wait(2000)
|
|
104
|
+
Con:
|
|
105
|
+
createCategoryWithApiWait()
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Expected Results
|
|
109
|
+
- Create operation waits for POST response
|
|
110
|
+
- List refreshes after create
|
|
111
|
+
- New category appears in list
|
|
112
|
+
- No arbitrary delays needed
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## @test APIAWARE-003: Direct ApiInterceptor usage for custom flows
|
|
117
|
+
|
|
118
|
+
### Metadata
|
|
119
|
+
- **Priority:** Medium
|
|
120
|
+
- **Type:** Regression
|
|
121
|
+
- **Tags:** api-interceptor, custom-flow, manual-setup
|
|
122
|
+
|
|
123
|
+
```gherkin:en
|
|
124
|
+
Scenario: Direct ApiInterceptor usage
|
|
125
|
+
|
|
126
|
+
Given I am logged in as Owner
|
|
127
|
+
And I have setup API intercepts manually
|
|
128
|
+
When I navigate to categories page
|
|
129
|
+
And I wait for the page to load
|
|
130
|
+
And I wait for the initial list via api.waitForList()
|
|
131
|
+
And I open the create dialog
|
|
132
|
+
And I fill the form with test data
|
|
133
|
+
And I save the category
|
|
134
|
+
And I wait for create via api.waitForCreate()
|
|
135
|
+
And I wait for refresh via api.waitForRefresh()
|
|
136
|
+
And the dialog closes
|
|
137
|
+
Then the category should be visible in the list
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```gherkin:es
|
|
141
|
+
Scenario: Uso directo de ApiInterceptor
|
|
142
|
+
|
|
143
|
+
Given estoy logueado como Owner
|
|
144
|
+
And he configurado intercepts de API manualmente
|
|
145
|
+
When navego a la pagina de categorias
|
|
146
|
+
And espero que la pagina cargue
|
|
147
|
+
And espero la lista inicial via api.waitForList()
|
|
148
|
+
And abro el dialogo de crear
|
|
149
|
+
And completo el formulario con datos de prueba
|
|
150
|
+
And guardo la categoria
|
|
151
|
+
And espero create via api.waitForCreate()
|
|
152
|
+
And espero refresh via api.waitForRefresh()
|
|
153
|
+
And el dialogo cierra
|
|
154
|
+
Then la categoria deberia estar visible en la lista
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Expected Results
|
|
158
|
+
- Manual API intercept setup works
|
|
159
|
+
- Each wait method targets specific API call
|
|
160
|
+
- Full control over wait timing
|
|
161
|
+
- Complex flows can be orchestrated with precision
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Categories API-Aware Tests
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates the new API-aware POM pattern with deterministic waits
|
|
7
|
+
* using cy.intercept() instead of cy.wait(ms).
|
|
8
|
+
*
|
|
9
|
+
* Tags: @uat, @feat-posts, @api-aware, @categories
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as allure from 'allure-cypress'
|
|
13
|
+
import { CategoriesPOM, loginAsOwner } from '../../../../src'
|
|
14
|
+
|
|
15
|
+
describe('Categories - API-Aware Pattern Demo', {
|
|
16
|
+
tags: ['@uat', '@feat-posts', '@api-aware', '@categories']
|
|
17
|
+
}, () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
allure.epic('Posts System')
|
|
20
|
+
allure.feature('API-Aware Testing Pattern')
|
|
21
|
+
|
|
22
|
+
loginAsOwner()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('API-Aware Navigation', () => {
|
|
26
|
+
it('APIAWARE-001: Should navigate with deterministic API wait', { tags: '@smoke' }, () => {
|
|
27
|
+
allure.story('API-Aware Navigation')
|
|
28
|
+
allure.severity('critical')
|
|
29
|
+
|
|
30
|
+
// Use the new API-aware navigation method
|
|
31
|
+
// This replaces: visitCategoriesPage() + waitForPageLoad() + cy.wait(2000)
|
|
32
|
+
CategoriesPOM.visitWithApiWait()
|
|
33
|
+
|
|
34
|
+
// Assertions
|
|
35
|
+
CategoriesPOM.assertPageVisible()
|
|
36
|
+
cy.get(CategoriesPOM.listSelectors.rowGeneric).should('have.length.at.least', 1)
|
|
37
|
+
|
|
38
|
+
cy.log('API-aware navigation works correctly')
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('API-Aware CRUD', () => {
|
|
43
|
+
it('APIAWARE-002: Should create category with deterministic waits', () => {
|
|
44
|
+
allure.story('API-Aware Create')
|
|
45
|
+
|
|
46
|
+
const uniqueId = Math.random().toString(36).substring(2, 8)
|
|
47
|
+
const testData = {
|
|
48
|
+
name: `APITest${uniqueId}`,
|
|
49
|
+
slug: `apitest${uniqueId}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Navigate with API wait
|
|
53
|
+
CategoriesPOM.visitWithApiWait()
|
|
54
|
+
|
|
55
|
+
// Create with API-aware method
|
|
56
|
+
// This replaces: createCategory() + cy.wait(2000)
|
|
57
|
+
CategoriesPOM.createCategoryWithApiWait(testData)
|
|
58
|
+
|
|
59
|
+
// Verify category was created
|
|
60
|
+
CategoriesPOM.assertCategoryInList(testData.name)
|
|
61
|
+
|
|
62
|
+
cy.log('API-aware create works correctly')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('APIAWARE-003: Should use ApiInterceptor directly for custom flows', () => {
|
|
66
|
+
allure.story('Direct ApiInterceptor Usage')
|
|
67
|
+
|
|
68
|
+
const uniqueId = Math.random().toString(36).substring(2, 8)
|
|
69
|
+
const testData = {
|
|
70
|
+
name: `DirectAPI${uniqueId}`,
|
|
71
|
+
slug: `directapi${uniqueId}`
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Setup intercepts manually
|
|
75
|
+
CategoriesPOM.setupApiIntercepts()
|
|
76
|
+
|
|
77
|
+
// Navigate
|
|
78
|
+
CategoriesPOM.visitCategoriesPage()
|
|
79
|
+
CategoriesPOM.waitForPageLoad()
|
|
80
|
+
|
|
81
|
+
// Wait for initial list using api directly
|
|
82
|
+
CategoriesPOM.api.waitForList()
|
|
83
|
+
|
|
84
|
+
// Open dialog and fill form
|
|
85
|
+
CategoriesPOM.clickCreate()
|
|
86
|
+
CategoriesPOM.waitForDialogOpen()
|
|
87
|
+
CategoriesPOM.fillName(testData.name)
|
|
88
|
+
CategoriesPOM.fillSlug(testData.slug)
|
|
89
|
+
CategoriesPOM.saveCategory()
|
|
90
|
+
|
|
91
|
+
// Wait for create + refresh using api directly
|
|
92
|
+
CategoriesPOM.api.waitForCreate()
|
|
93
|
+
CategoriesPOM.api.waitForRefresh()
|
|
94
|
+
|
|
95
|
+
// Wait for dialog to close
|
|
96
|
+
CategoriesPOM.waitForDialogClose()
|
|
97
|
+
|
|
98
|
+
// Verify
|
|
99
|
+
CategoriesPOM.assertCategoryInList(testData.name)
|
|
100
|
+
|
|
101
|
+
cy.log('Direct ApiInterceptor usage works correctly')
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|