5673-claim-development & crudModel #71

Merged
alexm merged 33 commits from 5673-claim-development into dev 2023-09-28 07:46:02 +00:00
11 changed files with 218 additions and 71 deletions
Showing only changes of commit 98552bcd9e - Show all commits

View File

@ -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

View File

@ -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"
}

View File

@ -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) => { ... })

View File

@ -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')"

View File

@ -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" />

View File

@ -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>

View File

@ -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,
};
});

View File

@ -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');
// });
});

View File

@ -40,4 +40,71 @@ Cypress.Commands.add('login', (user) => {
window.localStorage.setItem('token', response.body.token);
});
});
Cypress.Commands.add('selectOption', (option) => {
Review

He fet tots estos comandos per a facilitar el fer els e2e i te funcions com getValue que ja te mira que tipo de componente es i teu trau.

Soles els he adaptat per als QSelects i QCheckbox que era el cas que necesitava si me para adaptar mes componentes ja se me fea mes jaleo pq no els gaste realment en un e2e

He fet tots estos comandos per a facilitar el fer els e2e i te funcions com getValue que ja te mira que tipo de componente es i teu trau. Soles els he adaptat per als QSelects i QCheckbox que era el cas que necesitava si me para adaptar mes componentes ja se me fea mes jaleo pq no els gaste realment en un e2e
//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();

View File

@ -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);
});
});
});

View File

@ -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;