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:
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]]);
+ });
+});