vuetify
Version:
Vue Material Component Framework
287 lines (219 loc) • 7.17 kB
text/typescript
// Service
import { Theme } from '../index'
// Preset
import { preset } from '../../../presets/default'
// Utilities
import { mergeDeep } from '../../../util/helpers'
// Types
import Vue from 'vue'
import {
VuetifyParsedTheme,
VuetifyThemeVariant,
ThemeOptions,
} from 'vuetify/types/services/theme'
const FillVariant = (variant: Partial<VuetifyThemeVariant> = {}) => {
return {
primary: '#1976D2',
secondary: '#424242',
accent: '#82B1FF',
error: '#FF5252',
info: '#2196F3',
success: '#4CAF50',
warning: '#FFC107',
...variant,
}
}
describe('Theme.ts', () => {
function rootFactory () {
return mergeDeep(JSON.parse(JSON.stringify(preset)), {
theme: {
default: 'light',
themes: {
dark: FillVariant(),
light: FillVariant(),
},
},
})
}
let mockTheme: (theme?: Partial<ThemeOptions>) => Theme
let instance: Vue
beforeEach(() => {
mockTheme = (themeOptions?: Partial<ThemeOptions>) => {
const options = { theme: themeOptions || {} }
const theme = new Theme(mergeDeep(rootFactory(), options))
instance = new Vue({
beforeCreate () {
theme.init(this)
},
})
return theme
}
})
afterEach(() => {
const style = document.getElementById('vuetify-theme-stylesheet')
style && style.remove()
})
it('should disable theme colors', () => {
const theme = mockTheme({ disable: true })
expect(theme.styleEl).toBeFalsy()
})
it('should generate theme and apply to document', () => {
const theme = mockTheme({
themes: {
light: FillVariant({
primary: '#000001',
secondary: '#000002',
accent: '#000003',
}),
},
})
const style = document.getElementById('vuetify-theme-stylesheet')
const html = style!.innerHTML
expect(html).toMatchSnapshot()
expect(html.indexOf('#000001') > -1).toBe(true)
expect(html.indexOf('#000002') > -1).toBe(true)
expect(html.indexOf('#000003') > -1).toBe(true)
})
it('should apply a new theme', () => {
const theme = mockTheme({
default: 'light',
themes: {
light: FillVariant(),
dark: FillVariant({
primary: '#FFFFFF',
}),
},
})
const style = document.getElementById('vuetify-theme-stylesheet')
const html = style!.innerHTML
theme.dark = true
expect(html).not.toEqual(style!.innerHTML)
})
it('should clear css', () => {
const theme = mockTheme()
const spy = jest.spyOn(theme, 'clearCss')
theme.dark = true
expect(spy).toHaveBeenCalledTimes(0)
theme.themes.light = FillVariant()
theme.dark = false
expect(spy).toHaveBeenCalledTimes(0)
theme.disabled = true
theme.dark = true
expect(spy).toHaveBeenCalledTimes(1)
})
it('should use themeCache', () => {
const cache = new Map()
const themeCache = {
get: jest.fn(theme => cache.get(theme)),
set: jest.fn((theme: VuetifyParsedTheme, css: string) => {
cache.set(theme, css)
}),
}
const theme = mockTheme({
options: { themeCache },
})
expect(theme.generatedStyles).toMatchSnapshot()
expect(themeCache.set).toHaveBeenCalledTimes(2)
theme.applyTheme()
expect(themeCache.get).toHaveBeenCalledTimes(3)
expect(themeCache.set).toHaveBeenCalledTimes(3)
expect(theme.generatedStyles).toMatchSnapshot()
})
it('should minify theme', () => {
const minifyTheme = jest.fn((css: string) => css + 'foobar')
const theme = mockTheme({
options: { minifyTheme },
})
const style = document.getElementById('vuetify-theme-stylesheet')
const html = style!.innerHTML
expect(minifyTheme).toHaveBeenCalled()
expect(html.indexOf('foobar') > -1).toBe(true)
expect(theme.generatedStyles).toMatchSnapshot()
})
it('should add nonce to stylesheet', () => {
const theme = mockTheme({
options: { cspNonce: 'foobar' },
})
const style = document.getElementById('vuetify-theme-stylesheet')
expect(style!.getAttribute('nonce')).toBe('foobar')
})
it('should initialize the theme', () => {
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
const ssrContext = { head: '' }
theme.init(instance, ssrContext)
expect(spy).toHaveBeenCalledTimes(1)
expect(ssrContext.head).toBeTruthy()
expect(ssrContext.head).toMatchSnapshot()
})
it('should set theme with vue-meta@1', () => {
const theme = mockTheme()
const anyInstance = instance as any
anyInstance.$meta = () => ({})
theme.init(anyInstance)
expect(typeof anyInstance.$options.metaInfo).toBe('function')
const metaInfo = anyInstance.$options.metaInfo()
expect(metaInfo).toBeTruthy()
expect(metaInfo.style).toHaveLength(1)
expect(metaInfo.style[0].cssText).toMatchSnapshot()
})
it('should set theme with vue-meta@2', () => {
const theme = mockTheme()
const anyInstance = instance as any
anyInstance.$meta = () => ({
getOptions: () => ({ keyName: 'metaInfo' }),
})
theme.init(anyInstance)
const metaKeyName = anyInstance.$meta().getOptions().keyName
expect(typeof anyInstance.$options[metaKeyName]).toBe('function')
const metaInfo = anyInstance.$options[metaKeyName]()
expect(metaInfo).toBeTruthy()
expect(metaInfo.style).toHaveLength(1)
expect(metaInfo.style[0].cssText).toMatchSnapshot()
})
it('should react to theme changes', async () => {
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
theme.themes.light.primary = '#000000'
await instance.$nextTick()
theme.themes.dark.secondary = '#000000'
await instance.$nextTick()
theme.currentTheme.accent = '#000000'
await instance.$nextTick()
expect(spy).toHaveBeenCalledTimes(3)
})
it('should reset themes', async () => {
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
expect(theme.generatedStyles).toMatchSnapshot()
theme.resetThemes()
expect(theme.generatedStyles).toMatchSnapshot()
expect(spy).toHaveBeenCalledTimes(1)
})
it('should set theme', () => {
const theme = mockTheme()
const spy = jest.spyOn(theme, 'applyTheme')
expect(theme.generatedStyles).toMatchSnapshot()
theme.setTheme('light', { accent: '#c0ffee' })
expect(theme.generatedStyles).toMatchSnapshot()
theme.setTheme('dark', { accent: '#c0ffee' })
expect(theme.generatedStyles).toMatchSnapshot()
expect(spy).toHaveBeenCalledTimes(2)
})
it('should use vue-meta@2.3 functionality', () => {
const theme = mockTheme()
const set = jest.fn()
const $meta = () => ({
addApp: () => ({ set }),
})
;(instance as any).$meta = $meta as any
theme.init(instance)
expect(set).toHaveBeenCalled()
})
it('should not generate variations', () => {
const theme = mockTheme({ options: { variations: false } })
const style = document.getElementById('vuetify-theme-stylesheet')
const html = style!.innerHTML
expect(html).toMatchSnapshot()
})
})