describe('API CRUD Operations', () => { const ADMIN_TOKEN = 'c86ae7afbe10fabe3c1d5e1a7fee74feaadfd5dc7be2ab62' const authHeaders = { Authorization: `Bearer ${ADMIN_TOKEN}` } describe('Oils API', () => { it('creates a new oil', () => { cy.request({ method: 'POST', url: '/api/oils', headers: authHeaders, body: { name: 'cypress测试油', bottle_price: 100, drop_count: 200 } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) it('lists oils including the new one', () => { cy.request('/api/oils').then(res => { const found = res.body.find(o => o.name === 'cypress测试油') expect(found).to.exist expect(found.bottle_price).to.eq(100) expect(found.drop_count).to.eq(200) }) }) it('deletes the test oil', () => { cy.request({ method: 'DELETE', url: '/api/oils/' + encodeURIComponent('cypress测试油'), headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) }) it('verifies oil is deleted', () => { cy.request('/api/oils').then(res => { const found = res.body.find(o => o.name === 'cypress测试油') expect(found).to.not.exist }) }) }) describe('Recipes API', () => { let testRecipeId it('creates a new recipe', () => { cy.request({ method: 'POST', url: '/api/recipes', headers: authHeaders, body: { name: 'Cypress测试配方', note: 'E2E测试用', ingredients: [ { oil_name: '薰衣草', drops: 5 }, { oil_name: '茶树', drops: 3 } ], tags: [] } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) testRecipeId = res.body.id expect(testRecipeId).to.be.a('number') }) }) it('reads the created recipe', () => { cy.request('/api/recipes').then(res => { const found = res.body.find(r => r.name === 'Cypress测试配方') expect(found).to.exist expect(found.note).to.eq('E2E测试用') expect(found.ingredients).to.have.length(2) testRecipeId = found.id }) }) it('updates the recipe', () => { cy.request('/api/recipes').then(res => { const found = res.body.find(r => r.name === 'Cypress测试配方') cy.request({ method: 'PUT', url: `/api/recipes/${found.id}`, headers: authHeaders, body: { name: 'Cypress更新配方', note: '已更新', ingredients: [ { oil_name: '薰衣草', drops: 10 }, { oil_name: '乳香', drops: 5 } ], tags: [] } }).then(res => { expect(res.status).to.eq(200) }) }) }) it('verifies the update', () => { cy.request('/api/recipes').then(res => { const found = res.body.find(r => r.name === 'Cypress更新配方') expect(found).to.exist expect(found.note).to.eq('已更新') expect(found.ingredients).to.have.length(2) testRecipeId = found.id }) }) it('deletes the test recipe', () => { cy.request('/api/recipes').then(res => { const found = res.body.find(r => r.name === 'Cypress更新配方') if (found) { cy.request({ method: 'DELETE', url: `/api/recipes/${found.id}`, headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) } }) }) }) describe('Tags API', () => { it('creates a new tag', () => { cy.request({ method: 'POST', url: '/api/tags', headers: authHeaders, body: { name: 'cypress-tag' } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) it('lists tags including the new one', () => { cy.request('/api/tags').then(res => { expect(res.body).to.include('cypress-tag') }) }) it('deletes the test tag', () => { cy.request({ method: 'DELETE', url: '/api/tags/cypress-tag', headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) }) }) describe('Diary API', () => { let diaryId it('creates a diary entry', () => { cy.request({ method: 'POST', url: '/api/diary', headers: authHeaders, body: { name: 'Cypress日记配方', ingredients: [{ oil: '薰衣草', drops: 3 }], note: '测试备注' } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) diaryId = res.body.id }) }) it('lists diary entries', () => { cy.request({ url: '/api/diary', headers: authHeaders }).then(res => { expect(res.body).to.be.an('array') const found = res.body.find(d => d.name === 'Cypress日记配方') expect(found).to.exist diaryId = found.id }) }) it('deletes the diary entry', () => { cy.request({ url: '/api/diary', headers: authHeaders }).then(res => { const found = res.body.find(d => d.name === 'Cypress日记配方') if (found) { cy.request({ method: 'DELETE', url: `/api/diary/${found.id}`, headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) } }) }) }) describe('Favorites API', () => { it('adds a recipe to favorites', () => { cy.request('/api/recipes').then(res => { const recipe = res.body[0] cy.request({ method: 'POST', url: `/api/favorites/${recipe.id}`, headers: authHeaders, body: {} }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) }) it('lists favorites', () => { cy.request({ url: '/api/favorites', headers: authHeaders }).then(res => { expect(res.body).to.be.an('array') expect(res.body.length).to.be.gte(1) }) }) it('removes the favorite', () => { cy.request('/api/recipes').then(res => { const recipe = res.body[0] cy.request({ method: 'DELETE', url: `/api/favorites/${recipe.id}`, headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) }) }) }) describe('Inventory API', () => { it('adds oil to inventory', () => { cy.request({ method: 'POST', url: '/api/inventory', headers: authHeaders, body: { oil_name: '薰衣草' } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) it('reads inventory', () => { cy.request({ url: '/api/inventory', headers: authHeaders }).then(res => { expect(res.status).to.eq(200) expect(res.body).to.be.an('array') }) }) }) describe('Bug Reports API', () => { let bugId it('submits a bug report', () => { cy.request({ method: 'POST', url: '/api/bug-report', headers: authHeaders, body: { content: 'Cypress E2E测试Bug', priority: 2 } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) it('lists bug reports', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { expect(res.body).to.be.an('array') const found = res.body.find(b => b.content.includes('Cypress E2E测试Bug')) expect(found).to.exist bugId = found.id }) }) it('deletes the test bug', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content.includes('Cypress E2E测试Bug')) if (found) { cy.request({ method: 'DELETE', url: `/api/bug-reports/${found.id}`, headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) } }) }) }) describe('Users API (admin)', () => { it('lists users', () => { cy.request({ url: '/api/users', headers: authHeaders }).then(res => { expect(res.body).to.be.an('array') expect(res.body.length).to.be.gte(1) const admin = res.body.find(u => u.role === 'admin') expect(admin).to.exist }) }) it('cannot access users without auth', () => { cy.request({ url: '/api/users', failOnStatusCode: false }).then(res => { expect(res.status).to.eq(403) }) }) }) describe('Audit Log API', () => { it('fetches audit log', () => { cy.request({ url: '/api/audit-log?limit=10&offset=0', headers: authHeaders }).then(res => { expect(res.status).to.eq(200) expect(res.body).to.be.an('array') }) }) }) describe('Notifications API', () => { it('fetches notifications', () => { cy.request({ url: '/api/notifications', headers: authHeaders }).then(res => { expect(res.status).to.eq(200) }) }) }) })