Skip to content

Commit 8da66ab

Browse files
committed
test: rewrite unit test and increase test coverage
1 parent 23008bb commit 8da66ab

File tree

14 files changed

+515
-126
lines changed

14 files changed

+515
-126
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
"@commitlint/config-conventional": "^19.1.0",
2020
"@semantic-release/changelog": "^6.0.3",
2121
"@semantic-release/git": "^10.0.1",
22+
"@testing-library/vue": "^8.1.0",
2223
"@typescript-eslint/eslint-plugin": "^7.4.0",
2324
"@typescript-eslint/parser": "^7.4.0",
2425
"@vitejs/plugin-vue": "^5.0.4",
2526
"@vitejs/plugin-vue-jsx": "^3.1.0",
2627
"@vitest/coverage-v8": "^2.0.5",
2728
"@vue/eslint-config-prettier": "^9.0.0",
28-
"@vue/test-utils": "^2.4.5",
2929
"cz-conventional-changelog": "^3.3.0",
3030
"eslint": "^8.57.0",
3131
"eslint-config-prettier": "^9.1.0",
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, it, expect, afterEach } from 'vitest'
2+
import { css, styled } from '../index'
3+
import { render, cleanup } from '@testing-library/vue'
4+
import { getStyle } from './utils'
5+
6+
describe('css', () => {
7+
afterEach(() => {
8+
cleanup()
9+
})
10+
11+
it('should get a template string array with css', async () => {
12+
const h = 10
13+
14+
const result = css`
15+
width: 100px;
16+
height: ${h}px;
17+
`.join('')
18+
19+
expect(result).toContain('width: 100px;')
20+
expect(result).toContain(`height: ${h}px;`)
21+
})
22+
23+
it('should apply css', () => {
24+
const mixin = css`
25+
width: 100px;
26+
height: 100px;
27+
${css`
28+
border-radius: 10px;
29+
`}
30+
${css`
31+
box-sizing: border-box;
32+
`}
33+
`
34+
const StyledComponent = styled.div`
35+
${mixin}
36+
`
37+
const instance = render(StyledComponent)
38+
const style = getStyle(instance.container.firstElementChild)
39+
expect(style?.width).eq('100px')
40+
expect(style?.height).eq('100px')
41+
expect(style?.borderRadius).eq('10px')
42+
expect(style?.boxSizing).eq('border-box')
43+
})
44+
})
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { describe, it, expect, afterEach } from 'vitest'
2+
import { cssClass, styled } from '../index'
3+
import { render, cleanup } from '@testing-library/vue'
4+
import { getStyle } from './utils'
5+
6+
describe('css class', () => {
7+
afterEach(() => {
8+
cleanup()
9+
})
10+
11+
it('should get a class name and inject style', async () => {
12+
const h = 10
13+
14+
const result = cssClass`
15+
width: 100px;
16+
height: ${h}px;
17+
`
18+
19+
expect(result.startsWith('styled-')).toBeTruthy()
20+
21+
const Component = styled.div.attrs({
22+
'data-testid': 'test',
23+
class: result,
24+
})``
25+
26+
const instance = render(Component)
27+
const style = getStyle(instance.getByTestId('test'))
28+
29+
expect(style?.width).eq('100px')
30+
expect(style?.height).eq('10px')
31+
})
32+
})
Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import { describe, it, expect } from 'vitest'
2-
import { mount } from '@vue/test-utils'
1+
import { describe, it, expect, afterEach } from 'vitest'
32
import { keyframes, styled } from '../index'
3+
import { render, cleanup } from '@testing-library/vue'
4+
import { getStyle } from './utils'
45

