Skip to content

Commit bb71f87

Browse files
committed
feat(useInterval): Adding useInterval function
1 parent cad9444 commit bb71f87

File tree

16 files changed

+320
-54
lines changed

16 files changed

+320
-54
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ Vue.use(VueCompositionAPI);
7070
- [`useMouseElement`](./src/components/useMouseElement/stories/useMouseElement.md) — tracks the mouse position relative to given element.
7171
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/sensors-usemouseelement--demo)
7272
- Animations
73+
- [`useInterval`](./src/components/useInterval/stories/useInterval.md) — updates the `counter` value repeatedly on a fixed time delay.
74+
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-useinterval--demo)
7375
- [`useIntervalFn`](./src/components/useIntervalFn/stories/useIntervalFn.md) — calls function repeatedly on a fixed time delay.
7476
[![Demo](https://img.shields.io/badge/demo-🚀-yellow.svg)](https://microcipcip.github.io/vue-use-kit/?path=/story/animations-useintervalfn--demo)
7577
- [`useRaf`](./src/components/useRaf/stories/useRaf.md) — returns `elapsedTime` with requestAnimationFrame.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useInterval'
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<template>
2+
<table class="table is-fullwidth">
3+
<thead>
4+
<tr>
5+
<th>Prop</th>
6+
<th>Value</th>
7+
</tr>
8+
</thead>
9+
<tbody>
10+
<tr>
11+
<td>counter</td>
12+
<td>
13+
<span>{{ counter }}</span>
14+
</td>
15+
</tr>
16+
<tr>
17+
<td colspan="2">
18+
<button class="button is-primary" @click="start" v-if="!isRunning">
19+
Start Interval
20+
</button>
21+
<button class="button is-danger" @click="stop" v-else>
22+
Stop Interval
23+
</button>
24+
</td>
25+
</tr>
26+
</tbody>
27+
</table>
28+
</template>
29+
30+
<script lang="ts">
31+
import Vue from 'vue'
32+
import { useInterval } from '@src/vue-use-kit'
33+
34+
export default Vue.extend({
35+
name: 'useIntervalDemo',
36+
setup() {
37+
const { isRunning, counter, start, stop } = useInterval(300)
38+
return { isRunning, counter, start, stop }
39+
}
40+
})
41+
</script>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# useInterval
2+
3+
Vue function that updates the `counter` value repeatedly on a fixed time delay.
4+
5+
## Reference
6+
7+
```typescript
8+
useInterval(
9+
ms?: number,
10+
runOnMount?: boolean
11+
): {
12+
isRunning: Ref<boolean>;
13+
counter: Ref<number>;
14+
start: () => void;
15+
stop: () => void;
16+
};
17+
```
18+
19+
### Parameters
20+
21+
- `ms: number` how many milliseconds to wait before updating the counter
22+
- `runOnMount: boolean` whether to run the interval on mount, `true` by default
23+
24+
### Returns
25+
26+
- `isRunning: Ref<boolean>` this value is `true` if the interval is running, `false` otherwise
27+
- `counter: Ref<number>` the number of times the interval has run
28+
- `start: Function` the function used for starting the interval
29+
- `stop: Function` the function used for stopping the interval
30+
31+
## Usage
32+
33+
```html
34+
<template>
35+
<div>
36+
<p>counter: {{ counter }}</p>
37+
38+
<button @click="start" v-if="!isRunning">Start Interval</button>
39+
<button @click="stop" v-else>Stop Interval</button>
40+
</div>
41+
</template>
42+
43+
<script lang="ts">
44+
import Vue from 'vue'
45+
import { useInterval } from 'vue-use-kit'
46+
47+
export default Vue.extend({
48+
name: 'UseIntervalDemo',
49+
setup() {
50+
const ms = 300
51+
52+
const { isRunning, counter, start, stop } = useInterval(ms)
53+
54+
return { isRunning, counter, start, stop }
55+
}
56+
})
57+
</script>
58+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { storiesOf } from '@storybook/vue'
2+
import path from 'path'
3+
import StoryTitle from '@src/helpers/StoryTitle.vue'
4+
import UseIntervalDemo from './UseIntervalDemo.vue'
5+
6+
const functionName = 'useInterval'
7+
const functionPath = path.resolve(__dirname, '..')
8+
const notes = require(`./${functionName}.md`).default
9+
10+
const basicDemo = () => ({
11+
components: { StoryTitle, demo: UseIntervalDemo },
12+
template: `
13+
<div class="container">
14+
<story-title
15+
function-path="${functionPath}"
16+
source-name="${functionName}"
17+
demo-name="UseIntervalDemo.vue"
18+
>
19+
<template v-slot:title></template>
20+
<template v-slot:intro></template>
21+
</story-title>
22+
<demo />
23+
</div>`
24+
})
25+
26+
storiesOf('animations|useInterval', module)
27+
.addParameters({ notes })
28+
.add('Demo', basicDemo)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { mount } from '@src/helpers/test'
2+
import { useInterval } from '@src/vue-use-kit'
3+
4+
beforeEach(() => {
5+
jest.useFakeTimers()
6+
})
7+
8+
afterEach(() => {
9+
jest.clearAllTimers()
10+
})
11+
12+
const testComponent = () => ({
13+
template: `
14+
<div>
15+
<div id="isRunning" v-if="isRunning"></div>
16+
</div>
17+
`,
18+
setup() {
19+
const { isRunning } = useInterval(1000)
20+
return { isRunning }
21+
}
22+
})
23+
24+
describe('useInterval', () => {
25+
it('should show #isRunning when the intervals are called', async () => {
26+
const wrapper = mount(testComponent())
27+
jest.advanceTimersByTime(1500)
28+
29+
// Wait for Vue to append #isReady in the DOM
30+
await wrapper.vm.$nextTick()
31+
expect(wrapper.find('#isRunning').exists()).toBe(true)
32+
})
33+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ref } from '@src/api'
2+
import { useIntervalFn } from '@src/vue-use-kit'
3+
4+
export function useInterval(ms = 0, runOnMount = true) {
5+
const counter = ref(0)
6+
const animHandler = () => {
7+
counter.value = counter.value + 1
8+
}
9+
const { isRunning, start, stop } = useIntervalFn(animHandler, ms, runOnMount)
10+
return { isRunning, counter, start, stop }
11+
}
Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,97 @@
1-
// import { mount } from '@src/helpers/test'
2-
// import { useIntervalFn } from '@src/vue-use-kit'
1+
import { mount } from '@src/helpers/test'
2+
import { ref } from '@src/api'
3+
import { useIntervalFn } from '@src/vue-use-kit'
4+
5+
beforeEach(() => {
6+
jest.useFakeTimers()
7+
})
8+
9+
afterEach(() => {
10+
jest.clearAllTimers()
11+
})
12+
13+
const testComponent = (onMount = true) => ({
14+
template: `
15+
<div>
16+
<div id="callbackCounter" v-text="callbackCounter" />
17+
<div id="isRunning" v-if="isRunning"></div>
18+
<button id="stop" @click="stop"></button>
19+
<button id="start" @click="start"></button>
20+
</div>
21+
`,
22+
setup() {
23+
const callbackCounter = ref(0)
24+
const { isRunning, start, stop } = useIntervalFn(
25+
() => {
26+
callbackCounter.value = callbackCounter.value + 1
27+
},
28+
1000,
29+
onMount
30+
)
31+
return { isRunning, start, stop, callbackCounter }
32+
}
33+
})
334

435
describe('useIntervalFn', () => {
5-
it('should do something', () => {
6-
// Add test here
36+
it('should call setInterval when initialized', () => {
37+
expect(setInterval).toHaveBeenCalledTimes(0)
38+
mount(testComponent())
39+
jest.advanceTimersByTime(1500)
40+
expect(setInterval).toHaveBeenCalled()
41+
})
42+
43+
it('should call callback several times', async () => {
44+
const wrapper = mount(testComponent())
45+
jest.advanceTimersByTime(25500)
46+
await wrapper.vm.$nextTick()
47+
expect(wrapper.find('#callbackCounter').text()).toBe('25')
48+
})
49+
50+
it('should not show #isRunning when onMount is false', async () => {
51+
const wrapper = mount(testComponent(false))
52+
jest.advanceTimersByTime(1500)
53+
54+
// Wait for Vue rerender
55+
await wrapper.vm.$nextTick()
56+
expect(wrapper.find('#isRunning').exists()).toBe(false)
57+
})
58+
59+
it('should show #isRunning when the intervals are called', async () => {
60+
const wrapper = mount(testComponent())
61+
jest.advanceTimersByTime(1500)
62+
63+
// Wait for Vue to append #isReady in the DOM
64+
await wrapper.vm.$nextTick()
65+
expect(wrapper.find('#isRunning').exists()).toBe(true)
66+
})
67+
68+
it('should show #isRunning when start is called', async () => {
69+
const wrapper = mount(testComponent(false))
70+
jest.advanceTimersByTime(1500)
71+
72+
// Wait for Vue to append #isRunning in the DOM
73+
await wrapper.vm.$nextTick()
74+
expect(wrapper.find('#isRunning').exists()).toBe(false)
75+
wrapper.find('#start').trigger('click')
76+
jest.advanceTimersByTime(2500)
77+
78+
// Wait for Vue to remove #isRunning from the DOM
79+
await wrapper.vm.$nextTick()
80+
expect(wrapper.find('#isRunning').exists()).toBe(true)
81+
})
82+
83+
it('should hide #isRunning when stop is called', async () => {
84+
const wrapper = mount(testComponent())
85+
jest.advanceTimersByTime(1500)
86+
87+
// Wait for Vue to append #isRunning in the DOM
88+
await wrapper.vm.$nextTick()
89+
expect(wrapper.find('#isRunning').exists()).toBe(true)
90+
wrapper.find('#stop').trigger('click')
91+
jest.advanceTimersByTime(2500)
92+
93+
// Wait for Vue to remove #isRunning from the DOM
94+
await wrapper.vm.$nextTick()
95+
expect(wrapper.find('#isRunning').exists()).toBe(false)
796
})
897
})

src/components/useRaf/useRaf.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ const testComponent = (onMount = false) => ({
3535
})
3636

3737
describe('useRaf', () => {
38-
it('should not display #isRunning when onMount is false', async () => {
38+
it('should not show #isRunning when onMount is false', async () => {
3939
const wrapper = mount(testComponent(false))
4040
await wrapper.vm.$nextTick()
4141
expect(rafSpy).not.toHaveBeenCalled()
4242
expect(wrapper.find('#isRunning').exists()).toBe(false)
4343
expect(wrapper.find('#elapsed').text()).toBe('0')
4444
})
4545

46-
it('should display #isRunning when onMount is true', async () => {
46+
it('should show #isRunning when onMount is true', async () => {
4747
const wrapper = mount(testComponent(true))
4848
await wrapper.vm.$nextTick()
4949
expect(rafSpy).toHaveBeenCalled()

0 commit comments

Comments
 (0)