Skip to content

Commit 86c8a7e

Browse files
authored
Merge pull request #15 from ktsn/add-types
feat(types): add typescript declarations
2 parents 709ab99 + 1d0a6fd commit 86c8a7e

File tree

8 files changed

+339
-2
lines changed

8 files changed

+339
-2
lines changed

package.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
"version": "0.1.0",
44
"description": "Utilities for testing Vue components.",
55
"main": "dist/vue-test-utils.js",
6+
"types": "types/index.d.ts",
67
"files": [
78
"src",
8-
"dist/*.js"
9+
"dist/*.js",
10+
"types/index.d.ts"
911
],
1012
"scripts": {
1113
"build": "node build/build.js",
@@ -16,10 +18,11 @@
1618
"lint:docs": "eslint --ext js,vue,md docs --ignore-path .gitignore",
1719
"lint:fix": "npm run lint -- --fix",
1820
"postinstall": "node build/install-hooks.js",
19-
"test": "npm run lint && npm run lint:docs && npm run flow && npm run test:unit && npm run test:integration && npm run test:integration:karma",
21+
"test": "npm run lint && npm run lint:docs && npm run flow && npm run test:types && npm run test:unit && npm run test:integration && npm run test:integration:karma",
2022
"test:integration": "cross-env BABEL_ENV=test mocha-webpack --webpack-config build/webpack.test.config.js test/integration/specs --recursive --require test/integration/setup/mocha.setup.js",
2123
"test:integration:karma": "cross-env BABEL_ENV=test TARGET=browser karma start test/integration/setup/karma.conf.js --single-run",
2224
"test:unit": "cross-env BABEL_ENV=test mocha-webpack --webpack-config build/webpack.test.config.js test/unit/specs --recursive --require test/unit/setup/mocha.setup.js",
25+
"test:types": "tsc -p types",
2326
"release": "bash build/release.sh",
2427
"release:note": "node build/gen-release-note.js"
2528
},
@@ -72,6 +75,7 @@
7275
"shelljs": "^0.7.8",
7376
"sinon": "^2.3.2",
7477
"sinon-chai": "^2.10.0",
78+
"typescript": "^2.4.1",
7579
"vue": "^2.3.3",
7680
"vue-loader": "^12.2.1",
7781
"vue-router": "^2.6.0",

types/index.d.ts

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import Vue, { VNodeData, Component, ComponentOptions, FunctionalComponentOptions } from 'vue'
2+
3+
/**
4+
* Utility type to declare an extended Vue constructor
5+
*/
6+
type VueClass<V extends Vue> = (new (...args: any[]) => V) & typeof Vue
7+
8+
/**
9+
* Utility type for a selector
10+
*/
11+
type Selector = string | Component
12+
13+
/**
14+
* Utility type for slots
15+
*/
16+
type Slots = {
17+
[key: string]: (Component | string)[] | Component | string
18+
}
19+
20+
/**
21+
* Utility type for stubs which can be a string of template as a shorthand
22+
* If it is an array of string, the specified children are replaced by blank components
23+
*/
24+
type Stubs = {
25+
[key: string]: Component | string | true
26+
} | string[]
27+
28+
/**
29+
* Base class of Wrapper and WrapperArray
30+
* It has common methods on both Wrapper and WrapperArray
31+
*/
32+
interface BaseWrapper {
33+
contains (selector: Selector): boolean
34+
exists (): boolean
35+
36+
hasAttribute (attribute: string, value: string): boolean
37+
hasClass (className: string): boolean
38+
hasProp (prop: string, value: any): boolean
39+
hasStyle (style: string, value: string): boolean
40+
41+
is (selector: Selector): boolean
42+
isEmpty (): boolean
43+
isVueInstance (): boolean
44+
45+
update (): void
46+
setData (data: object): void
47+
setProps (props: object): void
48+
trigger (eventName: string, options?: object): void
49+
}
50+
51+
interface Wrapper<V extends Vue> extends BaseWrapper {
52+
readonly vm: V
53+
readonly element: HTMLElement
54+
readonly options: WrapperOptions
55+
56+
find<R extends Vue, Ctor extends VueClass<R> = VueClass<R>> (selector: Ctor): Wrapper<R>
57+
find<R extends Vue> (selector: ComponentOptions<R>): Wrapper<R>
58+
find (selector: FunctionalComponentOptions): Wrapper<Vue>
59+
find (selector: string): Wrapper<Vue>
60+
61+
findAll<R extends Vue, Ctor extends VueClass<R> = VueClass<R>> (selector: Ctor): WrapperArray<R>
62+
findAll<R extends Vue> (selector: ComponentOptions<R>): WrapperArray<R>
63+
findAll (selector: FunctionalComponentOptions): WrapperArray<Vue>
64+
findAll (selector: string): WrapperArray<Vue>
65+
66+
html (): string
67+
text (): string
68+
name (): string
69+
}
70+
71+
interface WrapperArray<V extends Vue> extends BaseWrapper {
72+
readonly length: number
73+
74+
at (index: number): Wrapper<V>
75+
}
76+
77+
interface WrapperOptions {
78+
attachedToDocument: boolean
79+
}
80+
81+
interface MountOptions<V extends Vue> extends ComponentOptions<V> {
82+
attachToDocument?: boolean
83+
clone?: boolean
84+
context?: VNodeData
85+
localVue?: typeof Vue
86+
intercept?: object
87+
slots?: Slots
88+
stubs?: Stubs
89+
}
90+
91+
type ShallowOptions<V extends Vue> = MountOptions<V>
92+
93+
export declare function createLocalVue (): typeof Vue
94+
95+
export declare function mount<V extends Vue, Ctor extends VueClass<V> = VueClass<V>> (component: Ctor, options?: MountOptions<V>): Wrapper<V>
96+
export declare function mount<V extends Vue> (component: ComponentOptions<V>, options?: MountOptions<V>): Wrapper<V>
97+
export declare function mount (component: FunctionalComponentOptions, options?: MountOptions<Vue>): Wrapper<Vue>
98+
99+
export declare function shallow<V extends Vue, Ctor extends VueClass<V> = VueClass<V>> (component: Ctor, options?: ShallowOptions<V>): Wrapper<V>
100+
export declare function shallow<V extends Vue> (component: ComponentOptions<V>, options?: ShallowOptions<V>): Wrapper<V>
101+
export declare function shallow (component: FunctionalComponentOptions, options?: ShallowOptions<Vue>): Wrapper<Vue>

