@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.
Files changed (220) hide show
  1. package/package.json +1 -1
  2. package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
  3. package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
  4. package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
  5. package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
  6. package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
  7. package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
  8. package/tests/cypress/e2e/_docs/README.md +215 -0
  9. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
  10. package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
  11. package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
  12. package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
  13. package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
  14. package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
  15. package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
  16. package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
  17. package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
  18. package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
  19. package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
  20. package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
  21. package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
  22. package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
  23. package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
  24. package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
  25. package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
  26. package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
  27. package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
  28. package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
  29. package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
  30. package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
  31. package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
  32. package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
  33. package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
  34. package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
  35. package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
  36. package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
  37. package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
  38. package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
  39. package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
  40. package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
  41. package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
  42. package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
  43. package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
  44. package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
  45. package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
  46. package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
  47. package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
  48. package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
  49. package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
  50. package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
  51. package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
  52. package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
  53. package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
  54. package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
  55. package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
  56. package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
  57. package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
  58. package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
  59. package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
  60. package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
  61. package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
  62. package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
  63. package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
  64. package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
  65. package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
  66. package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
  67. package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
  68. package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
  69. package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
  70. package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
  71. package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
  72. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
  73. package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
  74. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
  75. package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
  76. package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
  77. package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
  78. package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
  79. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
  80. package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
  81. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
  82. package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
  83. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
  84. package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
  85. package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
  86. package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
  87. package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
  88. package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
  89. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
  90. package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
  91. package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
  92. package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
  93. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
  94. package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
  95. package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
  96. package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
  97. package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
  98. package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
  99. package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
  100. package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
  101. package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
  102. package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
  103. package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
  104. package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
  105. package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
  106. package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
  107. package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
  108. package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
  109. package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
  110. package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
  111. package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
  112. package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
  113. package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
  114. package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
  115. package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
  116. package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
  117. package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
  118. package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
  119. package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
  120. package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
  121. package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
  122. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
  123. package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
  124. package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
  125. package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
  126. package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
  127. package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
  128. package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
  129. package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
  130. package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
  131. package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
  132. package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
  133. package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
  134. package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
  135. package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
  136. package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
  137. package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
  138. package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
  139. package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
  140. package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
  141. package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
  142. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
  143. package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
  144. package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
  145. package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
  146. package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
  147. package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
  148. package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
  149. package/tests/cypress/fixtures/blocks.json +218 -0
  150. package/tests/cypress/fixtures/entities.json +78 -0
  151. package/tests/cypress/fixtures/page-builder.json +21 -0
  152. package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
  153. package/tests/cypress/src/components/CustomersPOM.ts +439 -0
  154. package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
  155. package/tests/cypress/src/components/EntityForm.ts +375 -0
  156. package/tests/cypress/src/components/EntityList.ts +389 -0
  157. package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
  158. package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
  159. package/tests/cypress/src/components/PostsListPOM.ts +223 -0
  160. package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
  161. package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
  162. package/tests/cypress/src/components/TasksPOM.ts +272 -0
  163. package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
  164. package/tests/cypress/src/components/index.ts +21 -0
  165. package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
  166. package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
  167. package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
  168. package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
  169. package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
  170. package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
  171. package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
  172. package/tests/cypress/src/controllers/index.js +25 -0
  173. package/tests/cypress/src/core/AuthPOM.ts +450 -0
  174. package/tests/cypress/src/core/BasePOM.ts +86 -0
  175. package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
  176. package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
  177. package/tests/cypress/src/core/index.ts +14 -0
  178. package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
  179. package/tests/cypress/src/entities/PagesPOM.ts +137 -0
  180. package/tests/cypress/src/entities/PostsPOM.ts +137 -0
  181. package/tests/cypress/src/entities/TasksPOM.ts +176 -0
  182. package/tests/cypress/src/entities/index.ts +14 -0
  183. package/tests/cypress/src/features/BillingPOM.ts +385 -0
  184. package/tests/cypress/src/features/DashboardPOM.ts +245 -0
  185. package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
  186. package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
  187. package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
  188. package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
  189. package/tests/cypress/src/features/SettingsPOM.ts +362 -0
  190. package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
  191. package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
  192. package/tests/cypress/src/features/index.ts +28 -0
  193. package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
  194. package/tests/cypress/src/index.ts +101 -0
  195. package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
  196. package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
  197. package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
  198. package/tests/cypress/src/pages/dashboard/index.js +6 -0
  199. package/tests/cypress/src/pages/index.js +5 -0
  200. package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
  201. package/tests/cypress/src/pages/public/LandingPage.js +69 -0
  202. package/tests/cypress/src/pages/public/PricingPage.js +33 -0
  203. package/tests/cypress/src/pages/public/index.js +6 -0
  204. package/tests/cypress/src/selectors.ts +46 -0
  205. package/tests/cypress/src/session-helpers.ts +500 -0
  206. package/tests/cypress/support/doc-commands.ts +260 -0
  207. package/tests/cypress.config.ts +150 -0
  208. package/tests/jest/components/post-header.test.tsx +377 -0
  209. package/tests/jest/config/role-config.test.ts +529 -0
  210. package/tests/jest/jest.config.ts +81 -0
  211. package/tests/jest/langchain/COVERAGE.md +372 -0
  212. package/tests/jest/langchain/guardrails.test.ts +465 -0
  213. package/tests/jest/langchain/streaming.test.ts +367 -0
  214. package/tests/jest/langchain/token-tracker.test.ts +455 -0
  215. package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
  216. package/tests/jest/langchain/tracer.test.ts +823 -0
  217. package/tests/jest/user-roles/role-helpers.test.ts +432 -0
  218. package/tests/jest/validation/categories.test.ts +429 -0
  219. package/tests/jest/validation/posts.test.ts +546 -0
  220. 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
+ })