test(app): smoke tests for three layout skeletons
WS-3 session 1a Task 3. Vitest covers each layout with: (1) it mounts without throwing, (2) it renders the expected DOM structure (top-bar/main/footer for PortalLayout, none for PublicLayout, slot-passthrough for OrganizerLayout), (3) it places <RouterView /> in the right region. Vuetify components (VApp/VAppBar/VMain/VFooter) are stubbed to their semantic HTML equivalents so the structural assertions still hold without pulling vuetify/components into the trimmed-down vitest config (which lacks the CSS plugin needed to transform Vuetify's .css side effects). OrganizerLayout uses vi.mock to short-circuit the DefaultLayoutWithVerticalNav import for the same reason. Vitest count: 41 -> 49 in apps/app.
This commit is contained in:
33
apps/app/src/layouts/__tests__/OrganizerLayout.spec.ts
Normal file
33
apps/app/src/layouts/__tests__/OrganizerLayout.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
|
||||
// Mock the import path so OrganizerLayout's `import DefaultLayoutWithVerticalNav`
|
||||
// statement doesn't pull in the real component (which transitively imports
|
||||
// Vuetify .css files that the trimmed-down vitest config can't transform).
|
||||
vi.mock('@/layouts/components/DefaultLayoutWithVerticalNav.vue', () => ({
|
||||
default: { template: '<div><slot /></div>' },
|
||||
}))
|
||||
|
||||
const OrganizerLayout = (await import('../OrganizerLayout.vue')).default
|
||||
|
||||
describe('OrganizerLayout', () => {
|
||||
it('mounts without throwing', () => {
|
||||
const wrapper = mount(OrganizerLayout, {
|
||||
global: {
|
||||
stubs: { RouterView: true },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('renders a RouterView in its slot', () => {
|
||||
const wrapper = mount(OrganizerLayout, {
|
||||
global: {
|
||||
stubs: { RouterView: { template: '<div data-test="router-view" />' } },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('[data-test="router-view"]').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
50
apps/app/src/layouts/__tests__/PortalLayout.spec.ts
Normal file
50
apps/app/src/layouts/__tests__/PortalLayout.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PortalLayout from '../PortalLayout.vue'
|
||||
|
||||
// Stub Vuetify components as their semantic HTML equivalents so we can
|
||||
// assert structure without pulling vuetify/components (which loads .css
|
||||
// files that the trimmed-down vitest config can't transform).
|
||||
const vuetifyStubs = {
|
||||
VApp: { template: '<div><slot /></div>' },
|
||||
VAppBar: { template: '<header><slot /></header>' },
|
||||
VMain: { template: '<main><slot /></main>' },
|
||||
VFooter: { template: '<footer><slot /></footer>' },
|
||||
}
|
||||
|
||||
describe('PortalLayout', () => {
|
||||
it('mounts without throwing', () => {
|
||||
const wrapper = mount(PortalLayout, {
|
||||
global: {
|
||||
stubs: { ...vuetifyStubs, RouterView: true },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('renders a top app bar, main region, and footer', () => {
|
||||
const wrapper = mount(PortalLayout, {
|
||||
global: {
|
||||
stubs: { ...vuetifyStubs, RouterView: true },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('header').exists()).toBe(true)
|
||||
expect(wrapper.find('main').exists()).toBe(true)
|
||||
expect(wrapper.find('footer').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('renders a RouterView inside the main region', () => {
|
||||
const wrapper = mount(PortalLayout, {
|
||||
global: {
|
||||
stubs: {
|
||||
...vuetifyStubs,
|
||||
RouterView: { template: '<div data-test="router-view" />' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('main [data-test="router-view"]').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
47
apps/app/src/layouts/__tests__/PublicLayout.spec.ts
Normal file
47
apps/app/src/layouts/__tests__/PublicLayout.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import PublicLayout from '../PublicLayout.vue'
|
||||
|
||||
// Stub Vuetify components as their semantic HTML equivalents so we can
|
||||
// assert structure without pulling vuetify/components (which loads .css
|
||||
// files that the trimmed-down vitest config can't transform).
|
||||
const vuetifyStubs = {
|
||||
VApp: { template: '<div><slot /></div>' },
|
||||
VMain: { template: '<main><slot /></main>' },
|
||||
}
|
||||
|
||||
describe('PublicLayout', () => {
|
||||
it('mounts without throwing', () => {
|
||||
const wrapper = mount(PublicLayout, {
|
||||
global: {
|
||||
stubs: { ...vuetifyStubs, RouterView: true },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('does NOT render a header or footer (intentionally minimal)', () => {
|
||||
const wrapper = mount(PublicLayout, {
|
||||
global: {
|
||||
stubs: { ...vuetifyStubs, RouterView: true },
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('header').exists()).toBe(false)
|
||||
expect(wrapper.find('footer').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('renders a RouterView inside main', () => {
|
||||
const wrapper = mount(PublicLayout, {
|
||||
global: {
|
||||
stubs: {
|
||||
...vuetifyStubs,
|
||||
RouterView: { template: '<div data-test="router-view" />' },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.find('main [data-test="router-view"]').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user