0
0
Fork 0

feat: refs #7220 ok FormModel

This commit is contained in:
Javier Segarra 2024-10-20 01:46:20 +02:00
parent 3a04fc5029
commit e49a91255f
6 changed files with 339 additions and 29 deletions

View File

@ -4,6 +4,9 @@ const {
} = require('@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server');
module.exports = defineConfig({
env: {
baseUrl: 'http://localhost:9000/',
},
e2e: {
baseUrl: 'http://localhost:9000/',
experimentalStudio: true,
@ -33,7 +36,10 @@ module.exports = defineConfig({
indexHtmlFile: 'test/cypress/support/component-index.html',
supportFile: 'test/cypress/support/component.js',
specPattern: 'test/cypress/components/**/*.spec.js',
devServer: injectQuasarDevServerConfig(),
devServer: {
framework: 'quasar',
bundler: 'vite',
},
setupNodeEvents(on, config) {
// implement node event listeners here
on('after:spec', (results) => {

View File

@ -1,8 +1,9 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useArrayDataStore = defineStore('arrayDataStore', () => {
const state = ref({});
const defaultOpts = {
filter: {},
userFilter: {},
@ -24,7 +25,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
}
function set(key) {
state.value[key] = getDefaultState();
state.value[key] = getDefaultState(); // Ahora asigna el estado a la clave 'key'
}
function clear(key) {

View File

@ -0,0 +1,22 @@
import { setActivePinia, createPinia } from 'pinia';
import { useArrayDataStore } from './useArrayDataStore';
describe('useArrayDataStore', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('should initialize isLoading to false', () => {
const store = useArrayDataStore();
store.set('testKey');
expect(store.get('testKey').isLoading).toBe(false);
});
it('should reset isLoading to false', () => {
const store = useArrayDataStore();
store.set('testKey');
store.get('testKey').isLoading = true;
store.reset('testKey', ['isLoading']);
expect(store.get('testKey').isLoading).toBe(false);
});
});

View File

@ -1,31 +1,34 @@
import { createTestingPinia } from '@pinia/testing';
import axios from 'axios';
import { setActivePinia } from 'pinia';
import { createPinia } from 'pinia';
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
import { useArrayData } from 'src/composables/useArrayData';
import { useArrayDataStore } from 'src/stores/useArrayDataStore';
// import { useRouter } from 'vue-router';
import { useRouter } from 'vue-router';
// import vueRouter from 'vue-router';
describe('<CreateBankEntityForm />', () => {
const mockApiResponse = { results: [{ id: 1, name: 'Test' }] };
const arrayDataStore = useArrayDataStore();
// const arrayDataStore = useArrayDataStore();
const mockStoreData = { filter: {}, userFilter: {}, userParams: {}, url: 'mockUrl' };
let store, arrayData;
before(() => {
cy.login('developer');
// cy.stub(arrayDataStore, 'get').callsFake(() => 'asd');
cy.stub(arrayDataStore, 'get')
.callsFake((e, fn) => (e = fn))
.as('update');
const arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
// cy.stub(arrayDataStore, 'get')
// .callsFake((e, fn) => (e = fn))
// .as('update');
// const arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
cy.stub(arrayData).callsFake(() => ({
userParams: {},
userFilter: {},
order: {},
searchUrl: 'searchUrl',
}));
// cy.stub(vueRouter, 'useRouter').callsFake(() => ({
// cy.stub(arrayData).callsFake(() => ({
// userParams: {},
// userFilter: {},
// order: {},
// searchUrl: 'searchUrl',
// }));
// cy.stub(vueRouter).callsFake(() => ({
// push: () => {},
// replace: () => {},
// currentRoute: {
@ -38,14 +41,69 @@ describe('<CreateBankEntityForm />', () => {
// },
// },
// }));
Cypress.config('defaultCommandTimeout', 500);
// const spy = cy.spy();
// createTestingPinia({
// createSpy: () => spy,
// });
// // one way:
// store = useArrayDataStore();
// // another way with the same error:
// useArrayDataStore(
// createTestingPinia({
// createSpy: () => spy,
// initialState: {
// state: { ArrayData: cy.spy() },
// },
// })
// );
// cy.stub(useArrayDataStore, 'get').callsFake(() => cy.spy());
// cy.stub(useArrayData, 'get').callsFake(() => store);
// arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
});
beforeEach(() => {
// cy._mount(CreateBankEntityForm, {
// global: {
// plugins: [store],
// },
// });
// Stub del método get del store
// cy.spy(useRouter(), 'replace');
// cy.spy(useRouter(), 'push');
});
it('should intercept axios.get for a specific route', () => {
// Configura Pinia y la store
const pinia = createPinia();
setActivePinia(pinia);
const arrayDataStore = useArrayDataStore();
cy.stub(arrayDataStore, 'get').returns(mockStoreData).as('getStub');
cy.stub(arrayData, 'arrayDataStore').callsFake(() => store);
cy.createWrapper(CreateBankEntityForm);
// Obtén la instancia de la store de Pinia
// const store = useArrayDataStore();
// Asegúrate de que el método `set` esté disponible
// Usar cy.stub() para espiar la función set y personalizar su comportamiento
// cy.stub(store, 'set').callsFake(() => {
// console.log('store.set fue llamado');
// // Simular que set se ejecuta correctamente
// store.get('key').data = 'Fake Data';
// });
// expect(store.set).to.be.a('function');
// store.set('key'); // Inicializar el estado con `set`
// store.get('key').data = 'Test Data'; // Simular que tenemos datos
// // Simula que agregamos usuarios a la store
// store.setUsers([
// { id: 1, name: 'John Doe' },
// { id: 2, name: 'Jane Doe' },
// ]);
});
xit('should intercept axios.get for a specific route', () => {
// Intercepta la llamada a axios.get para una ruta específica
cy.stub(axios, 'get')
.callsFake((url, params) => {
@ -58,7 +116,11 @@ describe('<CreateBankEntityForm />', () => {
.as('axiosStub');
const onFetchSpy = cy.spy().as('onFetchSpy');
// Configura Pinia y la store
const pinia = createPinia();
setActivePinia(pinia);
const arrayDataStore = useArrayDataStore();
cy.stub(arrayDataStore, 'get').returns(mockStoreData).as('getStub');
cy.createWrapper(CreateBankEntityForm, {
props: {
showEntityField: true,

View File

@ -1,8 +1,142 @@
import { Notify } from 'quasar';
import FormModel from 'src/components/FormModel.vue';
// import useNotify from 'src/composables/useNotify';
import { useState } from 'src/composables/useState';
import { useStateStore } from 'src/stores/useStateStore';
describe.skip('<FormModel />', () => {
it('TODO: boilerplate', () => {
// see: https://on.cypress.io/mounting-vue
cy.createWrapper(FormModel, { props: {} });
describe('<FormModel />', () => {
let piniaOptions = null;
let saveSpy, notifySpy, component, wrapper;
beforeEach(() => {
piniaOptions = {
stubActions: false,
createSpy: cy.spy, // Use Cypress spy function
};
const state = useState();
const stateStore = useStateStore();
cy.stub(stateStore, 'isSubToolbarShown').returns(true).as('isSubToolbarShown');
state.set('testModel', { name: 'Test', age: 30 });
const props = {
url: '',
model: 'testModel',
filter: {},
urlUpdate: '',
urlCreate: '/api/test/create',
defaultActions: true,
defaultButtons: {},
autoLoad: false,
formInitialData: {},
observeFormChanges: true,
mapper: null,
clearStoreOnUnmount: true,
saveFn: null,
goTo: '',
reload: false,
defaultTrim: true,
};
cy.mount(FormModel, {
piniaOptions,
props,
slots: {
form: `<template #form="{ data, validate, filter }">
<input data-cy="name" v-model="data.name" label="name" />
<input data-cy="age" v-model="data.age" label="age" type="number" />
<button type="submit">Save</button>
</template>`,
moreActions: `<template #moreActions>
<button @click="customAction">Custom Action</button>
</template>`,
},
}).then(({ component: cmp, wrapper: wpr }) => {
component = cmp;
wrapper = wpr;
saveSpy = cy.spy(component, 'save').as('saveSpy');
notifySpy = cy.spy(Notify, 'create').as('notifySpy');
});
});
it('should mount the component', () => {
cy.get('#formModel').should('exist');
});
it('should call the save method when the save button is clicked without changes', () => {
cy.get('#formModel').should('exist');
cy.get('button').contains('Save').click();
cy.get('@saveSpy').should('not.have.been.called');
cy.get('@notifySpy').should((spy) => {
expect(spy).to.have.been.calledWith({
message: 'No changes to save',
type: 'negative',
icon: 'error',
});
});
});
it('should call the save method when the save button is clicked with changes', () => {
cy.get('#formModel').should('exist');
cy.get('[data-cy="name"]').type('John Doe');
cy.get('button').contains('Save').click();
cy.get('@saveSpy').should('not.have.been.called');
cy.get('@notifySpy').should((spy) => {
const [args] = spy.getCall(0)?.args || [];
expect(args.type).to.equal('negative');
expect(args.icon).to.equal('error');
expect(args.message).not.to.equal('No changes to save');
});
});
/*
it('should display the confirmation dialog on route leave with unsaved changes', () => {
// Simulate form change
cy.get('#formModel').then((form) => {
form[0].__vue__.formData.name = 'Changed';
});
// Attempt to navigate away
cy.get('.q-dialog').should('be.visible');
cy.get('.q-dialog .q-dialog__title').should(
'contain',
'globals.unsavedPopup.title'
);
});
it('should call save method on form submit', async () => {
const saveSpy = cy.spy(formModel.value, 'save');
await formModel.value.$refs.myForm.trigger('submit');
expect(saveSpy).to.have.been.called;
});
it('should reset the form data', async () => {
formModel.value.formData.name = 'Changed';
await formModel.value.reset();
expect(formModel.value.formData.name).toBe('Test');
});
it('should show loading indicator when saving', async () => {
formModel.value.isLoading = true;
await nextTick();
expect(wrapper.findComponent({ name: 'QInnerLoading' }).props('showing')).toBe(true);
});
it('should render form slot content', () => {
expect(wrapper.find('input').exists()).toBe(true);
});
it('should update form data through slot inputs', async () => {
const nameInput = wrapper.find('input[type="text"]');
const ageInput = wrapper.find('input[type="number"]');
await nameInput.setValue('Updated Name');
await ageInput.setValue(25);
expect(formModel.value.formData.name).toBe('Updated Name');
expect(formModel.value.formData.age).toBe(25);
});
it('should render moreActions slot content', () => {
expect(wrapper.find('button').exists()).toBe(true);
});
it('should call custom action on button click', async () => {
const customActionSpy = cy.spy(formModel.value, 'customAction');
await wrapper.find('button').trigger('click');
expect(customActionSpy).to.have.been.called;
});*/
});

View File

@ -1,9 +1,13 @@
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-e2e-cypress';
import { createTestingPinia } from '@pinia/testing';
import { mount } from 'cypress/vue';
import { i18n } from 'src/boot/i18n';
import { Quasar } from 'quasar';
import { createPinia } from 'pinia';
const pinia = createTestingPinia({ createSpy: () => {}, stubActions: false });
import axios from 'axios';
installQuasarPlugin({ plugins: { Dialog, Notify } });
// setActivePinia(pinia);
// // Run this code before each *test*.
// beforeEach(() => {
// // New Pinia
@ -13,10 +17,72 @@ const pinia = createTestingPinia({ createSpy: () => {}, stubActions: false });
// setActivePinia(pinia);
// });
function createWrapper(component, options) {
// Crear un comando personalizado para montar componentes con Pinia
// Cypress.Commands.add('mountWithPinia', (component, options = {}) => {
// const pinia = createPinia();
// options.global = options.global || {};
// options.global.plugins = [Quasar, createPinia()]; // Incluye Quasar y Pinia
// return mount(component, options);
// });
// Registrar Quasar y sus componentes
setActivePinia(createPinia()); // Ensure Pinia is active
axios.defaults.baseURL = Cypress.env('baseUrl');
Cypress.Commands.add('mount', (component, options = {}) => {
const pinia = createTestingPinia(options.piniaOptions);
const components = options.global?.components || {};
const router = createRouter({
history: createWebHistory(),
routes: [],
});
const defaultOptions = {
global: {
plugins: [Quasar, i18n, pinia],
mocks: {
t: (tKey) => tKey,
$t: (tKey) => tKey,
$axios: axios, // Añadir axios como un mock global
},
plugins: [
Quasar,
(app) => {
app.use(router);
app.use(i18n);
app.use(pinia);
},
], // Añade Quasar y Pinia como plugins globales
},
};
const mountOptions = Object.assign({}, defaultOptions, options);
if (options.global) {
mountOptions.global.plugins = defaultOptions.global.plugins;
}
return mount(component, mountOptions);
// options.global.plugins.push({
// install(app) {
// app.use(i18n);
// app.use(router);
// // app.use(arrayDataStore);
// },
// });
// const wrapper = mount(component, mountOptions);
// const { vm } = wrapper;
// return wrapper;
});
function createWrapper(component, options = {}) {
const defaultOptions = {
global: {
plugins: [
Quasar,
i18n,
createTestingPinia({
createSpy: () => cy.spy(),
}),
],
stubs: [
'router-link',
'router-view',
@ -36,9 +102,13 @@ function createWrapper(component, options) {
$t: (tKey) => tKey,
},
};
const arrayDataStore = useArrayDataStore();
const mountOptions = Object.assign({}, defaultOptions);
options.global = options?.global || {};
options.global.plugins = options.global?.plugins || [];
// options.global.plugins.push([Quasar, {}]);
// options.global.plugins.push([i18n]);
// options.global.plugins.push(createTestingPinia());
if (options instanceof Object) {
Object.assign(mountOptions, options);
@ -57,8 +127,10 @@ function createWrapper(component, options) {
install(app) {
app.use(i18n);
app.use(options.router);
// app.use(arrayDataStore);
},
});
const wrapper = mount(component, mountOptions);
const vm = wrapper.vm;
@ -77,8 +149,7 @@ Cypress.Commands.add('createWrapper', createWrapper);
Cypress.Commands.add('_vnMount', (component, options = {}) => {
const globalConfig = {
global: {
stubs: ['router-view', 'vue-i18n'],
plugins: [Quasar, i18n, pinia],
plugins: [Quasar, i18n],
mocks: { t: (key) => key },
},
};
@ -115,6 +186,11 @@ Cypress.Commands.add('_vnMount', (component, options = {}) => {
import 'quasar/dist/quasar.css';
import { createRouter } from 'vue-router';
import { createMemoryHistory } from 'vue-router';
import { setActivePinia } from 'pinia';
import { useArrayDataStore } from 'src/stores/useArrayDataStore';
import { createWebHistory } from 'vue-router';
import { Dialog } from 'quasar';
import { Notify } from 'quasar';
Cypress.Commands.add('vue', () => {
return cy.wrap(Cypress.vueWrapper);
});
@ -152,3 +228,12 @@ Cypress.Commands.add('login', (user) => {
});
});
});
// Define el comando personalizado
Cypress.Commands.add('stubUseArrayDataStore', (stubData = {}) => {
const arrayDataStore = useArrayDataStore();
if (arrayDataStore.get.restore) {
arrayDataStore.get.restore();
}
cy.stub(arrayDataStore, 'get').returns(stubData).as('getStub');
});