Skip to content

Add filter feature on Selector functions and WrapperArray #334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/en/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* [WrapperArray](./wrapper-array/README.md)
* [at](./wrapper-array/at.md)
* [contains](./wrapper-array/contains.md)
* [filter](./wrapper-array/filter.md)
* [exists](./wrapper/exists.md)
* [destroy](./wrapper-array/destroy.md)
* [hasStyle](./wrapper-array/hasStyle.md)
Expand Down
1 change: 1 addition & 0 deletions docs/en/api/wrapper-array/contains.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Use any valid [selector](../selectors.md).

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{boolean}`

Expand Down
23 changes: 23 additions & 0 deletions docs/en/api/wrapper-array/filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# filter(predicate)

Filter `WrapperArray` with a predicate function on `Wrapper` objects.

Behavior of this method is similar to [Array.prototype.filter](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/filter)

- **Arguments:**
- `{function} predicate`

- **Returns:** `{WrapperArray}`

A new `WrapperArray` instance containing `Wrapper` instances that returns true for the predicate function.

- **Example:**

```js
import { shallow } from 'vue-test-utils'
import { expect } from 'chai'
import Foo from './Foo.vue'

const wrapper = shallow(Foo)
const filteredDivArray = wrapper.findAll('div', (w) => !w.hasClass('filtered'))
```
3 changes: 2 additions & 1 deletion docs/en/api/wrapper/contains.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# `contains(selector)`

Assert `Wrapper` contains an element or component matching [selector](../selectors.md).
Assert `Wrapper` contains an element or component matching [selector](../selectors.md) and optional predicate.

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{boolean}`

Expand Down
5 changes: 3 additions & 2 deletions docs/en/api/wrapper/find.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# find(selector)

Returns [`Wrapper`](README.md) of first DOM node or Vue component matching selector.
Returns [`Wrapper`](README.md) of first DOM node or Vue component matching selector and predicate.

Use any valid [selector](../selectors.md).
Use any valid [selector](../selectors.md) and an optional predicate.

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{Wrapper}`

Expand Down
3 changes: 2 additions & 1 deletion docs/en/api/wrapper/findAll.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

Returns a [`WrapperArray`](../wrapper-array/README.md) of [Wrappers](README.md).

Use any valid [selector](../selectors.md).
Use any valid [selector](../selectors.md) and an optional predicate.

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{WrapperArray}`

Expand Down
1 change: 1 addition & 0 deletions docs/fr/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* [WrapperArray (EN)](./wrapper-array/README.md)
* [at (EN)](./wrapper-array/at.md)
* [contains (EN)](./wrapper-array/contains.md)
* [filter (EN)](./wrapper-array/filter.md)
* [exists (EN)](./wrapper/exists.md)
* [destroy (EN)](./wrapper-array/destroy.md)
* [hasAttribute (EN)](./wrapper-array/hasAttribute.md)
Expand Down
23 changes: 23 additions & 0 deletions docs/fr/api/wrapper-array/filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# filter(predicate)

<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Filter `WrapperArray` with a predicate function on `Wrapper` objects.</p>

Behavior of this method is similar to [Array.prototype.filter](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/filter)

- **Arguments:**
- `{function} predicate`

- **Returns:** `{WrapperArray}`

A new `WrapperArray` instance containing `Wrapper` instances that returns true for the predicate function.

- **Example:**

```js
import { shallow } from 'vue-test-utils'
import { expect } from 'chai'
import Foo from './Foo.vue'

const wrapper = shallow(Foo)
const filteredDivArray = wrapper.findAll('div', (w) => !w.hasClass('filtered'))
```
3 changes: 2 additions & 1 deletion docs/fr/api/wrapper/contains.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# `contains(selector)`

<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Assert `Wrapper` contains an element or component matching [selector](../selectors.md).</p>
<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Assert `Wrapper` contains an element or component matching [selector](../selectors.md) and optional predicate.</p>

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{boolean}`

Expand Down
26 changes: 26 additions & 0 deletions docs/fr/api/wrapper/filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# filter(predicate)

Filter `WrapperArray` with a predicate function on `Wrapper` objects.

Behavior of this method is similar to [Array.prototype.filter](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/filter)

- **Arguments:**
- `{function} predicate`

- **Returns:** `{WrapperArray}`

A new `WrapperArray` instance containing `Wrapper` instances that returns true for the predicate function.

- **Example:**

```js
import { shallow } from 'vue-test-utils'
import { expect } from 'chai'
import Foo from './Foo.vue'
import Bar from './Bar.vue'

