Skip to content

Commit b09e2ea

Browse files
authored
Merge pull request #244 from vuejs/class-component
wip: class component support
2 parents 8a1f348 + e589a44 commit b09e2ea

File tree

5 files changed

+135
-18
lines changed

5 files changed

+135
-18
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"typescript": "^3.7.5",
4242
"vue": "^3.0.2",
4343
"vue-class-component": "^8.0.0-beta.4",
44-
"vue-jest": "^5.0.0-alpha.5",
44+
"vue-jest": "^5.0.0-alpha.6",
4545
"vue-router": "^4.0.0-rc.1",
4646
"vuex": "^4.0.0-beta.4"
4747
},

src/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,13 @@ export const mergeDeep = (
6666
}
6767

6868
export function isClassComponent(component: any) {
69-
return '__vccBase' in component
69+
// TypeScript
70+
return (
71+
component.toString().includes('_super.apply(this, arguments) || this') ||
72+
// native ES6
73+
(typeof component === 'function' &&
74+
/^\s*class\s+/.test(component.toString()))
75+
)
7076
}
7177

7278
export function isFunctionalComponent(component: any) {

tests/components/ClassComponent.vue

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<div class="hello">
3+
<h1 data-computed>{{ computedMsg }}</h1>
4+
<h2 data-props>{{ msg }}</h2>
5+
<h3 data-methods>{{ dataText }}</h3>
6+
<button @click="changeMessage('Hello')" />
7+
</div>
8+
</template>
9+
10+
<script lang="ts">
11+
import { Options, Vue } from 'vue-class-component'
12+
@Options({
13+
props: {
14+
msg: String
15+
}
16+
})
17+
export default class ClassComponent extends Vue {
18+
dataText: string = ''
19+
get computedMsg(): string {
20+
return `Message: ${(this.$props as any).msg}`
21+
}
22+
23+
changeMessage(text: string): void {
24+
this.dataText = 'Updated'
25+
}
26+
}
27+
</script>

tests/features/classComponent.spec.ts

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,107 @@ import 'reflect-metadata'
22
import { h } from 'vue'
33
import { Options, Vue } from 'vue-class-component'
44
import { mount } from '../../src'
5+
import ClassComponent from '../components/ClassComponent.vue'
56

6-
test('data: $props should be available', () => {
7-
@Options({
8-
props: ['foo']
7+
describe('class component', () => {
8+
it('minimal class component', () => {
9+
class Foo extends Vue {
10+
render() {
11+
return h('span')
12+
}
13+
}
14+
const wrapper = mount(Foo)
15+
expect(wrapper.find('span').exists()).toBe(true)
916
})
10-
class MyComp extends Vue {
11-
message = 'answer is ' + (this.$props as any).foo
12-
render() {
13-
return h('div', this.message)
17+
18+
it('data: $props should be available', () => {
19+
@Options({
20+
props: ['foo']
21+
})
22+
class MyComp extends Vue {
23+
message = 'answer is ' + (this.$props as any).foo
24+
render() {
25+
return h('div', this.message)
26+
}
1427
}
15-
}
1628

17-
const wrapper = mount(MyComp, {
18-
props: {
19-
foo: 42
29+
const wrapper = mount(MyComp, {
30+
props: {
31+
foo: 42
32+
}
33+
})
34+
35+
expect(wrapper.html()).toBe('<div>answer is 42</div>')
36+
})
37+
38+
it('hooks', () => {
39+
let created = false
40+
class MyComp extends Vue {
41+
created() {
42+
created = true
43+
}
44+
render() {
45+
return h('div')
46+
}
2047
}
48+
mount(MyComp)
49+
expect(created).toBe(true)
2150
})
2251

23-
expect(wrapper.html()).toBe('<div>answer is 42</div>')
52+
it('methods', () => {
53+
let msg: string = ''
54+
55+
class MyComp extends Vue {
56+
hello() {
57+
msg = 'hi'
58+
}
59+
content() {
60+
return 'content'
61+
}
62+
render() {
63+
return h('div', this.content())
64+
}
65+
}
66+
67+
const wrapper = mount(MyComp)
68+
wrapper.vm.hello()
69+
expect(wrapper.html()).toBe('<div>content</div>')
70+
expect(msg).toBe('hi')
71+
})
72+
73+
it('computed', () => {
74+
class MyComp extends Vue {
75+
a!: number
76+
data() {
77+
return {
78+
a: 1
79+
}
80+
}
81+
get b() {
82+
return this.a + 1
83+
}
84+
render() {
85+
return h('div')
86+
}
87+
}
88+
89+
const wrapper = mount(MyComp)
90+
expect(wrapper.vm.a).toBe(1)
91+
expect(wrapper.vm.b).toBe(2)
92+
wrapper.vm.a = 2
93+
expect(wrapper.vm.b).toBe(3)
94+
})
95+
96+
it('works with shallow mount and SFC', async () => {
97+
const wrapper = mount(ClassComponent, {
98+
props: {
99+
msg: 'Props Message'
100+
},
101+
shallow: true
102+
})
103+
expect(wrapper.get('[data-computed]').text()).toBe('Message: Props Message')
104+
expect(wrapper.get('[data-props]').text()).toBe('Props Message')
105+
await wrapper.get('button').trigger('click')
106+
expect(wrapper.get('[data-methods]').text()).toBe('Updated')
107+
})
24108
})

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6164,10 +6164,10 @@ vue-class-component@^8.0.0-beta.4:
61646164
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-8.0.0-beta.4.tgz#bff95cdd44eb450a4a4e54b69da22099613d8071"
61656165
integrity sha512-+QXBhVH/Mz8dEC+IU7e8XXM54Tn0Aj9/saybeuK8XmhQiJlcijCB8kB7CYpBEMpHWaA+DoLr6LvHMbclYRCwZQ==
61666166

6167-
vue-jest@^5.0.0-alpha.5:
6168-
version "5.0.0-alpha.5"
6169-
resolved "https://registry.yarnpkg.com/vue-jest/-/vue-jest-5.0.0-alpha.5.tgz#a24b7569ba2078836a316033f283e151afc4906b"
6170-
integrity sha512-/ddNgiJYEtStK4kfTgIRSpBrkkrFepsCyu6qhIi2ph8rJk8OaI6HJANMjzD2tz2mnGqQOf0mTyZICVfDnLLZHA==
6167+
vue-jest@^5.0.0-alpha.6:
6168+
version "5.0.0-alpha.6"
6169+
resolved "https://registry.yarnpkg.com/vue-jest/-/vue-jest-5.0.0-alpha.6.tgz#76615809ba84278e7cd3b7d6d3cc7f18caa2e893"
6170+
integrity sha512-B0GtGnAZhdS51hoLMqAQimO0574sPBHAyev8YNFNioKk1TbAMCUfDoUDxkPvVKXxeKdWBnXA+kgR9+KP1FizXA==
61716171
dependencies:
61726172
"@babel/plugin-transform-modules-commonjs" "^7.2.0"
61736173
chalk "^2.1.0"

0 commit comments

Comments
 (0)