// Ignore uncaught exceptions from the Vue app during E2E tests. // Vue components may throw on API errors, missing data, etc. // These are tracked separately; E2E tests focus on user-visible behavior. Cypress.on('uncaught:exception', () => false) // ── Admin token management ────────────────────────────── // In CI, the backend is started with ADMIN_TOKEN env var set to a known value. // Locally, the admin token may be the hardcoded dev value. // This helper tries multiple strategies to obtain a working admin token. let _cachedAdminToken = null /** * Get a working admin token. Tries: * 1. Cached token from previous call * 2. CYPRESS_ADMIN_TOKEN env var (set via CI or cypress.env.json) * 3. Hardcoded local dev token * 4. Register a user and use its token (viewer-level fallback) * * Returns the token via cy.wrap() so it can be used in chains. */ Cypress.Commands.add('getAdminToken', () => { if (_cachedAdminToken) { return cy.wrap(_cachedAdminToken) } // Strategy 1: Try the CI token (passed via CYPRESS_ADMIN_TOKEN env or set in config) const envToken = Cypress.env('ADMIN_TOKEN') if (envToken) { return cy.request({ url: '/api/me', headers: { Authorization: `Bearer ${envToken}` } }).then(res => { if (res.body && res.body.role === 'admin') { _cachedAdminToken = envToken return cy.wrap(envToken) } // Token didn't work as admin, fall through return _tryLocalToken() }) } return _tryLocalToken() }) function _tryLocalToken() { // Strategy 2: Try the hardcoded local dev token const LOCAL_TOKEN = 'c86ae7afbe10fabe3c1d5e1a7fee74feaadfd5dc7be2ab62' return cy.request({ url: '/api/me', headers: { Authorization: `Bearer ${LOCAL_TOKEN}` }, failOnStatusCode: false }).then(res => { if (res.status === 200 && res.body && res.body.role === 'admin') { _cachedAdminToken = LOCAL_TOKEN return cy.wrap(LOCAL_TOKEN) } // Strategy 3: Register a test user — will be viewer but some tests just need any auth // For admin-requiring tests, the CI must set ADMIN_TOKEN properly return cy.request({ method: 'POST', url: '/api/register', body: { username: 'cypress_admin_fallback', password: 'cypresstest1234' }, failOnStatusCode: false }).then(regRes => { if (regRes.status === 201 || regRes.status === 200) { _cachedAdminToken = regRes.body.token return cy.wrap(regRes.body.token) } // Maybe already registered, try login return cy.request({ method: 'POST', url: '/api/login', body: { username: 'cypress_admin_fallback', password: 'cypresstest1234' }, failOnStatusCode: false }).then(loginRes => { if (loginRes.status === 200) { _cachedAdminToken = loginRes.body.token return cy.wrap(loginRes.body.token) } // Last resort: return local token anyway _cachedAdminToken = LOCAL_TOKEN return cy.wrap(LOCAL_TOKEN) }) }) }) } // Custom commands for the oil calculator app // Login as admin via token injection — uses dynamic token Cypress.Commands.add('loginAsAdmin', () => { cy.getAdminToken().then(token => { cy.window().then(win => { win.localStorage.setItem('oil_auth_token', token) }) }) }) // Login with a specific token Cypress.Commands.add('loginWithToken', (token) => { cy.window().then(win => { win.localStorage.setItem('oil_auth_token', token) }) }) // Get auth headers for API requests Cypress.Commands.add('adminHeaders', () => { return cy.getAdminToken().then(token => { return { Authorization: `Bearer ${token}` } }) }) // Verify toast message appears Cypress.Commands.add('expectToast', (text) => { cy.get('.toast').should('contain', text) }) // Navigate via nav tabs Cypress.Commands.add('goToSection', (label) => { cy.get('.nav-tab').contains(label).click() })