@nextsparkjs/theme-default 0.1.0-beta.20 → 0.1.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/tests/cypress/e2e/_devtools/access.bdd.md +262 -0
- package/tests/cypress/e2e/_devtools/access.cy.ts +171 -0
- package/tests/cypress/e2e/_devtools/navigation.bdd.md +261 -0
- package/tests/cypress/e2e/_devtools/navigation.cy.ts +157 -0
- package/tests/cypress/e2e/_devtools/pages.bdd.md +303 -0
- package/tests/cypress/e2e/_devtools/pages.cy.ts +184 -0
- package/tests/cypress/e2e/_docs/README.md +215 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin-teams.narration.json +155 -0
- package/tests/cypress/e2e/_docs/tutorials/sector7-superadmin.cy.ts +390 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.doc.cy.ts +349 -0
- package/tests/cypress/e2e/_docs/tutorials/teams-system.narration.json +165 -0
- package/tests/cypress/e2e/_selectors/auth.cy.ts +306 -0
- package/tests/cypress/e2e/_selectors/billing.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-mobile.cy.ts +113 -0
- package/tests/cypress/e2e/_selectors/dashboard-navigation.cy.ts +89 -0
- package/tests/cypress/e2e/_selectors/dashboard-sidebar.cy.ts +60 -0
- package/tests/cypress/e2e/_selectors/dashboard-topnav.cy.ts +146 -0
- package/tests/cypress/e2e/_selectors/devtools.cy.ts +210 -0
- package/tests/cypress/e2e/_selectors/global-search.cy.ts +88 -0
- package/tests/cypress/e2e/_selectors/pages-editor.cy.ts +179 -0
- package/tests/cypress/e2e/_selectors/posts-editor.cy.ts +282 -0
- package/tests/cypress/e2e/_selectors/public.cy.ts +112 -0
- package/tests/cypress/e2e/_selectors/settings-api-keys.cy.ts +228 -0
- package/tests/cypress/e2e/_selectors/settings-billing.cy.ts +105 -0
- package/tests/cypress/e2e/_selectors/settings-layout.cy.ts +119 -0
- package/tests/cypress/e2e/_selectors/settings-password.cy.ts +71 -0
- package/tests/cypress/e2e/_selectors/settings-profile.cy.ts +82 -0
- package/tests/cypress/e2e/_selectors/settings-teams.cy.ts +68 -0
- package/tests/cypress/e2e/_selectors/superadmin.cy.ts +185 -0
- package/tests/cypress/e2e/_selectors/tasks.cy.ts +242 -0
- package/tests/cypress/e2e/_selectors/taxonomies.cy.ts +126 -0
- package/tests/cypress/e2e/_selectors/teams.cy.ts +142 -0
- package/tests/cypress/e2e/_superadmin/all-teams.bdd.md +261 -0
- package/tests/cypress/e2e/_superadmin/all-teams.cy.ts +177 -0
- package/tests/cypress/e2e/_superadmin/all-users.bdd.md +406 -0
- package/tests/cypress/e2e/_superadmin/all-users.cy.ts +294 -0
- package/tests/cypress/e2e/_superadmin/dashboard.bdd.md +235 -0
- package/tests/cypress/e2e/_superadmin/dashboard.cy.ts +149 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.bdd.md +290 -0
- package/tests/cypress/e2e/_superadmin/subscriptions-overview.cy.ts +194 -0
- package/tests/cypress/e2e/ai/ai-usage.cy.ts +209 -0
- package/tests/cypress/e2e/ai/chat-api.cy.ts +107 -0
- package/tests/cypress/e2e/ai/guardrails.cy.ts +332 -0
- package/tests/cypress/e2e/api/billing/BillingAPIController.js +319 -0
- package/tests/cypress/e2e/api/billing/check-action.cy.ts +326 -0
- package/tests/cypress/e2e/api/billing/checkout.cy.ts +358 -0
- package/tests/cypress/e2e/api/billing/lifecycle.cy.ts +423 -0
- package/tests/cypress/e2e/api/billing/plans/README.md +345 -0
- package/tests/cypress/e2e/api/billing/plans/business.cy.ts +412 -0
- package/tests/cypress/e2e/api/billing/plans/downgrade.cy.ts +510 -0
- package/tests/cypress/e2e/api/billing/plans/fixtures/billing-plans.json +163 -0
- package/tests/cypress/e2e/api/billing/plans/free.cy.ts +500 -0
- package/tests/cypress/e2e/api/billing/plans/pro.cy.ts +497 -0
- package/tests/cypress/e2e/api/billing/plans/starter.cy.ts +342 -0
- package/tests/cypress/e2e/api/billing/portal.cy.ts +313 -0
- package/tests/cypress/e2e/api/devtools/registries.bdd.md +300 -0
- package/tests/cypress/e2e/api/devtools/registries.cy.ts +368 -0
- package/tests/cypress/e2e/api/entities/blocks-scope.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/customers-crud.cy.ts +648 -0
- package/tests/cypress/e2e/api/entities/customers-metas.cy.ts +839 -0
- package/tests/cypress/e2e/api/entities/pages-crud.cy.ts +425 -0
- package/tests/cypress/e2e/api/entities/pages-status.cy.ts +335 -0
- package/tests/cypress/e2e/api/entities/post-categories-crud.cy.ts +610 -0
- package/tests/cypress/e2e/api/entities/posts-crud.cy.ts +709 -0
- package/tests/cypress/e2e/api/entities/posts-status.cy.ts +396 -0
- package/tests/cypress/e2e/api/entities/tasks-crud.cy.ts +602 -0
- package/tests/cypress/e2e/api/entities/tasks-metas.cy.ts +878 -0
- package/tests/cypress/e2e/api/entities/users-crud.cy.ts +469 -0
- package/tests/cypress/e2e/api/entities/users-metas.cy.ts +913 -0
- package/tests/cypress/e2e/api/entities/users-security.cy.ts +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.bdd.md +375 -0
- package/tests/cypress/e2e/api/scheduled-actions/cron-endpoint.cy.ts +346 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.bdd.md +451 -0
- package/tests/cypress/e2e/api/scheduled-actions/devtools-endpoint.cy.ts +447 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.bdd.md +649 -0
- package/tests/cypress/e2e/api/scheduled-actions/scheduling.cy.ts +333 -0
- package/tests/cypress/e2e/api/settings/api-keys.crud.cy.ts +923 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/app-roles/developer-login.cy.ts +144 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.bdd.md +118 -0
- package/tests/cypress/e2e/uat/auth/app-roles/superadmin-login.cy.ts +84 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.bdd.md +288 -0
- package/tests/cypress/e2e/uat/auth/custom-roles/editor-login.cy.ts +188 -0
- package/tests/cypress/e2e/uat/auth/login-logout.bdd.md +160 -0
- package/tests/cypress/e2e/uat/auth/login-logout.cy.ts +116 -0
- package/tests/cypress/e2e/uat/auth/password-reset.bdd.md +289 -0
- package/tests/cypress/e2e/uat/auth/password-reset.cy.ts +200 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.bdd.md +225 -0
- package/tests/cypress/e2e/uat/auth/team-roles/admin-login.cy.ts +148 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.bdd.md +251 -0
- package/tests/cypress/e2e/uat/auth/team-roles/member-login.cy.ts +163 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.bdd.md +231 -0
- package/tests/cypress/e2e/uat/auth/team-roles/owner-login.cy.ts +141 -0
- package/tests/cypress/e2e/uat/billing/extended.bdd.md +273 -0
- package/tests/cypress/e2e/uat/billing/extended.cy.ts +209 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.bdd.md +407 -0
- package/tests/cypress/e2e/uat/billing/feature-gates.cy.ts +307 -0
- package/tests/cypress/e2e/uat/billing/page.bdd.md +329 -0
- package/tests/cypress/e2e/uat/billing/page.cy.ts +250 -0
- package/tests/cypress/e2e/uat/billing/status.bdd.md +190 -0
- package/tests/cypress/e2e/uat/billing/status.cy.ts +145 -0
- package/tests/cypress/e2e/uat/billing/team-switch.bdd.md +156 -0
- package/tests/cypress/e2e/uat/billing/team-switch.cy.ts +122 -0
- package/tests/cypress/e2e/uat/billing/usage.bdd.md +218 -0
- package/tests/cypress/e2e/uat/billing/usage.cy.ts +176 -0
- package/tests/cypress/e2e/uat/blocks/hero.bdd.md +124 -0
- package/tests/cypress/e2e/uat/blocks/hero.cy.ts +56 -0
- package/tests/cypress/e2e/uat/devtools/api-tester.cy.ts +390 -0
- package/tests/cypress/e2e/uat/entities/customers/member.bdd.md +275 -0
- package/tests/cypress/e2e/uat/entities/customers/member.cy.ts +122 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.bdd.md +243 -0
- package/tests/cypress/e2e/uat/entities/customers/owner.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.bdd.md +476 -0
- package/tests/cypress/e2e/uat/entities/pages/block-crud.cy.ts +486 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.bdd.md +460 -0
- package/tests/cypress/e2e/uat/entities/pages/block-editor.cy.ts +301 -0
- package/tests/cypress/e2e/uat/entities/pages/list.bdd.md +432 -0
- package/tests/cypress/e2e/uat/entities/pages/list.cy.ts +273 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.bdd.md +696 -0
- package/tests/cypress/e2e/uat/entities/pages/public-rendering.cy.ts +340 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.bdd.md +161 -0
- package/tests/cypress/e2e/uat/entities/posts/categories-api-aware.cy.ts +104 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.bdd.md +375 -0
- package/tests/cypress/e2e/uat/entities/posts/categories.cy.ts +241 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.bdd.md +429 -0
- package/tests/cypress/e2e/uat/entities/posts/editor.cy.ts +257 -0
- package/tests/cypress/e2e/uat/entities/posts/list.bdd.md +340 -0
- package/tests/cypress/e2e/uat/entities/posts/list.cy.ts +177 -0
- package/tests/cypress/e2e/uat/entities/posts/public.bdd.md +614 -0
- package/tests/cypress/e2e/uat/entities/posts/public.cy.ts +249 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.bdd.md +222 -0
- package/tests/cypress/e2e/uat/entities/tasks/member.cy.ts +165 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.bdd.md +419 -0
- package/tests/cypress/e2e/uat/entities/tasks/owner.cy.ts +191 -0
- package/tests/cypress/e2e/uat/roles/editor-role.bdd.md +552 -0
- package/tests/cypress/e2e/uat/roles/editor-role.cy.ts +210 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.bdd.md +450 -0
- package/tests/cypress/e2e/uat/roles/member-restrictions.cy.ts +189 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.bdd.md +530 -0
- package/tests/cypress/e2e/uat/roles/owner-full-crud.cy.ts +247 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.bdd.md +736 -0
- package/tests/cypress/e2e/uat/scheduled-actions/devtools-ui.cy.ts +740 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.bdd.md +553 -0
- package/tests/cypress/e2e/uat/teams/roles-matrix.cy.ts +185 -0
- package/tests/cypress/e2e/uat/teams/switcher.bdd.md +1151 -0
- package/tests/cypress/e2e/uat/teams/switcher.cy.ts +497 -0
- package/tests/cypress/e2e/uat/teams/team-switcher.md +198 -0
- package/tests/cypress/fixtures/blocks.json +218 -0
- package/tests/cypress/fixtures/entities.json +78 -0
- package/tests/cypress/fixtures/page-builder.json +21 -0
- package/tests/cypress/src/components/CategoriesPOM.ts +382 -0
- package/tests/cypress/src/components/CustomersPOM.ts +439 -0
- package/tests/cypress/src/components/DevKeyringPOM.ts +160 -0
- package/tests/cypress/src/components/EntityForm.ts +375 -0
- package/tests/cypress/src/components/EntityList.ts +389 -0
- package/tests/cypress/src/components/PageBuilderPOM.ts +710 -0
- package/tests/cypress/src/components/PostEditorPOM.ts +370 -0
- package/tests/cypress/src/components/PostsListPOM.ts +223 -0
- package/tests/cypress/src/components/PublicPagePOM.ts +447 -0
- package/tests/cypress/src/components/PublicPostPOM.ts +146 -0
- package/tests/cypress/src/components/TasksPOM.ts +272 -0
- package/tests/cypress/src/components/TeamSwitcherPOM.ts +450 -0
- package/tests/cypress/src/components/index.ts +21 -0
- package/tests/cypress/src/controllers/ApiKeysAPIController.js +178 -0
- package/tests/cypress/src/controllers/BaseAPIController.js +317 -0
- package/tests/cypress/src/controllers/CustomerAPIController.js +251 -0
- package/tests/cypress/src/controllers/PagesAPIController.js +226 -0
- package/tests/cypress/src/controllers/PostsAPIController.js +250 -0
- package/tests/cypress/src/controllers/TaskAPIController.js +240 -0
- package/tests/cypress/src/controllers/UsersAPIController.js +242 -0
- package/tests/cypress/src/controllers/index.js +25 -0
- package/tests/cypress/src/core/AuthPOM.ts +450 -0
- package/tests/cypress/src/core/BasePOM.ts +86 -0
- package/tests/cypress/src/core/BlockEditorBasePOM.ts +576 -0
- package/tests/cypress/src/core/DashboardEntityPOM.ts +692 -0
- package/tests/cypress/src/core/index.ts +14 -0
- package/tests/cypress/src/entities/CustomersPOM.ts +172 -0
- package/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/tests/cypress/src/entities/PostsPOM.ts +137 -0
- package/tests/cypress/src/entities/TasksPOM.ts +176 -0
- package/tests/cypress/src/entities/index.ts +14 -0
- package/tests/cypress/src/features/BillingPOM.ts +385 -0
- package/tests/cypress/src/features/DashboardPOM.ts +245 -0
- package/tests/cypress/src/features/DevtoolsPOM.ts +739 -0
- package/tests/cypress/src/features/PageBuilderPOM.ts +263 -0
- package/tests/cypress/src/features/PostEditorPOM.ts +313 -0
- package/tests/cypress/src/features/ScheduledActionsPOM.ts +463 -0
- package/tests/cypress/src/features/SettingsPOM.ts +362 -0
- package/tests/cypress/src/features/SuperadminPOM.ts +331 -0
- package/tests/cypress/src/features/SuperadminTeamRolesPOM.ts +285 -0
- package/tests/cypress/src/features/index.ts +28 -0
- package/tests/cypress/src/helpers/ApiInterceptor.ts +177 -0
- package/tests/cypress/src/index.ts +101 -0
- package/tests/cypress/src/pages/dashboard/Dashboard.js +677 -0
- package/tests/cypress/src/pages/dashboard/DashboardPage.js +43 -0
- package/tests/cypress/src/pages/dashboard/DashboardStats.js +546 -0
- package/tests/cypress/src/pages/dashboard/index.js +6 -0
- package/tests/cypress/src/pages/index.js +5 -0
- package/tests/cypress/src/pages/public/FeaturesPage.js +28 -0
- package/tests/cypress/src/pages/public/LandingPage.js +69 -0
- package/tests/cypress/src/pages/public/PricingPage.js +33 -0
- package/tests/cypress/src/pages/public/index.js +6 -0
- package/tests/cypress/src/selectors.ts +46 -0
- package/tests/cypress/src/session-helpers.ts +500 -0
- package/tests/cypress/support/doc-commands.ts +260 -0
- package/tests/cypress.config.ts +150 -0
- package/tests/jest/components/post-header.test.tsx +377 -0
- package/tests/jest/config/role-config.test.ts +529 -0
- package/tests/jest/jest.config.ts +81 -0
- package/tests/jest/langchain/COVERAGE.md +372 -0
- package/tests/jest/langchain/guardrails.test.ts +465 -0
- package/tests/jest/langchain/streaming.test.ts +367 -0
- package/tests/jest/langchain/token-tracker.test.ts +455 -0
- package/tests/jest/langchain/tracer-callbacks.test.ts +881 -0
- package/tests/jest/langchain/tracer.test.ts +823 -0
- package/tests/jest/user-roles/role-helpers.test.ts +432 -0
- package/tests/jest/validation/categories.test.ts +429 -0
- package/tests/jest/validation/posts.test.ts +546 -0
- package/tests/tsconfig.json +15 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
/// <reference types="cypress" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-Categories API - CRUD Tests
|
|
5
|
+
*
|
|
6
|
+
* Test suite for Post-Categories API endpoints (abstracts taxonomies internally).
|
|
7
|
+
* Tests GET, POST, PUT, DELETE operations.
|
|
8
|
+
*
|
|
9
|
+
* Entity characteristics:
|
|
10
|
+
* - Required fields: name
|
|
11
|
+
* - Optional fields: slug (auto-generated if not provided), description, icon, color, parentId
|
|
12
|
+
* - Unique constraint: type + slug (internally type='post_category')
|
|
13
|
+
* - Access: authenticated users only (dual auth: session + API key)
|
|
14
|
+
* - Hierarchical support: parentId for nested categories
|
|
15
|
+
* - Soft delete: deletedAt when category has posts
|
|
16
|
+
*
|
|
17
|
+
* Tags: @api, @feat-posts, @crud, @categories
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import * as allure from 'allure-cypress'
|
|
21
|
+
|
|
22
|
+
describe('Post-Categories API - CRUD Operations', {
|
|
23
|
+
tags: ['@api', '@feat-posts', '@crud', '@categories']
|
|
24
|
+
}, () => {
|
|
25
|
+
// Test constants
|
|
26
|
+
const SUPERADMIN_API_KEY = 'test_api_key_for_testing_purposes_only_not_a_real_secret_key_abc123'
|
|
27
|
+
const BASE_URL = Cypress.config('baseUrl') || 'http://localhost:5173'
|
|
28
|
+
const API_CATEGORIES = `${BASE_URL}/api/v1/post-categories`
|
|
29
|
+
|
|
30
|
+
// Track created categories for cleanup
|
|
31
|
+
let createdCategories: string[] = []
|
|
32
|
+
|
|
33
|
+
// Helper to make authenticated API key requests
|
|
34
|
+
const apiRequest = (method: string, url: string, body?: object) => {
|
|
35
|
+
return cy.request({
|
|
36
|
+
method,
|
|
37
|
+
url,
|
|
38
|
+
headers: {
|
|
39
|
+
'x-api-key': SUPERADMIN_API_KEY,
|
|
40
|
+
'Content-Type': 'application/json'
|
|
41
|
+
},
|
|
42
|
+
body,
|
|
43
|
+
failOnStatusCode: false
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
allure.epic('API')
|
|
49
|
+
allure.feature('Post Categories')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
// Cleanup: Delete categories created during tests
|
|
54
|
+
createdCategories.forEach((categoryId) => {
|
|
55
|
+
apiRequest('DELETE', `${API_CATEGORIES}/${categoryId}`)
|
|
56
|
+
})
|
|
57
|
+
createdCategories = []
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// ============================================================
|
|
61
|
+
// GET /api/v1/post-categories - List Categories
|
|
62
|
+
// ============================================================
|
|
63
|
+
describe('GET /api/v1/post-categories - List Categories', () => {
|
|
64
|
+
it('CAT_API_001: Should list categories with valid API key', { tags: '@smoke' }, () => {
|
|
65
|
+
allure.story('CRUD Operations')
|
|
66
|
+
allure.severity('critical')
|
|
67
|
+
|
|
68
|
+
apiRequest('GET', API_CATEGORIES).then((response) => {
|
|
69
|
+
expect(response.status).to.eq(200)
|
|
70
|
+
expect(response.body.success).to.be.true
|
|
71
|
+
expect(response.body.data).to.be.an('array')
|
|
72
|
+
|
|
73
|
+
cy.log(`Found ${response.body.data.length} categories`)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('CAT_API_002: Should return category with expected structure', () => {
|
|
78
|
+
apiRequest('GET', API_CATEGORIES).then((response) => {
|
|
79
|
+
expect(response.status).to.eq(200)
|
|
80
|
+
|
|
81
|
+
if (response.body.data.length > 0) {
|
|
82
|
+
const category = response.body.data[0]
|
|
83
|
+
|
|
84
|
+
// Verify category structure (type is not included in list responses)
|
|
85
|
+
expect(category).to.have.property('id')
|
|
86
|
+
expect(category).to.have.property('slug')
|
|
87
|
+
expect(category).to.have.property('name')
|
|
88
|
+
expect(category).to.have.property('isActive')
|
|
89
|
+
|
|
90
|
+
cy.log(`Category structure verified: ${category.name}`)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('CAT_API_003: Should only return active categories by default', () => {
|
|
96
|
+
apiRequest('GET', API_CATEGORIES).then((response) => {
|
|
97
|
+
expect(response.status).to.eq(200)
|
|
98
|
+
|
|
99
|
+
// All returned categories should be active
|
|
100
|
+
response.body.data.forEach((category: any) => {
|
|
101
|
+
expect(category.isActive).to.be.true
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
cy.log(`All ${response.body.data.length} categories are active`)
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('CAT_API_004: Should allow public read access without authentication', { tags: '@security' }, () => {
|
|
109
|
+
/**
|
|
110
|
+
* NOTE: GET /api/v1/post-categories is publicly accessible
|
|
111
|
+
* to allow frontend applications to fetch categories for filtering.
|
|
112
|
+
* Only write operations (POST, PUT, DELETE) require authentication.
|
|
113
|
+
*/
|
|
114
|
+
cy.request({
|
|
115
|
+
method: 'GET',
|
|
116
|
+
url: API_CATEGORIES,
|
|
117
|
+
failOnStatusCode: false
|
|
118
|
+
}).then((response) => {
|
|
119
|
+
expect(response.status).to.eq(200)
|
|
120
|
+
expect(response.body.success).to.be.true
|
|
121
|
+
expect(response.body.data).to.be.an('array')
|
|
122
|
+
|
|
123
|
+
cy.log('Categories list is publicly accessible (by design)')
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
// ============================================================
|
|
129
|
+
// POST /api/v1/post-categories - Create Category
|
|
130
|
+
// ============================================================
|
|
131
|
+
describe('POST /api/v1/post-categories - Create Category', () => {
|
|
132
|
+
it('CAT_API_010: Should create category with valid data', { tags: '@smoke' }, () => {
|
|
133
|
+
allure.story('CRUD Operations')
|
|
134
|
+
allure.severity('critical')
|
|
135
|
+
|
|
136
|
+
const timestamp = Date.now()
|
|
137
|
+
const categoryData = {
|
|
138
|
+
name: `Test Category ${timestamp}`,
|
|
139
|
+
slug: `test-category-${timestamp}`,
|
|
140
|
+
description: 'Test category description',
|
|
141
|
+
icon: 'bookmark',
|
|
142
|
+
color: '#FF5733'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((response) => {
|
|
146
|
+
expect(response.status).to.eq(201)
|
|
147
|
+
expect(response.body.success).to.be.true
|
|
148
|
+
|
|
149
|
+
const category = response.body.data
|
|
150
|
+
expect(category).to.have.property('id')
|
|
151
|
+
expect(category.type).to.eq('post_category')
|
|
152
|
+
expect(category.slug).to.eq(categoryData.slug)
|
|
153
|
+
expect(category.name).to.eq(categoryData.name)
|
|
154
|
+
expect(category.description).to.eq(categoryData.description)
|
|
155
|
+
expect(category.icon).to.eq(categoryData.icon)
|
|
156
|
+
expect(category.color).to.eq(categoryData.color)
|
|
157
|
+
|
|
158
|
+
createdCategories.push(category.id)
|
|
159
|
+
cy.log(`Created category: ${category.name} (ID: ${category.id})`)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('CAT_API_011: Should auto-generate slug from name if not provided', () => {
|
|
164
|
+
const categoryData = {
|
|
165
|
+
name: `Auto Slug Category ${Date.now()}`
|
|
166
|
+
// slug not provided
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((response) => {
|
|
170
|
+
expect(response.status).to.eq(201)
|
|
171
|
+
|
|
172
|
+
const category = response.body.data
|
|
173
|
+
expect(category.slug).to.exist
|
|
174
|
+
expect(category.slug).to.match(/^[a-z0-9\-]+$/)
|
|
175
|
+
expect(category.name).to.eq(categoryData.name)
|
|
176
|
+
|
|
177
|
+
createdCategories.push(category.id)
|
|
178
|
+
cy.log(`Created category with auto-generated slug: ${category.slug}`)
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('CAT_API_012: Should create category with minimal data', () => {
|
|
183
|
+
const minimalData = {
|
|
184
|
+
name: `Minimal Category ${Date.now()}`
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
apiRequest('POST', API_CATEGORIES, minimalData).then((response) => {
|
|
188
|
+
expect(response.status).to.eq(201)
|
|
189
|
+
|
|
190
|
+
const category = response.body.data
|
|
191
|
+
expect(category.name).to.eq(minimalData.name)
|
|
192
|
+
expect(category.slug).to.exist
|
|
193
|
+
expect(category.isActive).to.be.true // Default value
|
|
194
|
+
|
|
195
|
+
createdCategories.push(category.id)
|
|
196
|
+
cy.log(`Created minimal category: ${category.id}`)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('CAT_API_013: Should create category with icon and color', () => {
|
|
201
|
+
const categoryData = {
|
|
202
|
+
name: `Styled Category ${Date.now()}`,
|
|
203
|
+
icon: 'star',
|
|
204
|
+
color: '#3B82F6'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((response) => {
|
|
208
|
+
expect(response.status).to.eq(201)
|
|
209
|
+
|
|
210
|
+
const category = response.body.data
|
|
211
|
+
expect(category.icon).to.eq(categoryData.icon)
|
|
212
|
+
expect(category.color).to.eq(categoryData.color)
|
|
213
|
+
|
|
214
|
+
createdCategories.push(category.id)
|
|
215
|
+
cy.log(`Created styled category with icon '${category.icon}' and color '${category.color}'`)
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('CAT_API_014: Should reject creation without name', () => {
|
|
220
|
+
const invalidData = {
|
|
221
|
+
slug: `no-name-${Date.now()}`
|
|
222
|
+
// Missing: name
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
apiRequest('POST', API_CATEGORIES, invalidData).then((response) => {
|
|
226
|
+
expect(response.status).to.eq(400)
|
|
227
|
+
expect(response.body.success).to.be.false
|
|
228
|
+
|
|
229
|
+
cy.log('Creation without name rejected with 400')
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('CAT_API_015: Should reject invalid slug format', () => {
|
|
234
|
+
const invalidData = {
|
|
235
|
+
name: 'Test Category',
|
|
236
|
+
slug: 'Invalid Slug With Spaces!'
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
apiRequest('POST', API_CATEGORIES, invalidData).then((response) => {
|
|
240
|
+
expect(response.status).to.eq(400)
|
|
241
|
+
expect(response.body.success).to.be.false
|
|
242
|
+
|
|
243
|
+
cy.log('Invalid slug format rejected with 400')
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('CAT_API_016: Should reject duplicate slug', () => {
|
|
248
|
+
const uniqueSlug = `duplicate-cat-${Date.now()}`
|
|
249
|
+
|
|
250
|
+
// Create first category
|
|
251
|
+
const categoryData1 = {
|
|
252
|
+
name: 'First Category',
|
|
253
|
+
slug: uniqueSlug
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
apiRequest('POST', API_CATEGORIES, categoryData1).then((response1) => {
|
|
257
|
+
expect(response1.status).to.eq(201)
|
|
258
|
+
createdCategories.push(response1.body.data.id)
|
|
259
|
+
|
|
260
|
+
// Try to create duplicate
|
|
261
|
+
const categoryData2 = {
|
|
262
|
+
name: 'Second Category',
|
|
263
|
+
slug: uniqueSlug // Same slug
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
apiRequest('POST', API_CATEGORIES, categoryData2).then((response2) => {
|
|
267
|
+
expect(response2.status).to.be.oneOf([400, 409])
|
|
268
|
+
expect(response2.body.success).to.be.false
|
|
269
|
+
|
|
270
|
+
cy.log('Duplicate slug rejected')
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('CAT_API_017: Should create hierarchical category with parentId', () => {
|
|
276
|
+
// First create a parent category
|
|
277
|
+
const parentData = {
|
|
278
|
+
name: `Parent Category ${Date.now()}`
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
apiRequest('POST', API_CATEGORIES, parentData).then((parentResponse) => {
|
|
282
|
+
expect(parentResponse.status).to.eq(201)
|
|
283
|
+
const parentId = parentResponse.body.data.id
|
|
284
|
+
createdCategories.push(parentId)
|
|
285
|
+
|
|
286
|
+
// Create child category
|
|
287
|
+
const childData = {
|
|
288
|
+
name: `Child Category ${Date.now()}`,
|
|
289
|
+
parentId: parentId
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
apiRequest('POST', API_CATEGORIES, childData).then((childResponse) => {
|
|
293
|
+
expect(childResponse.status).to.eq(201)
|
|
294
|
+
|
|
295
|
+
const childCategory = childResponse.body.data
|
|
296
|
+
expect(childCategory.parentId).to.eq(parentId)
|
|
297
|
+
|
|
298
|
+
createdCategories.push(childCategory.id)
|
|
299
|
+
cy.log(`Created hierarchical category: ${childCategory.name} (parent: ${parentId})`)
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('CAT_API_018: Should reject creation without authentication', { tags: '@security' }, () => {
|
|
305
|
+
const categoryData = {
|
|
306
|
+
name: 'Unauthorized Category'
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
cy.request({
|
|
310
|
+
method: 'POST',
|
|
311
|
+
url: API_CATEGORIES,
|
|
312
|
+
body: categoryData,
|
|
313
|
+
failOnStatusCode: false
|
|
314
|
+
}).then((response) => {
|
|
315
|
+
expect(response.status).to.eq(401)
|
|
316
|
+
expect(response.body.success).to.be.false
|
|
317
|
+
|
|
318
|
+
cy.log('Creation without authentication rejected with 401')
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// ============================================================
|
|
324
|
+
// GET /api/v1/post-categories/{id} - Get Category by ID
|
|
325
|
+
// ============================================================
|
|
326
|
+
describe('GET /api/v1/post-categories/{id} - Get Category by ID', () => {
|
|
327
|
+
let testCategoryId: string
|
|
328
|
+
|
|
329
|
+
beforeEach(() => {
|
|
330
|
+
// Create a test category
|
|
331
|
+
const categoryData = {
|
|
332
|
+
name: `Test Get By ID ${Date.now()}`,
|
|
333
|
+
description: 'Test category for GET by ID'
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((response) => {
|
|
337
|
+
testCategoryId = response.body.data.id
|
|
338
|
+
createdCategories.push(testCategoryId)
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('CAT_API_020: Should get category by valid ID', () => {
|
|
343
|
+
cy.then(() => {
|
|
344
|
+
apiRequest('GET', `${API_CATEGORIES}/${testCategoryId}`).then((response) => {
|
|
345
|
+
expect(response.status).to.eq(200)
|
|
346
|
+
expect(response.body.success).to.be.true
|
|
347
|
+
expect(response.body.data.id).to.eq(testCategoryId)
|
|
348
|
+
// Note: type field is not included in GET by ID response
|
|
349
|
+
expect(response.body.data).to.have.property('name')
|
|
350
|
+
expect(response.body.data).to.have.property('slug')
|
|
351
|
+
|
|
352
|
+
cy.log(`Got category: ${response.body.data.name}`)
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
it('CAT_API_021: Should return 404 for non-existent category', () => {
|
|
358
|
+
apiRequest('GET', `${API_CATEGORIES}/non-existent-id-12345`).then((response) => {
|
|
359
|
+
expect(response.status).to.eq(404)
|
|
360
|
+
expect(response.body.success).to.be.false
|
|
361
|
+
|
|
362
|
+
cy.log('Non-existent category returns 404')
|
|
363
|
+
})
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
// ============================================================
|
|
368
|
+
// PUT /api/v1/post-categories/{id} - Update Category
|
|
369
|
+
// ============================================================
|
|
370
|
+
describe('PUT /api/v1/post-categories/{id} - Update Category', () => {
|
|
371
|
+
let testCategoryId: string
|
|
372
|
+
|
|
373
|
+
beforeEach(() => {
|
|
374
|
+
const categoryData = {
|
|
375
|
+
name: `Test Update ${Date.now()}`,
|
|
376
|
+
description: 'Original description'
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((response) => {
|
|
380
|
+
testCategoryId = response.body.data.id
|
|
381
|
+
createdCategories.push(testCategoryId)
|
|
382
|
+
})
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('CAT_API_030: Should update category name', () => {
|
|
386
|
+
const updateData = {
|
|
387
|
+
name: 'Updated Category Name'
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
cy.then(() => {
|
|
391
|
+
apiRequest('PUT', `${API_CATEGORIES}/${testCategoryId}`, updateData).then((response) => {
|
|
392
|
+
expect(response.status).to.eq(200)
|
|
393
|
+
expect(response.body.data.name).to.eq(updateData.name)
|
|
394
|
+
|
|
395
|
+
cy.log(`Updated category name to: ${updateData.name}`)
|
|
396
|
+
})
|
|
397
|
+
})
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('CAT_API_031: Should update category slug', () => {
|
|
401
|
+
const updateData = {
|
|
402
|
+
slug: `updated-slug-${Date.now()}`
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
cy.then(() => {
|
|
406
|
+
apiRequest('PUT', `${API_CATEGORIES}/${testCategoryId}`, updateData).then((response) => {
|
|
407
|
+
expect(response.status).to.eq(200)
|
|
408
|
+
expect(response.body.data.slug).to.eq(updateData.slug)
|
|
409
|
+
|
|
410
|
+
cy.log(`Updated category slug to: ${updateData.slug}`)
|
|
411
|
+
})
|
|
412
|
+
})
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
it('CAT_API_032: Should update category description', () => {
|
|
416
|
+
const updateData = {
|
|
417
|
+
description: 'Updated description text'
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
cy.then(() => {
|
|
421
|
+
apiRequest('PUT', `${API_CATEGORIES}/${testCategoryId}`, updateData).then((response) => {
|
|
422
|
+
expect(response.status).to.eq(200)
|
|
423
|
+
expect(response.body.data.description).to.eq(updateData.description)
|
|
424
|
+
|
|
425
|
+
cy.log('Updated category description')
|
|
426
|
+
})
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it('CAT_API_033: Should update category icon and color', () => {
|
|
431
|
+
const updateData = {
|
|
432
|
+
icon: 'heart',
|
|
433
|
+
color: '#EF4444'
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
cy.then(() => {
|
|
437
|
+
apiRequest('PUT', `${API_CATEGORIES}/${testCategoryId}`, updateData).then((response) => {
|
|
438
|
+
expect(response.status).to.eq(200)
|
|
439
|
+
expect(response.body.data.icon).to.eq(updateData.icon)
|
|
440
|
+
expect(response.body.data.color).to.eq(updateData.color)
|
|
441
|
+
|
|
442
|
+
cy.log(`Updated icon to '${updateData.icon}' and color to '${updateData.color}'`)
|
|
443
|
+
})
|
|
444
|
+
})
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('CAT_API_034: Should toggle isActive status', () => {
|
|
448
|
+
const updateData = {
|
|
449
|
+
isActive: false
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
cy.then(() => {
|
|
453
|
+
apiRequest('PUT', `${API_CATEGORIES}/${testCategoryId}`, updateData).then((response) => {
|
|
454
|
+
expect(response.status).to.eq(200)
|
|
455
|
+
expect(response.body.data.isActive).to.be.false
|
|
456
|
+
|
|
457
|
+
cy.log('Category deactivated')
|
|
458
|
+
})
|
|
459
|
+
})
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
it('CAT_API_035: Should return 404 for non-existent category', () => {
|
|
463
|
+
apiRequest('PUT', `${API_CATEGORIES}/non-existent-id-12345`, {
|
|
464
|
+
name: 'New Name'
|
|
465
|
+
}).then((response) => {
|
|
466
|
+
expect(response.status).to.eq(404)
|
|
467
|
+
expect(response.body.success).to.be.false
|
|
468
|
+
|
|
469
|
+
cy.log('Update non-existent category returns 404')
|
|
470
|
+
})
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
it('CAT_API_036: Should reject update without authentication', { tags: '@security' }, () => {
|
|
474
|
+
cy.then(() => {
|
|
475
|
+
cy.request({
|
|
476
|
+
method: 'PUT',
|
|
477
|
+
url: `${API_CATEGORIES}/${testCategoryId}`,
|
|
478
|
+
body: { name: 'Unauthorized Update' },
|
|
479
|
+
failOnStatusCode: false
|
|
480
|
+
}).then((response) => {
|
|
481
|
+
expect(response.status).to.eq(401)
|
|
482
|
+
expect(response.body.success).to.be.false
|
|
483
|
+
|
|
484
|
+
cy.log('Update without authentication rejected with 401')
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
})
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
// ============================================================
|
|
491
|
+
// DELETE /api/v1/post-categories/{id} - Delete Category
|
|
492
|
+
// ============================================================
|
|
493
|
+
describe('DELETE /api/v1/post-categories/{id} - Delete Category', () => {
|
|
494
|
+
it('CAT_API_040: Should delete category by valid ID', () => {
|
|
495
|
+
// Create category to delete
|
|
496
|
+
const categoryData = {
|
|
497
|
+
name: `Test Delete ${Date.now()}`
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((createResponse) => {
|
|
501
|
+
const categoryId = createResponse.body.data.id
|
|
502
|
+
|
|
503
|
+
// Delete the category
|
|
504
|
+
apiRequest('DELETE', `${API_CATEGORIES}/${categoryId}`).then((deleteResponse) => {
|
|
505
|
+
expect(deleteResponse.status).to.eq(200)
|
|
506
|
+
expect(deleteResponse.body.success).to.be.true
|
|
507
|
+
|
|
508
|
+
// Verify deletion (may be soft delete or hard delete depending on usage)
|
|
509
|
+
apiRequest('GET', `${API_CATEGORIES}/${categoryId}`).then((getResponse) => {
|
|
510
|
+
// Should either be 404 (hard delete) or exist but deletedAt set (soft delete)
|
|
511
|
+
expect(getResponse.status).to.be.oneOf([200, 404])
|
|
512
|
+
cy.log(`Deleted category: ${categoryId}`)
|
|
513
|
+
})
|
|
514
|
+
})
|
|
515
|
+
})
|
|
516
|
+
})
|
|
517
|
+
|
|
518
|
+
it('CAT_API_041: Should return 404 for non-existent category', () => {
|
|
519
|
+
apiRequest('DELETE', `${API_CATEGORIES}/non-existent-id-12345`).then((response) => {
|
|
520
|
+
expect(response.status).to.eq(404)
|
|
521
|
+
expect(response.body.success).to.be.false
|
|
522
|
+
|
|
523
|
+
cy.log('Delete non-existent category returns 404')
|
|
524
|
+
})
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
it('CAT_API_042: Should reject deletion without authentication', { tags: '@security' }, () => {
|
|
528
|
+
// Create a category first
|
|
529
|
+
const categoryData = {
|
|
530
|
+
name: `Auth Delete Test ${Date.now()}`
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((createResponse) => {
|
|
534
|
+
const categoryId = createResponse.body.data.id
|
|
535
|
+
createdCategories.push(categoryId)
|
|
536
|
+
|
|
537
|
+
// Try to delete without auth
|
|
538
|
+
cy.request({
|
|
539
|
+
method: 'DELETE',
|
|
540
|
+
url: `${API_CATEGORIES}/${categoryId}`,
|
|
541
|
+
failOnStatusCode: false
|
|
542
|
+
}).then((response) => {
|
|
543
|
+
expect(response.status).to.eq(401)
|
|
544
|
+
expect(response.body.success).to.be.false
|
|
545
|
+
|
|
546
|
+
cy.log('Deletion without authentication rejected with 401')
|
|
547
|
+
})
|
|
548
|
+
})
|
|
549
|
+
})
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
// ============================================================
|
|
553
|
+
// Integration Test - Complete CRUD Lifecycle
|
|
554
|
+
// ============================================================
|
|
555
|
+
describe('Integration - Complete CRUD Lifecycle', () => {
|
|
556
|
+
it('CAT_API_100: Should complete full lifecycle: Create -> Read -> Update -> Delete', () => {
|
|
557
|
+
const timestamp = Date.now()
|
|
558
|
+
const categoryData = {
|
|
559
|
+
name: `Lifecycle Test ${timestamp}`,
|
|
560
|
+
slug: `lifecycle-test-${timestamp}`,
|
|
561
|
+
description: 'Lifecycle test description',
|
|
562
|
+
icon: 'check',
|
|
563
|
+
color: '#10B981'
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// 1. CREATE
|
|
567
|
+
apiRequest('POST', API_CATEGORIES, categoryData).then((createResponse) => {
|
|
568
|
+
expect(createResponse.status).to.eq(201)
|
|
569
|
+
const createdCategory = createResponse.body.data
|
|
570
|
+
cy.log(`1. Created category: ${createdCategory.id}`)
|
|
571
|
+
|
|
572
|
+
// 2. READ
|
|
573
|
+
apiRequest('GET', `${API_CATEGORIES}/${createdCategory.id}`).then((readResponse) => {
|
|
574
|
+
expect(readResponse.status).to.eq(200)
|
|
575
|
+
expect(readResponse.body.data.name).to.eq(categoryData.name)
|
|
576
|
+
cy.log(`2. Read category: ${createdCategory.id}`)
|
|
577
|
+
|
|
578
|
+
// 3. UPDATE
|
|
579
|
+
const updateData = {
|
|
580
|
+
name: 'Updated Lifecycle Category',
|
|
581
|
+
description: 'Updated description',
|
|
582
|
+
icon: 'star',
|
|
583
|
+
color: '#F59E0B'
|
|
584
|
+
}
|
|
585
|
+
apiRequest('PUT', `${API_CATEGORIES}/${createdCategory.id}`, updateData).then((updateResponse) => {
|
|
586
|
+
expect(updateResponse.status).to.eq(200)
|
|
587
|
+
expect(updateResponse.body.data.name).to.eq(updateData.name)
|
|
588
|
+
expect(updateResponse.body.data.description).to.eq(updateData.description)
|
|
589
|
+
expect(updateResponse.body.data.icon).to.eq(updateData.icon)
|
|
590
|
+
expect(updateResponse.body.data.color).to.eq(updateData.color)
|
|
591
|
+
cy.log(`3. Updated category: ${updateData.name}`)
|
|
592
|
+
|
|
593
|
+
// 4. DELETE
|
|
594
|
+
apiRequest('DELETE', `${API_CATEGORIES}/${createdCategory.id}`).then((deleteResponse) => {
|
|
595
|
+
expect(deleteResponse.status).to.eq(200)
|
|
596
|
+
cy.log(`4. Deleted category: ${createdCategory.id}`)
|
|
597
|
+
|
|
598
|
+
// 5. VERIFY DELETION
|
|
599
|
+
apiRequest('GET', `${API_CATEGORIES}/${createdCategory.id}`).then((finalResponse) => {
|
|
600
|
+
// May return 404 or 200 with deletedAt depending on implementation
|
|
601
|
+
cy.log('5. Verified deletion')
|
|
602
|
+
cy.log('Full CRUD lifecycle completed successfully')
|
|
603
|
+
})
|
|
604
|
+
})
|
|
605
|
+
})
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
})
|
|
609
|
+
})
|
|
610
|
+
})
|