56
describe('keyframes', () => {
7+
afterEach(() => {
8+
// Reset env
9+
cleanup()
10+
})
11+
612
it('should have keyframes', async () => {
713
const kf = keyframes`
814
from {
@@ -19,23 +25,19 @@ describe('keyframes', () => {
1925
const StyledComponent = styled.div`
2026
width: 40px;
2127
height: 40px;
22-
background: ${(props: any) => props.theme.error};
2328
animation-duration: 3s;
2429
animation-name: ${kf};
2530
animation-iteration-count: infinite;
2631
`
2732

28-
mount(StyledComponent)
29-
// Make sure the keyframes are defined
30-
const cssRules = document.styleSheets[0].cssRules
31-
const keyframesRule = Array.from(cssRules as unknown as CSSKeyframesRule[]).find((rule) => rule?.name === kf)
32-
33-
expect(keyframesRule).not.toBeUndefined()
34-
expect(keyframesRule?.name).toBe(kf)
33+
const instance = render(StyledComponent)
34+
const element = instance.container.firstElementChild
3535

3636
// Make sure the animation is applied correctly
37-
const styleRule = Array.from(cssRules as unknown as CSSStyleRule[]).find((rule) => rule instanceof CSSStyleRule)
38-
expect(styleRule).not.toBeUndefined()
39-
expect(styleRule!.style['animation-name' as any]).toBe(kf)
37+
const style = getStyle(element)
38+
expect(style).toBeDefined()
39+
expect(style?.animationName).toBe(kf)
40+
expect(style?.animationDuration).toBe('3s')
41+
expect(style?.animationIterationCount).toBe('infinite')
4042
})
4143
})
Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,121 @@
1-
import { createGlobalStyle, styled } from '../index'
1+
import { createGlobalStyle, isStyledComponent, styled } from '../index'
22
import { afterEach, describe, expect, it } from 'vitest'
3-
import { mount } from '@vue/test-utils'
3+
import { render, cleanup } from '@testing-library/vue'
4+
import { getStyle } from './utils'
45
import { ref } from 'vue'
56

67
describe('styled', () => {
78
afterEach(() => {
89
// Reset env
9-
const styleTags = document.querySelectorAll('style')
10-
styleTags.forEach((styleTag) => {
11-
styleTag.innerHTML = ''
12-
})
10+
cleanup()
1311
})
1412

1513
it('should create a styled component', async () => {
1614
const MyComponent = {
1715
template: '<div>Hello World</div>',
1816
}
1917

20-
const StyledComponent = styled(MyComponent)`
21-
color: blue;
18+
const StyledComponent = styled(MyComponent).attrs({ 'data-testid': 'test' })`
19+
color: rgb(0, 0, 255);
2220
`
23-
expect(StyledComponent).toBeDefined()
24-
expect(StyledComponent.name).toMatch(/^styled-/)
2521

26-
const wrapper = mount(StyledComponent)
27-
const className = wrapper.find('div').element.className
22+
// Is styled component
23+
expect(isStyledComponent(StyledComponent)).toBeTruthy()
24+
25+
const instance = render(StyledComponent)
26+
const element = instance.getByTestId('test')
27+
28+
// Is element exist
29+
expect(element).toBeDefined()
30+
31+
// Is applied style correctly
32+
const style = getStyle(element)
33+
expect(style).toBeDefined()
34+
expect(style?.color).eq('rgb(0, 0, 255)')
2835

29-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).selectorText).toBe(`.${className}`)
30-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.color).toBe('blue')
31-
expect(wrapper.text()).toBe('Hello World')
36+
// Is element text content correct
37+
expect(element.textContent).eq('Hello World')
3238
})
3339

3440
it('should throw error if the element is invalid', () => {
35-
// 模拟一个无效的元素类型
41+
// Mock a invalid element
3642
const invalidElement = 'invalid-element'
3743

38-
// 断言当传入无效的元素类型时,应该抛出错误
44+
// should throw error
3945
expect(() => {
4046
styled(invalidElement)
4147
}).toThrowError('The element is invalid.')
4248
})
4349

