From 98552bcd9e0f4f03480a66efe17a79dcf971b03b Mon Sep 17 00:00:00 2001
From: alexm <alexm@verdnatura.es>
Date: Mon, 21 Aug 2023 15:14:19 +0200
Subject: [PATCH] refs #5673 test(CrudModel): front and e2e

---
 .eslintrc.js                                  |   2 +-
 cypress/fixtures/example.json                 |   5 +
 cypress/support/commands.js                   |  25 ++++
 src/components/CrudModel.vue                  |   4 +-
 src/components/FormModel.vue                  |   7 +-
 src/pages/Claim/Card/ClaimCard.vue            |  15 ++-
 src/stores/useStateStore.js                   |  11 +-
 .../integration/claimDevelopment.spec.js      | 108 +++++++++++-------
 test/cypress/support/commands.js              |  67 +++++++++++
 .../components/common/CrudModel.spec.js       |  40 +++++--
 test/vitest/helper.js                         |   5 +
 11 files changed, 218 insertions(+), 71 deletions(-)
 create mode 100644 cypress/fixtures/example.json
 create mode 100644 cypress/support/commands.js

diff --git a/.eslintrc.js b/.eslintrc.js
index 09dc09c1e3..c8bdecb1a4 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -64,7 +64,7 @@ module.exports = {
     },
     overrides: [
         {
-            files: ['test/cypress/**/*.spec.{js,ts}'],
+            files: ['test/cypress/**/*.*'],
             extends: [
                 // Add Cypress-specific lint rules, globals and Cypress plugin
                 // See https://github.com/cypress-io/eslint-plugin-cypress#rules
diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json
new file mode 100644
index 0000000000..02e4254378
--- /dev/null
+++ b/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+  "name": "Using fixtures to represent data",
+  "email": "hello@cypress.io",
+  "body": "Fixtures are a great way to mock data for responses to routes"
+}
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
new file mode 100644
index 0000000000..66ea16ef0e
--- /dev/null
+++ b/cypress/support/commands.js
@@ -0,0 +1,25 @@
+// ***********************************************
+// This example commands.js shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
\ No newline at end of file
diff --git a/src/components/CrudModel.vue b/src/components/CrudModel.vue
index 6b8c577a06..280282ffda 100644
--- a/src/components/CrudModel.vue
+++ b/src/components/CrudModel.vue
@@ -285,8 +285,8 @@ function isEmpty(obj) {
         </template>
     </VnPaginate>
     <SkeletonTable v-if="!formData" />
-    <Teleport to="#st-actions" v-if="stateStore.isSubToolbarShown()">
-        <QBtnGroup push class="q-gutter-x-sm">
+    <Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
+        <QBtnGroup push flat class="q-gutter-x-sm">
             <slot name="moreActions" />
             <QBtn
                 :label="tMobile('globals.remove')"
diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue
index 3c05333f54..28a3759b89 100644
--- a/src/components/FormModel.vue
+++ b/src/components/FormModel.vue
@@ -65,7 +65,7 @@ async function fetch() {
     });
 
     state.set($props.model, data);
-    originalData.value = Object.assign({}, data);
+    originalData.value = data && JSON.parse(JSON.stringify(data));
 
     watch(formData.value, () => (hasChanges.value = true));
 
@@ -82,13 +82,14 @@ async function save() {
     isLoading.value = true;
     await axios.patch($props.urlUpdate || $props.url, formData.value);
 
-    originalData.value = formData.value;
+    originalData.value = JSON.parse(JSON.stringify(formData.value));
     hasChanges.value = false;
     isLoading.value = false;
 }
 
 function reset() {
     state.set($props.model, originalData.value);
+    watch(formData.value, () => (hasChanges.value = true));
     hasChanges.value = false;
 }
 // eslint-disable-next-line vue/no-dupe-keys
@@ -120,7 +121,7 @@ watch(formUrl, async () => {
     <QForm v-if="formData" @submit="save" @reset="reset" class="q-pa-md">
         <slot name="form" :data="formData" :validate="validate" :filter="filter"></slot>
     </QForm>
-    <Teleport to="#st-actions" v-if="stateStore.isSubToolbarShown()">
+    <Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
         <div v-if="$props.defaultActions">
             <QBtnGoup push class="q-gutter-x-sm">
                 <slot name="moreActions" />
diff --git a/src/pages/Claim/Card/ClaimCard.vue b/src/pages/Claim/Card/ClaimCard.vue
index 142657ba53..d52b918e18 100644
--- a/src/pages/Claim/Card/ClaimCard.vue
+++ b/src/pages/Claim/Card/ClaimCard.vue
@@ -29,7 +29,6 @@ const claimSections = [
 let salixUrl;
 onMounted(async () => {
     salixUrl = await getUrl(`claim/${entityId.value}`);
-    stateStore.setSubtoolbar();
 });
 </script>
 <template>
@@ -65,13 +64,13 @@ onMounted(async () => {
         </QScrollArea>
     </QDrawer>
     <QPageContainer>
-        <QToolbar class="bg-vn-dark justify-end">
-            <div id="st-data"></div>
-            <QSpace />
-            <div id="st-actions"></div>
-        </QToolbar>
-        <QPage class="q-pa-md">
-            <RouterView></RouterView>
+        <QPage>
+            <QToolbar class="bg-vn-dark justify-end">
+                <div id="st-data"></div>
+                <QSpace />
+                <div id="st-actions"></div>
+            </QToolbar>
+            <div class="q-pa-md"><RouterView></RouterView></div>
         </QPage>
     </QPageContainer>
 </template>
diff --git a/src/stores/useStateStore.js b/src/stores/useStateStore.js
index cf259a7670..74b65e71f0 100644
--- a/src/stores/useStateStore.js
+++ b/src/stores/useStateStore.js
@@ -5,7 +5,6 @@ export const useStateStore = defineStore('stateStore', () => {
     const isMounted = ref(false);
     const leftDrawer = ref(false);
     const rightDrawer = ref(false);
-    const subToolbar = ref(false);
 
     function toggleLeftDrawer() {
         leftDrawer.value = !leftDrawer.value;
@@ -19,10 +18,6 @@ export const useStateStore = defineStore('stateStore', () => {
         isMounted.value = true;
     }
 
-    function setSubtoolbar() {
-        subToolbar.value = true;
-    }
-
     function isHeaderMounted() {
         return isMounted.value;
     }
@@ -36,7 +31,10 @@ export const useStateStore = defineStore('stateStore', () => {
     }
 
     function isSubToolbarShown() {
-        return subToolbar.value;
+        return (
+            !!document.querySelector('#st-data') &&
+            !!document.querySelector('#st-actions')
+        );
     }
 
     return {
@@ -48,7 +46,6 @@ export const useStateStore = defineStore('stateStore', () => {
         toggleRightDrawer,
         isLeftDrawerShown,
         isRightDrawerShown,
-        setSubtoolbar,
         isSubToolbarShown,
     };
 });
diff --git a/test/cypress/integration/claimDevelopment.spec.js b/test/cypress/integration/claimDevelopment.spec.js
index ec41e92a36..f05710eeaf 100755
--- a/test/cypress/integration/claimDevelopment.spec.js
+++ b/test/cypress/integration/claimDevelopment.spec.js
@@ -1,55 +1,77 @@
 /// <reference types="cypress" />
-describe('ClaimPhoto', () => {
+describe('ClaimDevelopment', () => {
+    const claimId = 1;
+
     beforeEach(() => {
-        const claimId = 1;
+        cy.viewport(1920, 1080);
         cy.login('developer');
-        cy.visit(`/#/claim/${claimId}/photos`);
+        cy.visit(`/#/claim/${claimId}/development`);
     });
 
-    it('should add new file', () => {
-        cy.get('label > .q-btn').click();
-        cy.get('label > .q-btn input').selectFile('test/cypress/fixtures/image.jpg', {
-            force: true,
-        });
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
-    });
-
-    it('should add new file with drag and drop', () => {
-        cy.get('.container').selectFile('test/cypress/fixtures/image.jpg', {
-            action: 'drag-drop',
-        });
-        cy.get('.q-notification__message').should('have.text', 'Data saved');
-    });
-
-    it('should open first image dialog change to second and close', () => {
+    it('should reset line', () => {
+        cy.get('tbody > :nth-child(1) > :nth-child(2)').click();
+        cy.selectOption('Novato');
+        cy.get('[title="Reset"]').click();
         cy.get(
-            ':nth-child(1) > .q-card > .q-img > .q-img__container > .q-img__image'
-        ).click();
-        cy.get('.q-carousel__slide > .q-img > .q-img__container > .q-img__image').should(
-            'be.visible'
-        );
-
-        cy.get('.q-carousel__control > .q-btn > .q-btn__content > .q-icon').click();
-
-        cy.get(
-            '.q-dialog__inner > .q-toolbar > .q-btn > .q-btn__content > .q-icon'
-        ).click();
-        cy.get('.q-carousel__slide > .q-img > .q-img__container > .q-img__image').should(
-            'not.be.visible'
-        );
+            ':nth-child(1) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
+        ).should('have.text', 'Prisas');
     });
 
-    it('should remove third and fourth file', () => {
-        cy.get(
-            '.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
-        ).click();
-        cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
-        cy.get('.q-notification__message').should('have.text', 'Data deleted');
+    it('should edit line', () => {
+        cy.get('tbody > :nth-child(1) > :nth-child(2)').click();
+        cy.selectOption('Novato');
+        cy.get('[title="Save"]').click();
 
+        cy.visit(`/#/claim/${claimId}/development`);
         cy.get(
-            '.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
-        ).click();
-        cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
-        cy.get('.q-notification__message').should('have.text', 'Data deleted');
+            ':nth-child(1) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
+        ).should('have.text', 'Novato');
+
+        //Restart data
+        cy.get('tbody > :nth-child(1) > :nth-child(2)');
+        cy.selectOption('Prisas');
+        cy.get('[title="Save"]').click();
     });
+
+    it('should add new line', () => {
+        //check third if row exist
+        cy.get('.q-page-sticky > div > .q-btn').click();
+        cy.get('tbody > :nth-child(3)').should('exist');
+
+        //fill in data
+        const rowData = ['', '', ''];
+        cy.fillTableRow(3, rowData);
+    });
+
+    // it('should remove last line', () => {
+    //     cy.get(
+    //         ':nth-child(1) > .q-card > .q-img > .q-img__container > .q-img__image'
+    //     ).click();
+    //     cy.get('.q-carousel__slide > .q-img > .q-img__container > .q-img__image').should(
+    //         'be.visible'
+    //     );
+
+    //     cy.get('.q-carousel__control > .q-btn > .q-btn__content > .q-icon').click();
+
+    //     cy.get(
+    //         '.q-dialog__inner > .q-toolbar > .q-btn > .q-btn__content > .q-icon'
+    //     ).click();
+    //     cy.get('.q-carousel__slide > .q-img > .q-img__container > .q-img__image').should(
+    //         'not.be.visible'
+    //     );
+    // });
+
+    // it('should remove third and fourth file', () => {
+    //     cy.get(
+    //         '.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
+    //     ).click();
+    //     cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
+    //     cy.get('.q-notification__message').should('have.text', 'Data deleted');
+
+    //     cy.get(
+    //         '.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
+    //     ).click();
+    //     cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
+    //     cy.get('.q-notification__message').should('have.text', 'Data deleted');
+    // });
 });
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index a3a61c4232..eca5f6c8ca 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -40,4 +40,71 @@ Cypress.Commands.add('login', (user) => {
         window.localStorage.setItem('token', response.body.token);
     });
 });
+
+Cypress.Commands.add('selectOption', (option) => {
+    //cy.visit('/#/login');
+    cy.get('.q-item__label').then(() => {
+        cy.contains('.q-item__label', option).click();
+    });
+});
+
+// Cypress.Commands.add('fillRow', (row, options) => {
+//     //cy.visit('/#/login');
+//     for (let [i, option] of options.entries()) {
+//         i++;
+//         console.log(i);
+//         const selector = `tbody > :nth-child(${row}) > :nth-child(${i})`;
+//         if (cy.get(selector).should('have.class', 'q-select'))
+//             cy.selectOption(selector, option);
+//     }
+// });
+Cypress.Commands.add('fillTableRow', (rowNumber, data) => {
+    // Obtener todas las filas de la tabla
+    cy.get('table tbody tr').eq(rowNumber).as('currentRow');
+
+    // Iterar sobre cada dato en el array 'data'
+    data.forEach((value, index) => {
+        // Basándonos en el índice, encontramos la celda correspondiente y verificamos el tipo de input
+        cy.get('@currentRow')
+            .find('td')
+            .eq(index)
+            .find('input')
+            .invoke('attr', 'type')
+            .then((type) => {
+                switch (type) {
+                    case 'text':
+                        cy.get('@currentRow')
+                            .find('td')
+                            .eq(index)
+                            .find('input[type="text"]')
+                            .clear()
+                            .type(value);
+                        break;
+
+                    case 'checkbox':
+                        if (value) {
+                            // Puede adaptar esto según cómo represente los valores booleanos en su array 'data'
+                            cy.get('@currentRow')
+                                .find('td')
+                                .eq(index)
+                                .find('input[type="checkbox"]')
+                                .check();
+                        } else {
+                            cy.get('@currentRow')
+                                .find('td')
+                                .eq(index)
+                                .find('input[type="checkbox"]')
+                                .uncheck();
+                        }
+                        break;
+
+                    // ... Puede agregar más casos para otros tipos de inputs según sea necesario
+
+                    default:
+                        // Manejar cualquier otro tipo de input o agregar lógica de error aquí si es necesario
+                        break;
+                }
+            });
+    });
+});
 // registerCommands();
diff --git a/test/vitest/__tests__/components/common/CrudModel.spec.js b/test/vitest/__tests__/components/common/CrudModel.spec.js
index 6547437ca4..518c3ad605 100644
--- a/test/vitest/__tests__/components/common/CrudModel.spec.js
+++ b/test/vitest/__tests__/components/common/CrudModel.spec.js
@@ -1,13 +1,16 @@
-import { createWrapper } from 'app/test/vitest/helper';
+import { createWrapper, axios } from 'app/test/vitest/helper';
 import CrudModel from 'components/CrudModel.vue';
-import { vi, afterEach, beforeAll, describe, expect, it } from 'vitest';
+import { vi, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
 
 describe.only('CrudModel', () => {
     let vm;
     beforeAll(() => {
         vm = createWrapper(CrudModel, {
             global: {
-                stubs: ['VnPaginate', 'useState'],
+                stubs: ['vnPaginate', 'useState', 'arrayData', 'useStateStore'],
+                mocks: {
+                    fetch: vi.fn(),
+                },
             },
             propsData: {
                 dataRequired: {
@@ -15,6 +18,15 @@ describe.only('CrudModel', () => {
                     name: 'name',
                     autoLoad: true,
                 },
+                dataKey: 'crudModelKey',
+                model: 'crudModel',
+                url: 'crudModelUrl',
+            },
+            attrs: {
+                url: 'crudModelUrl',
+                dataKey: 'CustomerList',
+                order: 'id DESC',
+                limit: 3,
             },
         }).vm;
     });
@@ -24,12 +36,26 @@ describe.only('CrudModel', () => {
     });
 
     describe('insert()', () => {
-        it('should new element in list', () => {
+        it('should new element in list with index 0 if formData not has data', () => {
+            vi.mock('src/composables/useValidator', () => ({
+                default: () => {},
+                fetch: () => {
+                    vi.fn();
+                },
+            }));
+            vi.spyOn(axios, 'get').mockResolvedValue({
+                data: [
+                    { id: 1, name: 'Tony Stark' },
+                    { id: 2, name: 'Jessica Jones' },
+                    { id: 3, name: 'Bruce Wayne' },
+                ],
+            });
+            vm.state.set('crudModel', []);
             vm.insert();
 
-            expect(vm.message).toEqual(
-                `A minimum amount of 50€ (VAT excluded) is required for your order ${orderId} of ${shipped} to receive it without additional shipping costs.`
-            );
+            expect(vm.formData.length).toEqual(1);
+            expect(vm.formData[0].id).toEqual(1);
+            expect(vm.formData[0].$index).toEqual(0);
         });
     });
 });
diff --git a/test/vitest/helper.js b/test/vitest/helper.js
index 8a6fb14159..186f4ee3a4 100644
--- a/test/vitest/helper.js
+++ b/test/vitest/helper.js
@@ -64,6 +64,10 @@ export function createWrapper(component, options) {
         global: {
             plugins: [i18n, pinia],
         },
+        mocks: {
+            t: (tKey) => tKey,
+            $t: (tKey) => tKey,
+        },
     };
 
     const mountOptions = Object.assign({}, defaultOptions);
@@ -75,6 +79,7 @@ export function createWrapper(component, options) {
             mountOptions.global.plugins = defaultOptions.global.plugins;
         }
     }
+    console.log(mountOptions);
 
     const wrapper = mount(component, mountOptions);
     const vm = wrapper.vm;