Merge branch '8647_fix_warnings' of https: refs #8647//gitea.verdnatura.es/verdnatura/salix-front into 8647_fix_warnings
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
Jorge Penadés 2025-04-10 18:10:45 +02:00
commit 85fa1543c1
15 changed files with 171 additions and 109 deletions

View File

@ -67,7 +67,7 @@ describe('Axios boot', () => {
}; };
const result = onResponseError(error); const result = onResponseError(error);
expect(result).rejects.toEqual(expect.objectContaining(error)); await expect(result).rejects.toEqual(expect.objectContaining(error));
}); });
it('should call to the Notify plugin with a message from the response property', async () => { it('should call to the Notify plugin with a message from the response property', async () => {
@ -83,7 +83,7 @@ describe('Axios boot', () => {
}; };
const result = onResponseError(error); const result = onResponseError(error);
expect(result).rejects.toEqual(expect.objectContaining(error)); await expect(result).rejects.toEqual(expect.objectContaining(error));
}); });
}); });
}); });

View File

@ -61,7 +61,7 @@ const $props = defineProps({
default: null, default: null,
}, },
saveFn: { saveFn: {
type: [String, Function], type: Function,
default: null, default: null,
}, },
beforeSaveFn: { beforeSaveFn: {

View File

@ -99,6 +99,10 @@ const $props = defineProps({
type: Function, type: Function,
default: () => {}, default: () => {},
}, },
preventSubmit: {
type: Boolean,
default: true,
},
}); });
const emit = defineEmits(['onFetch', 'onDataSaved']); const emit = defineEmits(['onFetch', 'onDataSaved']);
const modelValue = computed( const modelValue = computed(
@ -301,7 +305,7 @@ function onBeforeSave(formData, originalData) {
); );
} }
async function onKeyup(evt) { async function onKeyup(evt) {
if (evt.key === 'Enter' && !('prevent-submit' in attrs)) { if (evt.key === 'Enter' && !$props.preventSubmit) {
const input = evt.target; const input = evt.target;
if (input.type == 'textarea' && evt.shiftKey) { if (input.type == 'textarea' && evt.shiftKey) {
let { selectionStart, selectionEnd } = input; let { selectionStart, selectionEnd } = input;
@ -330,6 +334,7 @@ defineExpose({
<template> <template>
<div class="column items-center full-width"> <div class="column items-center full-width">
<QForm <QForm
v-on="$attrs"
ref="myForm" ref="myForm"
v-if="formData" v-if="formData"
@submit.prevent="save" @submit.prevent="save"

View File

@ -23,7 +23,7 @@ describe('CrudModel', () => {
dataKey: 'crudModelKey', dataKey: 'crudModelKey',
model: 'crudModel', model: 'crudModel',
url: 'crudModelUrl', url: 'crudModelUrl',
saveFn: '', saveFn: vi.fn(),
}, },
}); });
wrapper = wrapper.wrapper; wrapper = wrapper.wrapper;
@ -225,7 +225,7 @@ describe('CrudModel', () => {
expect(vm.isLoading).toBe(false); expect(vm.isLoading).toBe(false);
expect(vm.hasChanges).toBe(false); expect(vm.hasChanges).toBe(false);
await wrapper.setProps({ saveFn: '' }); await wrapper.setProps({ saveFn: null });
}); });
it("should use default url if there's not saveFn", async () => { it("should use default url if there's not saveFn", async () => {

View File

@ -152,10 +152,22 @@ const value = computed({
}, },
}); });
const arrayDataKey =
$props.dataKey ??
($props.url?.length > 0 ? $props.url : ($attrs.name ?? $attrs.label));
const arrayData = useArrayData(arrayDataKey, {
url: $props.url,
searchUrl: false,
mapKey: $attrs['map-key'],
});
const computedSortBy = computed(() => { const computedSortBy = computed(() => {
return $props.sortBy || $props.optionLabel + ' ASC'; return $props.sortBy || $props.optionLabel + ' ASC';
}); });
const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
watch(options, (newValue) => { watch(options, (newValue) => {
setOptions(newValue); setOptions(newValue);
}); });
@ -174,16 +186,6 @@ onMounted(() => {
if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300); if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300);
}); });
const arrayDataKey =
$props.dataKey ??
($props.url?.length > 0 ? $props.url : ($attrs.name ?? $attrs.label));
const arrayData = useArrayData(arrayDataKey, {
url: $props.url,
searchUrl: false,
mapKey: $attrs['map-key'],
});
function findKeyInOptions() { function findKeyInOptions() {
if (!$props.options) return; if (!$props.options) return;
return filter($props.modelValue, $props.options)?.length; return filter($props.modelValue, $props.options)?.length;
@ -287,8 +289,6 @@ function nullishToTrue(value) {
return value ?? true; return value ?? true;
} }
const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
async function onScroll({ to, direction, from, index }) { async function onScroll({ to, direction, from, index }) {
const lastIndex = myOptions.value.length - 1; const lastIndex = myOptions.value.length - 1;

View File

@ -41,10 +41,12 @@ describe('VnDms', () => {
companyFk: 2, companyFk: 2,
dmsTypeFk: 3, dmsTypeFk: 3,
description: 'This is a test description', description: 'This is a test description',
files: { files: [
name: 'example.txt', {
content: new Blob(['file content'], { type: 'text/plain' }), name: 'example.txt',
}, content: new Blob(['file content'], { type: 'text/plain' }),
},
],
}; };
const expectedBody = { const expectedBody = {

View File

@ -90,8 +90,10 @@ describe('VnLog', () => {
vm = createWrapper(VnLog, { vm = createWrapper(VnLog, {
global: { global: {
stubs: [], stubs: ['FetchData', 'vue-i18n'],
mocks: {}, mocks: {
fetch: vi.fn(),
},
}, },
propsData: { propsData: {
model: 'Claim', model: 'Claim',

View File

@ -12,7 +12,7 @@ const props = defineProps({
default: '', default: '',
}, },
filter: { filter: {
type: [String, Object], type: Object,
default: null, default: null,
}, },
userFilter: { userFilter: {

View File

@ -69,7 +69,7 @@ const props = defineProps({
default: null, default: null,
}, },
searchUrl: { searchUrl: {
type: String, type: [String, Boolean],
default: null, default: null,
}, },
disableInfiniteScroll: { disableInfiniteScroll: {

View File

@ -31,7 +31,7 @@ describe('CardSummary', () => {
propsData: { propsData: {
dataKey: 'cardSummaryKey', dataKey: 'cardSummaryKey',
url: 'cardSummaryUrl', url: 'cardSummaryUrl',
filter: 'cardFilter', filter: { key: 'cardFilter' },
}, },
}); });
vm = wrapper.vm; vm = wrapper.vm;
@ -55,7 +55,7 @@ describe('CardSummary', () => {
it('should set correct props to the store', () => { it('should set correct props to the store', () => {
expect(vm.store.url).toEqual('cardSummaryUrl'); expect(vm.store.url).toEqual('cardSummaryUrl');
expect(vm.store.filter).toEqual('cardFilter'); expect(vm.store.filter).toEqual({ key: 'cardFilter' });
}); });
it('should respond to prop changes and refetch data', async () => { it('should respond to prop changes and refetch data', async () => {

View File

@ -4,6 +4,8 @@ import { useArrayData } from 'composables/useArrayData';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import * as vueRouter from 'vue-router'; import * as vueRouter from 'vue-router';
import { setActivePinia, createPinia } from 'pinia'; import { setActivePinia, createPinia } from 'pinia';
import { defineComponent, h } from 'vue';
import { mount } from '@vue/test-utils';
describe('useArrayData', () => { describe('useArrayData', () => {
const filter = '{"limit":20,"skip":0}'; const filter = '{"limit":20,"skip":0}';
@ -43,7 +45,7 @@ describe('useArrayData', () => {
it('should fetch and replace url with new params', async () => { it('should fetch and replace url with new params', async () => {
vi.spyOn(axios, 'get').mockResolvedValueOnce({ data: [] }); vi.spyOn(axios, 'get').mockResolvedValueOnce({ data: [] });
const arrayData = useArrayData('ArrayData', { const arrayData = mountArrayData('ArrayData', {
url: 'mockUrl', url: 'mockUrl',
searchUrl: 'params', searchUrl: 'params',
}); });
@ -72,7 +74,7 @@ describe('useArrayData', () => {
data: [{ id: 1 }], data: [{ id: 1 }],
}); });
const arrayData = useArrayData('ArrayData', { const arrayData = mountArrayData('ArrayData', {
url: 'mockUrl', url: 'mockUrl',
navigate: {}, navigate: {},
}); });
@ -94,7 +96,7 @@ describe('useArrayData', () => {
], ],
}); });
const arrayData = useArrayData('ArrayData', { const arrayData = mountArrayData('ArrayData', {
url: 'mockUrl', url: 'mockUrl',
oneRecord: true, oneRecord: true,
}); });
@ -107,3 +109,17 @@ describe('useArrayData', () => {
}); });
}); });
}); });
function mountArrayData(...args) {
let arrayData;
const TestComponent = defineComponent({
setup() {
arrayData = useArrayData(...args);
return () => h('div');
},
});
const asd = mount(TestComponent);
return arrayData;
}

View File

@ -64,88 +64,84 @@ describe('session', () => {
}); });
}); });
describe( describe('login', () => {
'login', const expectedUser = {
() => { id: 999,
const expectedUser = { name: `T'Challa`,
id: 999, nickname: 'Black Panther',
name: `T'Challa`, lang: 'en',
nickname: 'Black Panther', userConfig: {
lang: 'en', darkMode: false,
userConfig: { },
darkMode: false, worker: { department: { departmentFk: 155 } },
};
const rolesData = [
{
role: {
name: 'salesPerson',
}, },
worker: { department: { departmentFk: 155 } }, },
}; {
const rolesData = [ role: {
{ name: 'admin',
role: {
name: 'salesPerson',
},
}, },
{ },
role: { ];
name: 'admin', beforeEach(() => {
}, vi.spyOn(axios, 'get').mockImplementation((url) => {
}, if (url === 'VnUsers/acls') return Promise.resolve({ data: [] });
]; return Promise.resolve({
beforeEach(() => { data: { roles: rolesData, user: expectedUser },
vi.spyOn(axios, 'get').mockImplementation((url) => {
if (url === 'VnUsers/acls') return Promise.resolve({ data: [] });
return Promise.resolve({
data: { roles: rolesData, user: expectedUser },
});
}); });
}); });
});
it('should fetch the user roles and then set token in the sessionStorage', async () => { it('should fetch the user roles and then set token in the sessionStorage', async () => {
const expectedRoles = ['salesPerson', 'admin']; const expectedRoles = ['salesPerson', 'admin'];
const expectedToken = 'mySessionToken'; const expectedToken = 'mySessionToken';
const expectedTokenMultimedia = 'mySessionTokenMultimedia'; const expectedTokenMultimedia = 'mySessionTokenMultimedia';
const keepLogin = false; const keepLogin = false;
await session.login({ await session.login({
token: expectedToken, token: expectedToken,
tokenMultimedia: expectedTokenMultimedia, tokenMultimedia: expectedTokenMultimedia,
keepLogin, keepLogin,
});
const roles = state.getRoles();
const localToken = localStorage.getItem('token');
const sessionToken = sessionStorage.getItem('token');
expect(roles.value).toEqual(expectedRoles);
expect(localToken).toBeNull();
expect(sessionToken).toEqual(expectedToken);
await session.destroy(); // this clears token and user for any other test
}); });
it('should fetch the user roles and then set token in the localStorage', async () => { const roles = state.getRoles();
const expectedRoles = ['salesPerson', 'admin']; const localToken = localStorage.getItem('token');
const expectedToken = 'myLocalToken'; const sessionToken = sessionStorage.getItem('token');
const expectedTokenMultimedia = 'myLocalTokenMultimedia';
const keepLogin = true;
await session.login({ expect(roles.value).toEqual(expectedRoles);
token: expectedToken, expect(localToken).toBeNull();
tokenMultimedia: expectedTokenMultimedia, expect(sessionToken).toEqual(expectedToken);
keepLogin,
});
const roles = state.getRoles(); await session.destroy(); // this clears token and user for any other test
const localToken = localStorage.getItem('token'); });
const sessionToken = sessionStorage.getItem('token');
expect(roles.value).toEqual(expectedRoles); it('should fetch the user roles and then set token in the localStorage', async () => {
expect(localToken).toEqual(expectedToken); const expectedRoles = ['salesPerson', 'admin'];
expect(sessionToken).toBeNull(); const expectedToken = 'myLocalToken';
const expectedTokenMultimedia = 'myLocalTokenMultimedia';
const keepLogin = true;
await session.destroy(); // this clears token and user for any other test await session.login({
token: expectedToken,
tokenMultimedia: expectedTokenMultimedia,
keepLogin,
}); });
},
{}, const roles = state.getRoles();
); const localToken = localStorage.getItem('token');
const sessionToken = sessionStorage.getItem('token');
expect(roles.value).toEqual(expectedRoles);
expect(localToken).toEqual(expectedToken);
expect(sessionToken).toBeNull();
await session.destroy(); // this clears token and user for any other test
});
});
describe('RenewToken', () => { describe('RenewToken', () => {
const expectedToken = 'myToken'; const expectedToken = 'myToken';

View File

@ -6,26 +6,37 @@ import { buildFilter } from 'filters/filterPanel';
import { isDialogOpened } from 'src/filters'; import { isDialogOpened } from 'src/filters';
export function useArrayData(key, userOptions) { export function useArrayData(key, userOptions) {
key ??= useRoute().meta.moduleName; let route = null;
let router = null;
// Si no hay key, intentamos obtenerla del route
if (!key) {
key = initialRoute?.meta?.moduleName;
route = initialRoute;
router = initialRouter;
}
if (!key) throw new Error('ArrayData: A key is required to use this composable'); if (!key) throw new Error('ArrayData: A key is required to use this composable');
const arrayDataStore = useArrayDataStore(); // Move inside function const arrayDataStore = useArrayDataStore(); // Move inside function
if (!arrayDataStore.get(key)) arrayDataStore.set(key); if (!arrayDataStore.get(key)) arrayDataStore.set(key);
const store = arrayDataStore.get(key); const store = arrayDataStore.get(key);
const route = useRoute();
const router = useRouter();
let canceller = null; let canceller = null;
const { route: initialRoute, router: initialRouter } = (() => {
if (!route) route = useRoute();
if (!router) router = useRouter();
return { route, router };
})();
onMounted(() => { onMounted(() => {
setOptions(); setOptions();
reset(['skip']); reset(['skip']);
route = initialRoute;
const query = route.query; router = initialRouter;
const searchUrl = store.searchUrl; const searchUrl = store.searchUrl;
if (query[searchUrl]) { const query = route.query[searchUrl];
const params = JSON.parse(query[searchUrl]); if (query) {
const params = JSON.parse(query);
const filter = const filter =
params?.filter && typeof params?.filter == 'object' params?.filter && typeof params?.filter == 'object'
? params?.filter ? params?.filter

View File

@ -4,6 +4,7 @@ import { createTestingPinia } from '@pinia/testing';
import { vi } from 'vitest'; import { vi } from 'vitest';
import { i18n } from 'src/boot/i18n'; import { i18n } from 'src/boot/i18n';
import { Notify, Dialog } from 'quasar'; import { Notify, Dialog } from 'quasar';
import keyShortcut from 'src/boot/keyShortcut';
import * as useValidator from 'src/composables/useValidator'; import * as useValidator from 'src/composables/useValidator';
installQuasarPlugin({ installQuasarPlugin({
@ -26,8 +27,16 @@ vi.mock('vue', async (importOriginal) => {
} }
return actual.inject(key); return actual.inject(key);
}), }),
onMounted: vi.fn((fn) => (fn && typeof fn === 'function' ? fn() : undefined)),
onBeforeMount: vi.fn((fn) => (fn && typeof fn === 'function' ? fn() : undefined)),
onUpdated: vi.fn((fn) => (fn && typeof fn === 'function' ? fn() : undefined)),
onUnmounted: vi.fn((fn) => (fn && typeof fn === 'function' ? fn() : undefined)),
onBeforeUnmount: vi.fn((fn) =>
fn && typeof fn === 'function' ? fn() : undefined,
),
}; };
}); });
vi.mock('vue-router', () => ({ vi.mock('vue-router', () => ({
useRouter: () => ({ useRouter: () => ({
push: mockPush, push: mockPush,

View File

@ -1,5 +1,26 @@
// This file will be run before each test file, don't delete or vitest will not work. import { afterAll, beforeAll, vi } from 'vitest';
import { vi } from 'vitest';
let vueWarnings = [];
const originalConsoleWarn = console.warn;
beforeAll(() => {
console.warn = (...args) => {
vueWarnings.push(args.join(' '));
};
});
afterEach(() => {
if (vueWarnings.length > 0) {
const allWarnings = vueWarnings.join('\n');
vueWarnings = [];
throw new Error(`Vue warnings detected during test:\n${allWarnings}`);
}
});
afterAll(() => {
console.warn = originalConsoleWarn;
});
vi.mock('axios'); vi.mock('axios');
vi.mock('vue-router', () => ({ vi.mock('vue-router', () => ({