4450
it('should style styled component', async () => {
4551
const StyledComponent = styled.div`
52+
width: 80px;
4653
height: 36px;
4754
`
4855

49-
const StyledComponent2 = styled(StyledComponent).attrs({ style: 'color: blue' })`
56+
const StyledComponent2 = styled(StyledComponent).attrs({ 'data-testid': 'test' })`
57+
color: rgb(0, 0, 255);
5058
height: 44px;
5159
`
5260

53-
const wrapper = mount(StyledComponent2, { slots: { default: () => 'Hello World' } })
54-
const className = wrapper.find('div').element.className
55-
expect(className).contain((document.styleSheets[0].cssRules[0] as CSSStyleRule).selectorText.replace(/\./, ''))
56-
expect(className).contain((document.styleSheets[0].cssRules[1] as CSSStyleRule).selectorText.replace(/\./, ''))
57-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.height).toBe('36px')
58-
expect((document.styleSheets[0].cssRules[1] as CSSStyleRule).style.height).toBe('44px')
59-
expect(wrapper.find('div').element.className).toMatch(/^styled-/)
60-
expect(wrapper.text()).toBe('Hello World')
61-
expect(wrapper.find('div').element.style.color).toBe('blue')
61+
const instance = render(StyledComponent2)
62+
const element = instance.getByTestId('test')
63+
64+
// Is applied style correctly
65+
const style = getStyle(element)
66+
expect(style).toBeDefined()
67+
expect(style?.color).eq('rgb(0, 0, 255)')
68+
expect(style?.height).eq('44px')
69+
expect(style?.width).eq('80px')
6270
})
6371

6472
it('should inject attrs', async () => {
6573
const StyledComponent = styled.div.attrs({
66-
style: 'color: red',
74+
'data-testid': 'test',
6775
})`
6876
height: 36px;
6977
`
70-
const wrapper = mount(StyledComponent)
78+
const instance = render(StyledComponent)
79+
const element = instance.getByTestId('test')
80+
81+
expect(element).toBeDefined()
82+
expect(element.dataset['testid']).eq('test')
7183

72-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.height).toBe('36px')
73-
expect(wrapper.find('div').element.style.color).toBe('red')
84+
const style = getStyle(element)
85+
expect(style?.height).eq('36px')
7486
})
7587

7688
it('should react to props change', async () => {
77-
const StyledComponent = styled('div', { color: String })`
89+
const StyledComponent = styled('div', { color: String }).attrs({ 'data-testid': 'test' })`
7890
color: ${(props) => props.color};
7991
`
80-
const color = ref('red')
81-
const wrapper = mount(StyledComponent, {
82-
props: {
83-
color: color.value,
84-
},
92+
const color = ref('rgb(255, 0, 0)')
93+
const instance = render(StyledComponent, {
94+
props: { color: color.value },
8595
})
8696

87-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style['color']).toBe('red')
97+
const element = instance.getByTestId('test')
98+
const style = getStyle(element)
99+
expect(style?.color).eq('rgb(255, 0, 0)')
88100

89-
await wrapper.setProps({ color: 'blue' })
90-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style['color']).toBe('blue')
101+
color.value = 'rgb(0, 0, 255)'
102+
await instance.rerender({ color: color.value })
103+
const newStyle = getStyle(element)
104+
expect(newStyle?.color).eq('rgb(0, 0, 255)')
91105
})
92106

93107
it('should create a global style component', async () => {
94108
const GlobalStyle = createGlobalStyle`
95109
body {
96-
background: red;
110+
background: rgb(255, 0, 0);
97111
}
98112
`
99-
mount(GlobalStyle)
113+
const instance = render(GlobalStyle)
100114

101115
expect(GlobalStyle).toBeDefined()
102116
expect(GlobalStyle.name).toMatch(/^styled-global.+/)
103-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).selectorText).toBe('body')
104-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.background).toBe('red')
117+
118+
const style = getStyle(instance.baseElement)
119+
expect(style?.background).toBe('rgb(255, 0, 0)')
105120
})
106121
})
Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,40 @@
1-
import { describe, it, expect } from 'vitest'
2-
import { mount } from '@vue/test-utils'
1+
import { describe, it, expect, afterEach } from 'vitest'
2+
import { render, cleanup, waitFor } from '@testing-library/vue'
33
import { ThemeProvider, styled } from '../index'
44
import { h, reactive } from 'vue'
5+
import { getStyle } from './utils'
56

67
describe('theme-provider', () => {
7-
const StyledComponent = styled.p`
8-
background: ${(props) => props.theme.primary};
9-
`
10-
const theme = reactive({
11-
primary: 'red',
12-
})
13-
const wrapper = mount(ThemeProvider, {
14-
props: {
15-
theme,
16-
},
17-
slots: {
18-
default: () => h(StyledComponent),
19-
},
8+
afterEach(() => {
9+
// Reset env
10+
cleanup()
2011
})
2112

22-
it('should use theme', async () => {
23-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.background).toBe('red')
24-
})
13+
it('should render with theme', async () => {
14+
const StyledComponent = styled.p.attrs({ 'data-testid': 'test' })`
15+
background: ${(props) => props.theme.primary};
16+
`
17+
const theme = reactive({
18+
primary: 'rgb(255, 0, 0)',
19+
})
20+
21+
const instance = render(ThemeProvider, {
22+
props: {
23+
theme,
24+
},
25+
slots: {
26+
default: () => h(StyledComponent),
27+
},
28+
})
29+
30+
const element = instance.getByTestId('test')
31+
const preStyle = getStyle(element)
32+
expect(preStyle?.background).toBe('rgb(255, 0, 0)')
2533

26-
it('should react to theme change', async () => {
27-
theme.primary = 'blue'
28-
await wrapper.setProps({
29-
theme,
34+
theme.primary = 'rgb(0, 0, 255)'
35+
await waitFor(() => {
36+
const newStyle = getStyle(element)
37+
return expect(newStyle?.background).eq('rgb(0, 0, 255)')
3038
})
31-
expect((document.styleSheets[0].cssRules[0] as CSSStyleRule).style.background).toBe('blue')
3239
})
3340
})

0 commit comments

Comments
 (0)