const wrapper = shallow(Foo)
const divArray = wrapper.findAll('div')
expect(divArray.contains('p')).toBe(true)
expect(divArray.contains(Bar)).toBe(true)
```
5 changes: 3 additions & 2 deletions docs/fr/api/wrapper/find.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# find(selector)

<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Returns [`Wrapper`](README.md) of first DOM node or Vue component matching selector.</p>
<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Returns [`Wrapper`](README.md) of first DOM node or Vue component matching selector and predicate.</p>

Use any valid [selector](../selectors.md).
Use any valid [selector](../selectors.md) and an optional predicate.

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{Wrapper}`

Expand Down
3 changes: 2 additions & 1 deletion docs/fr/api/wrapper/findAll.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

<p><strong>⚠Cette page est actuellement en cours de traduction française. Vous pouvez repasser plus tard ou <a href="https://github.com/vuejs-fr/vue-test-utils" target="_blank">participer à la traduction</a> de celle-ci dès maintenant !</strong></p><p>Returns a [`WrapperArray`](../wrapper-array/README.md) of [Wrappers](README.md).</p>

Use any valid [selector](../selectors.md).
Use any valid [selector](../selectors.md) and an optional predicate.

- **Arguments:**
- `{string|Component} selector`
- `{function} predicate`

- **Returns:** `{WrapperArray}`

Expand Down
7 changes: 4 additions & 3 deletions flow/wrapper.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import type Wrapper from '~src/Wrapper'
import type WrapperArray from '~src/WrapperArray'

declare type Selector = any
declare type WrapperPredicate = (wrapper: Wrapper, index?: number, array?: Array<Wrapper>) => boolean;