types/test/mount.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import Vuex from 'vuex'
2+
import { mount, createLocalVue } from '../'
3+
import { normalOptions, functionalOptions, Normal, ClassComponent } from './resources'
4+
5+
/**
6+
* Should create wrapper vm based on (function) component options or constructors
7+
* The users can specify component type via the type parameter
8+
*/
9+
const normalWrapper = mount(normalOptions)
10+
const normalFoo: string = normalWrapper.vm.foo
11+
12+
const classWrapper = mount<ClassComponent>(ClassComponent)
13+
const classFoo: string = classWrapper.vm.bar
14+
15+
const functinalWrapper = mount(functionalOptions)
16+
17+
/**
18+
* Test for mount options
19+
*/
20+
const localVue = createLocalVue()
21+
localVue.use(Vuex)
22+
23+
const store = new Vuex.Store({})
24+
25+
mount<ClassComponent>(ClassComponent, {
26+
attachToDocument: true,
27+
clone: true,
28+
localVue,
29+
intercept: {
30+
$store: store
31+
},
32+
slots: {
33+
default: `<div>Foo</div>`,
34+
foo: [normalOptions, functionalOptions],
35+
bar: ClassComponent
36+
},
37+
stubs: {
38+
foo: normalOptions,
39+
bar: functionalOptions,
40+
baz: ClassComponent,
41+
qux: `<div>Test</div>`
42+
}
43+
})
44+
45+
mount(functionalOptions, {
46+
context: {
47+
props: { foo: 'test' }
48+
},
49+
stubs: ['child']
50+
})
51+
52+
/**
53+
* MountOptions should receive Vue's component options
54+
*/
55+
mount<ClassComponent>(ClassComponent, {
56+
propsData: {
57+
test: 'test'
58+
},
59+
created () {
60+
this.bar
61+
}
62+
})

types/test/resources.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import Vue, { ComponentOptions, FunctionalComponentOptions } from 'vue'
2+
3+
/**
4+
* Normal component options
5+
*/
6+
export interface Normal extends Vue {
7+
foo: string
8+
}
9+
export const normalOptions: ComponentOptions<Normal> = {
10+
name: 'normal',
11+
data () {
12+
return {
13+
foo: 'bar'
14+
}
15+
}
16+
}
17+
18+
/**
19+
* Functional component options
20+
*/
21+
export const functionalOptions: FunctionalComponentOptions = {
22+
functional: true,
23+
render (h) {
24+
return h('div')
25+
}
26+
}
27+
28+
/**
29+
* Component constructor declared with vue-class-component etc.
30+
*/
31+
export class ClassComponent extends Vue {
32+
bar = 'bar'
33+
}

