Skip to content

Commit

Permalink
[ONL-6889] Replace mitt with useEcCountdown. (#1818)
Browse files Browse the repository at this point in the history
* [ONL-6889] chore: Replace mitt with useEcCountdown.

* [ONL-6889] chore: Expose restart function.

* [ONL-6889] pr: Addressed comments.

* [ONL-6889] fix: Fixed test snapshots.

* 2.6.1
  • Loading branch information
mcibique authored Jan 19, 2024
1 parent 5e54d3c commit d2f86ba
Show file tree
Hide file tree
Showing 12 changed files with 385 additions and 156 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,4 @@ If you need to support every single locale on the planet, we recommend to polyfi

[floating-vue](https://floating-vue.starpad.dev/)

[mitt](https://www.npmjs.com/package/mitt)

[svg-country-flags](https://www.npmjs.com/package/svg-country-flags)
15 changes: 2 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ebury/chameleon-components",
"version": "2.6.0",
"version": "2.6.1",
"main": "src/main.js",
"sideEffects": false,
"author": "Ebury Team (http://labs.ebury.rocks/)",
Expand Down Expand Up @@ -45,7 +45,6 @@
"floating-vue": "2.0.0-beta.16",
"focus-trap": "6.9.4",
"lodash": "4.17.21",
"mitt": "3.0.1",
"svg-country-flags": "1.2.10",
"tailwindcss": "3.3.5",
"vue": "3.3.4"
Expand Down
92 changes: 92 additions & 0 deletions src/components/ec-timer/__snapshots__/ec-timer.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,98 @@ exports[`EcTimer > :props > should render as expected 1`] = `
</div>
`;

exports[`EcTimer > :props > should restart when seconds prop is updated > after restart 1`] = `
<div
class="ec-timer"
data-test="ec-timer"
>
<svg
class="ec-timer__svg"
height="52"
viewBox="0 0 52 52"
width="52"
>
<circle
class="ec-timer__elapsed"
cx="50%"
cy="50%"
fill="transparent"
r="24"
stroke-width="4"
/>
<circle
class="ec-timer__remaining"
cx="50%"
cy="50%"
fill="transparent"
r="24"
stroke-dasharray="150.79644737231007"
stroke-dashoffset="301.59289474462014"
stroke-width="4"
/>
<text
class="ec-timer__text"
data-test="ec-timer__text-only-seconds"
dominant-baseline="central"
text-anchor="middle"
x="50%"
y="50%"
>
30
s
</text>
</svg>
</div>
`;

exports[`EcTimer > :props > should restart when seconds prop is updated > before restart 1`] = `
<div
class="ec-timer"
data-test="ec-timer"
>
<svg
class="ec-timer__svg"
height="52"
viewBox="0 0 52 52"
width="52"
>
<circle
class="ec-timer__elapsed"
cx="50%"
cy="50%"
fill="transparent"
r="24"
stroke-width="4"
/>
<circle
class="ec-timer__remaining"
cx="50%"
cy="50%"
fill="transparent"
r="24"
stroke-dasharray="150.79644737231007"
stroke-dashoffset="226.1946710584651"
stroke-width="4"
/>
<text
class="ec-timer__text"
data-test="ec-timer__text-only-seconds"
dominant-baseline="central"
text-anchor="middle"
x="50%"
y="50%"
>
10
s
</text>
</svg>
</div>
`;

exports[`EcTimer > :props > when "showMinutes" is true > when "isRunning" is false > should render as expected 1`] = `
<div
class="ec-timer"
Expand Down
57 changes: 35 additions & 22 deletions src/components/ec-timer/ec-timer.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import fakeTimers from '@sinonjs/fake-timers';
import { mount } from '@vue/test-utils';
import { vi } from 'vitest';

import { withMockedConsole } from '../../../tests/utils/console';
import EcTimer from './ec-timer.vue';

describe('EcTimer', () => {
let clock;

beforeEach(() => {
clock = fakeTimers.install();
});

afterEach(() => {
if (clock) {
clock.uninstall();
}
});

function mountTimer(props, mountOpts) {
return mount(EcTimer, {
props,
Expand Down Expand Up @@ -60,13 +71,11 @@ describe('EcTimer', () => {
});

it('should clear the interval if we set "isRunning" to false', async () => {
const clearTimeoutSpy = vi.spyOn(window, 'clearInterval');
const wrapper = mountTimer({ seconds: 20, isRunning: true });

expect(clearTimeoutSpy).toHaveBeenCalledTimes(0);
expect(clock.countTimers()).toBe(1);

await wrapper.setProps({ isRunning: false });
expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
expect(clock.countTimers()).toBe(0);
});

it('should render as expected', () => {
Expand All @@ -75,6 +84,17 @@ describe('EcTimer', () => {
expect(wrapper.element).toMatchSnapshot();
});

it('should restart when seconds prop is updated', async () => {
const wrapper = mountTimer({ seconds: 20, isRunning: true });
clock.tick(10000);
await wrapper.vm.$nextTick();
expect(wrapper.element).toMatchSnapshot('before restart');

await wrapper.setProps({ seconds: 30 });

expect(wrapper.element).toMatchSnapshot('after restart');
});

describe('when "showMinutes" is true', () => {
describe('when "isRunning" is false', () => {
it('should render as expected', () => {
Expand All @@ -92,11 +112,17 @@ describe('EcTimer', () => {
});
});

it('should render a timer with minutes', () => {
it('should render a timer with leading zero in minutes', () => {
const wrapper = mountTimer({ seconds: 20, isRunning: true, showMinutes: true });

expect(wrapper.findByDataTest('ec-timer__text-with-minutes').text()).toBe('0:20');
});

it('should render a timer with minutes', () => {
const wrapper = mountTimer({ seconds: 80, isRunning: true, showMinutes: true });

expect(wrapper.findByDataTest('ec-timer__text-with-minutes').text()).toBe('1:20');
});
});
});

Expand All @@ -119,18 +145,6 @@ describe('EcTimer', () => {
});

describe('@events', () => {
let clock;

beforeEach(() => {
clock = fakeTimers.install();
});

afterEach(() => {
if (clock) {
clock.uninstall();
}
});

it('should emit an event called "time-expired" after the countdown completes', async () => {
const wrapper = mountTimer({ seconds: 20, isRunning: true });

Expand Down Expand Up @@ -165,12 +179,11 @@ describe('EcTimer', () => {
});
});

it('should clear the interval before we destroy the components', () => {
const clearTimeoutSpy = vi.spyOn(window, 'clearInterval');
it('should clear the interval before destroying the component', () => {
const wrapper = mountTimer({ seconds: 20, isRunning: true });
expect(clock.countTimers()).toBe(1);

expect(clearTimeoutSpy).toHaveBeenCalledTimes(0);
wrapper.unmount();
expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
expect(clock.countTimers()).toBe(0);
});
});
46 changes: 15 additions & 31 deletions src/components/ec-timer/ec-timer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,9 @@
</template>

<script setup>
import {
computed, onBeforeUnmount, ref, watchEffect,
} from 'vue';
import { computed, onBeforeUnmount, watchEffect } from 'vue';
import Countdown from '../../utils/countdown';
import useEcCountdown from '../../composables/use-ec-countdown/use-ec-countdown';
const props = defineProps({
/**
Expand Down Expand Up @@ -94,46 +92,32 @@ const strokeWidth = 4;
const diameter = radius * 2 + strokeWidth;
const viewbox = `0 0 ${diameter} ${diameter}`;
const circumference = 2 * Math.PI * radius;
const steps = circumference / props.seconds;
const steps = computed(() => circumference / props.seconds);
const offset = computed(() => {
if (totalSecondsLeft.value === 0) {
return circumference;
}
return circumference + steps * totalSecondsLeft.value;
return circumference + steps.value * totalSecondsLeft.value;
});
const minutesLeft = computed(() => Math.floor(totalSecondsLeft.value / 60));
const minuteSecondsLeft = computed(() => totalSecondsLeft.value % 60);
const totalSecondsLeft = ref(props.seconds);
let countdown = null;
function startCountdown() {
countdown = new Countdown();
countdown.start(props.seconds);
countdown.on('time-updated', (newValue) => {
totalSecondsLeft.value = newValue;
});
countdown.on('time-expired', () => {
/**
* Emitted after the countdown is finish
* @event time-expired
* @type {void}
*/
emit('time-expired');
});
}
const seconds = computed(() => props.seconds);
function stopCountdown() {
if (countdown) {
countdown.stop();
countdown = null;
}
}
const {
start: startCountdown,
stop: stopCountdown,
secondsLeft: totalSecondsLeft,
onTimeExpired,
} = useEcCountdown(seconds);
onTimeExpired(() => {
emit('time-expired');
});
watchEffect(() => {
if (props.isRunning) {
Expand Down
1 change: 1 addition & 0 deletions src/composables/use-ec-countdown/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './use-ec-countdown';
Loading

0 comments on commit d2f86ba

Please sign in to comment.