diff --git a/frontend/src/App.vue b/frontend/src/App.vue index a78fb6f..23d4cd8 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,7 +1,19 @@ + + diff --git a/frontend/src/__tests__/AboutPage.spec.ts b/frontend/src/__tests__/AboutPage.spec.ts new file mode 100644 index 0000000..df7ab24 --- /dev/null +++ b/frontend/src/__tests__/AboutPage.spec.ts @@ -0,0 +1,10 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import AboutPage from '@/pages/AboutPage.vue' + +describe('AboutPage', () => { + it('renders heading', () => { + const wrapper = mount(AboutPage) + expect(wrapper.text()).toContain('Om BilHälsning') + }) +}) diff --git a/frontend/src/__tests__/App.spec.ts b/frontend/src/__tests__/App.spec.ts index 579492b..4d39ba0 100644 --- a/frontend/src/__tests__/App.spec.ts +++ b/frontend/src/__tests__/App.spec.ts @@ -1,9 +1,23 @@ import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import App from '@/App.vue' +import AppHeader from '@/components/AppHeader.vue' +import AppFooter from '@/components/AppFooter.vue' import router from '@/router' describe('App', () => { + it('renders AppHeader and AppFooter', async () => { + router.push('/') + await router.isReady() + const wrapper = mount(App, { + global: { + plugins: [router], + }, + }) + expect(wrapper.findComponent(AppHeader).exists()).toBe(true) + expect(wrapper.findComponent(AppFooter).exists()).toBe(true) + }) + it('renders RouterView with HomePage content', async () => { router.push('/') await router.isReady() @@ -12,6 +26,6 @@ describe('App', () => { plugins: [router], }, }) - expect(wrapper.text()).toContain('BilHälsning') + expect(wrapper.text()).toContain('Skicka ett brev till en fordonsägare') }) }) diff --git a/frontend/src/__tests__/AppFooter.spec.ts b/frontend/src/__tests__/AppFooter.spec.ts new file mode 100644 index 0000000..42587d1 --- /dev/null +++ b/frontend/src/__tests__/AppFooter.spec.ts @@ -0,0 +1,54 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { createRouter, createMemoryHistory } from 'vue-router' +import AppFooter from '@/components/AppFooter.vue' + +function createTestRouter() { + return createRouter({ + history: createMemoryHistory(), + routes: [ + { + path: '/om', + name: 'about', + component: { template: '
About
' }, + }, + { + path: '/kontakt', + name: 'contact', + component: { template: '
Contact
' }, + }, + { + path: '/integritetspolicy', + name: 'privacy', + component: { template: '
Privacy
' }, + }, + { + path: '/villkor', + name: 'terms', + component: { template: '
Terms
' }, + }, + ], + }) +} + +describe('AppFooter', () => { + it('renders all four links', () => { + const router = createTestRouter() + const wrapper = mount(AppFooter, { + global: { plugins: [router] }, + }) + const links = wrapper.findAll('a') + + expect(links[0].text()).toBe('Om oss') + expect(links[0].attributes('href')).toBe('/om') + + expect(links[1].text()).toBe('Kontakt') + expect(links[1].attributes('href')).toBe('/kontakt') + + expect(links[2].text()).toBe('Integritetspolicy') + expect(links[2].attributes('href')).toBe('/integritetspolicy') + + expect(links[3].text()).toBe('Villkor') + expect(links[3].attributes('href')).toBe('/villkor') + }) +}) diff --git a/frontend/src/__tests__/AppHeader.spec.ts b/frontend/src/__tests__/AppHeader.spec.ts new file mode 100644 index 0000000..a4bd878 --- /dev/null +++ b/frontend/src/__tests__/AppHeader.spec.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { createRouter, createMemoryHistory } from 'vue-router' +import AppHeader from '@/components/AppHeader.vue' + +function createTestRouter() { + return createRouter({ + history: createMemoryHistory(), + routes: [ + { path: '/', name: 'home', component: { template: '
Home
' } }, + ], + }) +} + +describe('AppHeader', () => { + it('renders the logo text', () => { + const router = createTestRouter() + const wrapper = mount(AppHeader, { + global: { plugins: [router] }, + }) + expect(wrapper.text()).toContain('BilHälsning') + }) + + it('has a link to home', () => { + const router = createTestRouter() + const wrapper = mount(AppHeader, { + global: { plugins: [router] }, + }) + const links = wrapper.findAll('a') + const homeLink = links.find((a) => a.attributes('href') === '/') + expect(homeLink).toBeTruthy() + }) +}) diff --git a/frontend/src/__tests__/ComposePage.spec.ts b/frontend/src/__tests__/ComposePage.spec.ts new file mode 100644 index 0000000..6c00756 --- /dev/null +++ b/frontend/src/__tests__/ComposePage.spec.ts @@ -0,0 +1,43 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import { createRouter, createMemoryHistory } from 'vue-router' +import ComposePage from '@/pages/ComposePage.vue' + +function createTestRouter() { + return createRouter({ + history: createMemoryHistory(), + routes: [{ path: '/compose', name: 'compose', component: ComposePage }], + }) +} + +describe('ComposePage', () => { + it('renders heading', async () => { + const router = createTestRouter() + router.push('/compose') + await router.isReady() + const wrapper = mount(ComposePage, { + global: { plugins: [router] }, + }) + expect(wrapper.text()).toContain('Skriv ditt brev') + }) + + it('displays plate from query param', async () => { + const router = createTestRouter() + router.push({ path: '/compose', query: { plate: 'ABC123' } }) + await router.isReady() + const wrapper = mount(ComposePage, { + global: { plugins: [router] }, + }) + expect(wrapper.text()).toContain('ABC123') + }) + + it('does not show plate when no query param', async () => { + const router = createTestRouter() + router.push('/compose') + await router.isReady() + const wrapper = mount(ComposePage, { + global: { plugins: [router] }, + }) + expect(wrapper.find('.compose__plate').exists()).toBe(false) + }) +}) diff --git a/frontend/src/__tests__/ContactPage.spec.ts b/frontend/src/__tests__/ContactPage.spec.ts new file mode 100644 index 0000000..a317239 --- /dev/null +++ b/frontend/src/__tests__/ContactPage.spec.ts @@ -0,0 +1,10 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import ContactPage from '@/pages/ContactPage.vue' + +describe('ContactPage', () => { + it('renders heading', () => { + const wrapper = mount(ContactPage) + expect(wrapper.text()).toContain('Kontakta oss') + }) +}) diff --git a/frontend/src/__tests__/HomePage.spec.ts b/frontend/src/__tests__/HomePage.spec.ts index 97d93c0..c899d7a 100644 --- a/frontend/src/__tests__/HomePage.spec.ts +++ b/frontend/src/__tests__/HomePage.spec.ts @@ -1,10 +1,85 @@ import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' +import { createRouter, createMemoryHistory } from 'vue-router' import HomePage from '@/pages/HomePage.vue' +import ComposePage from '@/pages/ComposePage.vue' + +function createTestRouter() { + return createRouter({ + history: createMemoryHistory(), + routes: [ + { path: '/', name: 'home', component: HomePage }, + { path: '/compose', name: 'compose', component: ComposePage }, + ], + }) +} + +function mountHome(router: ReturnType) { + return mount(HomePage, { + global: { plugins: [router] }, + }) +} describe('HomePage', () => { - it('mounts successfully', () => { - const wrapper = mount(HomePage) - expect(wrapper.text()).toContain('BilHälsning') + it('renders subtitle', () => { + const router = createTestRouter() + const wrapper = mountHome(router) + expect(wrapper.text()).toContain('Skicka ett brev till en fordonsägare') + }) + + it('does not show CTA button initially', () => { + const router = createTestRouter() + const wrapper = mountHome(router) + expect(wrapper.find('.home__cta').exists()).toBe(false) + }) + + it('does not show CTA while loading', async () => { + const router = createTestRouter() + const wrapper = mountHome(router) + const plateInput = wrapper.findComponent({ name: 'PlateInput' }) + + await plateInput.vm.$emit('lookup', 'ABC123') + await wrapper.vm.$nextTick() + + expect(wrapper.find('.home__cta').exists()).toBe(false) + }) + + it('does not show CTA after not-found', async () => { + const router = createTestRouter() + const wrapper = mountHome(router) + const plateInput = wrapper.findComponent({ name: 'PlateInput' }) + + await plateInput.vm.$emit('lookup', 'UNKNOWN') + await new Promise((resolve) => setTimeout(resolve, 500)) + + expect(wrapper.find('.home__cta').exists()).toBe(false) + }) + + it('shows CTA button when vehicle data present', async () => { + const router = createTestRouter() + const wrapper = mountHome(router) + const plateInput = wrapper.findComponent({ name: 'PlateInput' }) + + await plateInput.vm.$emit('update:modelValue', 'ABC123') + await plateInput.vm.$emit('lookup', 'ABC123') + await new Promise((resolve) => setTimeout(resolve, 500)) + + const cta = wrapper.find('.home__cta') + expect(cta.exists()).toBe(true) + expect(cta.text()).toBe('Skicka ett brev till ägaren') + }) + + it('CTA links to compose page with plate query param', async () => { + const router = createTestRouter() + const wrapper = mountHome(router) + const plateInput = wrapper.findComponent({ name: 'PlateInput' }) + + await plateInput.vm.$emit('update:modelValue', 'ABC123') + await plateInput.vm.$emit('lookup', 'ABC123') + await new Promise((resolve) => setTimeout(resolve, 500)) + + const cta = wrapper.find('.home__cta') + const href = cta.attributes('href') + expect(href).toBe('/compose?plate=ABC123') }) }) diff --git a/frontend/src/components/AppFooter.vue b/frontend/src/components/AppFooter.vue new file mode 100644 index 0000000..3234322 --- /dev/null +++ b/frontend/src/components/AppFooter.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue new file mode 100644 index 0000000..e135b32 --- /dev/null +++ b/frontend/src/components/AppHeader.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/pages/AboutPage.vue b/frontend/src/pages/AboutPage.vue new file mode 100644 index 0000000..94b0caa --- /dev/null +++ b/frontend/src/pages/AboutPage.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/frontend/src/pages/ComposePage.vue b/frontend/src/pages/ComposePage.vue new file mode 100644 index 0000000..e8e0d65 --- /dev/null +++ b/frontend/src/pages/ComposePage.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/frontend/src/pages/ContactPage.vue b/frontend/src/pages/ContactPage.vue new file mode 100644 index 0000000..7f8d9bd --- /dev/null +++ b/frontend/src/pages/ContactPage.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/frontend/src/pages/HomePage.vue b/frontend/src/pages/HomePage.vue index 240eb89..804e984 100644 --- a/frontend/src/pages/HomePage.vue +++ b/frontend/src/pages/HomePage.vue @@ -1,5 +1,6 @@