Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8277-createEntryControl
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
gitea/salix-front/pipeline/pr-dev This commit is unstable
Details
This commit is contained in:
commit
b5b69055bd
|
@ -44,6 +44,7 @@ export default defineConfig({
|
|||
supportFile: 'test/cypress/support/index.js',
|
||||
videosFolder: 'test/cypress/videos',
|
||||
downloadsFolder: 'test/cypress/downloads',
|
||||
tmpUploadFolder: 'test/cypress/storage/tmp/dms',
|
||||
video: false,
|
||||
specPattern: 'test/cypress/integration/**/*.spec.js',
|
||||
experimentalRunAllSpecs: true,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useRoute } from 'vue-router';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
@ -12,6 +13,7 @@ import FormModelPopup from 'components/FormModelPopup.vue';
|
|||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
|
||||
const $props = defineProps({
|
||||
|
@ -86,11 +88,16 @@ function getUrl() {
|
|||
}
|
||||
|
||||
async function save() {
|
||||
const body = mapperDms(dms.value);
|
||||
const response = await axios.post(getUrl(), body[0], body[1]);
|
||||
emit('onDataSaved', body[1].params, response);
|
||||
delete dms.value.files;
|
||||
return response;
|
||||
try {
|
||||
const body = mapperDms(dms.value);
|
||||
const response = await axios.post(getUrl(), body[0], body[1]);
|
||||
emit('onDataSaved', body[1].params, response);
|
||||
notify(t('globals.dataSaved'), 'positive');
|
||||
delete dms.value.files;
|
||||
return response;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function defaultData() {
|
||||
|
@ -211,7 +218,7 @@ function addDefaultData(data) {
|
|||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
en:
|
||||
contentTypesInfo: Allowed file types {allowedContentTypes}
|
||||
EntryDmsDescription: Reference {reference}
|
||||
WorkersDescription: Working of employee id {reference}
|
||||
|
|
|
@ -13,10 +13,12 @@ import VnDms from 'src/components/common/VnDms.vue';
|
|||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
const route = useRoute();
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
const rows = ref([]);
|
||||
const dmsRef = ref();
|
||||
const formDialog = ref({});
|
||||
|
@ -88,7 +90,6 @@ const dmsFilter = {
|
|||
],
|
||||
},
|
||||
},
|
||||
where: { [$props.filter]: route.params.id },
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
|
@ -258,9 +259,16 @@ function deleteDms(dmsFk) {
|
|||
},
|
||||
})
|
||||
.onOk(async () => {
|
||||
await axios.post(`${$props.deleteModel ?? $props.model}/${dmsFk}/removeFile`);
|
||||
const index = rows.value.findIndex((row) => row.id == dmsFk);
|
||||
rows.value.splice(index, 1);
|
||||
try {
|
||||
await axios.post(
|
||||
`${$props.deleteModel ?? $props.model}/${dmsFk}/removeFile`,
|
||||
);
|
||||
const index = rows.value.findIndex((row) => row.id == dmsFk);
|
||||
rows.value.splice(index, 1);
|
||||
notify(t('globals.dataDeleted'), 'positive');
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -298,7 +306,9 @@ defineExpose({
|
|||
:data-key="$props.model"
|
||||
:url="$props.model"
|
||||
:user-filter="dmsFilter"
|
||||
search-url="dmsFilter"
|
||||
:order="['dmsFk DESC']"
|
||||
:filter="{ where: { [$props.filter]: route.params.id } }"
|
||||
auto-load
|
||||
@on-fetch="setData"
|
||||
>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { onMounted, watch, computed, ref, useAttrs } from 'vue';
|
||||
import { date } from 'quasar';
|
||||
import { nextTick, watch, computed, ref, useAttrs } from 'vue';
|
||||
import { date, getCssVar } from 'quasar';
|
||||
import VnDate from './VnDate.vue';
|
||||
import { useRequired } from 'src/composables/useRequired';
|
||||
|
||||
|
@ -20,61 +20,18 @@ const $props = defineProps({
|
|||
});
|
||||
|
||||
const vnInputDateRef = ref(null);
|
||||
const errColor = getCssVar('negative');
|
||||
const textColor = ref('');
|
||||
|
||||
const dateFormat = 'DD/MM/YYYY';
|
||||
const isPopupOpen = ref();
|
||||
const hover = ref();
|
||||
const mask = ref();
|
||||
|
||||
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
|
||||
|
||||
const formattedDate = computed({
|
||||
get() {
|
||||
if (!model.value) return model.value;
|
||||
return date.formatDate(new Date(model.value), dateFormat);
|
||||
},
|
||||
set(value) {
|
||||
if (value == model.value) return;
|
||||
let newDate;
|
||||
if (value) {
|
||||
// parse input
|
||||
if (value.includes('/') && value.length >= 10) {
|
||||
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
|
||||
value = date.formatDate(
|
||||
new Date(value).toISOString(),
|
||||
'YYYY-MM-DDTHH:mm:ss.SSSZ',
|
||||
);
|
||||
}
|
||||
const [year, month, day] = value.split('-').map((e) => parseInt(e));
|
||||
newDate = new Date(year, month - 1, day);
|
||||
if (model.value) {
|
||||
const orgDate =
|
||||
model.value instanceof Date ? model.value : new Date(model.value);
|
||||
|
||||
newDate.setHours(
|
||||
orgDate.getHours(),
|
||||
orgDate.getMinutes(),
|
||||
orgDate.getSeconds(),
|
||||
orgDate.getMilliseconds(),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isNaN(newDate)) model.value = newDate.toISOString();
|
||||
},
|
||||
});
|
||||
|
||||
const popupDate = computed(() =>
|
||||
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value,
|
||||
);
|
||||
onMounted(() => {
|
||||
// fix quasar bug
|
||||
mask.value = '##/##/####';
|
||||
});
|
||||
watch(
|
||||
() => model.value,
|
||||
(val) => (formattedDate.value = val),
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const styleAttrs = computed(() => {
|
||||
return $props.isOutlined
|
||||
|
@ -86,28 +43,139 @@ const styleAttrs = computed(() => {
|
|||
: {};
|
||||
});
|
||||
|
||||
const inputValue = ref('');
|
||||
|
||||
const validateAndCleanInput = (value) => {
|
||||
inputValue.value = value.replace(/[^0-9./-]/g, '');
|
||||
};
|
||||
|
||||
const manageDate = (date) => {
|
||||
formattedDate.value = date;
|
||||
inputValue.value = date.split('/').reverse().join('/');
|
||||
isPopupOpen.value = false;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => model.value,
|
||||
(nVal) => {
|
||||
if (nVal) inputValue.value = date.formatDate(new Date(model.value), dateFormat);
|
||||
else inputValue.value = '';
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const formatDate = () => {
|
||||
let value = inputValue.value;
|
||||
if (!value || value === model.value) {
|
||||
textColor.value = '';
|
||||
return;
|
||||
}
|
||||
const regex =
|
||||
/^([0]?[1-9]|[12][0-9]|3[01])([./-])([0]?[1-9]|1[0-2])([./-](\d{1,4}))?$/;
|
||||
if (!regex.test(value)){
|
||||
textColor.value = errColor;
|
||||
return;
|
||||
}
|
||||
|
||||
value = value.replace(/[.-]/g, '/');
|
||||
const parts = value.split('/');
|
||||
if (parts.length < 2) {
|
||||
textColor.value = errColor;
|
||||
return;
|
||||
}
|
||||
|
||||
let [day, month, year] = parts;
|
||||
if (day.length === 1) day = '0' + day;
|
||||
if (month.length === 1) month = '0' + month;
|
||||
|
||||
const currentYear = Date.vnNew().getFullYear();
|
||||
if (!year) year = currentYear;
|
||||
const millennium = currentYear.toString().slice(0, 1);
|
||||
|
||||
switch (year.length) {
|
||||
case 1:
|
||||
year = `${millennium}00${year}`;
|
||||
break;
|
||||
case 2:
|
||||
year = `${millennium}0${year}`;
|
||||
break;
|
||||
case 3:
|
||||
year = `${millennium}${year}`;
|
||||
break;
|
||||
case 4:
|
||||
break;
|
||||
}
|
||||
|
||||
let isoCandidate = `${year}/${month}/${day}`;
|
||||
isoCandidate = date.formatDate(
|
||||
new Date(isoCandidate).toISOString(),
|
||||
'YYYY-MM-DDTHH:mm:ss.SSSZ',
|
||||
);
|
||||
const [isoYear, isoMonth, isoDay] = isoCandidate.split('-').map((e) => parseInt(e));
|
||||
const parsedDate = new Date(isoYear, isoMonth - 1, isoDay);
|
||||
|
||||
const isValidDate =
|
||||
parsedDate instanceof Date &&
|
||||
!isNaN(parsedDate) &&
|
||||
parsedDate.getFullYear() === parseInt(year) &&
|
||||
parsedDate.getMonth() === parseInt(month) - 1 &&
|
||||
parsedDate.getDate() === parseInt(day);
|
||||
|
||||
if (!isValidDate) {
|
||||
textColor.value = errColor;
|
||||
return;
|
||||
}
|
||||
|
||||
if (model.value) {
|
||||
const original =
|
||||
model.value instanceof Date ? model.value : new Date(model.value);
|
||||
parsedDate.setHours(
|
||||
original.getHours(),
|
||||
original.getMinutes(),
|
||||
original.getSeconds(),
|
||||
original.getMilliseconds(),
|
||||
);
|
||||
}
|
||||
|
||||
model.value = parsedDate.toISOString();
|
||||
|
||||
textColor.value = '';
|
||||
};
|
||||
|
||||
const handleEnter = (event) => {
|
||||
formatDate();
|
||||
|
||||
nextTick(() => {
|
||||
const newEvent = new KeyboardEvent('keydown', {
|
||||
key: 'Enter',
|
||||
code: 'Enter',
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
vnInputDateRef.value?.$el?.dispatchEvent(newEvent);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div @mouseover="hover = true" @mouseleave="hover = false">
|
||||
{{ console.log($q) }}
|
||||
<QInput
|
||||
ref="vnInputDateRef"
|
||||
v-model="formattedDate"
|
||||
v-model="inputValue"
|
||||
class="vn-input-date"
|
||||
:mask="mask"
|
||||
placeholder="dd/mm/aaaa"
|
||||
v-bind="{ ...$attrs, ...styleAttrs }"
|
||||
:class="{ required: isRequired }"
|
||||
:rules="mixinRules"
|
||||
:clearable="false"
|
||||
:input-style="{color: textColor}"
|
||||
@click="isPopupOpen = !isPopupOpen"
|
||||
@keydown="isPopupOpen = false"
|
||||
@blur="formatDate"
|
||||
@keydown.enter.prevent="handleEnter"
|
||||
hide-bottom-space
|
||||
:data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
|
||||
@update:model-value="validateAndCleanInput"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon
|
||||
|
@ -116,11 +184,12 @@ const manageDate = (date) => {
|
|||
v-if="
|
||||
($attrs.clearable == undefined || $attrs.clearable) &&
|
||||
hover &&
|
||||
model &&
|
||||
inputValue &&
|
||||
!$attrs.disable
|
||||
"
|
||||
@click="
|
||||
vnInputDateRef.focus();
|
||||
inputValue = null;
|
||||
model = null;
|
||||
isPopupOpen = false;
|
||||
"
|
||||
|
|
|
@ -5,52 +5,71 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
|||
let vm;
|
||||
let wrapper;
|
||||
|
||||
function generateWrapper(date, outlined, required) {
|
||||
function generateWrapper(outlined = false, required = false) {
|
||||
wrapper = createWrapper(VnInputDate, {
|
||||
props: {
|
||||
modelValue: date,
|
||||
modelValue: '2000-12-31T23:00:00.000Z',
|
||||
'onUpdate:modelValue': (e) => wrapper.setProps({ modelValue: e }),
|
||||
},
|
||||
attrs: {
|
||||
isOutlined: outlined,
|
||||
required: required
|
||||
required: required,
|
||||
},
|
||||
});
|
||||
wrapper = wrapper.wrapper;
|
||||
vm = wrapper.vm;
|
||||
};
|
||||
}
|
||||
|
||||
describe('VnInputDate', () => {
|
||||
|
||||
describe('formattedDate', () => {
|
||||
it('formats a valid date correctly', async () => {
|
||||
generateWrapper('2023-12-25', false, false);
|
||||
describe('formattedDate', () => {
|
||||
it('validateAndCleanInput should remove non-numeric characters', async () => {
|
||||
generateWrapper();
|
||||
vm.validateAndCleanInput('10a/1s2/2dd0a23');
|
||||
await vm.$nextTick();
|
||||
expect(vm.formattedDate).toBe('25/12/2023');
|
||||
expect(vm.inputValue).toBe('10/12/2023');
|
||||
});
|
||||
|
||||
it('updates the model value when a new date is set', async () => {
|
||||
const input = wrapper.find('input');
|
||||
await input.setValue('31/12/2023');
|
||||
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
|
||||
expect(wrapper.emitted()['update:modelValue'][0][0]).toBe('2023-12-31T00:00:00.000Z');
|
||||
it('manageDate should reverse the date', async () => {
|
||||
generateWrapper();
|
||||
vm.manageDate('10/12/2023');
|
||||
await vm.$nextTick();
|
||||
expect(vm.inputValue).toBe('2023/12/10');
|
||||
});
|
||||
|
||||
it('should not update the model value when an invalid date is set', async () => {
|
||||
it('formatDate should format the date correctly when a valid date is entered with full year', async () => {
|
||||
const input = wrapper.find('input');
|
||||
await input.setValue('invalid-date');
|
||||
expect(wrapper.emitted()['update:modelValue'][0][0]).toBe('2023-12-31T00:00:00.000Z');
|
||||
});
|
||||
await input.setValue('25.12/2002');
|
||||
await vm.$nextTick();
|
||||
await vm.formatDate();
|
||||
expect(vm.model).toBe('2002-12-24T23:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should format the date correctly when a valid date is entered with short year', async () => {
|
||||
const input = wrapper.find('input');
|
||||
await input.setValue('31.12-23');
|
||||
await vm.$nextTick();
|
||||
await vm.formatDate();
|
||||
expect(vm.model).toBe('2023-12-30T23:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should format the date correctly when a valid date is entered without year', async () => {
|
||||
const input = wrapper.find('input');
|
||||
await input.setValue('12.03');
|
||||
await vm.$nextTick();
|
||||
await vm.formatDate();
|
||||
expect(vm.model).toBe('2001-03-11T23:00:00.000Z');
|
||||
});
|
||||
});
|
||||
|
||||
describe('styleAttrs', () => {
|
||||
it('should return empty styleAttrs when isOutlined is false', async () => {
|
||||
generateWrapper('2023-12-25', false, false);
|
||||
generateWrapper();
|
||||
await vm.$nextTick();
|
||||
expect(vm.styleAttrs).toEqual({});
|
||||
expect(vm.styleAttrs).toEqual({});
|
||||
});
|
||||
|
||||
it('should set styleAttrs when isOutlined is true', async () => {
|
||||
generateWrapper('2023-12-25', true, false);
|
||||
it('should set styleAttrs when isOutlined is true', async () => {
|
||||
generateWrapper(true, false);
|
||||
await vm.$nextTick();
|
||||
expect(vm.styleAttrs.outlined).toBe(true);
|
||||
});
|
||||
|
@ -58,15 +77,15 @@ describe('VnInputDate', () => {
|
|||
|
||||
describe('required', () => {
|
||||
it('should not applies required class when isRequired is false', async () => {
|
||||
generateWrapper('2023-12-25', false, false);
|
||||
generateWrapper();
|
||||
await vm.$nextTick();
|
||||
expect(wrapper.find('.vn-input-date').classes()).not.toContain('required');
|
||||
});
|
||||
|
||||
|
||||
it('should applies required class when isRequired is true', async () => {
|
||||
generateWrapper('2023-12-25', false, true);
|
||||
generateWrapper(false, true);
|
||||
await vm.$nextTick();
|
||||
expect(wrapper.find('.vn-input-date').classes()).toContain('required');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -162,6 +162,9 @@ globals:
|
|||
department: Department
|
||||
noData: No data available
|
||||
vehicle: Vehicle
|
||||
selectDocumentId: Select document id
|
||||
document: Document
|
||||
import: Import from existing
|
||||
pageTitles:
|
||||
logIn: Login
|
||||
addressEdit: Update address
|
||||
|
|
|
@ -166,6 +166,9 @@ globals:
|
|||
noData: Datos no disponibles
|
||||
department: Departamento
|
||||
vehicle: Vehículo
|
||||
selectDocumentId: Seleccione el id de gestión documental
|
||||
document: Documento
|
||||
import: Importar desde existente
|
||||
pageTitles:
|
||||
logIn: Inicio de sesión
|
||||
addressEdit: Modificar consignatario
|
||||
|
|
|
@ -164,6 +164,7 @@ onMounted(async () => {
|
|||
unelevated
|
||||
filled
|
||||
dense
|
||||
data-cy="formSubmitBtn"
|
||||
/>
|
||||
<QBtn
|
||||
v-else
|
||||
|
@ -174,6 +175,7 @@ onMounted(async () => {
|
|||
filled
|
||||
dense
|
||||
@click="getStatus = 'stopping'"
|
||||
data-cy="formStopBtn"
|
||||
/>
|
||||
</QForm>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
const route = useRoute();
|
||||
|
||||
const dmsOptions = ref([]);
|
||||
const dmsId = ref(null);
|
||||
|
||||
const importDms = async () => {
|
||||
try {
|
||||
if (!dmsId.value) throw new Error(t(`vehicle.errors.documentIdEmpty`));
|
||||
|
||||
const data = {
|
||||
vehicleFk: route.params.id,
|
||||
dmsFk: dmsId.value,
|
||||
};
|
||||
|
||||
await axios.post('vehicleDms', data);
|
||||
notify(t('globals.dataSaved'), 'positive');
|
||||
dmsId.value = null;
|
||||
emit('onDataSaved');
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Dms"
|
||||
:filter="{ fields: ['id'], order: 'id ASC' }"
|
||||
auto-load
|
||||
@on-fetch="(data) => (dmsOptions = data)"
|
||||
/>
|
||||
<FormModelPopup
|
||||
model="DmsImport"
|
||||
:title="t('globals.selectDocumentId')"
|
||||
:form-initial-data="{}"
|
||||
:save-fn="importDms"
|
||||
>
|
||||
<template #form-inputs>
|
||||
<VnSelect
|
||||
:label="t('globals.document')"
|
||||
:options="dmsOptions"
|
||||
hide-selected
|
||||
option-label="id"
|
||||
option-value="id"
|
||||
v-model="dmsId"
|
||||
/>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
</template>
|
|
@ -0,0 +1,42 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import VnDmsList from 'src/components/common/VnDmsList.vue';
|
||||
import VehicleDmsImportForm from 'src/pages/Route/Vehicle/Card/VehicleDmsImportForm.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const dmsListRef = ref(null);
|
||||
const showImportDialog = ref(false);
|
||||
|
||||
const onDataSaved = () => dmsListRef.value.dmsRef.fetch();
|
||||
</script>
|
||||
<template>
|
||||
<VnDmsList
|
||||
ref="dmsListRef"
|
||||
model="VehicleDms"
|
||||
update-model="vehicles"
|
||||
delete-model="VehicleDms"
|
||||
download-model="dms"
|
||||
default-dms-code="vehicles"
|
||||
filter="vehicleFk"
|
||||
/>
|
||||
<QDialog v-model="showImportDialog">
|
||||
<VehicleDmsImportForm @on-data-saved="onDataSaved()" />
|
||||
</QDialog>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 90]">
|
||||
<QBtn
|
||||
fab
|
||||
color="primary"
|
||||
icon="file_copy"
|
||||
@click="showImportDialog = true"
|
||||
class="fill-icon"
|
||||
data-cy="importBtn"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('globals.import') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QPageSticky>
|
||||
</template>
|
|
@ -18,3 +18,5 @@ vehicle:
|
|||
params:
|
||||
vehicleTypeFk: Type
|
||||
vehicleStateFk: State
|
||||
errors:
|
||||
documentIdEmpty: The document identifier can't be empty
|
||||
|
|
|
@ -18,3 +18,5 @@ vehicle:
|
|||
params:
|
||||
vehicleTypeFk: Tipo
|
||||
vehicleStateFk: Estado
|
||||
errors:
|
||||
documentIdEmpty: El número de documento no puede estar vacío
|
||||
|
|
|
@ -34,7 +34,7 @@ const importDms = async () => {
|
|||
dmsId.value = null;
|
||||
emit('onDataSaved');
|
||||
} catch (e) {
|
||||
throw new Error(e.message);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -49,7 +49,7 @@ const importDms = async () => {
|
|||
<FormModelPopup
|
||||
url-create="genera"
|
||||
model="DmsImport"
|
||||
:title="t('Select document id')"
|
||||
:title="t('globals.selectDocumentId')"
|
||||
:form-initial-data="{}"
|
||||
:save-fn="importDms"
|
||||
>
|
||||
|
@ -70,7 +70,6 @@ const importDms = async () => {
|
|||
|
||||
<i18n>
|
||||
es:
|
||||
Select document id: Introduzca id de gestion documental
|
||||
Document: Documento
|
||||
The document indentifier can't be empty: El número de documento no puede estar vacío
|
||||
</i18n>
|
||||
|
|
|
@ -166,7 +166,11 @@ const vehicleCard = {
|
|||
component: () => import('src/pages/Route/Vehicle/Card/VehicleCard.vue'),
|
||||
redirect: { name: 'VehicleSummary' },
|
||||
meta: {
|
||||
menu: ['VehicleBasicData', 'VehicleNotes'],
|
||||
menu: [
|
||||
'VehicleBasicData',
|
||||
'VehicleNotes',
|
||||
'VehicleDms',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -195,7 +199,16 @@ const vehicleCard = {
|
|||
icon: 'vn:notes',
|
||||
},
|
||||
component: () => import('src/pages/Route/Vehicle/Card/VehicleNotes.vue'),
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'VehicleDms',
|
||||
path: 'dms',
|
||||
meta: {
|
||||
title: 'dms',
|
||||
icon: 'cloud_upload',
|
||||
},
|
||||
component: () => import('src/pages/Route/Vehicle/VehicleDms.vue'),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('EntryDms', () => {
|
|||
cy.dataCy('recalc').should('be.disabled');
|
||||
|
||||
cy.dataCy('dateFrom').should('be.visible').click().type('01-01-2001');
|
||||
cy.dataCy('dateTo').should('be.visible').click().type('01-01-2001');
|
||||
cy.dataCy('dateTo').should('be.visible').click().type('01-01-2001{enter}');
|
||||
|
||||
cy.dataCy('recalc').should('be.enabled').click();
|
||||
cy.get('.q-notification__message').should(
|
||||
|
|
|
@ -22,6 +22,7 @@ describe('InvoiceOut global invoicing', () => {
|
|||
cy.get('.q-date__years-content > :nth-child(2) > .q-btn').click();
|
||||
cy.get('.q-date__calendar-days > :nth-child(6) > .q-btn').click();
|
||||
cy.get('[label="Max date ticket"]').type('01-01-2001{enter}');
|
||||
cy.dataCy('formSubmitBtn').click();
|
||||
cy.get('.q-card').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
describe('RouteAutonomous', () => {
|
||||
const getLinkSelector = (colField) =>
|
||||
`tr:first-child > [data-col-field="${colField}"] > .no-padding > .link`;
|
||||
const getLinkSelector = (colField, link = true) =>
|
||||
`tr:first-child > [data-col-field="${colField}"] > .no-padding${link ? ' > .link' : ''}`;
|
||||
|
||||
const selectors = {
|
||||
reference: 'Reference_input',
|
||||
date: 'tr:first-child > [data-col-field="dated"]',
|
||||
total: '.value > .text-h6',
|
||||
routeId: getLinkSelector('routeFk', false),
|
||||
agencyRoute: getLinkSelector('agencyModeName'),
|
||||
agencyAgreement: getLinkSelector('agencyAgreement'),
|
||||
received: getLinkSelector('invoiceInFk'),
|
||||
autonomous: getLinkSelector('supplierName'),
|
||||
firstRowCheckbox: '.q-virtual-scroll__content tr:first-child .q-checkbox__bg',
|
||||
|
@ -13,22 +14,30 @@ describe('RouteAutonomous', () => {
|
|||
createInvoiceBtn: '.q-card > .q-btn',
|
||||
saveFormBtn: 'FormModelPopup_save',
|
||||
summaryIcon: 'tableAction-0',
|
||||
summaryPopupBtn: '.header > :nth-child(2) > .q-btn__content > .q-icon',
|
||||
summaryHeader: '.summaryHeader > :nth-child(2)',
|
||||
descriptorHeader: '.summaryHeader > div',
|
||||
descriptorTitle: '.q-item__label--header > .title > span',
|
||||
summaryGoToSummaryBtn: '.header > .q-icon',
|
||||
descriptorGoToSummaryBtn: '.descriptor > .header > a[href] > .q-btn',
|
||||
descriptorRouteSubtitle: '[data-cy="vnDescriptor_subtitle"]',
|
||||
descriptorAgencyAndSupplierTitle: '[data-cy="vnDescriptor_description"]',
|
||||
descriptorInvoiceInTitle: '[data-cy="vnDescriptor_title"]',
|
||||
descriptorOpenSummaryBtn: '.q-menu > .descriptor [data-cy="openSummaryBtn"]',
|
||||
descriptorGoToSummaryBtn: '.q-menu > .descriptor [data-cy="goToSummaryBtn"]',
|
||||
summaryGoToSummaryBtn: '.summaryHeader [data-cy="goToSummaryBtn"]',
|
||||
};
|
||||
|
||||
const data = {
|
||||
reference: 'Test invoice',
|
||||
total: '€206.40',
|
||||
supplier: 'PLANTS SL',
|
||||
route: 'first route',
|
||||
const newInvoice = {
|
||||
Reference: { val: 'Test invoice' },
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
Warehouse: { val: 'Warehouse One', type: 'select' },
|
||||
Type: { val: 'Vehiculos', type: 'select' },
|
||||
Description: { val: 'Test description' },
|
||||
};
|
||||
|
||||
const summaryUrl = '/summary';
|
||||
const total = '€206.40';
|
||||
|
||||
const urls = {
|
||||
summaryAgencyUrlRegex: /agency\/\d+\/summary/,
|
||||
summaryInvoiceInUrlRegex: /invoice-in\/\d+\/summary/,
|
||||
summarySupplierUrlRegex: /supplier\/\d+\/summary/,
|
||||
summaryRouteUrlRegex: /route\/\d+\/summary/,
|
||||
};
|
||||
const dataSaved = 'Data saved';
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -47,7 +56,7 @@ describe('RouteAutonomous', () => {
|
|||
it.skip('Should create invoice in to selected route', () => {
|
||||
cy.get(selectors.firstRowCheckbox).click();
|
||||
cy.get(selectors.createInvoiceBtn).click();
|
||||
cy.dataCy(selectors.reference).type(data.reference);
|
||||
cy.fillInForm(newInvoice);
|
||||
cy.dataCy('attachFile').click();
|
||||
cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
|
||||
force: true,
|
||||
|
@ -59,62 +68,120 @@ describe('RouteAutonomous', () => {
|
|||
it('Should display the total price of the selected rows', () => {
|
||||
cy.get(selectors.firstRowCheckbox).click();
|
||||
cy.get(selectors.secondRowCheckbox).click();
|
||||
cy.validateContent(selectors.total, data.total);
|
||||
cy.validateContent(selectors.total, total);
|
||||
});
|
||||
|
||||
it('Should redirect to the summary when clicking a route', () => {
|
||||
cy.get(selectors.date).click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.route);
|
||||
cy.url().should('include', summaryUrl);
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.routeId,
|
||||
expectedUrlRegex: urls.summaryRouteUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorRouteSubtitle,
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('Received pop-ups', () => {
|
||||
it('Should redirect to invoice in summary from the received descriptor pop-up', () => {
|
||||
cy.get(selectors.received).click();
|
||||
cy.validateContent(selectors.descriptorTitle, data.reference);
|
||||
cy.get(selectors.descriptorGoToSummaryBtn).click();
|
||||
cy.get(selectors.descriptorHeader).should('contain', data.supplier);
|
||||
cy.url().should('include', summaryUrl);
|
||||
describe('Agency route pop-ups', () => {
|
||||
it('Should redirect to the agency route summary from the agency route descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.agencyRoute,
|
||||
steps: [selectors.descriptorGoToSummaryBtn],
|
||||
expectedUrlRegex: urls.summaryAgencyUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to the agency route summary from summary pop-up from the agency route descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.agencyRoute,
|
||||
steps: [
|
||||
selectors.descriptorOpenSummaryBtn,
|
||||
selectors.summaryGoToSummaryBtn,
|
||||
],
|
||||
expectedUrlRegex: urls.summaryAgencyUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Agency route pop-ups', () => {
|
||||
it('Should redirect to the agency agreement summary from the agency agreement descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.agencyAgreement,
|
||||
steps: [selectors.descriptorGoToSummaryBtn],
|
||||
expectedUrlRegex: urls.summaryAgencyUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to the agency agreement summary from summary pop-up from the agency agreement descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.agencyAgreement,
|
||||
steps: [
|
||||
selectors.descriptorOpenSummaryBtn,
|
||||
selectors.summaryGoToSummaryBtn,
|
||||
],
|
||||
expectedUrlRegex: urls.summaryAgencyUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Received pop-ups', () => {
|
||||
it('Should redirect to the invoice in summary from the received descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.received,
|
||||
steps: [selectors.descriptorGoToSummaryBtn],
|
||||
expectedUrlRegex: urls.summaryInvoiceInUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorInvoiceInTitle,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to the invoiceIn summary from summary pop-up from the received descriptor pop-up', () => {
|
||||
cy.get(selectors.received).click();
|
||||
cy.validateContent(selectors.descriptorTitle, data.reference);
|
||||
cy.get(selectors.summaryPopupBtn).click();
|
||||
cy.get(selectors.descriptorHeader).should('contain', data.supplier);
|
||||
cy.get(selectors.summaryGoToSummaryBtn).click();
|
||||
cy.get(selectors.descriptorHeader).should('contain', data.supplier);
|
||||
cy.url().should('include', summaryUrl);
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.received,
|
||||
steps: [
|
||||
selectors.descriptorOpenSummaryBtn,
|
||||
selectors.summaryGoToSummaryBtn,
|
||||
],
|
||||
expectedUrlRegex: urls.summaryInvoiceInUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorInvoiceInTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Autonomous pop-ups', () => {
|
||||
it('Should redirect to the supplier summary from the received descriptor pop-up', () => {
|
||||
cy.get(selectors.autonomous).click();
|
||||
cy.validateContent(selectors.descriptorTitle, data.supplier);
|
||||
cy.get(selectors.descriptorGoToSummaryBtn).click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.supplier);
|
||||
cy.url().should('include', summaryUrl);
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.autonomous,
|
||||
steps: [selectors.descriptorGoToSummaryBtn],
|
||||
expectedUrlRegex: urls.summarySupplierUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to the supplier summary from summary pop-up from the autonomous descriptor pop-up', () => {
|
||||
cy.get(selectors.autonomous).click();
|
||||
cy.get(selectors.descriptorTitle).should('contain', data.supplier);
|
||||
cy.get(selectors.summaryPopupBtn).click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.supplier);
|
||||
cy.get(selectors.summaryGoToSummaryBtn).click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.supplier);
|
||||
cy.url().should('include', summaryUrl);
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.autonomous,
|
||||
steps: [
|
||||
selectors.descriptorOpenSummaryBtn,
|
||||
selectors.summaryGoToSummaryBtn,
|
||||
],
|
||||
expectedUrlRegex: urls.summarySupplierUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorAgencyAndSupplierTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Route pop-ups', () => {
|
||||
it('Should redirect to the summary from the route summary pop-up', () => {
|
||||
cy.dataCy(selectors.summaryIcon).first().click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.route);
|
||||
cy.get(selectors.summaryGoToSummaryBtn).click();
|
||||
cy.get(selectors.summaryHeader).should('contain', data.route);
|
||||
cy.url().should('include', summaryUrl);
|
||||
cy.get(selectors.routeId)
|
||||
.invoke('text')
|
||||
.then((routeId) => {
|
||||
routeId = routeId.trim();
|
||||
cy.dataCy(selectors.summaryIcon).first().click();
|
||||
cy.get(selectors.summaryGoToSummaryBtn).click();
|
||||
cy.url().should('match', urls.summaryRouteUrlRegex);
|
||||
cy.containContent(selectors.descriptorRouteSubtitle, routeId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -69,7 +69,8 @@ describe.skip('Route extended list', () => {
|
|||
.type(`{selectall}{backspace}${value}`);
|
||||
break;
|
||||
case 'checkbox':
|
||||
cy.get(selector).should('be.visible').click().click();
|
||||
cy.get(selector).should('be.visible').click()
|
||||
cy.get(selector).click();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
describe('Vehicle DMS', () => {
|
||||
const getSelector = (btnPosition) =>
|
||||
`tr:last-child > .text-right > .no-wrap > :nth-child(${btnPosition}) > .q-btn > .q-btn__content > .q-icon`;
|
||||
|
||||
const selectors = {
|
||||
lastRowDownloadBtn: getSelector(1),
|
||||
lastRowEditBtn: getSelector(2),
|
||||
lastRowDeleteBtn: getSelector(3),
|
||||
lastRowReference: 'tr:last-child > :nth-child(5) > .q-tr > :nth-child(1) > span',
|
||||
firstRowReference:
|
||||
'tr:first-child > :nth-child(5) > .q-tr > :nth-child(1) > span',
|
||||
firstRowId: 'tr:first-child > :nth-child(2) > .q-tr > :nth-child(1) > span',
|
||||
lastRowWorkerLink: 'tr:last-child > :nth-child(8) > .q-tr > .link',
|
||||
descriptorTitle: '.descriptor .title',
|
||||
descriptorOpenSummaryBtn: '.q-menu .descriptor [data-cy="openSummaryBtn"]',
|
||||
descriptorGoToSummaryBtn: '.q-menu .descriptor [data-cy="goToSummaryBtn"]',
|
||||
summaryGoToSummaryBtn: '.summaryHeader [data-cy="goToSummaryBtn"]',
|
||||
summaryTitle: '.summaryHeader',
|
||||
referenceInput: 'Reference_input',
|
||||
companySelect: 'Company_select',
|
||||
warehouseSelect: 'Warehouse_select',
|
||||
typeSelect: 'Type_select',
|
||||
fileInput: 'VnDms_inputFile',
|
||||
importBtn: '[data-cy="importBtn"]',
|
||||
addBtn: '[data-cy="addButton"]',
|
||||
saveFormBtn: 'FormModelPopup_save',
|
||||
};
|
||||
|
||||
const data = {
|
||||
Reference: { val: 'Vehicle:1234-ABC' },
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
Warehouse: { val: 'Warehouse One', type: 'select' },
|
||||
Type: { val: 'Vehiculos', type: 'select' },
|
||||
};
|
||||
|
||||
const updateData = {
|
||||
Reference: { val: 'Vehicle:4598-FGH' },
|
||||
Company: { val: 'CCs', type: 'select' },
|
||||
Warehouse: { val: 'Warehouse Two', type: 'select' },
|
||||
Type: { val: 'Facturas Recibidas', type: 'select' },
|
||||
};
|
||||
|
||||
const workerSummaryUrlRegex = /worker\/\d+\/summary/;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/route/vehicle/1/dms`);
|
||||
});
|
||||
|
||||
it('should display vehicle DMS', () => {
|
||||
cy.get('.q-table')
|
||||
.children()
|
||||
.should('be.visible')
|
||||
.should('have.length.greaterThan', 0);
|
||||
});
|
||||
|
||||
it.skip('Should download DMS', () => {
|
||||
const fileName = '11.jpg';
|
||||
cy.intercept('GET', /\/api\/dms\/11\/downloadFile/).as('download');
|
||||
cy.get(selectors.lastRowDownloadBtn).click();
|
||||
|
||||
cy.wait('@download').then((interception) => {
|
||||
expect(interception.response.statusCode).to.equal(200);
|
||||
expect(interception.response.headers['content-disposition']).to.contain(
|
||||
fileName,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should create new DMS', () => {
|
||||
const formSelectors = {
|
||||
actionBtn: selectors.addBtn,
|
||||
fileInput: selectors.fileInput,
|
||||
saveFormBtn: selectors.saveFormBtn,
|
||||
};
|
||||
|
||||
cy.testDmsAction('create', formSelectors, data, 'Data saved');
|
||||
});
|
||||
|
||||
it('Should import DMS', () => {
|
||||
const data = {
|
||||
Document: { val: '10', type: 'select' },
|
||||
};
|
||||
const formSelectors = {
|
||||
actionBtn: selectors.importBtn,
|
||||
selectorContentToCheck: selectors.lastRowReference,
|
||||
saveFormBtn: selectors.saveFormBtn,
|
||||
};
|
||||
|
||||
cy.testDmsAction('import', formSelectors, data, 'Data saved', '1');
|
||||
});
|
||||
|
||||
it('Should edit DMS', () => {
|
||||
const formSelectors = {
|
||||
actionBtn: selectors.lastRowEditBtn,
|
||||
selectorContentToCheck: selectors.lastRowReference,
|
||||
saveFormBtn: selectors.saveFormBtn,
|
||||
};
|
||||
|
||||
cy.testDmsAction(
|
||||
'edit',
|
||||
formSelectors,
|
||||
updateData,
|
||||
'Data saved',
|
||||
updateData.Reference.val,
|
||||
);
|
||||
});
|
||||
|
||||
it('Should delete DMS', () => {
|
||||
const formSelectors = {
|
||||
actionBtn: selectors.lastRowDeleteBtn,
|
||||
selectorContentToCheck: selectors.lastRowReference,
|
||||
};
|
||||
|
||||
cy.testDmsAction(
|
||||
'delete',
|
||||
formSelectors,
|
||||
null,
|
||||
'Data deleted',
|
||||
'Vehicle:3333-BAT',
|
||||
);
|
||||
});
|
||||
|
||||
describe('Worker pop-ups', () => {
|
||||
it('Should redirect to worker summary from worker descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.lastRowWorkerLink,
|
||||
steps: [selectors.descriptorGoToSummaryBtn],
|
||||
expectedUrlRegex: workerSummaryUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorTitle,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to worker summary from summary pop-up from worker descriptor pop-up', () => {
|
||||
cy.checkRedirectionFromPopUp({
|
||||
selectorToClick: selectors.lastRowWorkerLink,
|
||||
steps: [
|
||||
selectors.descriptorOpenSummaryBtn,
|
||||
selectors.summaryGoToSummaryBtn,
|
||||
],
|
||||
expectedUrlRegex: workerSummaryUrlRegex,
|
||||
expectedTextSelector: selectors.descriptorTitle,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -195,8 +195,8 @@ Cypress.Commands.add('fillInForm', (obj, opts = {}) => {
|
|||
break;
|
||||
case 'date':
|
||||
cy.get(el).type(
|
||||
`{selectall}{backspace}${val.split('-').join('')}`,
|
||||
);
|
||||
`{selectall}{backspace}${val}`,
|
||||
).blur();
|
||||
break;
|
||||
case 'time':
|
||||
cy.get(el).click();
|
||||
|
@ -635,3 +635,41 @@ Cypress.Commands.add('validateScrollContent', (validations) => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'checkRedirectionFromPopUp',
|
||||
({ selectorToClick, steps = [], expectedUrlRegex, expectedTextSelector }) => {
|
||||
cy.get(selectorToClick)
|
||||
.click()
|
||||
.invoke('text')
|
||||
.then((label) => {
|
||||
label = label.trim();
|
||||
|
||||
steps.forEach((stepSelector) => {
|
||||
cy.get(stepSelector).should('be.visible').click();
|
||||
});
|
||||
|
||||
cy.location().should('match', expectedUrlRegex);
|
||||
cy.containContent(expectedTextSelector, label);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
Cypress.Commands.add('testDmsAction', (action, selectors, data, message, content) => {
|
||||
cy.get(selectors.actionBtn).click();
|
||||
|
||||
if (action === 'create') {
|
||||
cy.dataCy(selectors.fileInput).selectFile('test/cypress/fixtures/image.jpg', {
|
||||
force: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (action !== 'delete') {
|
||||
cy.fillInForm(data);
|
||||
cy.dataCy(selectors.saveFormBtn).click();
|
||||
} else cy.clickConfirm();
|
||||
|
||||
cy.checkNotification(message);
|
||||
|
||||
if (action !== 'create') cy.containContent(selectors.selectorContentToCheck, content);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue