From 3a04fc5029f694b6073de578d6276e4f516f6531 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 18 Oct 2024 13:51:41 +0200 Subject: [PATCH] feat: refs #7220 ok --- cypress.config.js | 19 +++- quasar.config.js | 1 + src/components/FormModel.vue | 2 +- src/pages/Claim/Card/ClaimLines.vue | 26 +++-- .../components/CreateBankEntityForm.spec.js | 81 ++++++++++++- test/cypress/components/FetchData.spec.js | 67 +++++------ test/cypress/support/component.js | 106 +++++++++++++++++- 7 files changed, 242 insertions(+), 60 deletions(-) diff --git a/cypress.config.js b/cypress.config.js index c8c62c8faf..b30df2b3d8 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -1,4 +1,7 @@ const { defineConfig } = require('cypress'); +const { + injectQuasarDevServerConfig, +} = require('@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server'); module.exports = defineConfig({ e2e: { @@ -18,6 +21,11 @@ module.exports = defineConfig({ }, setupNodeEvents(on, config) { // implement node event listeners here + on('after:spec', (results) => { + // `results` is the tests results + console.error('results: ', results); + cy.exec('cd ../salix && gulp docker'); + }); }, }, @@ -25,9 +33,14 @@ module.exports = defineConfig({ indexHtmlFile: 'test/cypress/support/component-index.html', supportFile: 'test/cypress/support/component.js', specPattern: 'test/cypress/components/**/*.spec.js', - devServer: { - framework: 'vue', - bundler: 'vite', + devServer: injectQuasarDevServerConfig(), + setupNodeEvents(on, config) { + // implement node event listeners here + on('after:spec', (results) => { + // `results` is the tests results + console.error('results: ', results); + cy.exec('cd ../salix && gulp docker'); + }); }, }, }); diff --git a/quasar.config.js b/quasar.config.js index b59c62eeb1..68d1136228 100644 --- a/quasar.config.js +++ b/quasar.config.js @@ -87,6 +87,7 @@ module.exports = configure(function (/* ctx */) { alias: { composables: path.join(__dirname, './src/composables'), filters: path.join(__dirname, './src/filters'), + components: path.join(__dirname, './src/components'), }, vitePlugins: [ diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index a8bdc2368d..47554330af 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -363,7 +363,7 @@ defineExpose({ diff --git a/src/pages/Claim/Card/ClaimLines.vue b/src/pages/Claim/Card/ClaimLines.vue index 3954130340..1db57567b5 100644 --- a/src/pages/Claim/Card/ClaimLines.vue +++ b/src/pages/Claim/Card/ClaimLines.vue @@ -5,11 +5,11 @@ import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; import { useRoute } from 'vue-router'; import { useStateStore } from 'stores/useStateStore'; -import { useArrayData } from 'src/composables/useArrayData'; +import { useArrayData } from 'composables/useArrayData'; import { toDate, toCurrency, toPercentage } from 'filters/index'; -import CrudModel from 'src/components/CrudModel.vue'; -import FetchData from 'src/components/FetchData.vue'; -import VnDiscount from 'src/components/common/vnDiscount.vue'; +import CrudModel from 'components/CrudModel.vue'; +import FetchData from 'components/FetchData.vue'; +import VnDiscount from 'components/common/vnDiscount.vue'; import ClaimLinesImport from './ClaimLinesImport.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; @@ -20,7 +20,7 @@ const { t } = useI18n(); const stateStore = useStateStore(); const arrayData = useArrayData('ClaimLines'); const store = arrayData.store; - +const itemDescriptorProxy = ref(null); const claimFilter = { fields: ['ticketFk'], }; @@ -221,10 +221,12 @@ async function saveWhenHasChanges() { - + en: You are about to remove {count} rows: ' You are about to remove {count} row | diff --git a/test/cypress/components/CreateBankEntityForm.spec.js b/test/cypress/components/CreateBankEntityForm.spec.js index f639799e38..c4adc76dc2 100644 --- a/test/cypress/components/CreateBankEntityForm.spec.js +++ b/test/cypress/components/CreateBankEntityForm.spec.js @@ -1,8 +1,83 @@ +import axios from 'axios'; 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 vueRouter from 'vue-router'; describe('', () => { - it('TODO: boilerplate', () => { - // see: https://on.cypress.io/mounting-vue - cy.createWrapper(CreateBankEntityForm); + const mockApiResponse = { results: [{ id: 1, name: 'Test' }] }; + const arrayDataStore = useArrayDataStore(); + const mockStoreData = { filter: {}, userFilter: {}, userParams: {}, url: 'mockUrl' }; + + 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(arrayData).callsFake(() => ({ + userParams: {}, + userFilter: {}, + order: {}, + searchUrl: 'searchUrl', + })); + // cy.stub(vueRouter, 'useRouter').callsFake(() => ({ + // push: () => {}, + // replace: () => {}, + // currentRoute: { + // value: { + // params: { + // id: 1, + // }, + // meta: { moduleName: 'mockName' }, + // matched: [{ path: 'mockName/list' }], + // }, + // }, + // })); + }); + beforeEach(() => { + // Stub del método get del store + // cy.spy(useRouter(), 'replace'); + // cy.spy(useRouter(), 'push'); + }); + + it('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) => { + if (url === 'Countries') { + return Promise.resolve({ data: mockApiResponse }); + } + // Si la URL no coincide, llama al método original + return axios.get.wrappedMethod(url, params); + }) + .as('axiosStub'); + + const onFetchSpy = cy.spy().as('onFetchSpy'); + + cy.createWrapper(CreateBankEntityForm, { + props: { + showEntityField: true, + }, + attrs: { + onFetch: onFetchSpy, + }, + }); + + cy.get('@axiosStub').should((spy) => { + expect(spy).to.have.been.calledWith('Countries'); + }); + + cy.get('@onFetchSpy').should((spy) => { + expect(spy).to.have.been.calledWith(mockApiResponse); + }); + + // Verifica que los datos emitidos por el hijo son manejados por el padre + // cy.get('p').should('contain', 'Datos recibidos:'); // Verifica que los datos se muestran en el DOM + // cy.get('p').should('contain', 'Test'); // Verifica que el contenido de los datos es correcto }); }); diff --git a/test/cypress/components/FetchData.spec.js b/test/cypress/components/FetchData.spec.js index c0819f30ec..de22cb886b 100644 --- a/test/cypress/components/FetchData.spec.js +++ b/test/cypress/components/FetchData.spec.js @@ -1,63 +1,46 @@ +import axios from 'axios'; import FetchData from 'src/components/FetchData.vue'; describe.only('', () => { const mockApiResponse = { results: [{ id: 1, name: 'Test' }] }; - it('TODO: boilerplate', () => { + const url = '/api/Schemas/modelinfo'; + it('Autoload: true', () => { // see: https://on.cypress.io/mounting-vue - let _wrapper = null; + cy.stub(axios, 'get').resolves({ data: mockApiResponse }).as('axiosStub'); const onFetchSpy = cy.spy().as('onFetchSpy'); cy.createWrapper(FetchData, { props: { autoLoad: true, - url: 'http://localhost:9000/api/Schemas/modelinfo', + url, }, emits: { onFetch: onFetchSpy }, }); - cy.get('@onFetchSpy').should('have.been.called'); - // Intercepta la petición de axios para simular una respuesta - // cy.intercept('http://localhost:9000/api/Schemas/modelinfo', { - // statusCode: 200, - // body: mockApiResponse, - // }).as('dataFetched'); // Alias para poder esperar en el test - - // Verifica que la petición fue realizada automáticamente y la data es correcta - // cy.wait('@dataFetched').then(({ request, response }) => { - // expect(response.body).to.deep.equal(mockApiResponse); // Verifica la respuesta - // }); - // debugger; - - // Verifica que el evento onFetch fue emitido con los datos correctos + cy.get('@axiosStub').should((spy) => { + expect(spy).to.have.been.calledWith('/api/Schemas/modelinfo'); + const [url, params] = spy.getCall(0).args; + expect(url).to.equal('/api/Schemas/modelinfo'); + expect(params).to.deep.equal({ + params: { + filter: '{}', + }, + }); + }); + /*cy.get('@onFetchSpy').should('have.been.calledWith', mockApiResponse);*/ + cy.get('@onFetchSpy').should((spy) => { + expect(spy).to.have.been.calledWith(mockApiResponse); + }); }); - xit('TODO: boilerplate2', () => { + it('Autoload: false', () => { // see: https://on.cypress.io/mounting-vue + cy.stub(axios, 'get').resolves({ data: mockApiResponse }).as('axiosStub'); + const onFetchSpy = cy.spy().as('onFetchSpy'); cy.createWrapper(FetchData, { props: { autoLoad: false, - url: '/api/test-url', // La URL que va a usar en el fetch + url, }, + emits: { onFetch: onFetchSpy }, }); - // Intercepta la petición de axios para simular una respuesta - cy.intercept('GET', '**/api/test-url', { - statusCode: 200, - body: mockApiResponse, - }).as('fetchData'); // Alias para poder esperar en el test - // Verifica que no se hizo ninguna petición al montar el componente - cy.get('@fetchDataManual').should('not.exist'); - - // Llama manualmente al método fetch desde el componente expuesto - cy.window().then((win) => { - win.$vm.fetch(); // Llama al método fetch - }); - - // Verifica que la petición se ejecutó manualmente y la data es correcta - cy.wait('@fetchDataManual').then(({ request, response }) => { - expect(response.body).to.deep.equal(mockApiResponse); - }); - - // Verifica que el evento onFetch fue emitido con los datos correctos - cy.wrap(Cypress.vueWrapper.emitted('onFetch')[0][0]).should( - 'deep.equal', - mockApiResponse - ); + cy.get('@onFetchSpy').should('not.to.have.been.called'); }); }); diff --git a/test/cypress/support/component.js b/test/cypress/support/component.js index f3ca76ed1e..65e1bc61d3 100644 --- a/test/cypress/support/component.js +++ b/test/cypress/support/component.js @@ -17,6 +17,19 @@ function createWrapper(component, options) { const defaultOptions = { global: { plugins: [Quasar, i18n, pinia], + stubs: [ + 'router-link', + 'router-view', + 'vue-router', + 'vnPaginate', + 'useState', + 'arrayData', + 'arrayDataStore', + 'useArrayData', + 'useArrayDataStore', + 'useStateStore', + 'vue-i18n', + ], }, mocks: { t: (tKey) => tKey, @@ -33,7 +46,19 @@ function createWrapper(component, options) { mountOptions.global.plugins = defaultOptions.global.plugins; } } - + // create router if one is not provided + if (!options.router) { + options.router = createRouter({ + routes: [], + history: createMemoryHistory(), + }); + } + mountOptions.global.plugins.push({ + install(app) { + app.use(i18n); + app.use(options.router); + }, + }); const wrapper = mount(component, mountOptions); const vm = wrapper.vm; @@ -48,3 +73,82 @@ function createWrapper(component, options) { // } Cypress.Commands.add('createWrapper', createWrapper); + +Cypress.Commands.add('_vnMount', (component, options = {}) => { + const globalConfig = { + global: { + stubs: ['router-view', 'vue-i18n'], + plugins: [Quasar, i18n, pinia], + mocks: { t: (key) => key }, + }, + }; + options.global = options.global || {}; + // options.global.stubs = options.global.stubs || {}; + // options.global.stubs.transition = false; + // options.global.components = options.global.components || {}; + options.global.plugins = options.global.plugins || []; + + // Use store passed in from options, or initialize a new one + // const { /* store = getStore(), */ ...mountOptions } = options; + + // Add plugins here + options.global.plugins.push({ + install(app) { + app.use(i18n); + }, + }); + // Spy para capturar el evento onFetch + + // Agregar el spy a los atributos del componente + const finalOptions = { + ...globalConfig, + ...options, + attrs: { + ...options.attrs, + }, + }; + + console.log(finalOptions); + const cmp = mount(component, finalOptions); + return cmp; +}); +import 'quasar/dist/quasar.css'; +import { createRouter } from 'vue-router'; +import { createMemoryHistory } from 'vue-router'; +Cypress.Commands.add('vue', () => { + return cy.wrap(Cypress.vueWrapper); +}); +Cypress.Commands.add('_mount', (component, options) => { + // Wrap any parent components needed + // ie: return mount({component}, options) + options.global = options.global || {}; + options.global.plugins = options.global.plugins || []; + options.global.plugins.push([Quasar, {}]); + options.global.plugins.push([i18n]); + + return mount(component, options); +}); + +Cypress.Commands.add('login', (user) => { + //cy.visit('/#/login'); + cy.request({ + method: 'POST', + url: 'http://localhost:9000/api/accounts/login', + + body: { + user: user, + password: 'nightmare', + }, + }).then((response) => { + window.localStorage.setItem('token', response.body.token); + cy.request({ + method: 'GET', + url: 'http://localhost:9000/api/VnUsers/ShareToken', + headers: { + Authorization: window.localStorage.getItem('token'), + }, + }).then(({ body }) => { + window.localStorage.setItem('tokenMultimedia', body.multimediaToken.id); + }); + }); +});