types/test/shallow.ts

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import Vuex from 'vuex'
2+
import { shallow, createLocalVue } from '../'
3+
import { normalOptions, functionalOptions, Normal, ClassComponent } from './resources'
4+
5+
/**
6+
* Should create wrapper vm based on (function) component options or constructors
7+
* The users can specify component type via the type parameter
8+
*/
9+
const normalWrapper = shallow(normalOptions)
10+
const normalFoo: string = normalWrapper.vm.foo
11+
12+
const classWrapper = shallow<ClassComponent>(ClassComponent)
13+
const classFoo: string = classWrapper.vm.bar
14+
15+
const functinalWrapper = shallow(functionalOptions)
16+
17+
/**
18+
* Test for shallow options
19+
*/
20+
const localVue = createLocalVue()
21+
localVue.use(Vuex)
22+
23+
const store = new Vuex.Store({})
24+
25+
shallow<ClassComponent>(ClassComponent, {
26+
attachToDocument: true,
27+
clone: true,
28+
localVue,
29+
intercept: {
30+
$store: store
31+
},
32+
slots: {
33+
default: `<div>Foo</div>`,
34+
foo: [normalOptions, functionalOptions],
35+
baz: ClassComponent
36+
},
37+
stubs: {
38+
foo: normalOptions,
39+
bar: functionalOptions,
40+
baz: ClassComponent,
41+
qux: `<div>Test</div>`
42+
}
43+
})
44+
45+
shallow(functionalOptions, {
46+
context: {
47+
props: { foo: 'test' }
48+
},
49+
stubs: ['child']
50+
})
51+
52+
/**
53+
* ShallowOptions should receive Vue's component options
54+
*/
55+
shallow<ClassComponent>(ClassComponent, {
56+
propsData: {
57+
test: 'test'
58+
},
59+
created () {
60+
this.bar
61+
}
62+
})

types/test/wrapper.ts

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { mount } from '../'
2+
import { normalOptions, functionalOptions, Normal, ClassComponent } from './resources'
3+
4+
/**
5+
* Tests for BaseWrapper API
6+
*/
7+
let wrapper = mount<Normal>(normalOptions)
8+
9+
let bool: boolean = wrapper.contains('.foo')
10+
bool = wrapper.contains(normalOptions)
11+
bool = wrapper.contains(ClassComponent)
12+
13+
bool = wrapper.exists()
14+
15+
bool = wrapper.hasAttribute('foo', 'bar')
16+
bool = wrapper.hasClass('foo-class')
17+
bool = wrapper.hasProp('checked', true)
18+
bool = wrapper.hasStyle('color', 'red')
19+
20+
bool = wrapper.is(normalOptions)
21+
bool = wrapper.isEmpty()
22+
bool = wrapper.isVueInstance()
23+
24+
wrapper.update()
25+
wrapper.setData({ foo: 'bar' })
26+
wrapper.setProps({ checked: true })
27+
wrapper.trigger('mousedown.enter', {
28+
preventDefault: true
29+
})
30+
31+
/**
32+
* Tests for Wrapper API
33+
*/
34+
wrapper.vm.foo
35+
wrapper.vm.$emit('event', 'arg')
36+
37+
let el: HTMLElement = wrapper.element
38+
39+
bool = wrapper.options.attachedToDocument
40+
41+
let found = wrapper.find('.foo')
42+
found = wrapper.find(normalOptions)
43+
found = wrapper.find(functionalOptions)
44+
found = wrapper.find<ClassComponent>(ClassComponent)
45+
46+
let array = wrapper.findAll('.bar')
47+
array = wrapper.findAll(normalOptions)
48+
array = wrapper.findAll(functionalOptions)
49+
array = wrapper.findAll<ClassComponent>(ClassComponent)
50+
51+
let str: string = wrapper.html()
52+
str = wrapper.text()
53+
str = wrapper.name()
54+
55+
/**
56+
* Tests for WrapperArray API
57+
*/
58+
let num: number = array.length
59+
found = array.at(1)

types/tsconfig.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"module": "es2015",
4+
"moduleResolution": "node",
5+
"allowSyntheticDefaultImports": true,
6+
"strict": true,
7+
"noEmit": true
8+
},
9+
"include": [
10+
"**/*.ts"
11+
]
12+
}

yarn.lock

+4
Original file line numberDiff line numberDiff line change
@@ -6342,6 +6342,10 @@ typedarray@^0.0.6, typedarray@~0.0.5:
63426342
version "0.0.6"
63436343
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
63446344

6345+
typescript@^2.4.1:
6346+
version "2.4.1"
6347+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
6348+
63456349
uglify-js@^2.6, uglify-js@^2.8.27:
63466350
version "2.8.27"
63476351
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c"

0 commit comments

Comments
 (0)