describe('Performance', () => { it('home page loads within 5 seconds', () => { const start = Date.now() cy.visit('/') cy.get('.recipe-card', { timeout: 5000 }).should('have.length.gte', 1) cy.then(() => { const elapsed = Date.now() - start expect(elapsed).to.be.lt(5000) }) }) it('API /api/oils responds within 1 second', () => { const start = Date.now() cy.request('/api/oils').then(() => { expect(Date.now() - start).to.be.lt(1000) }) }) it('API /api/recipes responds within 2 seconds', () => { const start = Date.now() cy.request('/api/recipes').then(() => { expect(Date.now() - start).to.be.lt(2000) }) }) it('search filtering is near-instant', () => { cy.visit('/') cy.get('.recipe-card', { timeout: 10000 }).should('have.length.gte', 1) const start = Date.now() cy.get('input[placeholder*="搜索"]').type('薰衣草') cy.wait(300) cy.get('.recipe-card').should('exist') cy.then(() => { expect(Date.now() - start).to.be.lt(2000) }) }) it('oil reference page loads within 3 seconds', () => { const start = Date.now() cy.visit('/oils') cy.get('.oil-chip', { timeout: 3000 }).should('have.length.gte', 1) cy.then(() => { expect(Date.now() - start).to.be.lt(3000) }) }) it('handles 250+ recipes without crashing', () => { cy.request('/api/recipes').then(res => { expect(res.body.length).to.be.gte(200) }) cy.visit('/') cy.get('.recipe-card', { timeout: 10000 }).should('have.length.gte', 10) // Scroll to trigger lazy loading if any cy.scrollTo('bottom') cy.wait(500) cy.get('.main').should('be.visible') }) })