forked from verdnatura/salix-front
refs #5673 test(CrudModel): front and e2e
This commit is contained in:
parent
6c8329ec53
commit
98552bcd9e
|
@ -64,7 +64,7 @@ module.exports = {
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ['test/cypress/**/*.spec.{js,ts}'],
|
files: ['test/cypress/**/*.*'],
|
||||||
extends: [
|
extends: [
|
||||||
// Add Cypress-specific lint rules, globals and Cypress plugin
|
// Add Cypress-specific lint rules, globals and Cypress plugin
|
||||||
// See https://github.com/cypress-io/eslint-plugin-cypress#rules
|
// See https://github.com/cypress-io/eslint-plugin-cypress#rules
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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) => { ... })
|
|
@ -285,8 +285,8 @@ function isEmpty(obj) {
|
||||||
</template>
|
</template>
|
||||||
</VnPaginate>
|
</VnPaginate>
|
||||||
<SkeletonTable v-if="!formData" />
|
<SkeletonTable v-if="!formData" />
|
||||||
<Teleport to="#st-actions" v-if="stateStore.isSubToolbarShown()">
|
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
|
||||||
<QBtnGroup push class="q-gutter-x-sm">
|
<QBtnGroup push flat class="q-gutter-x-sm">
|
||||||
<slot name="moreActions" />
|
<slot name="moreActions" />
|
||||||
<QBtn
|
<QBtn
|
||||||
:label="tMobile('globals.remove')"
|
:label="tMobile('globals.remove')"
|
||||||
|
|
|
@ -65,7 +65,7 @@ async function fetch() {
|
||||||
});
|
});
|
||||||
|
|
||||||
state.set($props.model, data);
|
state.set($props.model, data);
|
||||||
originalData.value = Object.assign({}, data);
|
originalData.value = data && JSON.parse(JSON.stringify(data));
|
||||||
|
|
||||||
watch(formData.value, () => (hasChanges.value = true));
|
watch(formData.value, () => (hasChanges.value = true));
|
||||||
|
|
||||||
|
@ -82,13 +82,14 @@ async function save() {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
await axios.patch($props.urlUpdate || $props.url, formData.value);
|
await axios.patch($props.urlUpdate || $props.url, formData.value);
|
||||||
|
|
||||||
originalData.value = formData.value;
|
originalData.value = JSON.parse(JSON.stringify(formData.value));
|
||||||
hasChanges.value = false;
|
hasChanges.value = false;
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
state.set($props.model, originalData.value);
|
state.set($props.model, originalData.value);
|
||||||
|
watch(formData.value, () => (hasChanges.value = true));
|
||||||
hasChanges.value = false;
|
hasChanges.value = false;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line vue/no-dupe-keys
|
// 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">
|
<QForm v-if="formData" @submit="save" @reset="reset" class="q-pa-md">
|
||||||
<slot name="form" :data="formData" :validate="validate" :filter="filter"></slot>
|
<slot name="form" :data="formData" :validate="validate" :filter="filter"></slot>
|
||||||
</QForm>
|
</QForm>
|
||||||
<Teleport to="#st-actions" v-if="stateStore.isSubToolbarShown()">
|
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
|
||||||
<div v-if="$props.defaultActions">
|
<div v-if="$props.defaultActions">
|
||||||
<QBtnGoup push class="q-gutter-x-sm">
|
<QBtnGoup push class="q-gutter-x-sm">
|
||||||
<slot name="moreActions" />
|
<slot name="moreActions" />
|
||||||
|
|
|
@ -29,7 +29,6 @@ const claimSections = [
|
||||||
let salixUrl;
|
let salixUrl;
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
salixUrl = await getUrl(`claim/${entityId.value}`);
|
salixUrl = await getUrl(`claim/${entityId.value}`);
|
||||||
stateStore.setSubtoolbar();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -65,13 +64,13 @@ onMounted(async () => {
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
<QPageContainer>
|
<QPageContainer>
|
||||||
<QToolbar class="bg-vn-dark justify-end">
|
<QPage>
|
||||||
<div id="st-data"></div>
|
<QToolbar class="bg-vn-dark justify-end">
|
||||||
<QSpace />
|
<div id="st-data"></div>
|
||||||
<div id="st-actions"></div>
|
<QSpace />
|
||||||
</QToolbar>
|
<div id="st-actions"></div>
|
||||||
<QPage class="q-pa-md">
|
</QToolbar>
|
||||||
<RouterView></RouterView>
|
<div class="q-pa-md"><RouterView></RouterView></div>
|
||||||
</QPage>
|
</QPage>
|
||||||
</QPageContainer>
|
</QPageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -5,7 +5,6 @@ export const useStateStore = defineStore('stateStore', () => {
|
||||||
const isMounted = ref(false);
|
const isMounted = ref(false);
|
||||||
const leftDrawer = ref(false);
|
const leftDrawer = ref(false);
|
||||||
const rightDrawer = ref(false);
|
const rightDrawer = ref(false);
|
||||||
const subToolbar = ref(false);
|
|
||||||
|
|
||||||
function toggleLeftDrawer() {
|
function toggleLeftDrawer() {
|
||||||
leftDrawer.value = !leftDrawer.value;
|
leftDrawer.value = !leftDrawer.value;
|
||||||
|
@ -19,10 +18,6 @@ export const useStateStore = defineStore('stateStore', () => {
|
||||||
isMounted.value = true;
|
isMounted.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSubtoolbar() {
|
|
||||||
subToolbar.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isHeaderMounted() {
|
function isHeaderMounted() {
|
||||||
return isMounted.value;
|
return isMounted.value;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +31,10 @@ export const useStateStore = defineStore('stateStore', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSubToolbarShown() {
|
function isSubToolbarShown() {
|
||||||
return subToolbar.value;
|
return (
|
||||||
|
!!document.querySelector('#st-data') &&
|
||||||
|
!!document.querySelector('#st-actions')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -48,7 +46,6 @@ export const useStateStore = defineStore('stateStore', () => {
|
||||||
toggleRightDrawer,
|
toggleRightDrawer,
|
||||||
isLeftDrawerShown,
|
isLeftDrawerShown,
|
||||||
isRightDrawerShown,
|
isRightDrawerShown,
|
||||||
setSubtoolbar,
|
|
||||||
isSubToolbarShown,
|
isSubToolbarShown,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,55 +1,77 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
describe('ClaimPhoto', () => {
|
describe('ClaimDevelopment', () => {
|
||||||
|
const claimId = 1;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const claimId = 1;
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit(`/#/claim/${claimId}/photos`);
|
cy.visit(`/#/claim/${claimId}/development`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add new file', () => {
|
it('should reset line', () => {
|
||||||
cy.get('label > .q-btn').click();
|
cy.get('tbody > :nth-child(1) > :nth-child(2)').click();
|
||||||
cy.get('label > .q-btn input').selectFile('test/cypress/fixtures/image.jpg', {
|
cy.selectOption('Novato');
|
||||||
force: true,
|
cy.get('[title="Reset"]').click();
|
||||||
});
|
|
||||||
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', () => {
|
|
||||||
cy.get(
|
cy.get(
|
||||||
':nth-child(1) > .q-card > .q-img > .q-img__container > .q-img__image'
|
':nth-child(1) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
|
||||||
).click();
|
).should('have.text', 'Prisas');
|
||||||
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', () => {
|
it('should edit line', () => {
|
||||||
cy.get(
|
cy.get('tbody > :nth-child(1) > :nth-child(2)').click();
|
||||||
'.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
|
cy.selectOption('Novato');
|
||||||
).click();
|
cy.get('[title="Save"]').click();
|
||||||
cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
|
|
||||||
cy.get('.q-notification__message').should('have.text', 'Data deleted');
|
|
||||||
|
|
||||||
|
cy.visit(`/#/claim/${claimId}/development`);
|
||||||
cy.get(
|
cy.get(
|
||||||
'.multimediaParent > :nth-child(3) > .q-btn > .q-btn__content > .q-icon'
|
':nth-child(1) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > span'
|
||||||
).click();
|
).should('have.text', 'Novato');
|
||||||
cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
|
|
||||||
cy.get('.q-notification__message').should('have.text', 'Data deleted');
|
//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');
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,4 +40,71 @@ Cypress.Commands.add('login', (user) => {
|
||||||
window.localStorage.setItem('token', response.body.token);
|
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();
|
// registerCommands();
|
||||||
|
|
|
@ -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 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', () => {
|
describe.only('CrudModel', () => {
|
||||||
let vm;
|
let vm;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
vm = createWrapper(CrudModel, {
|
vm = createWrapper(CrudModel, {
|
||||||
global: {
|
global: {
|
||||||
stubs: ['VnPaginate', 'useState'],
|
stubs: ['vnPaginate', 'useState', 'arrayData', 'useStateStore'],
|
||||||
|
mocks: {
|
||||||
|
fetch: vi.fn(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
dataRequired: {
|
dataRequired: {
|
||||||
|
@ -15,6 +18,15 @@ describe.only('CrudModel', () => {
|
||||||
name: 'name',
|
name: 'name',
|
||||||
autoLoad: true,
|
autoLoad: true,
|
||||||
},
|
},
|
||||||
|
dataKey: 'crudModelKey',
|
||||||
|
model: 'crudModel',
|
||||||
|
url: 'crudModelUrl',
|
||||||
|
},
|
||||||
|
attrs: {
|
||||||
|
url: 'crudModelUrl',
|
||||||
|
dataKey: 'CustomerList',
|
||||||
|
order: 'id DESC',
|
||||||
|
limit: 3,
|
||||||
},
|
},
|
||||||
}).vm;
|
}).vm;
|
||||||
});
|
});
|
||||||
|
@ -24,12 +36,26 @@ describe.only('CrudModel', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('insert()', () => {
|
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();
|
vm.insert();
|
||||||
|
|
||||||
expect(vm.message).toEqual(
|
expect(vm.formData.length).toEqual(1);
|
||||||
`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[0].id).toEqual(1);
|
||||||
);
|
expect(vm.formData[0].$index).toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,6 +64,10 @@ export function createWrapper(component, options) {
|
||||||
global: {
|
global: {
|
||||||
plugins: [i18n, pinia],
|
plugins: [i18n, pinia],
|
||||||
},
|
},
|
||||||
|
mocks: {
|
||||||
|
t: (tKey) => tKey,
|
||||||
|
$t: (tKey) => tKey,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const mountOptions = Object.assign({}, defaultOptions);
|
const mountOptions = Object.assign({}, defaultOptions);
|
||||||
|
@ -75,6 +79,7 @@ export function createWrapper(component, options) {
|
||||||
mountOptions.global.plugins = defaultOptions.global.plugins;
|
mountOptions.global.plugins = defaultOptions.global.plugins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log(mountOptions);
|
||||||
|
|
||||||
const wrapper = mount(component, mountOptions);
|
const wrapper = mount(component, mountOptions);
|
||||||
const vm = wrapper.vm;
|
const vm = wrapper.vm;
|
||||||
|
|
Loading…
Reference in New Issue