0
0
Fork 0

refactor: refs #6897 clean up alignment and improve data attributes for better testing

This commit is contained in:
Pablo Natek 2025-02-10 11:41:41 +01:00
parent af2cbda077
commit 5f624bbf7f
9 changed files with 99 additions and 73 deletions

View File

@ -46,7 +46,6 @@ const enterEvent = {
const defaultAttrs = {
filled: !$props.showTitle,
// class: 'q-px-xs q-pb-xs q-pt-none fit',
dense: true,
};

View File

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

View File

@ -1,7 +1,9 @@
export function getColAlign(col) {
let align;
switch (col.component) {
case 'select':
align = 'left';
break;
case 'number':
align = 'right';
break;

View File

@ -640,6 +640,7 @@ onMounted(() => {
:table-height="$props.tableHeight ?? '84vh'"
auto-load
footer
data-cy="entry-buys"
>
<template #column-hex="{ row }">
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />

View File

@ -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() {
<QItem v-ripple clickable @click="cloneEntry(entity)" data-cy="clone-entry">
<QItemSection>{{ t('Clone') }}</QItemSection>
</QItem>
<QItem
v-ripple
clickable
@click="deleteEntry(entity)"
data-cy="delete-entry"
v-if="entity?.travelFk"
>
<QItem v-ripple clickable @click="deleteEntry(entity)" data-cy="delete-entry">
<QItemSection>{{ t('Delete') }}</QItemSection>
</QItem>
</template>
@ -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
</i18n>

View File

@ -51,6 +51,7 @@ onMounted(async () => {
:url="`Entries/${entityId}/getEntry`"
@on-fetch="(data) => setEntryData(data)"
data-key="EntrySummary"
data-cy="entry-summary"
>
<template #header-left>
<VnToSummary

View File

@ -44,7 +44,6 @@ const entryQueryFilter = {
const columns = computed(() => [
{
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,

View File

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

View File

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