diff --git a/src/components/VnTable/VnFilter.vue b/src/components/VnTable/VnFilter.vue
index d089717ef..27a7d4b10 100644
--- a/src/components/VnTable/VnFilter.vue
+++ b/src/components/VnTable/VnFilter.vue
@@ -46,7 +46,6 @@ const enterEvent = {
const defaultAttrs = {
filled: !$props.showTitle,
- // class: 'q-px-xs q-pb-xs q-pt-none fit',
dense: true,
};
diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue
index b1f202647..49c3085d1 100644
--- a/src/components/VnTable/VnTable.vue
+++ b/src/components/VnTable/VnTable.vue
@@ -137,6 +137,7 @@ const $props = defineProps({
type: Object,
},
});
+
const { t } = useI18n();
const stateStore = useStateStore();
const route = useRoute();
@@ -165,6 +166,7 @@ const editingField = ref(null);
const isTableMode = computed(() => mode.value == TABLE_MODE);
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
const selectRegex = /select/;
+const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
const tableModes = [
{
icon: 'view_column',
@@ -184,6 +186,7 @@ onBeforeMount(() => {
const urlParams = route.query[$props.searchUrl];
hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
});
+
onMounted(async () => {
if ($props.isEditable) document.addEventListener('click', clickHandler);
mode.value =
@@ -206,6 +209,7 @@ onMounted(async () => {
};
}
});
+
onUnmounted(async () => {
if ($props.isEditable) document.removeEventListener('click', clickHandler);
});
@@ -216,6 +220,16 @@ watch(
{ immediate: true },
);
+defineExpose({
+ create: createForm,
+ reload,
+ redirect: redirectFn,
+ selected,
+ CrudModelRef,
+ params,
+ tableRef,
+});
+
function splitColumns(columns) {
splittedColumns.value = {
columns: [],
@@ -281,17 +295,6 @@ function columnName(col) {
return name;
}
-const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
-defineExpose({
- create: createForm,
- reload,
- redirect: redirectFn,
- selected,
- CrudModelRef,
- params,
- tableRef,
-});
-
function handleOnDataSaved(_) {
if (_.onDataSaved) _.onDataSaved({ CrudModelRef: CrudModelRef.value });
else $props.create.onDataSaved(_);
@@ -512,6 +515,7 @@ function getCheckboxIcon(value) {
return 'indeterminate_check_box';
}
}
+
function getToggleIcon(value) {
if (value === null) return 'help_outline';
return value ? 'toggle_on' : 'toggle_off';
@@ -679,7 +683,8 @@ const checkbox = ref(null);
}"
:class="[
col.columnClass,
- 'body-cell no-margin no-padding text-center',
+ 'body-cell no-margin no-padding',
+ getColAlign(col),
]"
:data-row-index="rowIndex"
:data-col-field="col?.name"
diff --git a/src/composables/getColAlign.js b/src/composables/getColAlign.js
index 57ba7cfaf..c0338a984 100644
--- a/src/composables/getColAlign.js
+++ b/src/composables/getColAlign.js
@@ -1,7 +1,9 @@
export function getColAlign(col) {
let align;
-
switch (col.component) {
+ case 'select':
+ align = 'left';
+ break;
case 'number':
align = 'right';
break;
diff --git a/src/pages/Entry/Card/EntryBuys.vue b/src/pages/Entry/Card/EntryBuys.vue
index 3a902907b..4bc18a4cb 100644
--- a/src/pages/Entry/Card/EntryBuys.vue
+++ b/src/pages/Entry/Card/EntryBuys.vue
@@ -640,6 +640,7 @@ onMounted(() => {
:table-height="$props.tableHeight ?? '84vh'"
auto-load
footer
+ data-cy="entry-buys"
>
diff --git a/src/pages/Entry/Card/EntryDescriptor.vue b/src/pages/Entry/Card/EntryDescriptor.vue
index 8559b104a..8779fa7f2 100644
--- a/src/pages/Entry/Card/EntryDescriptor.vue
+++ b/src/pages/Entry/Card/EntryDescriptor.vue
@@ -124,7 +124,7 @@ async function recalculateRates(entity) {
async function cloneEntry() {
try {
const response = await axios.post(`Entries/${entityId.value}/cloneEntry`);
- push({ path: `/entry/${response.data[0].vNewEntryFk}` });
+ push({ path: `/entry/${response.data}` });
showNotification('positive', 'Entry cloned');
} catch (error) {
showNotification('negative', 'Failed to clone entry');
@@ -174,13 +174,7 @@ async function deleteEntry() {
{{ t('Clone') }}
-
+
{{ t('Delete') }}
@@ -293,4 +287,7 @@ es:
Failed to recalculate rates: No se pudieron recalcular las tarifas
Failed to clone entry: No se pudo clonar la entrada
Failed to delete entry: No se pudo eliminar la entrada
+ Recalculate rates: Recalcular tarifas
+ Clone: Clonar
+ Delete: Eliminar
diff --git a/src/pages/Entry/Card/EntrySummary.vue b/src/pages/Entry/Card/EntrySummary.vue
index 6b7477cfc..c40e2ba46 100644
--- a/src/pages/Entry/Card/EntrySummary.vue
+++ b/src/pages/Entry/Card/EntrySummary.vue
@@ -51,6 +51,7 @@ onMounted(async () => {
:url="`Entries/${entityId}/getEntry`"
@on-fetch="(data) => setEntryData(data)"
data-key="EntrySummary"
+ data-cy="entry-summary"
>
[
{
- align: 'center',
label: 'Ex',
toolTip: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
name: 'isExcludedFromAvailable',
@@ -52,7 +51,6 @@ const columns = computed(() => [
width: '35px',
},
{
- align: 'center',
label: 'Pe',
toolTip: t('entry.list.tableVisibleColumns.isOrdered'),
name: 'isOrdered',
@@ -60,7 +58,6 @@ const columns = computed(() => [
width: '35px',
},
{
- align: 'center',
label: 'Le',
toolTip: t('entry.list.tableVisibleColumns.isConfirmed'),
name: 'isConfirmed',
@@ -68,7 +65,6 @@ const columns = computed(() => [
width: '35px',
},
{
- align: 'center',
label: 'Re',
toolTip: t('entry.list.tableVisibleColumns.isReceived'),
name: 'isReceived',
@@ -76,7 +72,6 @@ const columns = computed(() => [
width: '35px',
},
{
- align: 'center',
label: t('entry.list.tableVisibleColumns.landed'),
name: 'landed',
component: 'date',
@@ -87,16 +82,15 @@ const columns = computed(() => [
width: '105px',
},
{
- align: 'right',
label: t('globals.id'),
name: 'id',
isId: true,
+ component: 'number',
chip: {
condition: () => true,
},
},
{
- align: 'left',
label: t('entry.list.tableVisibleColumns.supplierFk'),
name: 'supplierFk',
create: true,
diff --git a/test/cypress/integration/entry/entrylist.spec.js b/test/cypress/integration/entry/entrylist.spec.js
index 268fb761d..2eb9a7013 100644
--- a/test/cypress/integration/entry/entrylist.spec.js
+++ b/test/cypress/integration/entry/entrylist.spec.js
@@ -7,8 +7,8 @@ describe('Entry', () => {
it('Filter deleted entries and other fields', () => {
createEntry();
-
cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
+ cy.waitForElement('[data-cy="entry-buys"]');
deleteEntry();
cy.typeSearchbar('{enter}');
cy.get('span[title="Date"]').click().click();
@@ -31,30 +31,37 @@ describe('Entry', () => {
it('Clone entry and recalculate rates', () => {
createEntry();
- cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
- cy.url().then((perviousUrl) => {
- cy.log('URL antes de clonar:', perviousUrl);
+ cy.waitForElement('[data-cy="entry-buys"]');
+ cy.url().then((previousUrl) => {
cy.get('[data-cy="descriptor-more-opts"]').click();
- cy.get('div[data-cy="clone-entry"]').click();
+ cy.get('div[data-cy="clone-entry"]').should('be.visible').click();
- cy.url().then((newUrl) => {
- expect(perviousUrl).not.to.eq(newUrl);
+ cy.get('.q-notification__message').eq(1).should('have.text', 'Entry cloned');
- cy.get('[data-cy="descriptor-more-opts"]').click();
- cy.get('div[data-cy="recalculate-rates"]').click();
+ cy.url()
+ .should('not.eq', previousUrl)
+ .then(() => {
+ cy.waitForElement('[data-cy="entry-buys"]');
- cy.get('.q-notification__message')
- .eq(1)
- .should('have.text', 'Entry prices recalculated');
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ cy.get('div[data-cy="recalculate-rates"]').click();
- deleteEntry();
+ cy.get('.q-notification__message')
+ .eq(2)
+ .should('have.text', 'Entry prices recalculated');
- cy.visit(perviousUrl);
+ cy.get('[data-cy="descriptor-more-opts"]').click();
+ deleteEntry();
- deleteEntry();
- });
+ cy.log(previousUrl);
+
+ cy.visit(previousUrl);
+
+ cy.waitForElement('[data-cy="entry-buys"]');
+ deleteEntry();
+ });
});
});
@@ -174,13 +181,14 @@ describe('Entry', () => {
function goToEntryBuys() {
const entryBuySelector = 'a[data-cy="EntryBuys-menu-item"]';
cy.get(entryBuySelector).should('be.visible');
- cy.get(entryBuySelector).click();
+ cy.waitForElement('[data-cy="entry-buys"]');
cy.get(entryBuySelector).click();
}
function deleteEntry() {
cy.get('[data-cy="descriptor-more-opts"]').click();
- cy.get('div[data-cy="delete-entry"]').click();
+ cy.waitForElement('div[data-cy="delete-entry"]');
+ cy.get('div[data-cy="delete-entry"]').should('be.visible').click();
cy.url().should('include', 'list');
}
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index 2c93fbf84..aa4a1219e 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -87,36 +87,55 @@ Cypress.Commands.add('getValue', (selector) => {
});
// Fill Inputs
-Cypress.Commands.add('selectOption', (selector, option, timeout = 5000) => {
+Cypress.Commands.add('selectOption', (selector, option, timeout = 2500) => {
cy.waitForElement(selector, timeout);
- cy.get(selector).click();
- cy.get(selector).invoke('data', 'url').as('dataUrl');
- cy.get(selector)
- .clear()
- .type(option)
- .then(() => {
- cy.get('.q-menu', { timeout })
- .should('be.visible') // Asegurarse de que el menú está visible
- .and('exist') // Verificar que el menú existe
- .then(() => {
- cy.get('@dataUrl').then((url) => {
- if (url) {
- // Esperar a que el menú no esté visible (desaparezca)
- cy.get('.q-menu').should('not.be.visible');
- // Ahora esperar a que el menú vuelva a aparecer
- cy.get('.q-menu').should('be.visible').and('exist');
- }
- });
- });
- });
- // Finalmente, seleccionar la opción deseada
- cy.get('.q-menu:visible') // Asegurarse de que estamos dentro del menú visible
- .find('.q-item') // Encontrar los elementos de las opciones
- .contains(option) // Verificar que existe una opción que contenga el texto deseado
- .click(); // Hacer clic en la opción
+ cy.get(selector, { timeout })
+ .should('exist')
+ .should('be.visible')
+ .click()
+ .then(($el) => {
+ cy.wrap($el.is('input') ? $el : $el.find('input'))
+ .invoke('attr', 'aria-controls')
+ .then((ariaControl) => selectItem(selector, option, ariaControl));
+ });
});
+function selectItem(selector, option, ariaControl, hasWrite = true) {
+ if (!hasWrite) cy.wait(100);
+
+ getItems(ariaControl).then((items) => {
+ const matchingItem = items
+ .toArray()
+ .find((item) => item.innerText.includes(option));
+ if (matchingItem) return cy.wrap(matchingItem).click();
+
+ if (hasWrite) cy.get(selector).clear().type(option, { delay: 0 });
+ return selectItem(selector, option, ariaControl, false);
+ });
+}
+
+function getItems(ariaControl, startTime = Cypress._.now(), timeout = 2500) {
+ // Se intenta obtener la lista de opciones del desplegable de manera recursiva
+ return cy
+ .get('#' + ariaControl, { timeout })
+ .should('exist')
+ .find('.q-item')
+ .should('exist')
+ .then(($items) => {
+ if (!$items?.length || $items.first().text().trim() === '') {
+ if (Cypress._.now() - startTime > timeout) {
+ throw new Error(
+ `getItems: Tiempo de espera (${timeout}ms) excedido.`,
+ );
+ }
+ return getItems(ariaControl, startTime, timeout);
+ }
+
+ return cy.wrap($items);
+ });
+}
+
Cypress.Commands.add('countSelectOptions', (selector, option) => {
cy.waitForElement(selector);
cy.get(selector).click({ force: true });