diff --git a/frontend/e2e/admin-dashboard.spec.ts b/frontend/e2e/admin-dashboard.spec.ts index ed8abd0..8272ab6 100644 --- a/frontend/e2e/admin-dashboard.spec.ts +++ b/frontend/e2e/admin-dashboard.spec.ts @@ -47,13 +47,30 @@ test.describe('Admin dashboard', () => { await expect(page.getByText('GHI789').first()).toBeVisible() }) - test('click expand button shows letter content', async ({ page }) => { + test('show message button opens modal with full letter text', async ({ + page, + }) => { + await page.goto('/admin') + + await page + .locator('.admin__row', { hasText: 'ABC123' }) + .getByRole('button', { name: 'Visa meddelande' }) + .click() + + const dialog = page.getByRole('dialog', { name: 'Brevtext' }) + await expect(dialog).toBeVisible() + await expect(dialog).toContainText('fin bil') + await dialog.getByRole('button', { name: 'Stäng' }).click() + await expect(dialog).not.toBeVisible() + }) + + test('click expand button shows tracking section', async ({ page }) => { await page.goto('/admin') const expandBtns = page.locator('.admin__expand-btn') await expandBtns.first().click() - await expect(page.getByText('Brevtext')).toBeVisible() + await expect(page.getByText('Spårnings-ID').first()).toBeVisible() }) test('click expand button again collapses it', async ({ page }) => { @@ -61,10 +78,10 @@ test.describe('Admin dashboard', () => { const expandBtns = page.locator('.admin__expand-btn') await expandBtns.first().click() - await expect(page.getByText('Brevtext')).toBeVisible() + await expect(page.locator('.admin__tracking-input').first()).toBeVisible() await expandBtns.first().click() - await expect(page.getByText('Brevtext')).not.toBeVisible() + await expect(page.locator('.admin__tracking-input').first()).not.toBeVisible() }) test('status dropdown changes update order status', async ({ page }) => { diff --git a/frontend/src/__tests__/AdminDashboard.spec.ts b/frontend/src/__tests__/AdminDashboard.spec.ts index 8cffd4a..901d4c2 100644 --- a/frontend/src/__tests__/AdminDashboard.spec.ts +++ b/frontend/src/__tests__/AdminDashboard.spec.ts @@ -55,6 +55,16 @@ const mockOrders = [ amountPaid: null, createdAt: '2026-05-14T13:00:00Z', }, + { + id: 'c3eebc99-9c0b-4ef8-bb6d-6bb9bd380a13', + email: 'pending@example.com', + plate: 'PND111', + letterText: 'Väntar på betalning.', + status: 'pending_payment', + trackingId: null, + amountPaid: null, + createdAt: '2026-05-15T14:00:00Z', + }, ] describe('AdminDashboard', () => { @@ -91,8 +101,10 @@ describe('AdminDashboard', () => { const { wrapper } = mountPage() await new Promise((r) => setTimeout(r, 50)) expect(wrapper.text()).toContain('Datum') + expect(wrapper.text()).toContain('Beställnings-ID') expect(wrapper.text()).toContain('E-post') expect(wrapper.text()).toContain('Regnr') + expect(wrapper.text()).toContain('Meddelande') expect(wrapper.text()).toContain('Status') }) @@ -121,19 +133,30 @@ describe('AdminDashboard', () => { expect(wrapper.text()).toContain('Kunde inte hämta beställningar') }) - it('expands row on button click to show letter content', async () => { + it('opens message modal with full letter text', async () => { const { wrapper } = mountPage() await new Promise((r) => setTimeout(r, 50)) - const rows = wrapper.findAll('.admin__row') - expect(rows.length).toBe(2) - - const expandBtns = wrapper.findAll('.admin__expand-btn') - await expandBtns[0].trigger('click') + const messageBtns = wrapper.findAll('.admin__message-btn') + await messageBtns[0].trigger('click') await new Promise((r) => setTimeout(r, 50)) - expect(wrapper.text()).toContain('Hej fin bil!') - expect(wrapper.text()).toContain('Brevtext') + expect(wrapper.find('.admin-modal').exists()).toBe(true) + expect(wrapper.find('.admin-modal__body').text()).toBe('Hej fin bil!') + expect(wrapper.text()).toContain('ABC123') + expect(wrapper.text()).toContain('c1eebc99') + }) + + it('closes message modal on close button click', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + + await wrapper.findAll('.admin__message-btn')[0].trigger('click') + await new Promise((r) => setTimeout(r, 50)) + await wrapper.find('.admin-modal__close').trigger('click') + await new Promise((r) => setTimeout(r, 50)) + + expect(wrapper.find('.admin-modal').exists()).toBe(false) }) it('collapses row on second button click', async () => { @@ -143,11 +166,11 @@ describe('AdminDashboard', () => { const expandBtns = wrapper.findAll('.admin__expand-btn') await expandBtns[0].trigger('click') await new Promise((r) => setTimeout(r, 50)) - expect(wrapper.text()).toContain('Hej fin bil!') + expect(wrapper.find('.admin__expanded-row').exists()).toBe(true) await expandBtns[0].trigger('click') await new Promise((r) => setTimeout(r, 50)) - expect(wrapper.text()).not.toContain('Hej fin bil!') + expect(wrapper.find('.admin__expanded-row').exists()).toBe(false) }) it('only expands one row at a time', async () => { @@ -157,12 +180,12 @@ describe('AdminDashboard', () => { const expandBtns = wrapper.findAll('.admin__expand-btn') await expandBtns[0].trigger('click') await new Promise((r) => setTimeout(r, 50)) - expect(wrapper.text()).toContain('Hej fin bil!') + expect(wrapper.findAll('.admin__expanded-row')).toHaveLength(1) await expandBtns[1].trigger('click') await new Promise((r) => setTimeout(r, 50)) - expect(wrapper.text()).not.toContain('Hej fin bil!') - expect(wrapper.text()).toContain('Vill köpa din bil.') + expect(wrapper.findAll('.admin__expanded-row')).toHaveLength(1) + expect(wrapper.find('.admin__tracking-row').exists()).toBe(true) }) it('renders status dropdowns', async () => { @@ -170,7 +193,7 @@ describe('AdminDashboard', () => { await new Promise((r) => setTimeout(r, 50)) const selects = wrapper.findAll('.admin__status-select') - expect(selects.length).toBe(2) + expect(selects.length).toBe(3) }) it('fires status update API on dropdown change', async () => { @@ -309,11 +332,67 @@ describe('AdminDashboard', () => { expect(wrapper.text()).toContain('Att göra') }) + it('shows visa meddelande button in each row', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + expect(wrapper.findAll('.admin__message-btn')).toHaveLength(3) + expect(wrapper.text()).toContain('Visa meddelande') + }) + + it('filters orders when Väntar tab is clicked', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + + const stats = wrapper.findAll('.admin__stat') + const waitingTab = stats.find((stat) => stat.text().includes('Väntar')) + expect(waitingTab).toBeDefined() + await waitingTab!.trigger('click') + await new Promise((r) => setTimeout(r, 50)) + + expect(wrapper.text()).toContain('pending@example.com') + expect(wrapper.text()).not.toContain('test@bilhalsning.se') + expect(wrapper.text()).not.toContain('user@example.com') + }) + + it('filters orders by partial order id search', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + + await wrapper.find('#admin-order-search').setValue('c2eebc99') + await new Promise((r) => setTimeout(r, 50)) + + expect(wrapper.text()).toContain('user@example.com') + expect(wrapper.text()).not.toContain('test@bilhalsning.se') + expect(wrapper.text()).not.toContain('pending@example.com') + }) + + it('filters orders by registration number search', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + + await wrapper.find('#admin-order-search').setValue('abc123') + await new Promise((r) => setTimeout(r, 50)) + + expect(wrapper.text()).toContain('test@bilhalsning.se') + expect(wrapper.text()).not.toContain('user@example.com') + expect(wrapper.text()).not.toContain('pending@example.com') + }) + + it('shows shortened order id with full id in title', async () => { + const { wrapper } = mountPage() + await new Promise((r) => setTimeout(r, 50)) + + const orderIdCell = wrapper.find('.admin__order-id') + expect(orderIdCell.text()).toBe('c1eebc99') + expect(orderIdCell.attributes('title')).toBe(mockOrders[0].id) + }) + it('highlights processing rows', async () => { const { wrapper } = mountPage() await new Promise((r) => setTimeout(r, 50)) const rows = wrapper.findAll('.admin__row') - expect(rows[1].classes()).toContain('admin__row--todo') + const processingRow = rows.find((row) => row.text().includes('XYZ789')) + expect(processingRow?.classes()).toContain('admin__row--todo') }) }) diff --git a/frontend/src/pages/AdminPage.vue b/frontend/src/pages/AdminPage.vue index f07f5a9..2021671 100644 --- a/frontend/src/pages/AdminPage.vue +++ b/frontend/src/pages/AdminPage.vue @@ -1,5 +1,5 @@