declare interface BaseWrapper { // eslint-disable-line no-undef
at(index: number): Wrapper | void,
attributes(): { [name: string]: string } | void,
classes(): Array<string> | void,
contains(selector: Selector): boolean | void,
contains(selector: Selector, filter?: WrapperPredicate): boolean | void,
emitted(event?: string): { [name: string]: Array<Array<any>> } | Array<Array<any>> | void,
emittedByOrder(): Array<{ name: string; args: Array<any> }> | void,
exists(): boolean,
hasAttribute(attribute: string, value: string): boolean | void,
hasClass(className: string): boolean | void,
hasProp(prop: string, value: string): boolean | void,
hasStyle(style: string, value: string): boolean | void,
find(selector: Selector): Wrapper | void,
findAll(selector: Selector): WrapperArray | void,
find(selector: Selector, filter?: WrapperPredicate): Wrapper | void,
findAll(selector: Selector, filter?: WrapperPredicate): WrapperArray | void,
html(): string | void,
is(selector: Selector): boolean | void,
isEmpty(): boolean | void,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"scripts": {
"build": "node build/build.js",
"build:test": "NODE_ENV=test node build/build.js",
"build:test": "cross-env NODE_ENV=test node build/build.js",
"coverage": "cross-env NODE_ENV=coverage nyc --reporter=lcov --reporter=text npm run test:unit",
"docs": "cd docs && gitbook install && gitbook serve",
"docs:deploy": "build/update-docs.sh",
Expand Down
4 changes: 4 additions & 0 deletions src/wrappers/wrapper-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export default class WrapperArray implements BaseWrapper {
return this.wrappers[index]
}

filter (predicate: WrapperPredicate) {
return new WrapperArray(this.wrappers.filter(predicate))
}

attributes (): void {
this.throwErrorIfWrappersIsEmpty('attributes')

Expand Down
30 changes: 22 additions & 8 deletions src/wrappers/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,17 @@ export default class Wrapper implements BaseWrapper {
/**
* Checks if wrapper contains provided selector.
*/
contains (selector: Selector) {
contains (selector: Selector, predicate?: WrapperPredicate) {
const selectorType = getSelectorTypeOrThrow(selector, 'contains')
const nodes = findAll(this.vm, this.vnode, selectorType, selector)
let wrappers = nodes.map(node =>
createWrapper(node, this.update, this.options)
)
if (predicate) {
wrappers = wrappers.filter(predicate)
}
const is = selectorType === REF_SELECTOR ? false : this.is(selector)
return nodes.length > 0 || is
return wrappers.length > 0 || is
}

/**
Expand Down Expand Up @@ -220,27 +226,35 @@ export default class Wrapper implements BaseWrapper {
/**
* Finds first node in tree of the current wrapper that matches the provided selector.
*/
find (selector: Selector): Wrapper | ErrorWrapper | VueWrapper {
find (selector: Selector, predicate?: WrapperPredicate): Wrapper | ErrorWrapper | VueWrapper {
const selectorType = getSelectorTypeOrThrow(selector, 'find')
const nodes = findAll(this.vm, this.vnode, selectorType, selector)
if (nodes.length === 0) {
let wrappers = findAll(this.vm, this.vnode, selectorType, selector).map(node =>
createWrapper(node, this.update, this.options)
)
if (predicate) {
wrappers = wrappers.filter(predicate)
}
if (wrappers.length === 0) {
if (selector.ref) {
return new ErrorWrapper(`ref="${selector.ref}"`)
}
return new ErrorWrapper(typeof selector === 'string' ? selector : 'Component')
}
return createWrapper(nodes[0], this.update, this.options)
return wrappers[0]
}

/**
* Finds node in tree of the current wrapper that matches the provided selector.
*/
findAll (selector: Selector): WrapperArray {
findAll (selector: Selector, predicate?: WrapperPredicate): WrapperArray {
const selectorType = getSelectorTypeOrThrow(selector, 'findAll')
const nodes = findAll(this.vm, this.vnode, selectorType, selector)
const wrappers = nodes.map(node =>
let wrappers = nodes.map(node =>
createWrapper(node, this.update, this.options)
)
if (predicate) {
wrappers = wrappers.filter(predicate)
}
return new WrapperArray(wrappers)
}

Expand Down
6 changes: 6 additions & 0 deletions test/unit/specs/mount/Wrapper/contains.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ describe('contains', () => {
expect(wrapper.contains('input')).to.equal(true)
})

it('returns false if wrapper contains element filtered by predicate', () => {
const compiled = compileToFunctions('<div><input class="filtered" /></div>')
const wrapper = mount(compiled)
expect(wrapper.contains('input', w => !w.hasClass('filtered'))).to.equal(false)
})

it('returns true if wrapper contains Vue component', () => {
const wrapper = mount(ComponentWithChild)
expect(wrapper.contains(Component)).to.equal(true)
Expand Down
6 changes: 6 additions & 0 deletions test/unit/specs/mount/Wrapper/find.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ describe('find', () => {
expect(wrapper.find('.foo').vnode).to.be.an('object')
})

it('returns first Wrapper matching class selector and filter predicate passed', () => {
const compiled = compileToFunctions('<div><div class="foo fooFilter">filtered</div><div class="foo">not filtered</div></div>')
const wrapper = mount(compiled)
expect(wrapper.find('.foo', w => !w.hasClass('fooFilter')).text()).to.be.equals('not filtered')
})

it('returns Wrapper matching class selector passed if nested in a transition', () => {
const compiled = compileToFunctions('<transition><div /></transition>')
const wrapper = mount(compiled)
Expand Down
8 changes: 8 additions & 0 deletions test/unit/specs/mount/Wrapper/findAll.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ describe('findAll', () => {
expect(fooArr.length).to.equal(1)
})

it('returns an array of Wrapper of elements matching class selector passed and filter predicate', () => {
const compiled = compileToFunctions('<div><div class="foo fooFiltered">filtered</div><div class="foo">not filtered</div></div>')
const wrapper = mount(compiled)
const fooArr = wrapper.findAll('.foo', (wrapper) => !wrapper.hasClass('fooFiltered'))
expect(fooArr.length).to.equal(1)
expect(fooArr.at(0).text()).to.equal('not filtered')
})

it('returns an array of Wrapper of elements matching class selector passed if they are nested in a transition', () => {
const compiled = compileToFunctions('<transition><div /></transition>')
const wrapper = mount(compiled)
Expand Down
9 changes: 8 additions & 1 deletion test/unit/specs/wrappers/wrapper-array.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('WrapperArray', () => {
return wrapperArray
}

it('returns class with length equal to lenght of wrappers passed in constructor', () => {
it('returns class with length equal to length of wrappers passed in constructor', () => {
const wrapperArray = getWrapperArray()
expect(wrapperArray.length).to.equal(3)
})
Expand All @@ -24,6 +24,13 @@ describe('WrapperArray', () => {
expect(wrapperArray.at(0).text()).to.equal('1')
})

it('returns filtered wrapper when filter is called', () => {
const wrapperArray = getWrapperArray()
expect(wrapperArray.filter(w => {
return w.text() !== '2'
}).length).to.equal(2)
})

const methods = ['at', 'attributes', 'classes', 'contains', 'emitted', 'emittedByOrder', 'hasAttribute',
'hasClass', 'hasProp', 'hasStyle', 'find', 'findAll', 'html', 'text', 'is', 'isEmpty', 'isVueInstance',
'name', 'props', 'setComputed', 'setMethods', 'setData', 'setProps', 'trigger', 'update', 'destroy']
Expand Down
Loading