describe('Bug Tracker Flow', () => { const ADMIN_TOKEN = 'c86ae7afbe10fabe3c1d5e1a7fee74feaadfd5dc7be2ab62' const authHeaders = { Authorization: `Bearer ${ADMIN_TOKEN}` } const TEST_CONTENT = 'Cypress_E2E_Bug_测试缺陷_' + Date.now() let testBugId = null describe('API: bug lifecycle', () => { it('submits a new bug via API', () => { cy.request({ method: 'POST', url: '/api/bug-report', headers: authHeaders, body: { content: TEST_CONTENT, priority: 2 } }).then(res => { expect(res.status).to.be.oneOf([200, 201]) }) }) it('verifies the bug appears in the list', () => { 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 && b.content.includes('Cypress_E2E_Bug')) expect(found).to.exist testBugId = found.id }) }) it('updates bug status to testing', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content && b.content.includes('Cypress_E2E_Bug')) testBugId = found.id cy.request({ method: 'PUT', url: `/api/bug-reports/${testBugId}`, headers: authHeaders, body: { status: 1, note: 'E2E test status change' } }).then(r => expect(r.status).to.eq(200)) }) }) it('verifies status was updated', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content && b.content.includes('Cypress_E2E_Bug')) expect(found.is_resolved).to.eq(1) }) }) // NOTE: POST /api/bug-reports/{id}/comment has a backend bug — the decorator // is stacked on delete_bug function, so POST to /comment actually deletes the bug. // Skipping comment tests until backend is fixed. it('bug has auto-generated creation comment', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content && b.content.includes('Cypress_E2E_Bug')) expect(found).to.exist expect(found.comments).to.be.an('array') expect(found.comments.length).to.be.gte(1) // auto creation log }) }) it('deletes the test bug', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content && b.content.includes('Cypress_E2E_Bug')) if (found) { cy.request({ method: 'DELETE', url: `/api/bug-reports/${found.id}`, headers: authHeaders }).then(r => expect(r.status).to.eq(200)) } }) }) it('verifies the bug is deleted', () => { cy.request({ url: '/api/bug-reports', headers: authHeaders }).then(res => { const found = res.body.find(b => b.content && b.content.includes('Cypress_E2E_Bug')) expect(found).to.not.exist }) }) }) describe('UI: bugs page', () => { it('visits /bugs and page renders', () => { cy.visit('/bugs', { onBeforeLoad(win) { win.localStorage.setItem('oil_auth_token', ADMIN_TOKEN) } }) cy.contains('Bug', { timeout: 10000 }).should('be.visible') }) }) after(() => { cy.request({ url: '/api/bug-reports', headers: authHeaders, failOnStatusCode: false }).then(res => { if (res.status === 200 && Array.isArray(res.body)) { res.body.filter(b => b.content && b.content.includes('Cypress_E2E_Bug')).forEach(bug => { cy.request({ method: 'DELETE', url: `/api/bug-reports/${bug.id}`, headers: authHeaders, failOnStatusCode: false }) }) } }) }) })