Skip to content

Commit

Permalink
Port spec for Table (#58)
Browse files Browse the repository at this point in the history
* test(lib): update Table spec

- Updates the unit tests (spec) of `Table` so that they work with Vue 3
  and `@vue/test-utils` V2:
    - Removes `setVueInstance` because it does nothing on `buefy-next`.
    - Replaces `sinon`'s `useFakeTimers` with a combination of
      `jest.useFakeTimers` and `jest.advanceTimersByTime` so that we
      will be able to remove `sinon` from dependencies in the future.
      Awaits `$nextTick` after `jest.advanceTimersByTime` to make sure
      DOM is updated, otherwise the test fails.
    - Replaces `wrapper.find` with `wrapper.findComponent` to locate a
      component, because `wrapper.find` is dedicated to finding a DOM
      element on `@vue/test-utils` V2.
    - Replaces `isEmpty` of `Wrapper` with a combination of `element`
      and `toBeEmptyDOMElement`, because `Wrapper` no longer provides
      `isEmpty` on `@vue/test-utils` V2.
    - Replaces `contains` of `Wrapper` with a combination of `find` and
      `exists`, because `Wrapper` no longer provides `contains` on
      `@vue/test-utils` V2.
    - Replaces `wrapper.name()` with `wrapper.vm.$options.name`, because
      `wrapper.name` no longer exists in `@vue/test-utils` V2.
    - Replaces the test on `wrapper.isVueInstance()` with presence of
      `wrapper.vm`, because `wrapper.isVueInstance` no longer exists in
      `@vue/test-utils` V2.
    - Awaits `wrapper.setProps` to make sure the subsequent tests verify
      the updated state.
    - Replaces `propsData` with `props`, because `propsData` might be
      deprecated in the future.
    - Refreshes the snapshot. I temporarily fixed the bug I found while
      updating the spec (#8) to make the snapshot.
    - NOTE: the tests won't pass until the bug is fixed:
        - #8

issue #1

* test(lib): update TableColumn spec

- Updates the unit tests (spec) of `TableColumn` so that they can work
  with `@vue/test-utils` V2:
    - Replaces `find` with `findComponent` because `find` is dedicated
      to DOM elements on `@vue/test-utils` V2.
    - Replaces `wrapper.name()` with `wrapper.vm.$options.name` because
      `wrapper.name` no longer exists in `@vue/test-utils` V2.
    - Replaces the test on `wrapper.isVueInstance` with presence of
      `wrapper.vm` because `wrapper.isVueInstance` no longer exists in
      `@vue/test-utils` V2.
    - Removes the `sync` option for `mount` because it no longer exists
      in `@vue/test-utils`. It neither has any effect.

issue #1

* test(lib): update TableMobileSort spec

- Updates the unit tests (spec) of `TableMobileSort` so that they can
  work with `@vue/test-utils` V2:
    - Awaits `wrapper.setProps` to make sure the subsequent tests verify
      the updated state. Also replaces an old style async test case with
      async/await syntax.
    - Replaces `wrapper.name()` with `wrapper.vm.$options.name` because
      `wrapper.name` no longer exists in `@vue/test-utils` V2.
    - Replaces the test on `wrapper.isVueInstance()` with presence of
      `wrapper.vm` because `wrapper.isVueInstance` no longer exists in
      `@vue/test-utils` V2.
    - Removes `sync` option for `shallowMount` because it no longer
      exists in `@vue/test-utils` V2 and has no effect.

  The tests won't pass until the issue mentioned in the following
  comment is fixed:
    - #1 (comment)

issue #1

* fix(lib): TableMobileSort without columns

- Fixes the issue where `TableMobileSort` crashed at initialization if
  `columns` was `null` or `undefined`. This happened in unit tests. I do
  not think users of Buefy face this issue.

issue #1 (comment)
  • Loading branch information
kikuomax committed Sep 2, 2023
1 parent cc4f367 commit b61c9a2
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 87 deletions.
95 changes: 49 additions & 46 deletions src/components/table/Table.spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import Vue from 'vue'
import '@testing-library/jest-dom'
import { shallowMount } from '@vue/test-utils'
import { useFakeTimers } from 'sinon'
import BInput from '@components/input/Input'
import BTable from '@components/table/Table'
import { setVueInstance } from '../../utils/config'

describe('BTable', () => {
setVueInstance(Vue)

let wrapper
beforeEach(() => {
wrapper = shallowMount(BTable)
})

let tableCols = shallowMount(BTable, {
propsData: {
const tableCols = shallowMount(BTable, {
props: {
columns: [
{ label: 'default', width: '100px' },
{ label: 'pecent', width: '50%' },
Expand All @@ -25,15 +21,15 @@ describe('BTable', () => {
})

it('is called', () => {
expect(wrapper.name()).toBe('BTable')
expect(wrapper.isVueInstance()).toBeTruthy()
expect(wrapper.vm).toBeTruthy()
expect(wrapper.vm.$options.name).toBe('BTable')

expect(tableCols.name()).toBe('BTable')
expect(tableCols.isVueInstance()).toBeTruthy()
expect(tableCols.vm).toBeTruthy()
expect(tableCols.vm.$options.name).toBe('BTable')
})

it('has the filter row visible when searchable', () => {
wrapper.setProps({
it('has the filter row visible when searchable', async () => {
await wrapper.setProps({
columns: [
{
field: 'id',
Expand All @@ -46,7 +42,7 @@ describe('BTable', () => {
// Don't show if no searchable column
expect(wrapper.vm.hasSearchablenewColumns).toBe(false)
// Show if one or more searchable column
wrapper.setProps({
await wrapper.setProps({
columns: [
{
field: 'id',
Expand All @@ -65,12 +61,12 @@ describe('BTable', () => {
})

it('holds columns', () => {
let headers = tableCols.findAll('th')
const headers = tableCols.findAll('th')

expect(headers.length).toBeGreaterThanOrEqual(4)

let cols = headers.filter((th) => {
let div = th.find('div')
const cols = headers.filter((th) => {
const div = th.find('div')

return div.classes('th-wrap')
})
Expand All @@ -92,7 +88,7 @@ describe('BTable', () => {
]
beforeEach(() => {
wrapper = shallowMount(BTable, {
propsData: {
props: {
columns: [
{ label: 'ID', field: 'id' },
{ label: 'Name', field: 'name' }
Expand All @@ -106,39 +102,39 @@ describe('BTable', () => {
expect(wrapper.findAll('tbody tr.is-selected')).toHaveLength(0)
})

it('unselected( column-row-key )', () => {
wrapper.setProps({
it('unselected( column-row-key )', async () => {
await wrapper.setProps({
customRowKey: 'id'
})
expect(wrapper.findAll('tbody tr.is-selected')).toHaveLength(0)
})

it('compare by instance itself', () => {
wrapper.setProps({
it('compare by instance itself', async () => {
await wrapper.setProps({
selected: data[0]
})
const rows = wrapper.findAll('tbody tr')
expect(rows.at(0).classes()).toContain('is-selected')
})

it('target data and key match', () => {
wrapper.setProps({
it('target data and key match', async () => {
await wrapper.setProps({
selected: data[1],
customRowKey: 'id'
})
const rows = wrapper.findAll('tbody tr')
expect(rows.at(1).classes()).toContain('is-selected')
})

it('clear data', () => {
wrapper.setProps({
it('clear data', async () => {
await wrapper.setProps({
selected: data[0],
customRowKey: 'id'
})
const rows = wrapper.findAll('tbody tr')
expect(rows.at(0).classes()).toContain('is-selected')

wrapper.setProps({
await wrapper.setProps({
selected: undefined
})
expect(wrapper.findAll('tbody tr.is-selected')).toHaveLength(0)
Expand All @@ -159,7 +155,7 @@ describe('BTable', () => {

beforeEach(() => {
wrapper = shallowMount(BTable, {
propsData: {
props: {
columns: [
{ label: 'ID', field: 'id', numeric: true },
{ label: 'Name', field: 'name', searchable: true }
Expand All @@ -169,7 +165,7 @@ describe('BTable', () => {
})
headRows = wrapper.findAll('thead tr')
bodyRows = wrapper.findAll('tbody tr')
searchInput = wrapper.find(BInput)
searchInput = wrapper.findComponent(BInput)
})

it('displays filter row when at least one column is searchable', () => {
Expand All @@ -179,38 +175,43 @@ describe('BTable', () => {
it('displays filter input only on searchable columns', () => {
const filterCells = headRows.at(1).findAll('.th-wrap')

expect(filterCells.at(0).isEmpty()).toBe(true) // ID column is not searchable
expect(filterCells.at(1).contains(BInput)).toBe(true) // Name column is searchable
expect(filterCells.at(0).element).toBeEmptyDOMElement() // ID column is not searchable
expect(
filterCells.at(1).findComponent(BInput).exists()
).toBe(true) // Name column is searchable
})

it('displays all data', () => {
expect(bodyRows).toHaveLength(5)
})

it('displays filtered data when searching', () => {
searchInput.vm.$emit('input', 'J')
it('displays filtered data when searching', async () => {
searchInput.vm.$emit('update:modelValue', 'J')
await searchInput.vm.$nextTick() // makes sure the DOM is updated
bodyRows = wrapper.findAll('tbody tr')

expect(bodyRows).toHaveLength(2) // Jesse and João
})

it('displays filtered data when searching by name without accent', () => {
searchInput.vm.$emit('input', 'Joao')
it('displays filtered data when searching by name without accent', async () => {
searchInput.vm.$emit('update:modelValue', 'Joao')
await searchInput.vm.$nextTick() // makes sure the DOM is updated
bodyRows = wrapper.findAll('tbody tr')

expect(bodyRows).toHaveLength(1) // João
})

it('displays filtered data when searching by name with accent', () => {
searchInput.vm.$emit('input', 'João')
it('displays filtered data when searching by name with accent', async () => {
searchInput.vm.$emit('update:modelValue', 'João')
await searchInput.vm.$nextTick() // makes sure the DOM is updated
bodyRows = wrapper.findAll('tbody tr')

expect(bodyRows).toHaveLength(1) // João
})

it('displays filtered data when searching and updating data', () => {
searchInput.vm.$emit('input', 'J')
wrapper.setProps({
it('displays filtered data when searching and updating data', async () => {
searchInput.vm.$emit('update:modelValue', 'J')
await wrapper.setProps({
data: [
...data,
{ id: 6, name: 'Justin' }
Expand All @@ -221,18 +222,20 @@ describe('BTable', () => {
expect(bodyRows).toHaveLength(3) // Jesse, João and Justin
})

it('debounce search filtering when debounce-search is defined', () => {
let clock = useFakeTimers()
wrapper.setProps({
it('debounce search filtering when debounce-search is defined', async () => {
jest.useFakeTimers()
await wrapper.setProps({
debounceSearch: 1000
})
for (let i = 0; i < 10; i++) {
searchInput.vm.$emit('input', 'J'.repeat(10 - i))
clock.tick(500)
searchInput.vm.$emit('update:modelValue', 'J'.repeat(10 - i))
jest.advanceTimersByTime(500)
await wrapper.vm.$nextTick() // makes sure the DOM is updated
bodyRows = wrapper.findAll('tbody tr')
expect(bodyRows).toHaveLength(5) // No filtering yet
}
clock.tick(1000)
jest.advanceTimersByTime(1000)
await wrapper.vm.$nextTick() // makes sure the DOM is updated
bodyRows = wrapper.findAll('tbody tr')
expect(bodyRows).toHaveLength(2) // Filtering after debounce
})
Expand Down
6 changes: 3 additions & 3 deletions src/components/table/TableColumn.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ const WrapperComp = {

describe('BTableColumn', () => {
beforeEach(() => {
wrapper = mount(WrapperComp, { sync: false }).find({ ref: 'testItem' })
wrapper = mount(WrapperComp).findComponent({ ref: 'testItem' })
})

it('is called', () => {
expect(wrapper.name()).toBe('BTableColumn')
expect(wrapper.isVueInstance()).toBeTruthy()
expect(wrapper.vm).toBeTruthy()
expect(wrapper.vm.$options.name).toBe('BTableColumn')
})
})
17 changes: 7 additions & 10 deletions src/components/table/TableMobileSort.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ let wrapper

describe('BTableMobileSort', () => {
beforeEach(() => {
wrapper = shallowMount(BTableMobileSort, {sync: false})
wrapper = shallowMount(BTableMobileSort)
})

it('is called', () => {
expect(wrapper.name()).toBe('BTableMobileSort')
expect(wrapper.isVueInstance()).toBeTruthy()
expect(wrapper.vm).toBeTruthy()
expect(wrapper.vm.$options.name).toBe('BTableMobileSort')
})

it('render correctly', () => {
Expand All @@ -23,18 +23,15 @@ describe('BTableMobileSort', () => {
})
})

it('set mobileSort value when currentSortColumn is changed', (done) => {
wrapper.setProps({currentSortColumn: 'val'})
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.mobileSort).toEqual(wrapper.vm.currentSortColumn)
done()
})
it('set mobileSort value when currentSortColumn is changed', async () => {
await wrapper.setProps({ currentSortColumn: 'val' })
expect(wrapper.vm.mobileSort).toEqual(wrapper.vm.currentSortColumn)
})

it('emit sort event with mobileSort value when sort is called', () => {
wrapper.vm.mobileSort = 'val'
wrapper.vm.sort()
const valueEmitted = wrapper.emitted()['sort'][0]
const valueEmitted = wrapper.emitted().sort[0]
expect(valueEmitted).toContainEqual(wrapper.vm.mobileSort)
})
})
10 changes: 6 additions & 4 deletions src/components/table/TableMobileSort.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default {
sortMultipleSelect: '',
sortMultipleSelectIndex: -1,
mobileSort: this.currentSortColumn,
mobileSortIndex: this.columns.indexOf(this.currentSortColumn),
mobileSortIndex: this.columns ? this.columns.indexOf(this.currentSortColumn) : -1,
defaultEvent: {
shiftKey: true,
altKey: true,
Expand Down Expand Up @@ -168,12 +168,14 @@ export default {
mobileSortIndex(index) {
if (index !== -1) {
this.mobileSort = this.columns[index]
} else {
this.mobileSort = null
}
// `index` becomes -1 if `currentSortColumn` is not in `columns`
// never resets to null but retains `mobileSort` in that case
},
currentSortColumn(column) {
this.mobileSortIndex = this.columns.indexOf(column)
// replaces `mobileSort` whether `column` is in `columns` or not
this.mobileSort = column
this.mobileSortIndex = this.columns ? this.columns.indexOf(column) : -1
},
columns(newColumns) {
if (this.sortMultiple) {
Expand Down
32 changes: 16 additions & 16 deletions src/components/table/__snapshots__/Table.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

exports[`BTable render correctly 1`] = `
<div class="b-table">
<!---->
<!---->
<div class="table-wrapper has-mobile-cards">
<table class="table">
<!---->
<!---->
<tbody>
<tr class="is-empty">
<td colspan="0"></td>
</tr>
</tbody>
<!---->
</table>
<!---->
</div>
<!---->
<!--v-if-->
<!--v-if-->
<div class="table-wrapper has-mobile-cards">
<table class="table">
<!--v-if-->
<!--v-if-->
<tbody>
<tr class="is-empty">
<td colspan="0"></td>
</tr>
</tbody>
<!--v-if-->
</table>
<!--v-if-->
</div>
<!--v-if-->
</div>
`;
14 changes: 6 additions & 8 deletions src/components/table/__snapshots__/TableMobileSort.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

exports[`BTableMobileSort render correctly 1`] = `
<div class="field table-mobile-sort">
<div class="field has-addons">
<b-select-stub expanded="true" usehtml5validation="true" statusicon="true">
<!---->
</b-select-stub>
<div class="control"><button class="button is-primary">
<b-icon-stub icon="arrow-up" size="is-small" both="true" class="is-desc"></b-icon-stub>
</button></div>
</div>
<div class="field has-addons">
<b-select-stub modelvalue="-1" multiple="false" expanded=""></b-select-stub>
<div class="control"><button class="button is-primary">
<b-icon-stub icon="arrow-up" size="is-small" both="true" class="is-desc"></b-icon-stub>
</button></div>
</div>
</div>
`;

0 comments on commit b61c9a2

Please sign in to comment.