- Replace single-file 8441-line HTML with Vue 3 SPA - Pinia stores: auth, oils, recipes, diary, ui - Composables: useApi, useDialog, useSmartPaste, useOilTranslation - 6 shared components: RecipeCard, RecipeDetailOverlay, TagPicker, etc. - 9 page views: RecipeSearch, RecipeManager, Inventory, OilReference, etc. - 14 Cypress E2E test specs (113 tests), all passing - Multi-stage Dockerfile (Node build + Python runtime) - Demo video generation scripts (TTS + subtitles + screen recording) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85 lines
2.6 KiB
JavaScript
85 lines
2.6 KiB
JavaScript
describe('Recipe Detail', () => {
|
|
beforeEach(() => {
|
|
cy.visit('/')
|
|
cy.get('.recipe-card', { timeout: 10000 }).should('have.length.gte', 1)
|
|
})
|
|
|
|
it('opens detail overlay when clicking a recipe card', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.get('[class*="overlay"], [class*="detail"]').should('be.visible')
|
|
})
|
|
|
|
it('shows recipe name in detail view', () => {
|
|
// Get recipe name from card, however it's structured
|
|
cy.get('.recipe-card').first().invoke('text').then(cardText => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
// The detail view should show some text from the card
|
|
cy.get('[class*="overlay"], [class*="detail"]').should('be.visible')
|
|
})
|
|
})
|
|
|
|
it('shows ingredient info with drops', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
cy.contains('滴').should('exist')
|
|
})
|
|
|
|
it('shows cost with ¥ symbol', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
cy.contains('¥').should('exist')
|
|
})
|
|
|
|
it('closes detail overlay when clicking close button', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.get('[class*="overlay"], [class*="detail"]').should('be.visible')
|
|
cy.get('button').contains(/✕|关闭|←/).first().click()
|
|
cy.get('.recipe-card').should('be.visible')
|
|
})
|
|
|
|
it('shows action buttons in detail', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
// Should have at least one action button
|
|
cy.get('[class*="overlay"] button, [class*="detail"] button').should('have.length.gte', 1)
|
|
})
|
|
|
|
it('shows favorite star', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
cy.contains(/★|☆|收藏/).should('exist')
|
|
})
|
|
})
|
|
|
|
describe('Recipe Detail - Editor (Admin)', () => {
|
|
const ADMIN_TOKEN = 'c86ae7afbe10fabe3c1d5e1a7fee74feaadfd5dc7be2ab62'
|
|
|
|
beforeEach(() => {
|
|
cy.visit('/', {
|
|
onBeforeLoad(win) {
|
|
win.localStorage.setItem('oil_auth_token', ADMIN_TOKEN)
|
|
}
|
|
})
|
|
cy.get('.recipe-card', { timeout: 10000 }).should('have.length.gte', 1)
|
|
})
|
|
|
|
it('shows edit button for admin', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.wait(500)
|
|
cy.contains(/编辑|✏/).should('exist')
|
|
})
|
|
|
|
it('can switch to editor view', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.contains(/编辑|✏/).first().click()
|
|
cy.get('select, input[type="number"], .oil-select, .drops-input').should('exist')
|
|
})
|
|
|
|
it('editor shows save button', () => {
|
|
cy.get('.recipe-card').first().click()
|
|
cy.contains(/编辑|✏/).first().click()
|
|
cy.contains(/保存|💾/).should('exist')
|
|
})
|
|
})
|