Skip to content

Commit b385f87

Browse files
authored
Merge pull request #614 from VividLemon/master
fix(BButton): fixes and tests related to prop loading
2 parents 012289d + 2d53fbb commit b385f87

File tree

4 files changed

+147
-5
lines changed

4 files changed

+147
-5
lines changed

packages/bootstrap-vue-3/src/components/BButton/BButton.vue

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
<template>
22
<component :is="computedTag" class="btn" :class="classes" v-bind="attrs" @click="clicked">
33
<div
4-
v-if="loading"
4+
v-if="loadingBoolean"
55
class="btn-loading"
66
:class="{'mode-fill': loadingMode === 'fill', 'mode-inline': loadingMode === 'inline'}"
77
>
88
<slot name="loading">
9-
<BSpinner class="btn-spinner" :small="size !== 'lg'"></BSpinner>
9+
<b-spinner class="btn-spinner" :small="size !== 'lg'" />
1010
</slot>
1111
</div>
12-
<div class="btn-content" :class="{'btn-loading-fill': loading && loadingMode == 'fill'}">
12+
<div
13+
class="btn-content"
14+
:class="{'btn-loading-fill': loadingBoolean && loadingMode === 'fill'}"
15+
>
1316
<slot />
1417
</div>
1518
</component>
1619
</template>
1720

