@datametria/vue-components
Version:
DATAMETRIA Vue.js 3 Component Library with Multi-Brand Theming - 51 components + 10 composables with theming support, WCAG 2.2 AA, dark mode, responsive system
209 lines (171 loc) • 5.75 kB
text/typescript
/**
* ThemeProvider Tests
* @author Vander Loto - CTO DATAMETRIA
* @date 13/11/2025
*/
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import { h } from 'vue'
import ThemeProvider from '../ThemeProvider.vue'
import { useTheme } from '../useTheme'
import { defaultTokens } from '../tokens'
import type { Theme } from '../types'
const testTheme: Theme = {
name: 'Test Theme',
tokens: defaultTokens
}
const customTheme: Theme = {
name: 'Custom Theme',
tokens: {
...defaultTokens,
colors: {
...defaultTokens.colors,
primary: '#FF0000',
secondary: '#00FF00'
}
}
}
describe('ThemeProvider', () => {
it('should render children', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: {
default: '<div class="test-child">Child Content</div>'
}
})
expect(wrapper.text()).toContain('Child Content')
expect(wrapper.find('.test-child').exists()).toBe(true)
})
it('should apply default theme class', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
expect(wrapper.classes()).toContain('dm-theme')
})
it('should apply custom prefix class', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme, prefix: 'custom' },
slots: { default: '<div>Content</div>' }
})
expect(wrapper.classes()).toContain('custom-theme')
})
it('should generate CSS variables for colors', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-primary')
expect(style).toContain('#0072CE')
expect(style).toContain('--dm-secondary')
expect(style).toContain('#4B0078')
})
it('should generate CSS variables for neutral colors', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-neutral-50')
expect(style).toContain('--dm-neutral-900')
})
it('should generate CSS variables for typography', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-font-sans')
expect(style).toContain('--dm-text-base')
expect(style).toContain('--dm-font-bold')
})
it('should generate CSS variables for spacing', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-space-4')
expect(style).toContain('1rem')
})
it('should generate CSS variables for radius', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-radius-md')
})
it('should generate CSS variables for shadows', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-shadow-md')
})
it('should generate CSS variables for transitions', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--dm-transition-base')
})
it('should use custom prefix for CSS variables', () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme, prefix: 'custom' },
slots: { default: '<div>Content</div>' }
})
const style = wrapper.attributes('style')
expect(style).toContain('--custom-primary')
expect(style).not.toContain('--dm-primary')
})
it('should update CSS variables when theme changes', async () => {
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: { default: '<div>Content</div>' }
})
let style = wrapper.attributes('style')
expect(style).toContain('#0072CE')
await wrapper.setProps({ theme: customTheme })
style = wrapper.attributes('style')
expect(style).toContain('#FF0000')
})
it('should provide theme to child components', () => {
const ChildComponent = {
setup() {
const theme = useTheme()
return () => h('div', { class: 'child' }, theme.value.name)
}
}
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: {
default: h(ChildComponent)
}
})
expect(wrapper.text()).toContain('Test Theme')
})
it('should provide updated theme when changed', async () => {
const ChildComponent = {
setup() {
const theme = useTheme()
return () => h('div', { class: 'child' }, `${theme.value.name}-${theme.value.tokens.colors.primary}`)
}
}
const wrapper = mount(ThemeProvider, {
props: { theme: testTheme },
slots: {
default: h(ChildComponent)
}
})
expect(wrapper.text()).toContain('Test Theme')
expect(wrapper.text()).toContain('#0072CE')
await wrapper.setProps({ theme: customTheme })
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Custom Theme')
expect(wrapper.text()).toContain('#FF0000')
})
})