@nextsparkjs/theme-default 0.1.0-beta.2 → 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 +8 -4
- package/templates/(public)/page.tsx +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
- package/LICENSE +0 -21
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Superadmin Subscriptions Overview Tests
|
|
5
|
+
*
|
|
6
|
+
* Tests the Superadmin subscriptions overview page:
|
|
7
|
+
* - Subscriptions dashboard access
|
|
8
|
+
* - Revenue metrics display
|
|
9
|
+
* - Plan distribution stats
|
|
10
|
+
* - Subscription overview
|
|
11
|
+
*
|
|
12
|
+
* Note: The route is /superadmin/subscriptions (not /billing)
|
|
13
|
+
*
|
|
14
|
+
* Tags: @uat, @feat-superadmin, @superadmin, @subscriptions
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import * as allure from 'allure-cypress'
|
|
18
|
+
|
|
19
|
+
import { loginAsDefaultSuperadmin } from '../../src/session-helpers'
|
|
20
|
+
import { SuperadminPOM } from '../../src/features/SuperadminPOM'
|
|
21
|
+
|
|
22
|
+
describe('Superadmin - Subscriptions Overview', {
|
|
23
|
+
tags: ['@uat', '@feat-superadmin', '@superadmin', '@subscriptions']
|
|
24
|
+
}, () => {
|
|
25
|
+
const superadmin = SuperadminPOM.create()
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
allure.epic('Admin')
|
|
29
|
+
allure.feature('Subscriptions Overview')
|
|
30
|
+
allure.story('Platform Subscriptions')
|
|
31
|
+
loginAsDefaultSuperadmin()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe('ADMIN-SUBS-001: Subscriptions Page Access', { tags: '@smoke' }, () => {
|
|
35
|
+
it('should access subscriptions overview page', { tags: '@smoke' }, () => {
|
|
36
|
+
allure.severity('critical')
|
|
37
|
+
|
|
38
|
+
// 1. Visit Superadmin Subscriptions
|
|
39
|
+
superadmin.visitSubscriptions()
|
|
40
|
+
|
|
41
|
+
// 2. Validate subscriptions page
|
|
42
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
43
|
+
|
|
44
|
+
cy.log('✅ Subscriptions overview accessible')
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('ADMIN-SUBS-002: Revenue Metrics', () => {
|
|
49
|
+
it('should display revenue metrics if available', () => {
|
|
50
|
+
allure.severity('high')
|
|
51
|
+
|
|
52
|
+
// 1. Visit Superadmin Subscriptions
|
|
53
|
+
superadmin.visitSubscriptions()
|
|
54
|
+
|
|
55
|
+
// 2. Check for revenue metrics (defensive - page may not have these yet)
|
|
56
|
+
cy.get('body').then(($body) => {
|
|
57
|
+
if ($body.find(superadmin.selectors.subscriptionsMrr).length > 0) {
|
|
58
|
+
cy.get(superadmin.selectors.subscriptionsMrr).should('be.visible')
|
|
59
|
+
cy.log('✅ MRR metric displayed')
|
|
60
|
+
} else if ($body.find(superadmin.selectors.subscriptionsRevenue).length > 0) {
|
|
61
|
+
cy.get(superadmin.selectors.subscriptionsRevenue).should('be.visible')
|
|
62
|
+
cy.log('✅ Revenue metric displayed')
|
|
63
|
+
} else {
|
|
64
|
+
// Check page loads at minimum
|
|
65
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
66
|
+
cy.log('⚠️ Revenue metrics data-cy not found - page loads OK')
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('ADMIN-SUBS-003: Plan Distribution', () => {
|
|
73
|
+
it('should display plan distribution stats if available', () => {
|
|
74
|
+
allure.severity('high')
|
|
75
|
+
|
|
76
|
+
// 1. Visit Superadmin Subscriptions
|
|
77
|
+
superadmin.visitSubscriptions()
|
|
78
|
+
|
|
79
|
+
// 2. Check for plan distribution (defensive)
|
|
80
|
+
cy.get('body').then(($body) => {
|
|
81
|
+
if ($body.find(superadmin.selectors.subscriptionsPlanDistribution).length > 0) {
|
|
82
|
+
cy.get(superadmin.selectors.subscriptionsPlanDistribution).should('be.visible')
|
|
83
|
+
cy.log('✅ Plan distribution displayed')
|
|
84
|
+
} else if ($body.find('[data-cy^="superadmin-subscriptions-plan-count-"]').length > 0) {
|
|
85
|
+
cy.get('[data-cy^="superadmin-subscriptions-plan-count-"]').first().should('be.visible')
|
|
86
|
+
cy.log('✅ Plan counts displayed')
|
|
87
|
+
} else {
|
|
88
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
89
|
+
cy.log('⚠️ Plan distribution data-cy not found - page loads OK')
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('ADMIN-SUBS-004: Active Subscriptions Count', () => {
|
|
96
|
+
it('should display active subscriptions count if available', () => {
|
|
97
|
+
allure.severity('normal')
|
|
98
|
+
|
|
99
|
+
// 1. Visit Superadmin Subscriptions
|
|
100
|
+
superadmin.visitSubscriptions()
|
|
101
|
+
|
|
102
|
+
// 2. Check for subscriptions count (defensive)
|
|
103
|
+
cy.get('body').then(($body) => {
|
|
104
|
+
if ($body.find(superadmin.selectors.subscriptionsActiveCount).length > 0) {
|
|
105
|
+
cy.get(superadmin.selectors.subscriptionsActiveCount).should('be.visible')
|
|
106
|
+
cy.log('✅ Active subscriptions count displayed')
|
|
107
|
+
} else {
|
|
108
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
109
|
+
cy.log('⚠️ Active subscriptions count data-cy not found - page loads OK')
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('ADMIN-SUBS-005: Free vs Paid Teams', () => {
|
|
116
|
+
it('should display free vs paid teams breakdown if available', () => {
|
|
117
|
+
allure.severity('normal')
|
|
118
|
+
|
|
119
|
+
// 1. Visit Superadmin Subscriptions
|
|
120
|
+
superadmin.visitSubscriptions()
|
|
121
|
+
|
|
122
|
+
// 2. Check for free/paid breakdown (defensive)
|
|
123
|
+
cy.get('body').then(($body) => {
|
|
124
|
+
if ($body.find(superadmin.selectors.subscriptionsFreeTeams).length > 0) {
|
|
125
|
+
cy.get(superadmin.selectors.subscriptionsFreeTeams).should('be.visible')
|
|
126
|
+
cy.get(superadmin.selectors.subscriptionsPaidTeams).should('be.visible')
|
|
127
|
+
cy.log('✅ Free vs paid breakdown displayed')
|
|
128
|
+
} else {
|
|
129
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
130
|
+
cy.log('⚠️ Free/paid breakdown data-cy not found - page loads OK')
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe('ADMIN-SUBS-006: Trial Teams', () => {
|
|
137
|
+
it('should display teams on trial if available', () => {
|
|
138
|
+
allure.severity('normal')
|
|
139
|
+
|
|
140
|
+
// 1. Visit Superadmin Subscriptions
|
|
141
|
+
superadmin.visitSubscriptions()
|
|
142
|
+
|
|
143
|
+
// 2. Check for trial teams (defensive)
|
|
144
|
+
cy.get('body').then(($body) => {
|
|
145
|
+
if ($body.find(superadmin.selectors.subscriptionsTrialTeams).length > 0) {
|
|
146
|
+
cy.get(superadmin.selectors.subscriptionsTrialTeams).should('be.visible')
|
|
147
|
+
cy.log('✅ Trial teams displayed')
|
|
148
|
+
} else {
|
|
149
|
+
cy.url().should('include', '/superadmin/subscriptions')
|
|
150
|
+
cy.log('⚠️ Trial teams metric data-cy not found - page loads OK')
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
describe('ADMIN-SUBS-007: Navigate to Teams from Subscriptions', () => {
|
|
157
|
+
it('should navigate to teams page from subscriptions', () => {
|
|
158
|
+
allure.severity('normal')
|
|
159
|
+
|
|
160
|
+
// 1. Visit Superadmin Subscriptions
|
|
161
|
+
superadmin.visitSubscriptions()
|
|
162
|
+
|
|
163
|
+
// 2. Click on teams nav
|
|
164
|
+
superadmin.clickNavTeams()
|
|
165
|
+
|
|
166
|
+
// 3. Validate on teams page
|
|
167
|
+
cy.url().should('include', '/superadmin/teams')
|
|
168
|
+
|
|
169
|
+
cy.log('✅ Navigation to teams works')
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
describe('ADMIN-SUBS-008: Navigate Back to Dashboard', () => {
|
|
174
|
+
it('should navigate back to Superadmin dashboard', () => {
|
|
175
|
+
allure.severity('normal')
|
|
176
|
+
|
|
177
|
+
// 1. Visit Superadmin Subscriptions
|
|
178
|
+
superadmin.visitSubscriptions()
|
|
179
|
+
|
|
180
|
+
// 2. Click on dashboard nav
|
|
181
|
+
superadmin.clickNavDashboard()
|
|
182
|
+
|
|
183
|
+
// 3. Validate back at dashboard
|
|
184
|
+
cy.url().should('match', /\/superadmin\/?$/)
|
|
185
|
+
superadmin.assertDashboardVisible()
|
|
186
|
+
|
|
187
|
+
cy.log('✅ Navigation to dashboard works')
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
after(() => {
|
|
192
|
+
cy.log('✅ Superadmin subscriptions overview tests completed')
|
|
193
|
+
})
|
|
194
|
+
})
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Usage Dashboard E2E Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the AI usage tracking dashboard at /dashboard/settings/ai-usage
|
|
5
|
+
*
|
|
6
|
+
* Scope:
|
|
7
|
+
* - Page navigation and loading
|
|
8
|
+
* - Period selector functionality
|
|
9
|
+
* - Stats cards display
|
|
10
|
+
* - Empty state handling
|
|
11
|
+
* - Loading state visibility
|
|
12
|
+
*
|
|
13
|
+
* Limitations:
|
|
14
|
+
* - Cannot test with real token usage data without LLM provider
|
|
15
|
+
* - Tests verify UI structure and component rendering
|
|
16
|
+
* - Actual API data fetching requires backend implementation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { loginAsDefaultOwner } from '../../src/session-helpers'
|
|
20
|
+
|
|
21
|
+
describe('AI Usage Dashboard', {
|
|
22
|
+
tags: ['@feat-ai', '@ui', '@dashboard']
|
|
23
|
+
}, () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
// Login as owner user with team context
|
|
26
|
+
loginAsDefaultOwner()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('AI_USAGE_01: Page loads successfully', () => {
|
|
30
|
+
it('should navigate to AI usage page and display main container', () => {
|
|
31
|
+
// Navigate to AI usage dashboard
|
|
32
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
33
|
+
|
|
34
|
+
// Verify URL
|
|
35
|
+
cy.url().should('include', '/dashboard/settings/ai-usage')
|
|
36
|
+
|
|
37
|
+
// Verify page container exists
|
|
38
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should display page header with title', () => {
|
|
42
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
43
|
+
|
|
44
|
+
// Verify page structure (title is rendered in the component)
|
|
45
|
+
cy.get('[data-cy="ai-usage-page"]').within(() => {
|
|
46
|
+
// Header should be present (h1 or similar)
|
|
47
|
+
cy.get('h1').should('exist')
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('AI_USAGE_02: Period selector works', () => {
|
|
53
|
+
it('should display period selector with all options', () => {
|
|
54
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
55
|
+
|
|
56
|
+
// Wait for page to load
|
|
57
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
58
|
+
|
|
59
|
+
// Period selector should exist
|
|
60
|
+
cy.get('[data-cy="ai-usage-period-select"]').should('exist')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should have correct period options available', () => {
|
|
64
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
65
|
+
|
|
66
|
+
// Click period selector to open options
|
|
67
|
+
cy.get('[data-cy="ai-usage-period-select"]').click()
|
|
68
|
+
|
|
69
|
+
// Verify all period options are available
|
|
70
|
+
// Note: The exact selector for options may vary based on Select component implementation
|
|
71
|
+
// This is a structural test that verifies the selector is clickable
|
|
72
|
+
cy.get('[data-cy="ai-usage-period-select"]').should('exist')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('should allow selecting different periods', () => {
|
|
76
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
77
|
+
|
|
78
|
+
// Period selector should be interactive
|
|
79
|
+
cy.get('[data-cy="ai-usage-period-select"]').should('not.be.disabled')
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('AI_USAGE_03: Stats cards display', () => {
|
|
84
|
+
it('should display total tokens card', () => {
|
|
85
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
86
|
+
|
|
87
|
+
// Wait for page to load (either loading state or data)
|
|
88
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
89
|
+
|
|
90
|
+
// Total tokens card should exist (may show loading or data)
|
|
91
|
+
cy.get('[data-cy="ai-usage-total-tokens"]', { timeout: 10000 }).should('exist')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('should display total cost card', () => {
|
|
95
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
96
|
+
|
|
97
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
98
|
+
|
|
99
|
+
// Total cost card should exist
|
|
100
|
+
cy.get('[data-cy="ai-usage-total-cost"]', { timeout: 10000 }).should('exist')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should display requests card', () => {
|
|
104
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
105
|
+
|
|
106
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
107
|
+
|
|
108
|
+
// Requests card should exist
|
|
109
|
+
cy.get('[data-cy="ai-usage-requests"]', { timeout: 10000 }).should('exist')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('should display all three stats cards together', () => {
|
|
113
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
114
|
+
|
|
115
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
116
|
+
|
|
117
|
+
// All three cards should be present
|
|
118
|
+
cy.get('[data-cy="ai-usage-total-tokens"]').should('exist')
|
|
119
|
+
cy.get('[data-cy="ai-usage-total-cost"]').should('exist')
|
|
120
|
+
cy.get('[data-cy="ai-usage-requests"]').should('exist')
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('AI_USAGE_04: Empty state shown when no data', () => {
|
|
125
|
+
it('should display daily usage chart container', () => {
|
|
126
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
127
|
+
|
|
128
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
129
|
+
|
|
130
|
+
// Daily usage chart/container should exist
|
|
131
|
+
// May show "no data" message or actual chart
|
|
132
|
+
cy.get('[data-cy="ai-usage-chart"]', { timeout: 10000 }).should('exist')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should handle case when no usage data exists', () => {
|
|
136
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
137
|
+
|
|
138
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
139
|
+
|
|
140
|
+
// The component should gracefully handle empty data
|
|
141
|
+
// Either show loading, empty state, or zero values
|
|
142
|
+
cy.get('[data-cy="ai-usage-total-tokens"]').should('exist')
|
|
143
|
+
|
|
144
|
+
// Verify page doesn't crash with no data
|
|
145
|
+
cy.get('[data-cy="ai-usage-page"]').should('be.visible')
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('AI_USAGE_05: Loading state visible', () => {
|
|
150
|
+
it('should show loading state before data loads', () => {
|
|
151
|
+
// Intercept API call to delay response
|
|
152
|
+
cy.intercept('GET', '/api/v1/theme/default/ai/usage*', (req) => {
|
|
153
|
+
req.reply((res) => {
|
|
154
|
+
// Delay response to ensure loading state is visible
|
|
155
|
+
res.delay = 1000
|
|
156
|
+
})
|
|
157
|
+
}).as('getUsage')
|
|
158
|
+
|
|
159
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
160
|
+
|
|
161
|
+
// Loading state should be visible initially
|
|
162
|
+
cy.get('[data-cy="ai-usage-loading"]').should('exist')
|
|
163
|
+
|
|
164
|
+
// Wait for API call
|
|
165
|
+
cy.wait('@getUsage')
|
|
166
|
+
|
|
167
|
+
// Loading state should disappear after data loads
|
|
168
|
+
cy.get('[data-cy="ai-usage-loading"]').should('not.exist')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should display content after loading completes', () => {
|
|
172
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
173
|
+
|
|
174
|
+
// Wait for page to load completely
|
|
175
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
176
|
+
|
|
177
|
+
// Either loading is gone or content is visible
|
|
178
|
+
cy.get('[data-cy="ai-usage-page"]').within(() => {
|
|
179
|
+
// At least one of these should be visible
|
|
180
|
+
cy.get('[data-cy="ai-usage-loading"], [data-cy="ai-usage-total-tokens"]').should('exist')
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
describe('Additional UI Elements', () => {
|
|
186
|
+
it('should display usage by model section if data exists', () => {
|
|
187
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
188
|
+
|
|
189
|
+
cy.get('[data-cy="ai-usage-page"]').should('exist')
|
|
190
|
+
|
|
191
|
+
// Usage by model is conditionally rendered
|
|
192
|
+
// This test just verifies the selector pattern exists in the component
|
|
193
|
+
// It may or may not be visible depending on data
|
|
194
|
+
cy.get('[data-cy="ai-usage-page"]').should('be.visible')
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('should be responsive and not have layout issues', () => {
|
|
198
|
+
cy.visit('/dashboard/settings/ai-usage')
|
|
199
|
+
|
|
200
|
+
// Verify page renders without errors
|
|
201
|
+
cy.get('[data-cy="ai-usage-page"]').should('be.visible')
|
|
202
|
+
|
|
203
|
+
// Check that cards are laid out properly
|
|
204
|
+
cy.get('[data-cy="ai-usage-total-tokens"]').should('be.visible')
|
|
205
|
+
cy.get('[data-cy="ai-usage-total-cost"]').should('be.visible')
|
|
206
|
+
cy.get('[data-cy="ai-usage-requests"]').should('be.visible')
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
})
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
describe('AI Chat API', {
|
|
2
|
+
tags: ['@api', '@feat-ai', '@crud']
|
|
3
|
+
}, () => {
|
|
4
|
+
// Test constants - Using superadmin API key for API-level tests
|
|
5
|
+
const API_KEY = 'test_api_key_for_testing_purposes_only_not_a_real_secret_key_abc123'
|
|
6
|
+
const TEAM_ID = 'team-personal-superadmin-003'
|
|
7
|
+
const API_URL = '/api/v1/theme/default/ai/chat'
|
|
8
|
+
|
|
9
|
+
const getHeaders = () => ({
|
|
10
|
+
'Content-Type': 'application/json',
|
|
11
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
12
|
+
'x-team-id': TEAM_ID
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('AI_CHAT_001: POST - returns response for valid message', { tags: '@smoke' }, () => {
|
|
16
|
+
cy.request({
|
|
17
|
+
method: 'POST',
|
|
18
|
+
url: API_URL,
|
|
19
|
+
headers: getHeaders(),
|
|
20
|
+
body: { message: 'Hello' },
|
|
21
|
+
failOnStatusCode: false
|
|
22
|
+
}).then(response => {
|
|
23
|
+
// If Ollama is down, we might get 500, but we want to check the structure if it succeeds
|
|
24
|
+
if (response.status === 200) {
|
|
25
|
+
expect(response.body.success).to.be.true
|
|
26
|
+
expect(response.body.data.message).to.be.a('string')
|
|
27
|
+
expect(response.body.data.sessionId).to.be.a('string')
|
|
28
|
+
} else {
|
|
29
|
+
// If it fails, it should be likely due to Ollama connection
|
|
30
|
+
cy.log('Request failed, possibly due to Ollama not running:', response.body)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('AI_CHAT_002: POST - returns 400 for empty message', () => {
|
|
36
|
+
cy.request({
|
|
37
|
+
method: 'POST',
|
|
38
|
+
url: API_URL,
|
|
39
|
+
headers: getHeaders(),
|
|
40
|
+
body: { message: '' },
|
|
41
|
+
failOnStatusCode: false
|
|
42
|
+
}).then(response => {
|
|
43
|
+
expect(response.status).to.eq(400)
|
|
44
|
+
expect(response.body.success).to.be.false
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('AI_CHAT_003: POST - returns 401 without authentication', () => {
|
|
49
|
+
cy.request({
|
|
50
|
+
method: 'POST',
|
|
51
|
+
url: API_URL,
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
'x-team-id': TEAM_ID
|
|
55
|
+
},
|
|
56
|
+
body: { message: 'Hello' },
|
|
57
|
+
failOnStatusCode: false
|
|
58
|
+
}).then(response => {
|
|
59
|
+
expect(response.status).to.eq(401)
|
|
60
|
+
expect(response.body.success).to.be.false
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('AI_CHAT_004: POST - returns 400 without x-team-id header', () => {
|
|
65
|
+
cy.request({
|
|
66
|
+
method: 'POST',
|
|
67
|
+
url: API_URL,
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
'Authorization': `Bearer ${API_KEY}`
|
|
71
|
+
},
|
|
72
|
+
body: { message: 'Hello' },
|
|
73
|
+
failOnStatusCode: false
|
|
74
|
+
}).then(response => {
|
|
75
|
+
expect(response.status).to.eq(400)
|
|
76
|
+
expect(response.body.code).to.eq('TEAM_CONTEXT_REQUIRED')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('AI_CHAT_005: POST - maintains session context', () => {
|
|
81
|
+
cy.request({
|
|
82
|
+
method: 'POST',
|
|
83
|
+
url: API_URL,
|
|
84
|
+
headers: getHeaders(),
|
|
85
|
+
body: { message: 'My name is John' },
|
|
86
|
+
failOnStatusCode: false
|
|
87
|
+
}).then(response1 => {
|
|
88
|
+
if (response1.status === 200) {
|
|
89
|
+
const sessionId = response1.body.data.sessionId
|
|
90
|
+
|
|
91
|
+
cy.request({
|
|
92
|
+
method: 'POST',
|
|
93
|
+
url: API_URL,
|
|
94
|
+
headers: getHeaders(),
|
|
95
|
+
body: { message: 'What is my name?', sessionId }
|
|
96
|
+
}).then(response2 => {
|
|
97
|
+
expect(response2.status).to.eq(200)
|
|
98
|
+
expect(response2.body.data.sessionId).to.eq(sessionId)
|
|
99
|
+
// Note: This assertion depends on the model's capability, so it might be flaky
|
|
100
|
+
// expect(response2.body.data.message.toLowerCase()).to.include('john')
|
|
101
|
+
})
|
|
102
|
+
} else {
|
|
103
|
+
cy.log('Skipping session test - Ollama not running')
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
})
|