1821
<script lang="ts">
1922
import {computed, defineComponent, PropType, toRef} from 'vue'
23+
import BSpinner from '../BSpinner.vue'
2024
import {useBooleanish} from '../../composables'
2125
import type {Booleanish, ButtonType, ButtonVariant, InputSize, LinkTarget} from '../../types'
2226
import {isLink} from '../../utils'
2327
import BLink, {BLINK_PROPS} from '../BLink/BLink.vue'
2428
2529
export default defineComponent({
26-
components: {BLink},
30+
components: {BLink, BSpinner},
2731
props: {
2832
...BLINK_PROPS,
2933
active: {type: [Boolean, String] as PropType<Booleanish>, default: false},
@@ -48,6 +52,7 @@ export default defineComponent({
4852
const pillBoolean = useBooleanish(toRef(props, 'pill'))
4953
const pressedBoolean = useBooleanish(toRef(props, 'pressed'))
5054
const squaredBoolean = useBooleanish(toRef(props, 'squared'))
55+
const loadingBoolean = useBooleanish(toRef(props, 'loading'))
5156
5257
const isToggle = computed<boolean>(() => pressedBoolean.value === true)
5358
const isButton = computed<boolean>(
@@ -111,6 +116,7 @@ export default defineComponent({
111116
attrs,
112117
computedTag,
113118
clicked,
119+
loadingBoolean,
114120
}
115121
},
116122
})

packages/bootstrap-vue-3/src/components/BButton/button.spec.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {enableAutoUnmount, mount} from '@vue/test-utils'
22
import {afterEach, describe, expect, it} from 'vitest'
3+
import BSpinner from '../BSpinner.vue'
34
import BButton from './BButton.vue'
45
import BLink from '../BLink/BLink.vue'
56

@@ -461,4 +462,139 @@ describe('button', () => {
461462
})
462463
expect(wrapper.text()).toBe('foobar')
463464
})
465+
466+
it('contains div child when prop loading', () => {
467+
const wrapper = mount(BButton, {
468+
props: {loading: true},
469+
})
470+
const $div = wrapper.find('div')
471+
expect($div.exists()).toBe(true)
472+
})
473+
474+
it('first div child has static class btn-loading', () => {
475+
const wrapper = mount(BButton, {
476+
props: {loading: true},
477+
})
478+
const $div = wrapper.get('div')
479+
expect($div.classes()).toContain('btn-loading')
480+
})
481+
482+
it('first div child has class mode-fill when prop loadingMode is fill', () => {
483+
const wrapper = mount(BButton, {
484+
props: {loading: true, loadingMode: 'fill'},
485+
})
486+
const $div = wrapper.get('div')
487+
expect($div.classes()).toContain('mode-fill')
488+
})
489+
490+
it('first div child has class mode-inline when prop loadingMode is inline', () => {
491+
const wrapper = mount(BButton, {
492+
props: {loading: true, loadingMode: 'inline'},
493+
})
494+
const $div = wrapper.get('div')
495+
expect($div.classes()).toContain('mode-inline')
496+
})
497+
498+
it('first div child has nested BSpinner by default', () => {
499+
const wrapper = mount(BButton, {
500+
props: {loading: true, loadingMode: 'inline'},
501+
})
502+
const $div = wrapper.get('div')
503+
const $bspinner = $div.findComponent(BSpinner)
504+
expect($bspinner.exists()).toBe(true)
505+
})
506+
507+
it('first div child nested BSpinner has static class btn-spinner', () => {
508+
const wrapper = mount(BButton, {
509+
props: {loading: true, loadingMode: 'inline'},
510+
})
511+
const $div = wrapper.get('div')
512+
const $bspinner = $div.getComponent(BSpinner)
513+
expect($bspinner.classes()).toContain('btn-spinner')
514+
})
515+
516+
it('first div child nested BSpinner has prop small true when size is not lg', async () => {
517+
const wrapper = mount(BButton, {
518+
props: {loading: true, loadingMode: 'inline'},
519+
})
520+
const $div = wrapper.get('div')
521+
const $bspinner = $div.getComponent(BSpinner)
522+
expect($bspinner.props('small')).toBe(true)
523+
await wrapper.setProps({size: 'lg'})
524+
expect($bspinner.props('small')).toBe(false)
525+
})
526+
527+
it('first div child does not have bspinner when slot loading', async () => {
528+
const wrapper = mount(BButton, {
529+
props: {loading: true, loadingMode: 'inline'},
530+
slots: {loading: 'loading...'},
531+
})
532+
const $div = wrapper.get('div')
533+
const $bspinner = $div.findComponent(BSpinner)
534+
expect($bspinner.exists()).toBe(false)
535+
})
536+
537+
it('first div child renders slot loading', async () => {
538+
const wrapper = mount(BButton, {
539+
props: {loading: true, loadingMode: 'inline'},
540+
slots: {loading: 'loading...'},
541+
})
542+
const $div = wrapper.get('div')
543+
expect($div.text()).toBe('loading...')
544+
})
545+
546+
it('both child divs exist when prop loading', () => {
547+
const wrapper = mount(BButton, {
548+
props: {loading: true},
549+
})
550+
const [$first, $second] = wrapper.findAll('div')
551+
expect($first.exists()).toBe(true)
552+
expect($second.exists()).toBe(true)
553+
})
554+
555+
it('has a second child div when not prop loading', () => {
556+
const wrapper = mount(BButton)
557+
const $div = wrapper.find('div')
558+
expect($div.exists()).toBe(true)
559+
})
560+
561+
it('second child div has static class btn-content', () => {
562+
const wrapper = mount(BButton)
563+
const $div = wrapper.get('div')
564+
expect($div.classes()).toContain('btn-content')
565+
})
566+
567+
it('second child div does not have class btn-loading-fill when prop loading false', () => {
568+
const wrapper = mount(BButton)
569+
const $div = wrapper.get('div')
570+
expect($div.classes()).not.toContain('btn-loading-fill')
571+
})
572+
573+
it('second child div has class btn-loading-fill when prop loading and loadingMode is fill', async () => {
574+
const wrapper = mount(BButton, {
575+
props: {loading: true, loadingMode: 'fill'},
576+
})
577+
const [, $div] = wrapper.findAll('div')
578+
expect($div.classes()).toContain('btn-loading-fill')
579+
await wrapper.setProps({loadingMode: 'inline'})
580+
expect($div.classes()).not.toContain('btn-loading-fill')
581+
})
582+
583+
it('second child div renders default slot', () => {
584+
const wrapper = mount(BButton, {
585+
slots: {default: 'foobar'},
586+
})
587+
const $div = wrapper.get('div')
588+
expect($div.text()).toBe('foobar')
589+
})
590+
591+
it('renders both slots when prop loading in correct order', () => {
592+
const wrapper = mount(BButton, {
593+
props: {loading: true},
594+
slots: {default: 'foobar', loading: 'loading'},
595+
})
596+
const [$first, $second] = wrapper.findAll('div')
597+
expect($first.text()).toBe('loading')
598+
expect($second.text()).toBe('foobar')
599+
})
464600
})

packages/bootstrap-vue-3/src/components/BFormSelect/BFormSelectOption.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<option :value="value ?? ''" :disabled="disabledBoolean">
2+
<option :value="value" :disabled="disabledBoolean">
33
<slot />
44
</option>
55
</template>

0 commit comments

Comments
 (0)