import { describe, expect, it, beforeAll, vi, afterAll } from 'vitest'; import { createWrapper } from 'app/test/vitest/helper'; import { default as axios } from 'axios'; import FormModel from 'src/components/FormModel.vue'; import { useState } from 'src/composables/useState'; describe('FormModel', () => { const model = 'mockModel'; const url = 'mockUrl'; const formInitialData = { mockKey: 'mockVal' }; let state; beforeEach(() => { state = useState(); state.set(model, formInitialData); }); describe('modelValue', () => { it('should use the provided model', () => { const { vm } = mount({ propsData: { model } }); expect(vm.modelValue).toBe(model); }); it('should use the route meta title when model is not provided', () => { const { vm } = mount({}); expect(vm.modelValue).toBe('formModel_mockTitle'); }); }); describe('onMounted()', () => { let mockGet; beforeAll(() => { mockGet = vi.spyOn(axios, 'get').mockResolvedValue({ data: {} }); }); afterAll(() => { mockGet.mockRestore(); }); it('should not fetch when has formInitialData', () => { mount({ propsData: { url, model, autoLoad: true, formInitialData } }); expect(mockGet).not.toHaveBeenCalled(); }); it('should fetch when there is url and auto-load', () => { mount({ propsData: { url, model, autoLoad: true } }); expect(mockGet).toHaveBeenCalled(); }); it('should not observe changes', () => { const { vm } = mount({ propsData: { url, model, observeFormChanges: false, formInitialData }, }); expect(vm.hasChanges).toBe(true); vm.reset(); expect(vm.hasChanges).toBe(true); }); it('should observe changes', async () => { const { vm } = mount({ propsData: { url, model, formInitialData }, }); vm.state.set(model, formInitialData); expect(vm.hasChanges).toBe(false); await vm.$nextTick(); vm.formData.mockKey = 'newVal'; await vm.$nextTick(); expect(vm.hasChanges).toBe(true); vm.formData.mockKey = 'mockVal'; }); }); describe('trimData()', () => { let vm; beforeAll(() => { vm = mount({}).vm; }); it('should trim whitespace from string values', () => { const data = { key1: ' value1 ', key2: ' value2 ' }; const trimmedData = vm.trimData(data); expect(trimmedData).toEqual({ key1: 'value1', key2: 'value2' }); }); it('should not modify non-string values', () => { const data = { key1: 123, key2: true, key3: null, key4: undefined }; const trimmedData = vm.trimData(data); expect(trimmedData).toEqual(data); }); }); describe('save()', async () => { it('should not call if there are not changes', async () => { const { vm } = mount({ propsData: { url, model } }); await vm.save(); expect(vm.hasChanges).toBe(false); }); it('should call axios.post with the right data', async () => { const spy = vi.spyOn(axios, 'post').mockResolvedValue({ data: {} }); const urlCreate = 'mockUrlCreate'; const { vm } = mount({ propsData: { url, urlCreate, model } }); vm.formData = {}; await vm.$nextTick(); const formData = { mockKey: 'newVal', mockKey2: 'newVal2' }; vm.formData = formData; await vm.$nextTick(); await vm.save(); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith(urlCreate, formData); vm.formData.mockKey = 'mockVal'; }); it('should call axios.patch with the right data', async () => { const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} }); const { vm } = mount({ propsData: { url, model, formInitialData, }, }); await vm.$nextTick(); vm.formData.mockKey = 'newVal'; await vm.$nextTick(); await vm.save(); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith(url, { mockKey: 'newVal' }); vm.formData.mockKey = 'mockVal'; }); it('should use the saveFn', async () => { const { vm } = mount({ propsData: { url, model, formInitialData, saveFn: () => {} }, }); const spyPatch = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} }); const spySaveFn = vi.spyOn(vm.$props, 'saveFn'); await vm.$nextTick(); vm.formData.mockKey = 'newVal'; await vm.$nextTick(); await vm.save(); expect(spyPatch).not.toHaveBeenCalled(); expect(spySaveFn).toHaveBeenCalled(); vm.formData.mockKey = 'mockVal'; }); it('should reload the data after save', async () => { const { vm } = mount({ propsData: { url, model, formInitialData, reload: true }, }); vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} }); vm.formData.mockKey = 'newVal'; await vm.$nextTick(); await vm.save(); vm.formData.mockKey = 'mockVal'; }); }); }); function mount({ propsData = {} }) { return createWrapper(FormModel, { propsData, }); }