running-tools

A collection of tools for runners and their coaches
git clone https://git.ashermorgan.net/running-tools/
Log | Files | Refs | README

commit 282143d3f2fe613380ba2c9983b8ba8071ba8333
parent b396bb7b095a21a8331358ee21e063b120d2c0b4
Author: ashermorgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Tue, 10 Aug 2021 13:04:36 -0700

Implement TimeInput component

Diffstat:
Asrc/components/TimeInput.vue | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/unit/TimeInput.spec.js | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 162 insertions(+), 0 deletions(-)

diff --git a/src/components/TimeInput.vue b/src/components/TimeInput.vue @@ -0,0 +1,105 @@ +<template> + <div class="time-input"> + <int-input class="hours" + :min="0" :max="23" :padding="1" v-model="hours"/> + <span>:</span> + <int-input class="minutes" + :min="0" :max="59" :padding="2" v-model="minutes"/> + <span>:</span> + <decimal-input class="seconds" + :min="0" :max="59.99" :padding="2" :digits="2" v-model="seconds"/> + </div> +</template> + +<script> +import IntInput from '@/components/IntInput.vue'; +import DecimalInput from '@/components/DecimalInput.vue'; + +export default { + name: 'TimeInput', + + components: { + IntInput, + DecimalInput, + }, + + props: { + /** + * The input value + */ + value: { + type: Number, + default: 0, + validator: function(value) { + return value >= 0 && value <= 86399.99; + }, + }, + }, + + data: function() { + return { + /** + * The number of hours in the component value + */ + hours: Math.floor(this.value / 3600), + + /** + * The number of minutes in the component value + */ + minutes: Math.floor((this.value % 3600) / 60), + + /** + * The number of seconds in the component value + */ + seconds: this.value % 60, + }; + }, + + computed: { + /** + * The value of the component + */ + intValue: function() { + return (this.hours * 3600) + (this.minutes * 60) + this.seconds; + }, + }, + + watch: { + /** + * Update the component value when the value prop changes + * @param {Number} newValue The new prop value + */ + value: function(newValue) { + if (newValue !== this.intValue) { + this.hours = Math.floor(newValue / 3600); + this.minutes = Math.floor((newValue % 3600) / 60); + this.seconds = newValue % 60; + } + }, + + /** + * Emit the input event when the component value changes + * @param {Number} newValue The new component value + */ + intValue: function(newValue) { + this.$emit('input', newValue); + }, + }, +} +</script> + +<style scoped> +input { + text-align: center; +} +.hours, .minutes { + width: 2em; +} +.seconds { + width: 4em; +} +span { + font-weight: bold; + margin: 0px 0.2em; +} +</style> diff --git a/tests/unit/TimeInput.spec.js b/tests/unit/TimeInput.spec.js @@ -0,0 +1,57 @@ +import { expect } from 'chai'; +import { shallowMount } from '@vue/test-utils'; +import TimeInput from '@/components/TimeInput.vue'; + +describe('TimeInput.vue', () => { + it('value should be 0:00:0.00 by default', () => { + // Initialize component + const wrapper = shallowMount(TimeInput); + + // Assert value is 0:00:00.00 + expect(wrapper.vm._data.hours).to.equal(0); + expect(wrapper.vm._data.minutes).to.equal(0); + expect(wrapper.vm._data.seconds).to.equal(0.00); + }); + + it('should read value prop', () => { + // Initialize component + const wrapper = shallowMount(TimeInput, { + propsData: { value: 3600 + 60 + 1.5 } + }); + + // Assert value is 1:01:01.50 + expect(wrapper.vm._data.hours).to.equal(1); + expect(wrapper.vm._data.minutes).to.equal(1); + expect(wrapper.vm._data.seconds).to.equal(1.50); + }); + + it('should update when value prop changes', async () => { + // Initialize component + const wrapper = shallowMount(TimeInput); + + // Set value prop to 60 + await wrapper.setProps({ value: 60 }); + + // Assert value is 0:01:00.00 + expect(wrapper.vm._data.hours).to.equal(0); + expect(wrapper.vm._data.minutes).to.equal(1); + expect(wrapper.vm._data.seconds).to.equal(0.00); + }); + + it('should emit input event when value changes', async () => { + // Initialize component + const wrapper = shallowMount(TimeInput); + + // Change value to 1:00:00.00 + await wrapper.setData({ hours: 1 }); + + // Assert input event was emitted + expect(wrapper.emitted().input).to.deep.equal([[3600.00]]); + + // Change value to 1:00:01.50 + await wrapper.setData({ seconds: 1.5 }); + + // Assert another input event was emitted + expect(wrapper.emitted().input).to.deep.equal([[3600.00], [3601.50]]); + }); +});