diff --git a/training-front-end/src/components/ValidatedDatepicker.vue b/training-front-end/src/components/ValidatedDatepicker.vue
index 0ba678aa..dacb69de 100644
--- a/training-front-end/src/components/ValidatedDatepicker.vue
+++ b/training-front-end/src/components/ValidatedDatepicker.vue
@@ -41,7 +41,7 @@
const month = user_input.month;
const day = user_input.day;
if (year.length == 4 && month && day) {
- const newDate = new Date(`${year}-${month}-${day}`);
+ const newDate = new Date(Date.UTC(year, month, day, '00', '00', '00'));
if (!isNaN(newDate)) {
emit('update:modelValue', newDate);
}
@@ -52,7 +52,7 @@
const newDate = new Date(newValue);
if (!isNaN(newDate)) {
user_input.day = newDate?.getDate()
- user_input.month = newDate?.getMonth() + 1 //+1 to convert from 0 index array
+ user_input.month = newDate?.getMonth()
user_input.year = newDate?.getFullYear()
} else{
user_input.day = '';
@@ -110,40 +110,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/training-front-end/src/components/__tests__/ValidatedDatepicker.spec.js b/training-front-end/src/components/__tests__/ValidatedDatepicker.spec.js
new file mode 100644
index 00000000..e4bedcf3
--- /dev/null
+++ b/training-front-end/src/components/__tests__/ValidatedDatepicker.spec.js
@@ -0,0 +1,109 @@
+import { describe, it, expect } from "vitest";
+import { mount } from '@vue/test-utils';
+import ValidatedDatepicker from '../ValidatedDatepicker.vue';
+
+describe('ValidatedDatepicker', () => {
+ it('renders properly', async () => {
+ const wrapper = mount(ValidatedDatepicker, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ });
+
+ expect(wrapper.html()).toContain('Month');
+ expect(wrapper.html()).toContain('Day');
+ expect(wrapper.html()).toContain('Year');
+ });
+
+ it('displays errors when validator has errors', async () => {
+ const wrapper = mount(ValidatedDatepicker, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: true,
+ $errors: [{ $property: 'name', $message: 'Name is required' }]
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ });
+
+ expect(wrapper.find('.usa-error-message').text()).toBe('Name is required');
+ });
+
+ it('emits update:modelValue event on input', async () => {
+ const wrapper = mount(ValidatedDatepicker, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ });
+
+ const monthInput = wrapper.get('#testName-month');
+ const dayInput = wrapper.get('#testName-day');
+ const yearInput = wrapper.get('#testName-year');
+
+ await monthInput.setValue('1'); //zero index 1 = february
+ await dayInput.setValue('15');
+ await yearInput.setValue('2023');
+
+ expect(wrapper.emitted()).toHaveProperty('update:modelValue');
+ expect(wrapper.emitted()['update:modelValue'][0]).toEqual([new Date('2023-02-15')]);
+ });
+
+ it('updates user_input when modelValue changes', async () => {
+ const wrapper = mount(ValidatedDatepicker, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // Simulate user input
+ const monthInput = wrapper.get('#testName-month');
+ const dayInput = wrapper.get('#testName-day');
+ const yearInput = wrapper.get('#testName-year');
+
+ // Simulate modelValue change
+ await wrapper.setProps({
+ modelValue: new Date('2024-02-20')
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // Ensure user_input is updated
+ expect(monthInput.element.value).toBe('1');
+ expect(dayInput.element.value).toBe('20');
+ expect(yearInput.element.value).toBe('2024');
+
+ // Simulate modelValue change to undefined
+ await wrapper.setProps({
+ modelValue: undefined
+ });
+
+ await wrapper.vm.$nextTick();
+
+ // Ensure user_input is cleared
+ expect(monthInput.element.value).toBe('');
+ expect(dayInput.element.value).toBe('');
+ expect(yearInput.element.value).toBe('');
+ });
+});
\ No newline at end of file
diff --git a/training-front-end/src/components/__tests__/ValidatedInput.spec.js b/training-front-end/src/components/__tests__/ValidatedInput.spec.js
new file mode 100644
index 00000000..beac3fbb
--- /dev/null
+++ b/training-front-end/src/components/__tests__/ValidatedInput.spec.js
@@ -0,0 +1,60 @@
+import { describe, it, expect } from "vitest";
+import { mount } from '@vue/test-utils';
+import ValidatedInput from '../ValidatedInput.vue';
+
+describe('ValidatedInput', () => {
+ it('renders properly', () => {
+ const wrapper = mount(ValidatedInput, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ expect(wrapper.find('.usa-form-group').exists()).toBe(true)
+ expect(wrapper.find('.usa-label').text()).toBe('Test Label (*Required)')
+ expect(wrapper.find('input').exists()).toBe(true)
+ })
+
+ it('displays errors when validator has errors', async () => {
+ const wrapper = mount(ValidatedInput, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: true,
+ $errors: [{ $property: 'name', $message: 'Name is required' }]
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ expect(wrapper.find('.usa-input--error').exists()).toBe(true)
+ expect(wrapper.find('.usa-error-message').text()).toBe('Name is required')
+ })
+
+ it('emits update:modelValue event on input', async () => {
+ const wrapper = mount(ValidatedInput, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ const textarea = wrapper.find('input')
+ await textarea.setValue('new value')
+
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy()
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual(['new value'])
+ })
+})
\ No newline at end of file
diff --git a/training-front-end/src/components/__tests__/ValidatedSelect.spec.js b/training-front-end/src/components/__tests__/ValidatedSelect.spec.js
new file mode 100644
index 00000000..1267eee3
--- /dev/null
+++ b/training-front-end/src/components/__tests__/ValidatedSelect.spec.js
@@ -0,0 +1,75 @@
+import { describe, it, expect } from "vitest";
+import { mount } from '@vue/test-utils';
+import ValidatedSelect from '../ValidatedSelect.vue';
+
+describe('ValidatedSelect', () => {
+ it('renders properly', () => {
+ const wrapper = mount(ValidatedSelect, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label',
+ options: [
+ { id: 1, name: 'Option 1' },
+ { id: 2, name: 'Option 2' },
+ { id: 3, name: 'Option 3' }
+ ]
+ }
+ })
+
+ expect(wrapper.find('.usa-form-group').exists()).toBe(true)
+ expect(wrapper.find('.usa-label').text()).toBe('Test Label (*Required)')
+ expect(wrapper.findAll('option').length).toBe(4) // 3 options + default option
+ })
+
+ it('displays errors when validator has errors', async () => {
+ const wrapper = mount(ValidatedSelect, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: true,
+ $errors: [{ $property: 'name', $message: 'Name is required' }]
+ },
+ name: 'testName',
+ label: 'Test Label',
+ options: [
+ { id: 1, name: 'Option 1' },
+ { id: 2, name: 'Option 2' },
+ { id: 3, name: 'Option 3' }
+ ]
+ }
+ })
+
+ expect(wrapper.find('.usa-form-group--error').exists()).toBe(true)
+ expect(wrapper.find('.usa-error-message').text()).toBe('Name is required')
+ })
+
+ it('emits update:modelValue event on input', async () => {
+ const wrapper = mount(ValidatedSelect, {
+ props: {
+ modelValue: '',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label',
+ options: [
+ { id: 1, name: 'Option 1' },
+ { id: 2, name: 'Option 2' },
+ { id: 3, name: 'Option 3' }
+ ]
+ }
+ })
+
+ const select = wrapper.find('select')
+ await select.setValue('1')
+
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy()
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual(['1'])
+ })
+})
\ No newline at end of file
diff --git a/training-front-end/src/components/__tests__/ValidatedTextArea.spec.js b/training-front-end/src/components/__tests__/ValidatedTextArea.spec.js
new file mode 100644
index 00000000..626b820b
--- /dev/null
+++ b/training-front-end/src/components/__tests__/ValidatedTextArea.spec.js
@@ -0,0 +1,60 @@
+import { describe, it, expect } from "vitest";
+import { mount } from "@vue/test-utils";
+import ValidatedTextArea from "../ValidatedTextArea.vue";
+
+describe('ValidatedTextArea', () => {
+ it('renders properly', () => {
+ const wrapper = mount(ValidatedTextArea, {
+ props: {
+ modelValue: 'initial value',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ expect(wrapper.find('.usa-form-group').exists()).toBe(true)
+ expect(wrapper.find('.usa-label').text()).toBe('Test Label (*Required)')
+ expect(wrapper.find('textarea').exists()).toBe(true)
+ })
+
+ it('displays errors when validator has errors', async () => {
+ const wrapper = mount(ValidatedTextArea, {
+ props: {
+ modelValue: 'initial value',
+ validator: {
+ $error: true,
+ $errors: [{ $property: 'name', $message: 'Name is required' }]
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ expect(wrapper.find('.usa-input--error').exists()).toBe(true)
+ expect(wrapper.find('.usa-error-message').text()).toBe('Name is required')
+ })
+
+ it('emits update:modelValue event on input', async () => {
+ const wrapper = mount(ValidatedTextArea, {
+ props: {
+ modelValue: 'initial value',
+ validator: {
+ $error: false,
+ $errors: []
+ },
+ name: 'testName',
+ label: 'Test Label'
+ }
+ })
+
+ const textarea = wrapper.find('textarea')
+ await textarea.setValue('new value')
+
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy()
+ expect(wrapper.emitted('update:modelValue')[0]).toEqual(['new value'])
+ })
+})
\ No newline at end of file
diff --git a/training-front-end/vitest.config.js b/training-front-end/vitest.config.js
index f2ddd6f8..f6f5cd0f 100644
--- a/training-front-end/vitest.config.js
+++ b/training-front-end/vitest.config.js
@@ -8,6 +8,7 @@ export default defineConfig({
base: process.env.BASEURL,
plugins: [vue()],
test: {
+ globalSetup: './vitest.global-setup.ts',
environment: 'jsdom'
},
envPrefix: "PUBLIC_"
diff --git a/training-front-end/vitest.global-setup.ts b/training-front-end/vitest.global-setup.ts
new file mode 100644
index 00000000..448f548a
--- /dev/null
+++ b/training-front-end/vitest.global-setup.ts
@@ -0,0 +1,3 @@
+export const setup = () => {
+ process.env.TZ = 'UTC'
+ }
\ No newline at end of file