diff --git a/frontend/cypress/e2e/responsive.cy.js b/frontend/cypress/e2e/responsive.cy.js index 8cc5689..04efa25 100644 --- a/frontend/cypress/e2e/responsive.cy.js +++ b/frontend/cypress/e2e/responsive.cy.js @@ -39,6 +39,75 @@ describe('Responsive Design', () => { }) }) + describe('Mobile edit recipe overlay (375x667)', () => { + let adminToken + + before(() => { + cy.getAdminToken().then(token => { adminToken = token }) + }) + + beforeEach(() => { + cy.viewport(375, 667) + cy.visit('/manage', { + onBeforeLoad(win) { + win.localStorage.setItem('oil_auth_token', adminToken) + } + }) + cy.get('.recipe-manager', { timeout: 10000 }).should('exist') + cy.contains('公共配方库', { timeout: 10000 }).should('be.visible').click() + cy.get('.recipe-row', { timeout: 10000 }).should('have.length.gte', 1) + cy.get('.recipe-row .row-info').first().click() + cy.get('.overlay-panel', { timeout: 5000 }).should('be.visible') + }) + + it('editor table fits within panel without horizontal overflow', () => { + cy.get('.overlay-panel').then($panel => { + const panel = $panel[0] + expect(panel.scrollWidth, 'panel has no horizontal overflow') + .to.be.lte(panel.clientWidth + 1) + }) + cy.get('.overlay-panel .editor-table').then($table => { + const tableRect = $table[0].getBoundingClientRect() + const panelRect = Cypress.$('.overlay-panel')[0].getBoundingClientRect() + expect(tableRect.right, 'table right edge').to.be.lte(panelRect.right + 1) + expect(tableRect.left, 'table left edge').to.be.gte(panelRect.left - 1) + }) + }) + + it('all 4 data column headers (成分/用量/单价/小计) are visible in panel', () => { + const headers = ['成分', '用量', '单价', '小计'] + headers.forEach(label => { + cy.get('.overlay-panel .editor-table thead th').contains(label).then($th => { + const thRect = $th[0].getBoundingClientRect() + const panelRect = Cypress.$('.overlay-panel')[0].getBoundingClientRect() + expect(thRect.right, `${label} header right`).to.be.lte(panelRect.right + 1) + expect(thRect.left, `${label} header left`).to.be.gte(panelRect.left - 1) + }) + }) + }) + + it('oil search input does not push the row past panel edge', () => { + cy.get('.overlay-panel .form-select').first().then($input => { + const inputRect = $input[0].getBoundingClientRect() + const panelRect = Cypress.$('.overlay-panel')[0].getBoundingClientRect() + expect(inputRect.right, 'oil input right').to.be.lte(panelRect.right + 1) + }) + }) + + it('horizontal swipe does not switch tabs while editor overlay is open', () => { + cy.get('.nav-tab.active').invoke('text').then(activeBefore => { + // Overlay covers .main — touch events bubble from .overlay up to .main's handler + cy.get('.overlay') + .trigger('touchstart', { touches: [{ clientX: 320, clientY: 400 }], force: true }) + .trigger('touchmove', { touches: [{ clientX: 60, clientY: 400 }], force: true }) + .trigger('touchend', { force: true }) + cy.wait(200) + cy.get('.overlay-panel').should('be.visible') + cy.get('.nav-tab.active').invoke('text').should('eq', activeBefore) + }) + }) + }) + describe('Tablet viewport (768x1024)', () => { beforeEach(() => { cy.viewport(768, 1024)