@nextsparkjs/theme-default 0.1.0-beta.17 → 0.1.0-beta.171
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/api/ai/chat/stream/route.ts +4 -1
- package/api/ai/orchestrator/route.ts +10 -3
- package/api/ai/single-agent/route.ts +10 -3
- package/api/ai/usage/route.ts +4 -1
- package/blocks/benefits/component.tsx +4 -4
- package/blocks/cta-section/component.tsx +4 -4
- package/blocks/faq-accordion/component.tsx +2 -2
- package/blocks/features-grid/component.tsx +5 -5
- package/blocks/hero/component.tsx +2 -2
- package/blocks/hero/fields.ts +1 -1
- package/blocks/hero-with-form/component.tsx +7 -7
- package/blocks/hero-with-form/fields.ts +1 -1
- package/blocks/jumbotron/component.tsx +7 -7
- package/blocks/jumbotron/fields.ts +1 -1
- package/blocks/logo-cloud/component.tsx +6 -6
- package/blocks/logo-cloud/fields.ts +1 -1
- package/blocks/post-content/component.tsx +2 -2
- package/blocks/pricing-table/component.tsx +5 -5
- package/blocks/split-content/component.tsx +5 -5
- package/blocks/split-content/fields.ts +1 -1
- package/blocks/stats-counter/component.tsx +9 -9
- package/blocks/testimonials/component.tsx +4 -4
- package/blocks/testimonials/fields.ts +1 -1
- package/blocks/text-content/component.tsx +12 -10
- package/blocks/timeline/component.tsx +12 -12
- package/blocks/video-hero/component.tsx +7 -7
- package/blocks/video-hero/fields.ts +1 -1
- package/components/ai-chat/ChatPanel.tsx +7 -7
- package/components/ai-chat/Message.tsx +2 -2
- package/components/ai-chat/MessageInput.tsx +3 -3
- package/components/ai-chat/MessageList.tsx +3 -3
- package/components/ai-chat/TypingIndicator.tsx +2 -2
- package/config/app.config.ts +90 -62
- package/config/billing.config.ts +5 -10
- package/config/dashboard.config.ts +14 -0
- package/config/features.config.ts +10 -0
- package/config/permissions.config.ts +22 -23
- package/docs/{01-overview → public/01-overview}/01-introduction.md +5 -0
- package/docs/{01-overview → public/01-overview}/02-customization.md +5 -0
- package/docs/{02-features → public/02-features}/03-tasks-entity.md +5 -0
- package/docs/{03-ai → public/03-ai}/01-overview.md +5 -0
- package/docs/{03-ai → public/03-ai}/02-customization.md +5 -0
- package/docs/superadmin/01-setup/01-configuration.md +79 -0
- package/docs/superadmin/01-setup/02-deployment.md +82 -0
- package/docs/superadmin/02-management/01-users.md +83 -0
- package/docs/superadmin/03-integrations/01-langchain.md +139 -0
- package/emails/verify-email.ts +33 -0
- package/entities/customers/api/docs.md +107 -0
- package/entities/customers/api/presets.ts +80 -0
- package/entities/pages/api/docs.md +114 -0
- package/entities/pages/api/presets.ts +72 -0
- package/entities/posts/api/docs.md +120 -0
- package/entities/posts/api/presets.ts +74 -0
- package/entities/tasks/api/docs.md +126 -0
- package/entities/tasks/api/presets.ts +84 -0
- package/lib/selectors.ts +7 -4
- package/messages/de/admin.json +45 -0
- package/messages/en/admin.json +56 -0
- package/messages/en/navigation.json +2 -1
- package/messages/es/admin.json +56 -0
- package/messages/es/navigation.json +2 -1
- package/messages/fr/admin.json +45 -0
- package/messages/it/admin.json +45 -0
- package/messages/pt/admin.json +45 -0
- package/migrations/089_add_editor_team_role.sql +15 -23
- package/migrations/090_demo_users_teams.sql +11 -11
- package/migrations/091_greek_teams_billing.sql +15 -15
- package/migrations/093_pages_sample_data.sql +7 -7
- package/migrations/098_patterns_sample_data.sql +234 -0
- package/nextsparkjs-theme-default-0.1.0-beta.137.tgz +0 -0
- package/package.json +4 -3
- package/styles/globals.css +42 -0
- package/templates/(public)/page.tsx +1 -1
- package/tests/cypress/e2e/_utils/devtools/access.bdd.md +262 -0
- package/tests/cypress/e2e/_utils/devtools/access.cy.ts +171 -0
- package/tests/cypress/e2e/_utils/devtools/navigation.bdd.md +261 -0
- package/tests/cypress/e2e/_utils/devtools/navigation.cy.ts +157 -0
- package/tests/cypress/e2e/_utils/devtools/pages.bdd.md +303 -0
- package/tests/cypress/e2e/_utils/devtools/pages.cy.ts +184 -0
- package/tests/cypress/e2e/_utils/docs/README.md +215 -0
- package/tests/cypress/e2e/_utils/selectors/auth.bdd.md +354 -0
- package/tests/cypress/e2e/_utils/selectors/auth.cy.ts +310 -0
- package/tests/cypress/e2e/_utils/selectors/billing.bdd.md +276 -0
- package/tests/cypress/e2e/_utils/selectors/billing.cy.ts +182 -0
- package/tests/cypress/e2e/_utils/selectors/block-editor.bdd.md +615 -0
- package/tests/cypress/e2e/_utils/selectors/block-editor.cy.ts +783 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-container.cy.ts +52 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-mobile.bdd.md +205 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-mobile.cy.ts +137 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-navigation.bdd.md +147 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-navigation.cy.ts +114 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-sidebar.bdd.md +76 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-sidebar.cy.ts +68 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-topnav.bdd.md +326 -0
- package/tests/cypress/e2e/_utils/selectors/dashboard-topnav.cy.ts +177 -0
- package/tests/cypress/e2e/_utils/selectors/devtools.bdd.md +306 -0
- package/tests/cypress/e2e/_utils/selectors/devtools.cy.ts +273 -0
- package/tests/cypress/e2e/_utils/selectors/global-search.bdd.md +115 -0
- package/tests/cypress/e2e/_utils/selectors/global-search.cy.ts +93 -0
- package/tests/cypress/e2e/_utils/selectors/patterns.bdd.md +388 -0
- package/tests/cypress/e2e/_utils/selectors/patterns.cy.ts +559 -0
- package/tests/cypress/e2e/_utils/selectors/public.cy.ts +112 -0
- package/tests/cypress/e2e/_utils/selectors/settings-api-keys.bdd.md +266 -0
- package/tests/cypress/e2e/_utils/selectors/settings-api-keys.cy.ts +233 -0
- package/tests/cypress/e2e/_utils/selectors/settings-billing.bdd.md +78 -0
- package/tests/cypress/e2e/_utils/selectors/settings-billing.cy.ts +108 -0
- package/tests/cypress/e2e/_utils/selectors/settings-layout.bdd.md +129 -0
- package/tests/cypress/e2e/_utils/selectors/settings-layout.cy.ts +115 -0
- package/tests/cypress/e2e/_utils/selectors/settings-password.bdd.md +82 -0
- package/tests/cypress/e2e/_utils/selectors/settings-password.cy.ts +74 -0
- package/tests/cypress/e2e/_utils/selectors/settings-profile.bdd.md +77 -0
- package/tests/cypress/e2e/_utils/selectors/settings-profile.cy.ts +79 -0
- package/tests/cypress/e2e/_utils/selectors/settings-teams.bdd.md +130 -0
- package/tests/cypress/e2e/_utils/selectors/settings-teams.cy.ts +86 -0
- package/tests/cypress/e2e/_utils/selectors/superadmin.bdd.md +261 -0
- package/tests/cypress/e2e/_utils/selectors/superadmin.cy.ts +193 -0
- package/tests/cypress/e2e/_utils/selectors/tasks.bdd.md +593 -0
- package/tests/cypress/e2e/_utils/selectors/tasks.cy.ts +864 -0
- package/tests/cypress/e2e/_utils/selectors/taxonomies.cy.ts +126 -0
- package/tests/cypress/e2e/_utils/selectors/teams.bdd.md +278 -0
- package/tests/cypress/e2e/_utils/selectors/teams.cy.ts +195 -0
- package/tests/cypress/e2e/_utils/superadmin/all-teams.bdd.md +261 -0
- package/tests/cypress/e2e/_utils/superadmin/all-teams.cy.ts +177 -0
- package/tests/cypress/e2e/_utils/superadmin/all-users.bdd.md +406 -0
- package/tests/cypress/e2e/_utils/superadmin/all-users.cy.ts +294 -0
- package/tests/cypress/e2e/_utils/superadmin/dashboard.bdd.md +235 -0
- package/tests/cypress/e2e/_utils/superadmin/dashboard.cy.ts +149 -0
- package/tests/cypress/e2e/_utils/superadmin/subscriptions-overview.bdd.md +290 -0
- package/tests/cypress/e2e/_utils/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 +119 -0
- package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
- package/tests/cypress/e2e/api/_core/billing/BillingAPIController.js +319 -0
- package/tests/cypress/e2e/api/_core/billing/check-action.cy.ts +326 -0
- package/tests/cypress/e2e/api/_core/billing/checkout.cy.ts +358 -0
- package/tests/cypress/e2e/api/_core/billing/lifecycle.cy.ts +423 -0
- package/tests/cypress/e2e/api/_core/billing/plans/README.md +345 -0
- package/tests/cypress/e2e/api/_core/billing/plans/business.cy.ts +412 -0
- package/tests/cypress/e2e/api/_core/billing/plans/downgrade.cy.ts +510 -0
- package/tests/cypress/e2e/api/_core/billing/plans/fixtures/billing-plans.json +163 -0
- package/tests/cypress/e2e/api/_core/billing/plans/free.cy.ts +500 -0
- package/tests/cypress/e2e/api/_core/billing/plans/pro.cy.ts +497 -0
- package/tests/cypress/e2e/api/_core/billing/plans/starter.cy.ts +342 -0
- package/tests/cypress/e2e/api/_core/billing/portal.cy.ts +313 -0
- package/tests/cypress/e2e/api/_core/devtools/registries.bdd.md +300 -0
- package/tests/cypress/e2e/api/_core/devtools/registries.cy.ts +368 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/cron-endpoint.bdd.md +375 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/cron-endpoint.cy.ts +346 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/devtools-endpoint.bdd.md +451 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/devtools-endpoint.cy.ts +447 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/scheduling.bdd.md +649 -0
- package/tests/cypress/e2e/api/_core/scheduled-actions/scheduling.cy.ts +333 -0
- package/tests/cypress/e2e/api/_core/security/security-headers.cy.ts +601 -0
- package/tests/cypress/e2e/api/_core/settings/api-keys.crud.cy.ts +923 -0
- package/tests/cypress/e2e/api/_core/teams/teams-security.cy.ts +415 -0
- package/tests/cypress/e2e/api/_core/users/users-crud.cy.ts +469 -0
- package/tests/cypress/e2e/api/_core/users/users-metas.cy.ts +913 -0
- package/tests/cypress/e2e/api/_core/users/users-security.cy.ts +375 -0
- package/tests/cypress/e2e/api/entities/customers/customers-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/entities/customers/customers-metas.cy.ts +839 -0
- package/tests/cypress/e2e/api/entities/media/media-crud.cy.ts +600 -0
- package/tests/cypress/e2e/api/entities/media/media-role-permissions.cy.ts +617 -0
- package/tests/cypress/e2e/api/entities/media/media-team-isolation.cy.ts +464 -0
- package/tests/cypress/e2e/api/entities/pages/blocks-scope.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/pages/pages-crud.cy.ts +425 -0
- package/tests/cypress/e2e/api/entities/pages/pages-status.cy.ts +335 -0
- package/tests/cypress/e2e/api/entities/posts/post-categories-crud.cy.ts +610 -0
- package/tests/cypress/e2e/api/entities/posts/posts-crud.cy.ts +709 -0
- package/tests/cypress/e2e/api/entities/posts/posts-status.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/tasks/tasks-crud.cy.ts +602 -0
- package/tests/cypress/e2e/api/entities/tasks/tasks-metas.cy.ts +878 -0
- package/tests/cypress/e2e/patterns/patterns-in-pages.cy.ts +367 -0
- package/tests/cypress/e2e/uat/_core/auth/app-roles/developer-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/_core/auth/app-roles/developer-login.cy.ts +144 -0
- package/tests/cypress/e2e/uat/_core/auth/app-roles/superadmin-login.bdd.md +118 -0
- package/tests/cypress/e2e/uat/_core/auth/app-roles/superadmin-login.cy.ts +84 -0
- package/tests/cypress/e2e/uat/_core/auth/custom-roles/editor-login.bdd.md +288 -0
- package/tests/cypress/e2e/uat/_core/auth/custom-roles/editor-login.cy.ts +188 -0
- package/tests/cypress/e2e/uat/_core/auth/login-logout.bdd.md +160 -0
- package/tests/cypress/e2e/uat/_core/auth/login-logout.cy.ts +116 -0
- package/tests/cypress/e2e/uat/_core/auth/password-reset.bdd.md +289 -0
- package/tests/cypress/e2e/uat/_core/auth/password-reset.cy.ts +200 -0
- package/tests/cypress/e2e/uat/_core/auth/registration-control-invitation.cy.ts +176 -0
- package/tests/cypress/e2e/uat/_core/auth/registration-control-open.cy.ts +131 -0
- package/tests/cypress/e2e/uat/_core/auth/registration-control.cy.ts +140 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/admin-login.bdd.md +225 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/admin-login.cy.ts +148 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/member-login.bdd.md +251 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/member-login.cy.ts +163 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/owner-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/_core/auth/team-roles/owner-login.cy.ts +141 -0
- package/tests/cypress/e2e/uat/_core/billing/extended.bdd.md +273 -0
- package/tests/cypress/e2e/uat/_core/billing/extended.cy.ts +209 -0
- package/tests/cypress/e2e/uat/_core/billing/feature-gates.bdd.md +407 -0
- package/tests/cypress/e2e/uat/_core/billing/feature-gates.cy.ts +307 -0
- package/tests/cypress/e2e/uat/_core/billing/page.bdd.md +329 -0
- package/tests/cypress/e2e/uat/_core/billing/page.cy.ts +250 -0
- package/tests/cypress/e2e/uat/_core/billing/status.bdd.md +190 -0
- package/tests/cypress/e2e/uat/_core/billing/status.cy.ts +145 -0
- package/tests/cypress/e2e/uat/_core/billing/team-switch.bdd.md +156 -0
- package/tests/cypress/e2e/uat/_core/billing/team-switch.cy.ts +122 -0
- package/tests/cypress/e2e/uat/_core/billing/usage.bdd.md +218 -0
- package/tests/cypress/e2e/uat/_core/billing/usage.cy.ts +176 -0
- package/tests/cypress/e2e/uat/_core/blocks/hero.bdd.md +124 -0
- package/tests/cypress/e2e/uat/_core/blocks/hero.cy.ts +56 -0
- package/tests/cypress/e2e/uat/_core/devtools/api-tester.cy.ts +390 -0
- package/tests/cypress/e2e/uat/_core/performance/suspense-loading.cy.ts +134 -0
- package/tests/cypress/e2e/uat/_core/scheduled-actions/devtools-ui.bdd.md +736 -0
- package/tests/cypress/e2e/uat/_core/scheduled-actions/devtools-ui.cy.ts +740 -0
- package/tests/cypress/e2e/uat/_core/teams/inline-edit.cy.ts +278 -0
- package/tests/cypress/e2e/uat/_core/teams/roles-matrix.bdd.md +553 -0
- package/tests/cypress/e2e/uat/_core/teams/roles-matrix.cy.ts +185 -0
- package/tests/cypress/e2e/uat/_core/teams/switcher.bdd.md +1151 -0
- package/tests/cypress/e2e/uat/_core/teams/switcher.cy.ts +497 -0
- package/tests/cypress/e2e/uat/_core/teams/team-switcher.md +198 -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/features/roles/editor-role.bdd.md +552 -0
- package/tests/cypress/e2e/uat/features/roles/editor-role.cy.ts +210 -0
- package/tests/cypress/e2e/uat/features/roles/member-restrictions.bdd.md +450 -0
- package/tests/cypress/e2e/uat/features/roles/member-restrictions.cy.ts +189 -0
- package/tests/cypress/e2e/uat/features/roles/owner-full-crud.bdd.md +530 -0
- package/tests/cypress/e2e/uat/features/roles/owner-full-crud.cy.ts +247 -0
- package/tests/cypress/fixtures/blocks.json +218 -0
- package/tests/cypress/fixtures/entities.json +87 -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/MediaAPIController.js +231 -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 +33 -0
- package/tests/cypress/src/core/BlockEditorBasePOM.ts +874 -0
- package/tests/cypress/src/core/DashboardEntityPOM.ts +41 -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/PatternsPOM.ts +329 -0
- package/tests/cypress/src/entities/PostsPOM.ts +137 -0
- package/tests/cypress/src/entities/TasksPOM.ts +246 -0
- package/tests/cypress/src/entities/index.ts +16 -0
- package/tests/cypress/src/features/BillingPOM.ts +385 -0
- package/tests/cypress/src/features/DashboardPOM.ts +271 -0
- package/tests/cypress/src/features/DevtoolsPOM.ts +750 -0
- package/tests/cypress/src/features/PageBuilderPOM.ts +283 -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 +707 -0
- package/tests/cypress/src/features/SuperadminPOM.ts +851 -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 +20 -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 +518 -0
- package/tests/cypress/support/doc-commands.ts +260 -0
- package/tests/cypress/support/e2e.ts +90 -0
- package/tests/cypress.config.ts +178 -0
- package/tests/jest/__mocks__/@nextsparkjs/core/components/ui/badge.js +16 -0
- package/tests/jest/__mocks__/@nextsparkjs/core/lib/db.js +11 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +160 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/theme-registry.ts +68 -0
- package/tests/jest/__mocks__/jose.js +22 -0
- package/tests/jest/__mocks__/next/image.js +15 -0
- package/tests/jest/__mocks__/next-server.js +56 -0
- package/tests/jest/components/post-header.test.tsx +377 -0
- package/tests/jest/jest.config.cjs +154 -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 +370 -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/services/tasks.service.test.ts +707 -0
- package/tests/jest/setup.ts +170 -0
- package/tests/jest/tsconfig.jest.json +6 -0
- package/tests/jest/validation/categories.test.ts +429 -0
- package/tests/jest/validation/posts.test.ts +546 -0
- package/tests/tsconfig.json +21 -0
- /package/docs/{02-features → public/02-features}/01-components.md +0 -0
- /package/docs/{02-features → public/02-features}/02-styling.md +0 -0
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Selectors Validation: Patterns
|
|
3
|
+
*
|
|
4
|
+
* This test validates that patterns-specific selectors exist in the DOM.
|
|
5
|
+
* This is a lightweight test that ONLY checks selector presence, not functionality.
|
|
6
|
+
*
|
|
7
|
+
* Purpose:
|
|
8
|
+
* - Validate PatternsPOM and PageBuilderPOM selectors work correctly
|
|
9
|
+
* - Ensure all patterns-specific selectors are implemented
|
|
10
|
+
* - Validate KEY DIFFERENCES from standard entity editor:
|
|
11
|
+
* - NO slug input (patterns don't have slugs)
|
|
12
|
+
* - NO patterns tab in block picker (to prevent recursive patterns)
|
|
13
|
+
* - Run as Phase 12 sub-gate before functional tests
|
|
14
|
+
*
|
|
15
|
+
* Scope:
|
|
16
|
+
* - Navigate to patterns pages (requires login)
|
|
17
|
+
* - Assert elements exist in DOM (no form submissions)
|
|
18
|
+
* - Fast execution (< 30 seconds per describe block)
|
|
19
|
+
*
|
|
20
|
+
* Test IDs:
|
|
21
|
+
* - SEL_PAT_001: Patterns List Page Selectors (5 selectors)
|
|
22
|
+
* - SEL_PAT_002: Patterns List Table Actions (4 selectors)
|
|
23
|
+
* - SEL_PAT_003: Patterns Editor Header - KEY DIFFERENCES (5 selectors)
|
|
24
|
+
* - SEL_PAT_004: Patterns Editor Block Picker - KEY DIFFERENCES (5 selectors)
|
|
25
|
+
* - SEL_PAT_005: Patterns Reports Page (4 selectors)
|
|
26
|
+
* - SEL_PAT_006: Pattern Usage Stats (3 selectors)
|
|
27
|
+
* - SEL_PAT_007: Pattern Usage Report Controls (5 selectors)
|
|
28
|
+
* - SEL_PAT_008: Pattern Usage Table (3 selectors)
|
|
29
|
+
*
|
|
30
|
+
* DEPENDENCIES:
|
|
31
|
+
* - Sample patterns must exist (from seed data)
|
|
32
|
+
* - At least one pattern must have usages (for reports tests)
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { PatternsPOM } from '../../../src/entities/PatternsPOM'
|
|
36
|
+
import { cySelector } from '../../../src/selectors'
|
|
37
|
+
import { loginAsDefaultDeveloper } from '../../../src/session-helpers'
|
|
38
|
+
|
|
39
|
+
describe('Patterns Selectors Validation', { tags: ['@ui-selectors', '@patterns', '@feat-patterns'] }, () => {
|
|
40
|
+
const patterns = PatternsPOM.create()
|
|
41
|
+
|
|
42
|
+
// ============================================
|
|
43
|
+
// SEL_PAT_001: PATTERNS LIST PAGE SELECTORS (5 selectors)
|
|
44
|
+
// ============================================
|
|
45
|
+
describe('SEL_PAT_001: Patterns List Page Selectors', { tags: '@SEL_PAT_001' }, () => {
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
loginAsDefaultDeveloper()
|
|
48
|
+
patterns.visitList()
|
|
49
|
+
patterns.waitForList()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('SEL_PAT_001_01: should find page container', { tags: '@SEL_PAT_001_01' }, () => {
|
|
53
|
+
cy.get(patterns.selectors.page).should('exist')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('SEL_PAT_001_02: should find page title', { tags: '@SEL_PAT_001_02' }, () => {
|
|
57
|
+
cy.get(patterns.selectors.title).should('exist')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('SEL_PAT_001_03: should find add button', { tags: '@SEL_PAT_001_03' }, () => {
|
|
61
|
+
cy.get(patterns.selectors.addButton).should('exist')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('SEL_PAT_001_04: should find search container', { tags: '@SEL_PAT_001_04' }, () => {
|
|
65
|
+
cy.get(patterns.selectors.searchContainer).should('exist')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('SEL_PAT_001_05: should find table container (or empty state)', { tags: '@SEL_PAT_001_05' }, () => {
|
|
69
|
+
// Check for table OR empty state - both are valid depending on data
|
|
70
|
+
cy.get('body').then(($body) => {
|
|
71
|
+
if ($body.find(patterns.selectors.table).length > 0) {
|
|
72
|
+
cy.get(patterns.selectors.table).should('exist')
|
|
73
|
+
} else if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
74
|
+
// No patterns exist, empty state is acceptable
|
|
75
|
+
cy.log('⚠️ Table not found - patterns may not exist (empty state is valid)')
|
|
76
|
+
} else {
|
|
77
|
+
// Patterns exist but table not found - this is a real error
|
|
78
|
+
cy.get(patterns.selectors.table).should('exist')
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// ============================================
|
|
85
|
+
// SEL_PAT_002: PATTERNS LIST TABLE ACTIONS (4 selectors)
|
|
86
|
+
// REQUIRES: At least one pattern in the database
|
|
87
|
+
// NOTE: These tests are skipped if no patterns exist (data-dependent)
|
|
88
|
+
// ============================================
|
|
89
|
+
describe('SEL_PAT_002: Patterns List Table Actions', { tags: '@SEL_PAT_002' }, () => {
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
loginAsDefaultDeveloper()
|
|
92
|
+
patterns.visitList()
|
|
93
|
+
patterns.waitForList()
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('SEL_PAT_002_01: should find row menu for first pattern', { tags: '@SEL_PAT_002_01' }, () => {
|
|
97
|
+
// Check if patterns exist, skip if none
|
|
98
|
+
cy.get('body').then(($body) => {
|
|
99
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
100
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
101
|
+
return // Skip the rest of the test
|
|
102
|
+
}
|
|
103
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
104
|
+
const dataCy = $row.attr('data-cy')
|
|
105
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
106
|
+
if (patternId) {
|
|
107
|
+
cy.get(patterns.selectors.rowMenu(patternId)).should('exist')
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('SEL_PAT_002_02: should find edit action in row menu', { tags: '@SEL_PAT_002_02' }, () => {
|
|
114
|
+
cy.get('body').then(($body) => {
|
|
115
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
116
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
120
|
+
const dataCy = $row.attr('data-cy')
|
|
121
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
122
|
+
if (patternId) {
|
|
123
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
124
|
+
cy.get(patterns.selectors.rowAction('edit', patternId)).should('exist')
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('SEL_PAT_002_03: should find delete action in row menu', { tags: '@SEL_PAT_002_03' }, () => {
|
|
131
|
+
cy.get('body').then(($body) => {
|
|
132
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
133
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
137
|
+
const dataCy = $row.attr('data-cy')
|
|
138
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
139
|
+
if (patternId) {
|
|
140
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
141
|
+
cy.get(patterns.selectors.rowAction('delete', patternId)).should('exist')
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('SEL_PAT_002_04: should find usages quick action in row menu', { tags: '@SEL_PAT_002_04' }, () => {
|
|
148
|
+
cy.get('body').then(($body) => {
|
|
149
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
150
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
154
|
+
const dataCy = $row.attr('data-cy')
|
|
155
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
156
|
+
if (patternId) {
|
|
157
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
158
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).should('exist')
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// ============================================
|
|
166
|
+
// SEL_PAT_003: PATTERNS EDITOR HEADER - KEY DIFFERENCES (5 selectors)
|
|
167
|
+
// NOTE: Patterns editor does NOT have slug input (unlike pages/posts)
|
|
168
|
+
// ============================================
|
|
169
|
+
describe('SEL_PAT_003: Patterns Editor Header', { tags: '@SEL_PAT_003' }, () => {
|
|
170
|
+
beforeEach(() => {
|
|
171
|
+
loginAsDefaultDeveloper()
|
|
172
|
+
// Navigate to create a new pattern
|
|
173
|
+
cy.visit('/dashboard/patterns/create', { timeout: 60000 })
|
|
174
|
+
// Wait for editor to load using block editor selector
|
|
175
|
+
cy.get(cySelector('blockEditor.header.container'), { timeout: 15000 }).should('be.visible')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('SEL_PAT_003_01: should find header container', { tags: '@SEL_PAT_003_01' }, () => {
|
|
179
|
+
cy.get(cySelector('blockEditor.header.container')).should('exist')
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('SEL_PAT_003_02: should find title input', { tags: '@SEL_PAT_003_02' }, () => {
|
|
183
|
+
cy.get(cySelector('blockEditor.header.titleInput')).should('exist')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('SEL_PAT_003_03: should NOT have slug input (patterns-specific)', { tags: '@SEL_PAT_003_03' }, () => {
|
|
187
|
+
// KEY DIFFERENCE: Patterns do not have slugs
|
|
188
|
+
cy.get(cySelector('blockEditor.header.slugInput')).should('not.exist')
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('SEL_PAT_003_04: should find save button', { tags: '@SEL_PAT_003_04' }, () => {
|
|
192
|
+
cy.get(cySelector('blockEditor.header.saveButton')).should('exist')
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('SEL_PAT_003_05: should find view mode toggle', { tags: '@SEL_PAT_003_05' }, () => {
|
|
196
|
+
cy.get(cySelector('blockEditor.header.viewToggle')).should('exist')
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// ============================================
|
|
201
|
+
// SEL_PAT_004: PATTERNS EDITOR BLOCK PICKER - KEY DIFFERENCES (5 selectors)
|
|
202
|
+
// NOTE: Patterns block picker does NOT have patterns tab (to prevent recursion)
|
|
203
|
+
// ============================================
|
|
204
|
+
describe('SEL_PAT_004: Patterns Editor Block Picker', { tags: '@SEL_PAT_004' }, () => {
|
|
205
|
+
beforeEach(() => {
|
|
206
|
+
loginAsDefaultDeveloper()
|
|
207
|
+
cy.visit('/dashboard/patterns/create', { timeout: 60000 })
|
|
208
|
+
cy.get(cySelector('blockEditor.header.container'), { timeout: 15000 }).should('be.visible')
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('SEL_PAT_004_01: should find block picker container', { tags: '@SEL_PAT_004_01' }, () => {
|
|
212
|
+
cy.get(cySelector('blockEditor.blockPicker.container')).should('exist')
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('SEL_PAT_004_02: should find blocks tab', { tags: '@SEL_PAT_004_02' }, () => {
|
|
216
|
+
cy.get(cySelector('blockEditor.blockPicker.tabBlocks')).should('exist')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('SEL_PAT_004_03: should NOT have patterns tab (patterns-specific)', { tags: '@SEL_PAT_004_03' }, () => {
|
|
220
|
+
// KEY DIFFERENCE: Patterns cannot contain other patterns (prevent recursion)
|
|
221
|
+
cy.get(cySelector('blockEditor.blockPicker.tabPatterns')).should('not.exist')
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it.skip('SEL_PAT_004_04: should find config tab (skipped - patterns have no sidebarFields/taxonomies)', { tags: '@SEL_PAT_004_04' }, () => {
|
|
225
|
+
// Config tab only appears when entity has sidebarFields or taxonomies enabled
|
|
226
|
+
// Patterns entity doesn't have either, so this tab is correctly hidden
|
|
227
|
+
cy.get(cySelector('blockEditor.blockPicker.tabConfig')).should('exist')
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('SEL_PAT_004_05: should find search input', { tags: '@SEL_PAT_004_05' }, () => {
|
|
231
|
+
cy.get(cySelector('blockEditor.blockPicker.searchInput')).should('exist')
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// ============================================
|
|
236
|
+
// SEL_PAT_005: PATTERNS REPORTS PAGE (4 selectors)
|
|
237
|
+
// REQUIRES: A pattern with usages for meaningful tests
|
|
238
|
+
// NOTE: These tests are skipped if no patterns exist (data-dependent)
|
|
239
|
+
// ============================================
|
|
240
|
+
describe('SEL_PAT_005: Patterns Reports Page', { tags: '@SEL_PAT_005' }, () => {
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
loginAsDefaultDeveloper()
|
|
243
|
+
patterns.visitList()
|
|
244
|
+
patterns.waitForList()
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('SEL_PAT_005_01: should navigate to pattern usages and find report container', { tags: '@SEL_PAT_005_01' }, () => {
|
|
248
|
+
cy.get('body').then(($body) => {
|
|
249
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
250
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
254
|
+
const dataCy = $row.attr('data-cy')
|
|
255
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
256
|
+
if (patternId) {
|
|
257
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
258
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
259
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('SEL_PAT_005_02: should find back button on usages page', { tags: '@SEL_PAT_005_02' }, () => {
|
|
266
|
+
cy.get('body').then(($body) => {
|
|
267
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
268
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
272
|
+
const dataCy = $row.attr('data-cy')
|
|
273
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
274
|
+
if (patternId) {
|
|
275
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
276
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
277
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
278
|
+
cy.get(patterns.selectors.backButton).should('exist')
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('SEL_PAT_005_03: should find page title on usages page', { tags: '@SEL_PAT_005_03' }, () => {
|
|
285
|
+
cy.get('body').then(($body) => {
|
|
286
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
287
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
291
|
+
const dataCy = $row.attr('data-cy')
|
|
292
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
293
|
+
if (patternId) {
|
|
294
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
295
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
296
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
297
|
+
cy.get(patterns.selectors.headerTitle).should('exist')
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('SEL_PAT_005_04: should find edit button on usages page', { tags: '@SEL_PAT_005_04' }, () => {
|
|
304
|
+
cy.get('body').then(($body) => {
|
|
305
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
306
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
307
|
+
return
|
|
308
|
+
}
|
|
309
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
310
|
+
const dataCy = $row.attr('data-cy')
|
|
311
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
312
|
+
if (patternId) {
|
|
313
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
314
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
315
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
316
|
+
cy.get(patterns.selectors.editButton).should('exist')
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// ============================================
|
|
324
|
+
// SEL_PAT_006: PATTERN USAGE STATS (3 selectors)
|
|
325
|
+
// NOTE: These tests are skipped if no patterns exist (data-dependent)
|
|
326
|
+
// ============================================
|
|
327
|
+
describe('SEL_PAT_006: Pattern Usage Stats', { tags: '@SEL_PAT_006' }, () => {
|
|
328
|
+
// Helper to navigate to usages page if patterns exist
|
|
329
|
+
const navigateToUsagesIfPatternsExist = () => {
|
|
330
|
+
return cy.get('body').then(($body) => {
|
|
331
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
332
|
+
return false
|
|
333
|
+
}
|
|
334
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
335
|
+
const dataCy = $row.attr('data-cy')
|
|
336
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
337
|
+
if (patternId) {
|
|
338
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
339
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
340
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
return true
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
beforeEach(() => {
|
|
348
|
+
loginAsDefaultDeveloper()
|
|
349
|
+
patterns.visitList()
|
|
350
|
+
patterns.waitForList()
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
it('SEL_PAT_006_01: should find stats container', { tags: '@SEL_PAT_006_01' }, () => {
|
|
354
|
+
cy.get('body').then(($body) => {
|
|
355
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
356
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
360
|
+
cy.get(patterns.patternSelectors.usageStats.container).should('exist')
|
|
361
|
+
})
|
|
362
|
+
})
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
it('SEL_PAT_006_02: should find total usage card', { tags: '@SEL_PAT_006_02' }, () => {
|
|
366
|
+
cy.get('body').then(($body) => {
|
|
367
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
368
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
369
|
+
return
|
|
370
|
+
}
|
|
371
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
372
|
+
cy.get(patterns.patternSelectors.usageStats.total).should('exist')
|
|
373
|
+
})
|
|
374
|
+
})
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
it('SEL_PAT_006_03: should find usage by type cards (if usages exist)', { tags: '@SEL_PAT_006_03' }, () => {
|
|
378
|
+
cy.get('body').then(($body) => {
|
|
379
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
380
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
381
|
+
return
|
|
382
|
+
}
|
|
383
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
384
|
+
cy.get('body').then(($innerBody) => {
|
|
385
|
+
if ($innerBody.find(patterns.patternSelectors.usageStats.byType('pages')).length > 0) {
|
|
386
|
+
cy.get(patterns.patternSelectors.usageStats.byType('pages')).should('exist')
|
|
387
|
+
} else if ($innerBody.find(patterns.patternSelectors.usageStats.byType('posts')).length > 0) {
|
|
388
|
+
cy.get(patterns.patternSelectors.usageStats.byType('posts')).should('exist')
|
|
389
|
+
} else {
|
|
390
|
+
cy.log('No usage by type cards found - pattern may have no usages')
|
|
391
|
+
}
|
|
392
|
+
})
|
|
393
|
+
})
|
|
394
|
+
})
|
|
395
|
+
})
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
// ============================================
|
|
399
|
+
// SEL_PAT_007: PATTERN USAGE REPORT CONTROLS (5 selectors)
|
|
400
|
+
// NOTE: These tests are skipped if no patterns exist (data-dependent)
|
|
401
|
+
// ============================================
|
|
402
|
+
describe('SEL_PAT_007: Pattern Usage Report Controls', { tags: '@SEL_PAT_007' }, () => {
|
|
403
|
+
// Helper to navigate to usages page if patterns exist
|
|
404
|
+
const navigateToUsagesIfPatternsExist = () => {
|
|
405
|
+
return cy.get('body').then(($body) => {
|
|
406
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
410
|
+
const dataCy = $row.attr('data-cy')
|
|
411
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
412
|
+
if (patternId) {
|
|
413
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
414
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
415
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
416
|
+
}
|
|
417
|
+
})
|
|
418
|
+
return true
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
beforeEach(() => {
|
|
423
|
+
loginAsDefaultDeveloper()
|
|
424
|
+
patterns.visitList()
|
|
425
|
+
patterns.waitForList()
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
it('SEL_PAT_007_01: should find report container', { tags: '@SEL_PAT_007_01' }, () => {
|
|
429
|
+
cy.get('body').then(($body) => {
|
|
430
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
431
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
435
|
+
cy.get(patterns.patternSelectors.usageReport.container).should('exist')
|
|
436
|
+
})
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
it('SEL_PAT_007_02: should find filter select', { tags: '@SEL_PAT_007_02' }, () => {
|
|
441
|
+
cy.get('body').then(($body) => {
|
|
442
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
443
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
444
|
+
return
|
|
445
|
+
}
|
|
446
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
447
|
+
cy.get(patterns.patternSelectors.usageReport.filterSelect).should('exist')
|
|
448
|
+
})
|
|
449
|
+
})
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it('SEL_PAT_007_03: should find pagination container', { tags: '@SEL_PAT_007_03' }, () => {
|
|
453
|
+
cy.get('body').then(($body) => {
|
|
454
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
455
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
456
|
+
return
|
|
457
|
+
}
|
|
458
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
459
|
+
cy.get(patterns.patternSelectors.usageReport.pagination).should('exist')
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
})
|
|
463
|
+
|
|
464
|
+
it('SEL_PAT_007_04: should find prev page button', { tags: '@SEL_PAT_007_04' }, () => {
|
|
465
|
+
cy.get('body').then(($body) => {
|
|
466
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
467
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
468
|
+
return
|
|
469
|
+
}
|
|
470
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
471
|
+
cy.get(patterns.patternSelectors.usageReport.prevPage).should('exist')
|
|
472
|
+
})
|
|
473
|
+
})
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
it('SEL_PAT_007_05: should find next page button', { tags: '@SEL_PAT_007_05' }, () => {
|
|
477
|
+
cy.get('body').then(($body) => {
|
|
478
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
479
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
480
|
+
return
|
|
481
|
+
}
|
|
482
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
483
|
+
cy.get(patterns.patternSelectors.usageReport.nextPage).should('exist')
|
|
484
|
+
})
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('SEL_PAT_007_06: should find results info', { tags: '@SEL_PAT_007_06' }, () => {
|
|
489
|
+
cy.get('body').then(($body) => {
|
|
490
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
491
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
492
|
+
return
|
|
493
|
+
}
|
|
494
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
495
|
+
cy.get(patterns.patternSelectors.usageReport.resultsInfo).should('exist')
|
|
496
|
+
})
|
|
497
|
+
})
|
|
498
|
+
})
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
// ============================================
|
|
502
|
+
// SEL_PAT_008: PATTERN USAGE TABLE (3 selectors)
|
|
503
|
+
// NOTE: These tests are skipped if no patterns exist (data-dependent)
|
|
504
|
+
// ============================================
|
|
505
|
+
describe('SEL_PAT_008: Pattern Usage Table', { tags: '@SEL_PAT_008' }, () => {
|
|
506
|
+
// Helper to navigate to usages page if patterns exist
|
|
507
|
+
const navigateToUsagesIfPatternsExist = () => {
|
|
508
|
+
return cy.get('body').then(($body) => {
|
|
509
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
510
|
+
return false
|
|
511
|
+
}
|
|
512
|
+
cy.get('[data-cy^="patterns-row-"]').first().then(($row) => {
|
|
513
|
+
const dataCy = $row.attr('data-cy')
|
|
514
|
+
const patternId = dataCy?.replace('patterns-row-', '')
|
|
515
|
+
if (patternId) {
|
|
516
|
+
cy.get(patterns.selectors.rowMenu(patternId)).click()
|
|
517
|
+
cy.get(patterns.selectors.rowAction('usages', patternId)).click()
|
|
518
|
+
cy.get(patterns.patternSelectors.usageReport.container, { timeout: 15000 }).should('exist')
|
|
519
|
+
}
|
|
520
|
+
})
|
|
521
|
+
return true
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
beforeEach(() => {
|
|
526
|
+
loginAsDefaultDeveloper()
|
|
527
|
+
patterns.visitList()
|
|
528
|
+
patterns.waitForList()
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
it('SEL_PAT_008_01: should find usage table container (or empty state)', { tags: '@SEL_PAT_008_01' }, () => {
|
|
532
|
+
cy.get('body').then(($body) => {
|
|
533
|
+
if ($body.find('[data-cy^="patterns-row-"]').length === 0) {
|
|
534
|
+
cy.log('⚠️ No patterns found - skipping test (data-dependent)')
|
|
535
|
+
return
|
|
536
|
+
}
|
|
537
|
+
navigateToUsagesIfPatternsExist().then(() => {
|
|
538
|
+
cy.get('body').then(($innerBody) => {
|
|
539
|
+
if ($innerBody.find(patterns.patternSelectors.usageTable.container).length > 0) {
|
|
540
|
+
cy.get(patterns.patternSelectors.usageTable.container).should('exist')
|
|
541
|
+
} else {
|
|
542
|
+
cy.get(patterns.patternSelectors.usageTable.empty).should('exist')
|
|
543
|
+
}
|
|
544
|
+
})
|
|
545
|
+
})
|
|
546
|
+
})
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
it.skip('SEL_PAT_008_02: should find usage row (requires pattern with usages)', { tags: '@SEL_PAT_008_02' }, () => {
|
|
550
|
+
// This test requires the pattern to have actual usages
|
|
551
|
+
cy.get('[data-cy^="pattern-usage-row-"]').first().should('exist')
|
|
552
|
+
})
|
|
553
|
+
|
|
554
|
+
it.skip('SEL_PAT_008_03: should find view link in usage row (requires pattern with usages)', { tags: '@SEL_PAT_008_03' }, () => {
|
|
555
|
+
// This test requires the pattern to have actual usages
|
|
556
|
+
cy.get('[data-cy^="pattern-usage-view-"]').first().should('exist')
|
|
557
|
+
})
|
|
558
|
+
})
|
|
559
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI Selectors Validation: Public Pages
|
|
3
|
+
*
|
|
4
|
+
* This test validates that public page selectors exist in the DOM.
|
|
5
|
+
* This is a lightweight test that ONLY checks selector presence, not functionality.
|
|
6
|
+
*
|
|
7
|
+
* Purpose:
|
|
8
|
+
* - Validate PublicPagePOM navbar/footer selectors work correctly
|
|
9
|
+
* - Ensure all public.* selectors are implemented
|
|
10
|
+
* - Run as Phase 12 sub-gate before functional tests
|
|
11
|
+
*
|
|
12
|
+
* Scope:
|
|
13
|
+
* - Navigate to public pages (NO login required)
|
|
14
|
+
* - Assert elements exist in DOM (no form submissions)
|
|
15
|
+
* - Fast execution (< 30 seconds per describe block)
|
|
16
|
+
*
|
|
17
|
+
* NOTE: Public pages use PublicNavbar and PublicFooter from core.
|
|
18
|
+
* Blog and page selectors (public.page.*, public.blog.*) are pending
|
|
19
|
+
* as they require specific content to exist.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { PublicPagePOM } from '../../../src/components/PublicPagePOM'
|
|
23
|
+
|
|
24
|
+
describe('Public Page Selectors Validation', { tags: ['@ui-selectors'] }, () => {
|
|
25
|
+
// ============================================
|
|
26
|
+
// NAVBAR (4 selectors)
|
|
27
|
+
// ============================================
|
|
28
|
+
describe('Public Navbar', () => {
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
// Visit home page (public, no login needed)
|
|
31
|
+
cy.visit('/', { timeout: 60000, failOnStatusCode: false })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should find navbar container', () => {
|
|
35
|
+
cy.get(PublicPagePOM.navbarSelectors.container).should('exist')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should find navbar logo', () => {
|
|
39
|
+
cy.get(PublicPagePOM.navbarSelectors.logo).should('exist')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should find login button (when not logged in)', () => {
|
|
43
|
+
cy.get(PublicPagePOM.navbarSelectors.loginButton).should('exist')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should find signup button (when not logged in)', () => {
|
|
47
|
+
cy.get(PublicPagePOM.navbarSelectors.signupButton).should('exist')
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// ============================================
|
|
52
|
+
// FOOTER (2 selectors)
|
|
53
|
+
// ============================================
|
|
54
|
+
describe('Public Footer', () => {
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
cy.visit('/', { timeout: 60000, failOnStatusCode: false })
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should find footer container', () => {
|
|
60
|
+
cy.get(PublicPagePOM.footerSelectors.container).should('exist')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should find footer logo', () => {
|
|
64
|
+
cy.get(PublicPagePOM.footerSelectors.logo).should('exist')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// ============================================
|
|
69
|
+
// PAGE SELECTORS (3 selectors)
|
|
70
|
+
// NOTE: Requires published pages to exist
|
|
71
|
+
// ============================================
|
|
72
|
+
describe('Public Page Selectors', () => {
|
|
73
|
+
// public.page.container - dynamic selector 'public-page-{slug}'
|
|
74
|
+
it.skip('should find page container (requires published page)', () => {
|
|
75
|
+
// Example: cy.visit('/about-us')
|
|
76
|
+
// cy.get('[data-cy="public-page-about-us"]').should('exist')
|
|
77
|
+
cy.wrap(true).should('be.true')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// public.page.title - 'page-title'
|
|
81
|
+
it.skip('should find page title (requires published page)', () => {
|
|
82
|
+
// cy.get('[data-cy="page-title"]').should('exist')
|
|
83
|
+
cy.wrap(true).should('be.true')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// public.page.content - 'page-content'
|
|
87
|
+
it.skip('should find page content (requires published page)', () => {
|
|
88
|
+
// cy.get('[data-cy="page-content"]').should('exist')
|
|
89
|
+
cy.wrap(true).should('be.true')
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// ============================================
|
|
94
|
+
// BLOG SELECTORS (2 selectors)
|
|
95
|
+
// NOTE: Requires blog posts to exist
|
|
96
|
+
// ============================================
|
|
97
|
+
describe('Public Blog Selectors', () => {
|
|
98
|
+
// public.blog.listContainer - 'blog-list'
|
|
99
|
+
it.skip('should find blog list container (requires blog posts)', () => {
|
|
100
|
+
// cy.visit('/blog')
|
|
101
|
+
// cy.get('[data-cy="blog-list"]').should('exist')
|
|
102
|
+
cy.wrap(true).should('be.true')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// public.blog.postCard - dynamic selector 'blog-post-{slug}'
|
|
106
|
+
it.skip('should find blog post card (requires blog posts)', () => {
|
|
107
|
+
// cy.visit('/blog')
|
|
108
|
+
// cy.get('[data-cy="blog-post-my-first-post"]').should('exist')
|
|
109
|
+
cy.wrap(true).should('be.true')
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
})
|