Skip to content

Commit

Permalink
feat(wrapper): add support for getting prop, attribute and classes by…
Browse files Browse the repository at this point in the history
… key (#941)
  • Loading branch information
willsoto authored and eddyerburgh committed Aug 26, 2018
1 parent 8b566a6 commit 9bb9a87
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 18 deletions.
10 changes: 7 additions & 3 deletions docs/api/wrapper/attributes.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
## attributes()
## attributes([key])

Returns `Wrapper` DOM node attribute object.
Returns `Wrapper` DOM node attribute object. If `key` is provided, the value for the `key` will be returned.

- **Returns:** `{[attribute: string]: any}`
- **Arguments:**
- `{string} key` **optional**

- **Returns:** `{[attribute: string]: any} | string`

- **Example:**

Expand All @@ -12,4 +15,5 @@ import Foo from './Foo.vue'

const wrapper = mount(Foo)
expect(wrapper.attributes().id).toBe('foo')
expect(wrapper.attributes('id')).toBe('foo')
```
10 changes: 7 additions & 3 deletions docs/api/wrapper/classes.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
## classes()
## classes([className])

Return `Wrapper` DOM node classes.

Returns Array of class names.
Returns Array of class names. Or a boolean if a class name is provided.

- **Returns:** `Array<{string}>`
- **Arguments:**
- `{string} className` **optional**

- **Returns:** `Array<{string}> | boolean`

- **Example:**

Expand All @@ -14,4 +17,5 @@ import Foo from './Foo.vue'

const wrapper = mount(Foo)
expect(wrapper.classes()).toContain('bar')
expect(wrapper.classes('bar')).toBe(true)
```
10 changes: 7 additions & 3 deletions docs/api/wrapper/props.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
## props()
## props([key])

Return `Wrapper` `vm` props object.
Return `Wrapper` `vm` props object. If `key` is provided, the value for the `key` will be returned.

**Note the Wrapper must contain a Vue instance.**

- **Returns:** `{[prop: string]: any}`
- **Arguments:**
- `{string} key` **optional**

- **Returns:** `{[prop: string]: any} | any`

- **Example:**

Expand All @@ -18,4 +21,5 @@ const wrapper = mount(Foo, {
}
})
expect(wrapper.props().bar).toBe('baz')
expect(wrapper.props('bar')).toBe('baz')
```
6 changes: 3 additions & 3 deletions flow/wrapper.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ declare type Components = { [name: string]: Component };
declare interface BaseWrapper {
// eslint-disable-line no-undef
at(index: number): Wrapper | void;
attributes(): { [name: string]: string } | void;
classes(): Array<string> | void;
attributes(key?: string): { [name: string]: string } | string | void;
classes(className?: string): Array<string> | boolean | void;
contains(selector: Selector): boolean | void;
emitted(
event?: string
Expand All @@ -31,7 +31,7 @@ declare interface BaseWrapper {
isVisible(): boolean | void;
isVueInstance(): boolean | void;
name(): string | void;
props(): { [name: string]: any } | void;
props(key?: string): { [name: string]: any } | any | void;
text(): string | void;
setData(data: Object): void;
setComputed(computed: Object): void;
Expand Down
31 changes: 25 additions & 6 deletions packages/test-utils/src/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,22 +78,25 @@ export default class Wrapper implements BaseWrapper {
/**
* Returns an Object containing all the attribute/value pairs on the element.
*/
attributes (): { [name: string]: string } {
attributes (key?: string): { [name: string]: string } | string {
const attributes = this.element.attributes
const attributeMap = {}
for (let i = 0; i < attributes.length; i++) {
const att = attributes.item(i)
attributeMap[att.localName] = att.value
}
if (key) {
return attributeMap[key]
}
return attributeMap
}

/**
* Returns an Array containing all the classes on the element
*/
classes (): Array<string> {
const className = this.element.getAttribute('class')
let classes = className ? className.split(' ') : []
classes (className?: string): Array<string> | boolean {
const classAttribute = this.element.getAttribute('class')
let classes = classAttribute ? classAttribute.split(' ') : []
// Handle converting cssmodules identifiers back to the original class name
if (this.vm && this.vm.$style) {
const cssModuleIdentifiers = Object.keys(this.vm.$style)
Expand All @@ -106,9 +109,17 @@ export default class Wrapper implements BaseWrapper {
return acc
}, {})
classes = classes.map(
className => cssModuleIdentifiers[className] || className
name => cssModuleIdentifiers[name] || name
)
}

if (className) {
if (classes.indexOf(className) > -1) {
return true
} else {
return false
}
}
return classes
}

Expand Down Expand Up @@ -436,7 +447,7 @@ export default class Wrapper implements BaseWrapper {
/**
* Returns an Object containing the prop name/value pairs on the element
*/
props (): { [name: string]: any } {
props (key?: string): { [name: string]: any } | any {
if (this.isFunctionalComponent) {
throwError(
`wrapper.props() cannot be called on a mounted ` +
Expand All @@ -457,6 +468,11 @@ export default class Wrapper implements BaseWrapper {
}
})
}

if (key) {
return props[key]
}

return props
}

Expand All @@ -468,6 +484,7 @@ export default class Wrapper implements BaseWrapper {
throwError('wrapper.setChecked() must be passed a boolean')
}
const tagName = this.element.tagName
// $FlowIgnore
const type = this.attributes().type

if (tagName === 'SELECT') {
Expand Down Expand Up @@ -515,6 +532,7 @@ export default class Wrapper implements BaseWrapper {
*/
setSelected (): void {
const tagName = this.element.tagName
// $FlowIgnore
const type = this.attributes().type

if (tagName === 'OPTION') {
Expand Down Expand Up @@ -744,6 +762,7 @@ export default class Wrapper implements BaseWrapper {
*/
setValue (value: any): void {
const tagName = this.element.tagName
// $FlowIgnore
const type = this.attributes().type

if (tagName === 'SELECT') {
Expand Down
3 changes: 3 additions & 0 deletions packages/test-utils/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ interface BaseWrapper {
visible (): boolean

attributes(): { [name: string]: string }
attributes(key: string): string | void
classes(): Array<string>
classes(className: string): boolean
props(): { [name: string]: any }
props(key: string): any | void

hasAttribute (attribute: string, value: string): boolean
hasClass (className: string): boolean
Expand Down
16 changes: 16 additions & 0 deletions test/specs/wrapper/attributes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,20 @@ describeWithShallowAndMount('attributes', mountingMethod => {
const wrapper = mountingMethod(compiled)
expect(wrapper.attributes()).to.eql({})
})

it('returns the given attribute if wrapper contains attribute matching value', () => {
const attribute = 'attribute'
const value = 'value'
const compiled = compileToFunctions(`<div ${attribute}=${value}></div>`)
const wrapper = mountingMethod(compiled)
expect(wrapper.attributes('attribute')).to.eql(value)
})

it('returns undefined if the wrapper does not contain the matching value', () => {
const attribute = 'attribute'
const value = 'value'
const compiled = compileToFunctions(`<div ${attribute}=${value}></div>`)
const wrapper = mountingMethod(compiled)
expect(wrapper.attributes('fake')).to.eql(undefined)
})
})
16 changes: 16 additions & 0 deletions test/specs/wrapper/classes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@ describeWithShallowAndMount('classes', mountingMethod => {
expect(wrapper.classes()).to.contain('b-class')
expect(wrapper.find('text').classes()).to.contain('c-class')
})

it('returns true if the element has the class', () => {
const compiled = compileToFunctions(
'<svg class="a-class b-class"><text class="c-class"/></svg>'
)
const wrapper = mountingMethod(compiled)
expect(wrapper.classes('a-class')).to.eql(true)
expect(wrapper.classes('b-class')).to.eql(true)
expect(wrapper.find('text').classes('c-class')).to.eql(true)
expect(wrapper.classes('x-class')).to.eql(false)
})

it('returns false if the element does not have the class', () => {
const wrapper = mountingMethod(ComponentWithCssModules)
expect(wrapper.classes('x-class')).to.eql(false)
})
})
19 changes: 19 additions & 0 deletions test/specs/wrapper/props.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,23 @@ describeWithShallowAndMount('props', mountingMethod => {
.to.throw()
.with.property('message', message)
})

it('returns the given prop if a key is provided', () => {
const prop1 = {}
const prop2 = 'string val'
const wrapper = mountingMethod(ComponentWithProps, {
propsData: { prop1, prop2 }
})
expect(wrapper.props('prop1')).to.eql({})
expect(wrapper.props('prop2')).to.eql('string val')
})

it('returns undefined if the given key is not found', () => {
const prop1 = {}
const prop2 = 'string val'
const wrapper = mountingMethod(ComponentWithProps, {
propsData: { prop1, prop2 }
})
expect(wrapper.props('propNotHere')).to.eql(undefined)
})
})

0 comments on commit 9bb9a87

Please sign in to comment.