parent
694c5494ef
commit
4cb4ad9532
|
@ -1,8 +1,80 @@
|
|||
import UserPanel from 'src/components/UserPanel.vue';
|
||||
// UserPanel.spec.js
|
||||
import UserPanel from 'src/components/common/UserPanel.vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
describe.skip('<UserPanel />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<UserPanel />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock composables and dependencies
|
||||
cy.stub(window, 'useI18n').returns({
|
||||
t: (key) => key,
|
||||
locale: 'en',
|
||||
});
|
||||
cy.stub(window, 'useRouter').returns({});
|
||||
cy.stub(window, 'useState').returns({});
|
||||
cy.stub(window, 'useSession').returns({});
|
||||
cy.stub(window, 'useClipboard').returns({
|
||||
copyText: cy.stub().as('copyTextStub'),
|
||||
});
|
||||
cy.stub(window, 'useRole').returns({});
|
||||
cy.stub(window, 'useNotify').returns({
|
||||
notify: cy.stub().as('notifyStub'),
|
||||
});
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders user panel components', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.getComponent('VnSelect').should('exist');
|
||||
cy.getComponent('VnRow').should('exist');
|
||||
cy.getComponent('FetchData').should('exist');
|
||||
cy.getComponent('VnAvatar').should('exist');
|
||||
});
|
||||
|
||||
it('displays user locale correctly', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.wrap(Cypress.vueWrapper.vm.userLocale).should('equal', 'en');
|
||||
});
|
||||
|
||||
it('updates locale when userLocale is changed', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.wrap(Cypress.vueWrapper.vm.userLocale).set('fr');
|
||||
cy.wrap(Cypress.vueWrapper.vm.locale).should('equal', 'fr');
|
||||
});
|
||||
|
||||
it('copies text to clipboard', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.get('.copy-button').click();
|
||||
cy.get('@copyTextStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('notifies user on copy', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.get('.copy-button').click();
|
||||
cy.get('@notifyStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('fetches user data on mount', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('renders user avatar', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.getComponent('VnAvatar').should('exist');
|
||||
});
|
||||
|
||||
it('handles dark mode toggle', () => {
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.get('.dark-mode-toggle').click();
|
||||
cy.wrap(Cypress.vueWrapper.vm.$q.dark.isActive).should('be.true');
|
||||
});
|
||||
|
||||
it('handles logout action', () => {
|
||||
const routerPush = cy.spy().as('routerPush');
|
||||
cy.stub(window, 'useRouter').returns({ push: routerPush });
|
||||
|
||||
cy.createWrapper(UserPanel);
|
||||
cy.get('.logout-button').click();
|
||||
cy.get('@routerPush').should('have.been.calledWith', '/login');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,60 @@
|
|||
// RightMenu.spec.js
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
|
||||
describe.skip('<RightMenu />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<RightMenu />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock stores and composables
|
||||
cy.stub(window, 'useStateStore').returns({
|
||||
rightDrawer: false,
|
||||
isHeaderMounted: () => true,
|
||||
});
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
});
|
||||
|
||||
it('renders correctly', () => {
|
||||
cy.createWrapper(RightMenu);
|
||||
cy.get('#actions-append').should('exist');
|
||||
});
|
||||
|
||||
it('observes right panel content changes', () => {
|
||||
cy.createWrapper(RightMenu);
|
||||
const rightPanel = document.createElement('div');
|
||||
rightPanel.id = 'right-panel';
|
||||
document.body.appendChild(rightPanel);
|
||||
|
||||
const newChild = document.createElement('div');
|
||||
rightPanel.appendChild(newChild);
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.hasContent).should('equal', 1);
|
||||
rightPanel.remove();
|
||||
});
|
||||
|
||||
it('hides right drawer when no content and no slot', () => {
|
||||
cy.createWrapper(RightMenu);
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.rightDrawer).should('be.false');
|
||||
});
|
||||
|
||||
it('shows right drawer when slot content is provided', () => {
|
||||
cy.createWrapper(RightMenu, {
|
||||
slots: {
|
||||
'right-panel': '<div>Slot Content</div>',
|
||||
},
|
||||
});
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.rightDrawer).should('be.true');
|
||||
});
|
||||
|
||||
it('teleports content to #actions-append when header is mounted', () => {
|
||||
cy.createWrapper(RightMenu);
|
||||
cy.get('#actions-append').should('exist');
|
||||
});
|
||||
|
||||
it('does not teleport content when header is not mounted', () => {
|
||||
cy.stub(window, 'useStateStore').returns({
|
||||
rightDrawer: false,
|
||||
isHeaderMounted: () => false,
|
||||
});
|
||||
|
||||
cy.createWrapper(RightMenu);
|
||||
cy.get('#actions-append').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import VnAccountNumber from 'src/components/common/VnAccountNumber.vue';
|
||||
import { Quasar, QInput } from 'quasar';
|
||||
|
||||
describe('<VnAccountNumber />', () => {
|
||||
// VNAccountNumber.spec.js
|
||||
|
||||
describe.only('<VnAccountNumber />', () => {
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWeapper(VnAccountNumber, {
|
||||
global: {
|
||||
|
|
|
@ -67,9 +67,9 @@ describe('<VnBreadcrumbs />', () => {
|
|||
|
||||
router.push('/nometa');
|
||||
router.isReady().then(() => {
|
||||
mount(VnBreadcrumbs, {
|
||||
cy.createWrapper(VnBreadcrumbs, {
|
||||
global: {
|
||||
plugins: [router, Quasar],
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
cy.get('.breadcrumbs').should('not.exist');
|
||||
|
|
|
@ -1,8 +1,89 @@
|
|||
import VnCard from 'src/components/common/VnCard.vue';
|
||||
|
||||
describe.skip('<VnCard />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnCard);
|
||||
describe.only('<VnCard />', () => {
|
||||
beforeEach(() => {
|
||||
// Montar el componente antes de cada prueba con valores predeterminados
|
||||
cy.mount(VnCard, {
|
||||
props: {
|
||||
element: { name: 'Item' },
|
||||
id: 1,
|
||||
isSelected: false,
|
||||
title: 'Card Title',
|
||||
showCheckbox: true,
|
||||
hasInfoIcons: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should display title and ID chip', () => {
|
||||
// Verificar que el título esté presente
|
||||
cy.contains('Card Title').should('be.visible');
|
||||
|
||||
// Verificar que la etiqueta ID esté presente y visible
|
||||
cy.contains('ID: 1').should('be.visible');
|
||||
});
|
||||
|
||||
it('should display checkbox when showCheckbox is true', () => {
|
||||
// Verificar que el checkbox esté visible cuando showCheckbox es verdadero
|
||||
cy.get('.q-checkbox').should('exist');
|
||||
});
|
||||
|
||||
it('should emit toggleCardCheck event when checkbox is clicked', () => {
|
||||
// Espiar el evento `toggleCardCheck`
|
||||
const onToggleCardCheck = cy.spy().as('toggleCardCheckEvent');
|
||||
cy.mount({
|
||||
props: {
|
||||
element: { name: 'Item' },
|
||||
showCheckbox: true,
|
||||
},
|
||||
listeners: {
|
||||
toggleCardCheck: onToggleCardCheck,
|
||||
},
|
||||
});
|
||||
|
||||
// Hacer clic en el checkbox
|
||||
cy.get('.q-checkbox').click();
|
||||
|
||||
// Asegurarse de que el evento `toggleCardCheck` se emitió
|
||||
cy.get('@toggleCardCheckEvent').should('have.been.calledOnce');
|
||||
});
|
||||
|
||||
it('should display info-icons slot content when hasInfoIcons is true', () => {
|
||||
// Montar el componente con el slot info-icons
|
||||
cy.mount({
|
||||
props: {
|
||||
hasInfoIcons: true,
|
||||
},
|
||||
slots: {
|
||||
'info-icons': `<div class="info-icon-slot">Info Icon</div>`,
|
||||
},
|
||||
});
|
||||
|
||||
// Verificar que el contenido del slot `info-icons` esté visible
|
||||
cy.get('.info-icon-slot').should('be.visible');
|
||||
});
|
||||
|
||||
it('should display list-items slot content', () => {
|
||||
// Montar el componente con el slot `list-items`
|
||||
cy.mount({
|
||||
slots: {
|
||||
'list-items': `<div class="list-item-slot">List Item</div>`,
|
||||
},
|
||||
});
|
||||
|
||||
// Verificar que el contenido del slot `list-items` esté visible
|
||||
cy.get('.list-item-slot').should('be.visible');
|
||||
});
|
||||
|
||||
it('should display actions slot content', () => {
|
||||
// Montar el componente con el slot `actions`
|
||||
cy.mount({
|
||||
slots: {
|
||||
actions: `<button class="action-button">Action</button>`,
|
||||
},
|
||||
});
|
||||
|
||||
// Verificar que el contenido del slot `actions` esté visible
|
||||
cy.get('.action-button').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,107 @@
|
|||
// VnComponent.spec.js
|
||||
import VnComponent from 'src/components/common/VnComponent.vue';
|
||||
|
||||
describe.skip('<VnComponent />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnComponent);
|
||||
describe.only('<VnComponent />', () => {
|
||||
const basicProp = {
|
||||
component: 'TestComponent',
|
||||
attrs: { test: 'value' },
|
||||
};
|
||||
|
||||
const basicComponents = {
|
||||
TestComponent: {
|
||||
component: 'CustomTestComponent',
|
||||
attrs: { customAttr: 'customValue' },
|
||||
},
|
||||
};
|
||||
|
||||
it('renders single prop component', () => {
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: basicProp,
|
||||
modelValue: 'test',
|
||||
},
|
||||
});
|
||||
cy.get('TestComponent').should('exist');
|
||||
});
|
||||
|
||||
it('renders array of prop components', () => {
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: [basicProp, { ...basicProp, component: 'SecondComponent' }],
|
||||
modelValue: 'test',
|
||||
},
|
||||
});
|
||||
cy.get('TestComponent').should('exist');
|
||||
cy.get('SecondComponent').should('exist');
|
||||
});
|
||||
|
||||
it('mixes component attributes correctly', () => {
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: basicProp,
|
||||
components: basicComponents,
|
||||
modelValue: 'test',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('CustomTestComponent').invoke('props').should('deep.include', {
|
||||
test: 'value',
|
||||
customAttr: 'customValue',
|
||||
});
|
||||
});
|
||||
|
||||
it('handles event definitions', () => {
|
||||
const eventProp = {
|
||||
...basicProp,
|
||||
event: 'custom-event',
|
||||
};
|
||||
|
||||
const onCustomEvent = cy.spy().as('eventSpy');
|
||||
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: eventProp,
|
||||
modelValue: 'test',
|
||||
onCustomEvent,
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('TestComponent').trigger('custom-event');
|
||||
cy.get('@eventSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('applies forced attributes from components', () => {
|
||||
const componentsWithForced = {
|
||||
TestComponent: {
|
||||
...basicComponents.TestComponent,
|
||||
forceAttrs: { forcedAttr: 'forced' },
|
||||
},
|
||||
};
|
||||
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: basicProp,
|
||||
components: componentsWithForced,
|
||||
modelValue: 'test',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('CustomTestComponent')
|
||||
.invoke('props')
|
||||
.should('deep.include', { forcedAttr: 'forced' });
|
||||
});
|
||||
|
||||
it('handles value bindings', () => {
|
||||
cy.createWrapper(VnComponent, {
|
||||
props: {
|
||||
prop: basicProp,
|
||||
value: { testValue: 123 },
|
||||
modelValue: 'test',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('TestComponent')
|
||||
.invoke('props')
|
||||
.should('deep.include', { testValue: 123 });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,94 @@
|
|||
// VnDms.spec.js
|
||||
import VnDms from 'src/components/common/VnDms.vue';
|
||||
|
||||
describe.skip('<VnDms />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnDms);
|
||||
describe.only('<VnDms />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useRoute').returns({});
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders with required props', () => {
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
cy.get('.vn-dms').should('exist');
|
||||
});
|
||||
|
||||
it('initializes with default DMS code', () => {
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
defaultDmsCode: 'DMS001',
|
||||
},
|
||||
});
|
||||
cy.getComponent('VnSelect').should('have.value', 'DMS001');
|
||||
});
|
||||
|
||||
it('loads form with initial data', () => {
|
||||
const initialData = { field: 'value' };
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
formInitialData: initialData,
|
||||
},
|
||||
});
|
||||
cy.getComponent('FormModelPopup')
|
||||
.invoke('props', 'initialData')
|
||||
.should('deep.equal', initialData);
|
||||
});
|
||||
|
||||
it('fetches data from custom URL when provided', () => {
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
url: '/api/custom-dms',
|
||||
},
|
||||
});
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
url: '/api/custom-dms',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('emits onDataSaved event when form is submitted', () => {
|
||||
const onDataSaved = cy.spy().as('savedSpy');
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
onDataSaved,
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('FormModelPopup').trigger('saved');
|
||||
cy.get('@savedSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('renders child components correctly', () => {
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnRow').should('exist');
|
||||
cy.getComponent('VnSelect').should('exist');
|
||||
cy.getComponent('VnInput').should('exist');
|
||||
cy.getComponent('FormModelPopup').should('exist');
|
||||
});
|
||||
|
||||
it('handles fetch data errors gracefully', () => {
|
||||
cy.get('@axiosStub').rejects(new Error('Fetch Error'));
|
||||
cy.createWrapper(VnDms, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
// Verify error handling UI elements
|
||||
cy.get('.error-message').should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,112 @@
|
|||
// VnDmsList.spec.js
|
||||
import VnDmsList from 'src/components/common/VnDmsList.vue';
|
||||
|
||||
describe.skip('<VnDmsList />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnDmsList);
|
||||
describe.only('<VnDmsList />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useRoute').returns({});
|
||||
cy.stub(window, 'useQuasar').returns({});
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useSession').returns({
|
||||
getTokenMultimedia: () => 'test-token',
|
||||
});
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders with required model prop', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
cy.get('.vn-dms-list').should('exist');
|
||||
});
|
||||
|
||||
it('displays paginated data', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
cy.getComponent('VnPaginate').should('exist');
|
||||
});
|
||||
|
||||
it('handles file download', () => {
|
||||
cy.stub(window, 'downloadFile').as('downloadStub');
|
||||
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.download-button').click();
|
||||
cy.get('@downloadStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('shows DMS form dialog', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.add-dms-button').click();
|
||||
cy.getComponent('VnDms').should('exist');
|
||||
});
|
||||
|
||||
it('handles document deletion with confirmation', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
deleteModel: 'deleteTestModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.delete-button').click();
|
||||
cy.getComponent('VnConfirm').should('exist');
|
||||
cy.get('.confirm-delete-button').click();
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('displays user information using VnUserLink', () => {
|
||||
const testData = {
|
||||
rows: [{ id: 1, user: { id: 1, name: 'Test User' } }],
|
||||
};
|
||||
|
||||
cy.get('@axiosStub').resolves({ data: testData });
|
||||
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnUserLink').should('exist');
|
||||
});
|
||||
|
||||
it('shows document preview with VnImg', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnImg').should('exist');
|
||||
});
|
||||
|
||||
it('allows date filtering', () => {
|
||||
cy.createWrapper(VnDmsList, {
|
||||
props: {
|
||||
model: 'testModel',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnInputDate').type('2024-03-20');
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
params: { date: '2024-03-20' },
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,101 @@
|
|||
// VnInput.spec.js
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
describe.skip('<VnInput />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnInput />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useValidator').returns({
|
||||
validations: () => ({
|
||||
required: (isRequired, value) => (isRequired ? !!value : true),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
cy.createWrapper(VnInput);
|
||||
cy.get('.q-field').should('exist');
|
||||
cy.get('input').should('exist');
|
||||
});
|
||||
|
||||
it('binds model value correctly', () => {
|
||||
const testValue = 'test input';
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
modelValue: testValue,
|
||||
},
|
||||
});
|
||||
cy.get('input').should('have.value', testValue);
|
||||
});
|
||||
|
||||
it('emits update:modelValue on input', () => {
|
||||
const onModelValueUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
'onUpdate:modelValue': onModelValueUpdate,
|
||||
},
|
||||
});
|
||||
cy.get('input').type('new value');
|
||||
cy.get('@modelUpdateSpy').should('have.been.calledWith', 'new value');
|
||||
});
|
||||
|
||||
it('applies outlined style when isOutlined is true', () => {
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
isOutlined: true,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field--outlined').should('exist');
|
||||
});
|
||||
|
||||
it('displays info text when provided', () => {
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
info: 'Helper text',
|
||||
},
|
||||
});
|
||||
cy.get('.q-field__info').should('contain', 'Helper text');
|
||||
});
|
||||
|
||||
it('shows clear button when clearable is true and has value', () => {
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
modelValue: 'test',
|
||||
clearable: true,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field__clear').should('exist');
|
||||
});
|
||||
|
||||
it('clears input when clear button is clicked', () => {
|
||||
const onModelValueUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
modelValue: 'test',
|
||||
clearable: true,
|
||||
'onUpdate:modelValue': onModelValueUpdate,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field__clear').click();
|
||||
cy.get('@modelUpdateSpy').should('have.been.calledWith', null);
|
||||
});
|
||||
|
||||
it('emits keyup.enter event', () => {
|
||||
const onEnter = cy.spy().as('enterSpy');
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
'onKeyup.enter': onEnter,
|
||||
},
|
||||
});
|
||||
cy.get('input').type('{enter}');
|
||||
cy.get('@enterSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('handles numeric input', () => {
|
||||
cy.createWrapper(VnInput, {
|
||||
props: {
|
||||
modelValue: 123,
|
||||
},
|
||||
});
|
||||
cy.get('input').should('have.value', '123');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,103 @@
|
|||
// VnInputDate.spec.js
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
|
||||
describe.skip('<VnInputDate />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnInputDate />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useValidator').returns({
|
||||
validations: () => ({
|
||||
required: (isRequired, value) => (isRequired ? !!value : true),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
cy.createWrapper(VnInputDate);
|
||||
cy.getComponent('VnDate').should('exist');
|
||||
cy.get('input').should('exist');
|
||||
});
|
||||
|
||||
it('formats date correctly', () => {
|
||||
const testDate = '2024-03-20';
|
||||
cy.createWrapper(VnInputDate, {
|
||||
props: {
|
||||
modelValue: testDate,
|
||||
},
|
||||
});
|
||||
cy.get('input').should('have.value', '20/03/2024');
|
||||
});
|
||||
|
||||
it('validates required field', () => {
|
||||
cy.createWrapper(VnInputDate, {
|
||||
attrs: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
cy.get('input').clear();
|
||||
cy.get('.q-field__messages').should('contain', 'Field is required');
|
||||
});
|
||||
|
||||
it('opens date picker popup on click', () => {
|
||||
cy.createWrapper(VnInputDate);
|
||||
cy.get('input').click();
|
||||
cy.get('.q-date').should('be.visible');
|
||||
});
|
||||
|
||||
it('updates model value when date is selected', () => {
|
||||
const onModelUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnInputDate, {
|
||||
props: {
|
||||
'onUpdate:modelValue': onModelUpdate,
|
||||
},
|
||||
});
|
||||
cy.get('input').click();
|
||||
cy.get('.q-date__calendar-item').first().click();
|
||||
cy.get('@modelUpdateSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('applies outlined style when isOutlined is true', () => {
|
||||
cy.createWrapper(VnInputDate, {
|
||||
props: {
|
||||
isOutlined: true,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field--outlined').should('exist');
|
||||
});
|
||||
|
||||
it('handles custom validation rules', () => {
|
||||
const customRule = (val) =>
|
||||
new Date(val) <= new Date() || 'Date cannot be in the future';
|
||||
cy.createWrapper(VnInputDate, {
|
||||
attrs: {
|
||||
rules: [customRule],
|
||||
},
|
||||
});
|
||||
const futureDate = '31/12/2025';
|
||||
cy.get('input').type(futureDate);
|
||||
cy.get('.q-field__messages').should('contain', 'Date cannot be in the future');
|
||||
});
|
||||
|
||||
it('shows hover state', () => {
|
||||
cy.createWrapper(VnInputDate);
|
||||
cy.get('input').trigger('mouseenter');
|
||||
cy.get('.q-field--hover').should('exist');
|
||||
});
|
||||
|
||||
it('handles disabled state', () => {
|
||||
cy.createWrapper(VnInputDate, {
|
||||
attrs: {
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
cy.get('input').should('be.disabled');
|
||||
});
|
||||
|
||||
it('hides event indicator when showEvent is false', () => {
|
||||
cy.createWrapper(VnInputDate, {
|
||||
props: {
|
||||
showEvent: false,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field__event-indicator').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,47 @@
|
|||
// VnInputNumber.spec.js
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
|
||||
describe.skip('<VnInputNumber />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnInputNumber />', () => {
|
||||
it('renders correctly', () => {
|
||||
cy.createWrapper(VnInputNumber);
|
||||
cy.getComponent('VnInput').should('exist');
|
||||
cy.get('input[type="number"]').should('exist');
|
||||
});
|
||||
|
||||
it('accepts numeric input', () => {
|
||||
cy.createWrapper(VnInputNumber);
|
||||
cy.get('input').type('123');
|
||||
cy.get('input').should('have.value', '123');
|
||||
});
|
||||
|
||||
it('converts string input to number', () => {
|
||||
const onModelUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnInputNumber, {
|
||||
props: {
|
||||
'onUpdate:modelValue': onModelUpdate,
|
||||
},
|
||||
});
|
||||
cy.get('input').type('456');
|
||||
cy.get('@modelUpdateSpy').should('have.been.calledWith', 456);
|
||||
});
|
||||
|
||||
it('forwards attributes to VnInput', () => {
|
||||
cy.createWrapper(VnInputNumber, {
|
||||
attrs: {
|
||||
placeholder: 'Enter number',
|
||||
min: '0',
|
||||
max: '100',
|
||||
},
|
||||
});
|
||||
cy.get('input')
|
||||
.should('have.attr', 'placeholder', 'Enter number')
|
||||
.and('have.attr', 'min', '0')
|
||||
.and('have.attr', 'max', '100');
|
||||
});
|
||||
|
||||
it('handles invalid input', () => {
|
||||
cy.createWrapper(VnInputNumber);
|
||||
cy.get('input').type('abc');
|
||||
cy.get('input').should('have.value', '');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,93 @@
|
|||
// VnInputTime.spec.js
|
||||
import VnInputTime from 'src/components/common/VnInputTime.vue';
|
||||
|
||||
describe.skip('<VnInputTime />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnInputTime />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useValidator').returns({
|
||||
validations: () => ({
|
||||
required: (isRequired, value) => (isRequired ? !!value : true),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
cy.createWrapper(VnInputTime);
|
||||
cy.getComponent('VnTime').should('exist');
|
||||
cy.get('input').should('exist');
|
||||
});
|
||||
|
||||
it('formats time correctly', () => {
|
||||
const initialTime = '14:30';
|
||||
cy.createWrapper(VnInputTime, {
|
||||
props: {
|
||||
modelValue: initialTime,
|
||||
},
|
||||
});
|
||||
cy.get('input').should('have.value', initialTime);
|
||||
});
|
||||
|
||||
it('applies outlined style when isOutlined is true', () => {
|
||||
cy.createWrapper(VnInputTime, {
|
||||
props: {
|
||||
isOutlined: true,
|
||||
},
|
||||
});
|
||||
cy.get('.q-field--outlined').should('exist');
|
||||
});
|
||||
|
||||
it('validates required field', () => {
|
||||
cy.createWrapper(VnInputTime, {
|
||||
attrs: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
cy.get('input').clear();
|
||||
cy.get('.q-field__messages').should('contain', 'Field is required');
|
||||
});
|
||||
|
||||
it('opens time picker popup on click', () => {
|
||||
cy.createWrapper(VnInputTime);
|
||||
cy.get('input').click();
|
||||
cy.get('.q-time').should('be.visible');
|
||||
});
|
||||
|
||||
it('updates model value when time is selected', () => {
|
||||
const onModelUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnInputTime, {
|
||||
props: {
|
||||
'onUpdate:modelValue': onModelUpdate,
|
||||
},
|
||||
});
|
||||
cy.get('input').click();
|
||||
cy.get('.q-time__clock--hours .q-time__clock-position').first().click();
|
||||
cy.get('@modelUpdateSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('shows hover state', () => {
|
||||
cy.createWrapper(VnInputTime);
|
||||
cy.get('input').trigger('mouseenter');
|
||||
cy.get('.q-field--hover').should('exist');
|
||||
});
|
||||
|
||||
it('applies custom validation rules', () => {
|
||||
const customRule = (val) => val < '20:00' || 'Time must be before 20:00';
|
||||
cy.createWrapper(VnInputTime, {
|
||||
attrs: {
|
||||
rules: [customRule],
|
||||
},
|
||||
});
|
||||
cy.get('input').type('21:00');
|
||||
cy.get('.q-field__messages').should('contain', 'Time must be before 20:00');
|
||||
});
|
||||
|
||||
it('displays time-only format when timeOnly is true', () => {
|
||||
cy.createWrapper(VnInputTime, {
|
||||
props: {
|
||||
timeOnly: true,
|
||||
},
|
||||
});
|
||||
cy.get('input').type('14:30');
|
||||
cy.get('input').should('have.value', '14:30');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
describe.skip('<VnLocation />', () => {
|
||||
describe.only('<VnLocation />', () => {
|
||||
const location = {
|
||||
postcode: '46000',
|
||||
city: 'Valencia',
|
||||
|
|
|
@ -1,8 +1,73 @@
|
|||
import VnLogFilter from 'src/components/common/VnLogFilter.vue';
|
||||
|
||||
describe.skip('<VnLogFilter />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnLogFilter);
|
||||
describe.only('<VnLogFilter />', () => {
|
||||
const mountComponent = () => {
|
||||
// Stub del componente FetchData
|
||||
const FetchDataStub = {
|
||||
template: '<div class="fetch-data-stub"></div>',
|
||||
props: ['url', 'filter', 'autoLoad'],
|
||||
};
|
||||
|
||||
// Stub del componente VnFilterPanel
|
||||
const VnFilterPanelStub = {
|
||||
template:
|
||||
'<div class="vn-filter-panel-stub"><slot name="tags"></slot><slot name="body"></slot></div>',
|
||||
props: ['dataKey', 'searchButton'],
|
||||
};
|
||||
|
||||
cy.createWrapper(VnLogFilter, {
|
||||
global: {
|
||||
components: {
|
||||
FetchData: FetchDataStub,
|
||||
VnFilterPanel: VnFilterPanelStub,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
dataKey: 'testDataKey',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it('renderiza correctamente el componente', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-filter-panel-stub').should('exist');
|
||||
});
|
||||
|
||||
it('pasa las props correctas a FetchData', () => {
|
||||
const fetchDataSpy = cy.spy().as('fetchDataSpy');
|
||||
const FetchDataStub = {
|
||||
template: '<div class="fetch-data-stub"></div>',
|
||||
props: ['url', 'filter', 'autoLoad'],
|
||||
setup(props) {
|
||||
fetchDataSpy(props);
|
||||
},
|
||||
};
|
||||
|
||||
mountComponent({
|
||||
global: {
|
||||
components: {
|
||||
FetchData: FetchDataStub,
|
||||
VnFilterPanel: {
|
||||
template: '<div class="vn-filter-panel-stub"></div>',
|
||||
props: ['dataKey', 'searchButton'],
|
||||
},
|
||||
},
|
||||
},
|
||||
props: {
|
||||
dataKey: 'testDataKey',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('@fetchDataSpy').should('have.been.calledWithMatch', {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
filter: { where: { role: 'salesPerson' } },
|
||||
autoLoad: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('renderiza los slots de VnFilterPanel correctamente', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-filter-panel-stub').should('exist');
|
||||
// Aquí puedes agregar más verificaciones para los contenidos de los slots si es necesario
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,35 @@
|
|||
import VnPopup from 'src/components/common/VnPopup.vue';
|
||||
|
||||
describe.skip('<VnPopup />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnPopup);
|
||||
describe('<VnPopup />', () => {
|
||||
const mountComponent = (props = {}, slots = {}) => {
|
||||
cy.createWrapper(VnPopup, {
|
||||
props,
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
it('renderiza correctamente el componente', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-popup-proxy').should('exist');
|
||||
});
|
||||
|
||||
it('muestra el título y contenido proporcionados en las props', () => {
|
||||
const title = 'Título de Prueba';
|
||||
const content = 'Contenido de Prueba';
|
||||
mountComponent({ title, content });
|
||||
cy.get('.header').should('contain', title);
|
||||
cy.get('.change-detail').should('contain', content);
|
||||
});
|
||||
|
||||
it('renderiza los slots de título y contenido personalizados', () => {
|
||||
mountComponent(
|
||||
{},
|
||||
{
|
||||
title: '<div class="custom-title">Título Personalizado</div>',
|
||||
content: '<div class="custom-content">Contenido Personalizado</div>',
|
||||
}
|
||||
);
|
||||
cy.get('.custom-title').should('contain', 'Título Personalizado');
|
||||
cy.get('.custom-content').should('contain', 'Contenido Personalizado');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import VnProgressModal from 'src/components/common/VnProgressModal.vue';
|
||||
|
||||
describe.skip('<VnProgressModal />', () => {
|
||||
describe.only('<VnProgressModal />', () => {
|
||||
const mountComponent = (opt) => {
|
||||
cy.createWrapper(VnProgressModal, opt);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,42 @@
|
|||
import VnRadio from 'src/components/common/VnRadio.vue';
|
||||
|
||||
describe.skip('<VnRadio />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnRadio);
|
||||
describe.only('<VnRadio />', () => {
|
||||
const mountComponent = (options = {}) => {
|
||||
cy.createWrapper(VnRadio, {
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders correctly', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-radio').should('exist');
|
||||
});
|
||||
|
||||
it('applies dark mode correctly', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-radio').should('have.class', '--dark');
|
||||
});
|
||||
|
||||
it('updates model value when clicked', () => {
|
||||
const modelValue = false;
|
||||
mountComponent({ modelValue });
|
||||
cy.get('.q-radio').click();
|
||||
cy.get('.q-radio').should('have.class', 'q-radio--checked');
|
||||
});
|
||||
|
||||
it('passes custom attributes through v-bind', () => {
|
||||
const customProps = {
|
||||
color: 'primary',
|
||||
label: 'Test Label',
|
||||
};
|
||||
mountComponent({ attrs: customProps });
|
||||
cy.get('.q-radio')
|
||||
.should('have.class', 'text-primary')
|
||||
.and('contain', 'Test Label');
|
||||
});
|
||||
|
||||
it('maintains dense property', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-radio').should('have.class', 'q-radio--dense');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,70 @@
|
|||
// VnSectionMain.spec.js
|
||||
import VnSectionMain from 'src/components/common/VnSectionMain.vue';
|
||||
|
||||
describe.skip('<VnSectionMain />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnSectionMain />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock stores and composables
|
||||
cy.stub(window, 'useStateStore').returns({
|
||||
leftDrawer: false,
|
||||
});
|
||||
|
||||
cy.stub(window, 'useQuasar').returns({
|
||||
screen: {
|
||||
gt: {
|
||||
xs: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders main layout components', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-drawer').should('exist');
|
||||
cy.get('.q-page-container').should('exist');
|
||||
cy.get('.q-page').should('exist');
|
||||
});
|
||||
|
||||
it('initializes left drawer based on screen size and prop', () => {
|
||||
cy.createWrapper(VnSectionMain, {
|
||||
props: {
|
||||
leftDrawer: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.leftDrawer).should('be.true');
|
||||
});
|
||||
|
||||
it('hides drawer on small screens regardless of prop', () => {
|
||||
cy.stub(window, 'useQuasar').returns({
|
||||
screen: {
|
||||
gt: {
|
||||
xs: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
cy.createWrapper(VnSectionMain, {
|
||||
props: {
|
||||
leftDrawer: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.leftDrawer).should('be.false');
|
||||
});
|
||||
|
||||
it('renders LeftMenu inside drawer', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.getComponent('LeftMenu').should('exist');
|
||||
});
|
||||
|
||||
it('renders RouterView for main content', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-page').should('exist');
|
||||
cy.getComponent('RouterView').should('exist');
|
||||
});
|
||||
|
||||
it('applies correct drawer width', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-drawer').should('have.attr', 'width', '256');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,129 @@
|
|||
// VnSelect.spec.js
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
||||
describe.skip('<VnSelect />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnSelect />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useValidator').returns({
|
||||
validations: () => ({
|
||||
required: (isRequired, value) => (isRequired ? !!value : true),
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
const defaultOptions = [
|
||||
{ id: 1, name: 'Option 1' },
|
||||
{ id: 2, name: 'Option 2' },
|
||||
];
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
cy.createWrapper(VnSelect);
|
||||
cy.get('.q-select').should('exist');
|
||||
});
|
||||
|
||||
it('displays options with default option label and value', () => {
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
options: defaultOptions,
|
||||
},
|
||||
});
|
||||
cy.get('.q-select').click();
|
||||
cy.get('.q-item').should('have.length', 2);
|
||||
cy.get('.q-item').first().should('contain', 'Option 1');
|
||||
});
|
||||
|
||||
it('uses custom option label and value', () => {
|
||||
const customOptions = [
|
||||
{ code: 'A', title: 'Title A' },
|
||||
{ code: 'B', title: 'Title B' },
|
||||
];
|
||||
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
options: customOptions,
|
||||
optionLabel: 'title',
|
||||
optionValue: 'code',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-select').click();
|
||||
cy.get('.q-item').first().should('contain', 'Title A');
|
||||
});
|
||||
|
||||
it('emits update:modelValue when option is selected', () => {
|
||||
const onModelUpdate = cy.spy().as('modelUpdateSpy');
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
options: defaultOptions,
|
||||
'onUpdate:modelValue': onModelUpdate,
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-select').click();
|
||||
cy.get('.q-item').first().click();
|
||||
cy.get('@modelUpdateSpy').should('have.been.calledWith', 1);
|
||||
});
|
||||
|
||||
it('filters options based on optionFilter and optionFilterValue', () => {
|
||||
const filteredOptions = [
|
||||
{ id: 1, name: 'Option 1', type: 'A' },
|
||||
{ id: 2, name: 'Option 2', type: 'B' },
|
||||
];
|
||||
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
options: filteredOptions,
|
||||
optionFilter: 'type',
|
||||
optionFilterValue: 'A',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-select').click();
|
||||
cy.get('.q-item').should('have.length', 1);
|
||||
cy.get('.q-item').should('contain', 'Option 1');
|
||||
});
|
||||
|
||||
it('loads options from URL when provided', () => {
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
url: '/api/options',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('FetchData').should('exist');
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
url: '/api/options',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('emits remove event when clear button is clicked', () => {
|
||||
const onRemove = cy.spy().as('removeSpy');
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
modelValue: 1,
|
||||
options: defaultOptions,
|
||||
onRemove,
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-field__clear').click();
|
||||
cy.get('@removeSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('updates options externally', () => {
|
||||
cy.createWrapper(VnSelect, {
|
||||
props: {
|
||||
options: defaultOptions,
|
||||
},
|
||||
});
|
||||
|
||||
const newOptions = [{ id: 3, name: 'Option 3' }];
|
||||
cy.wrap(Cypress.vueWrapper).invoke('setProps', { options: newOptions });
|
||||
cy.get('.q-select').click();
|
||||
cy.get('.q-item').should('have.length', 1);
|
||||
cy.get('.q-item').should('contain', 'Option 3');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,70 @@
|
|||
import VnSelectCache from 'src/components/common/VnSelectCache.vue';
|
||||
// VnSectionMain.spec.js
|
||||
import VnSectionMain from 'src/components/common/VnSectionMain.vue';
|
||||
|
||||
describe.skip('<VnSelectCache />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnSelectCache);
|
||||
describe.only('<VnSectionMain />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock stores and composables
|
||||
cy.stub(window, 'useStateStore').returns({
|
||||
leftDrawer: false,
|
||||
});
|
||||
|
||||
cy.stub(window, 'useQuasar').returns({
|
||||
screen: {
|
||||
gt: {
|
||||
xs: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('renders main layout components', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-drawer').should('exist');
|
||||
cy.get('.q-page-container').should('exist');
|
||||
cy.get('.q-page').should('exist');
|
||||
});
|
||||
|
||||
it('initializes left drawer based on screen size and prop', () => {
|
||||
cy.createWrapper(VnSectionMain, {
|
||||
props: {
|
||||
leftDrawer: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.leftDrawer).should('be.true');
|
||||
});
|
||||
|
||||
it('hides drawer on small screens regardless of prop', () => {
|
||||
cy.stub(window, 'useQuasar').returns({
|
||||
screen: {
|
||||
gt: {
|
||||
xs: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
cy.createWrapper(VnSectionMain, {
|
||||
props: {
|
||||
leftDrawer: true,
|
||||
},
|
||||
});
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.stateStore.leftDrawer).should('be.false');
|
||||
});
|
||||
|
||||
it('renders LeftMenu inside drawer', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.getComponent('LeftMenu').should('exist');
|
||||
});
|
||||
|
||||
it('renders RouterView for main content', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-page').should('exist');
|
||||
cy.getComponent('RouterView').should('exist');
|
||||
});
|
||||
|
||||
it('applies correct drawer width', () => {
|
||||
cy.createWrapper(VnSectionMain);
|
||||
cy.get('.q-drawer').should('have.attr', 'width', '256');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,85 @@
|
|||
// VnSelectDialog.spec.js
|
||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||
|
||||
describe.skip('<VnSelectDialog />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnSelectDialog />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock role and ACL composables
|
||||
cy.stub(window, 'useRole').returns({
|
||||
hasAny: cy.stub().as('roleHasAnySpy'),
|
||||
});
|
||||
|
||||
cy.stub(window, 'useAcl').returns({
|
||||
hasAny: cy.stub().as('aclHasAnySpy'),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders select component', () => {
|
||||
cy.createWrapper(VnSelectDialog);
|
||||
cy.getComponent('VnSelect').should('exist');
|
||||
});
|
||||
|
||||
it('allows creation for developer role by default', () => {
|
||||
cy.get('@roleHasAnySpy').returns(true);
|
||||
|
||||
cy.createWrapper(VnSelectDialog);
|
||||
cy.get('.create-action-button').should('exist');
|
||||
});
|
||||
|
||||
it('hides creation button when user lacks role permission', () => {
|
||||
cy.get('@roleHasAnySpy').returns(false);
|
||||
|
||||
cy.createWrapper(VnSelectDialog);
|
||||
cy.get('.create-action-button').should('not.exist');
|
||||
});
|
||||
|
||||
it('checks ACL permissions when provided', () => {
|
||||
cy.get('@aclHasAnySpy').returns(true);
|
||||
|
||||
cy.createWrapper(VnSelectDialog, {
|
||||
props: {
|
||||
acls: ['create:item'],
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.create-action-button').should('exist');
|
||||
cy.get('@aclHasAnySpy').should('have.been.calledWith', ['create:item']);
|
||||
});
|
||||
|
||||
it('displays custom action icon', () => {
|
||||
cy.get('@roleHasAnySpy').returns(true);
|
||||
|
||||
cy.createWrapper(VnSelectDialog, {
|
||||
props: {
|
||||
actionIcon: 'edit',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.create-action-button .q-icon').should('have.attr', 'name', 'edit');
|
||||
});
|
||||
|
||||
it('shows tooltip when provided', () => {
|
||||
cy.get('@roleHasAnySpy').returns(true);
|
||||
|
||||
cy.createWrapper(VnSelectDialog, {
|
||||
props: {
|
||||
tooltip: 'Add new item',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.create-action-button').trigger('mouseenter');
|
||||
cy.get('.q-tooltip').should('contain', 'Add new item');
|
||||
});
|
||||
|
||||
it('emits model update when value changes', () => {
|
||||
const onModelUpdate = cy.spy().as('modelUpdateSpy');
|
||||
|
||||
cy.createWrapper(VnSelectDialog, {
|
||||
props: {
|
||||
'onUpdate:modelValue': onModelUpdate,
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnSelect').trigger('update:modelValue', 'newValue');
|
||||
cy.get('@modelUpdateSpy').should('have.been.calledWith', 'newValue');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,100 @@
|
|||
// VnSelectEnum.spec.js
|
||||
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
||||
|
||||
describe.skip('<VnSelectEnum />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnSelectEnum);
|
||||
describe.only('<VnSelectEnum />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders without errors', () => {
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
},
|
||||
});
|
||||
cy.getComponent('VnSelect').should('exist');
|
||||
});
|
||||
|
||||
it('loads enum options from API on mount', () => {
|
||||
const mockEnumData = ['OPTION1', 'OPTION2'];
|
||||
cy.get('@axiosStub').resolves({ data: mockEnumData });
|
||||
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('@axiosStub').should('have.been.calledWith', {
|
||||
method: 'get',
|
||||
url: '/api/enums/vn/test_table/test_column',
|
||||
});
|
||||
});
|
||||
|
||||
it('uses custom schema when provided', () => {
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
schema: 'custom',
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('@axiosStub').should('have.been.calledWith', {
|
||||
method: 'get',
|
||||
url: '/api/enums/custom/test_table/test_column',
|
||||
});
|
||||
});
|
||||
|
||||
it('uses translation function when provided', () => {
|
||||
const translation = (value) => `Translated ${value}`;
|
||||
const mockEnumData = ['OPTION1'];
|
||||
cy.get('@axiosStub').resolves({ data: mockEnumData });
|
||||
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
translation,
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnSelect')
|
||||
.invoke('props', 'options')
|
||||
.should('deep.equal', [{ label: 'Translated OPTION1', value: 'OPTION1' }]);
|
||||
});
|
||||
|
||||
it('uses default options when provided', () => {
|
||||
const defaultOptions = [
|
||||
{ label: 'Default 1', value: 'DEFAULT1' },
|
||||
{ label: 'Default 2', value: 'DEFAULT2' },
|
||||
];
|
||||
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
defaultOptions,
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnSelect')
|
||||
.invoke('props', 'options')
|
||||
.should('deep.equal', defaultOptions);
|
||||
});
|
||||
|
||||
it('handles API error gracefully', () => {
|
||||
cy.get('@axiosStub').rejects(new Error('API Error'));
|
||||
|
||||
cy.createWrapper(VnSelectEnum, {
|
||||
props: {
|
||||
table: 'test_table',
|
||||
column: 'test_column',
|
||||
},
|
||||
});
|
||||
|
||||
cy.getComponent('VnSelect').invoke('props', 'options').should('deep.equal', []);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* eslint-disable cypress/no-assigning-return-values */
|
||||
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
|
||||
|
||||
describe.skip('<VnSmsDialog />', () => {
|
||||
describe.only('<VnSmsDialog />', () => {
|
||||
const defaultProps = {
|
||||
phone: '123456789',
|
||||
subject: 'Test Subject',
|
||||
|
|
|
@ -1,8 +1,58 @@
|
|||
// VnSummaryDialog.spec.js
|
||||
import VnSummaryDialog from 'src/components/common/VnSummaryDialog.vue';
|
||||
|
||||
describe.skip('<VnSummaryDialog />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnSummaryDialog);
|
||||
describe.only('<VnSummaryDialog />', () => {
|
||||
const TestSummaryComponent = {
|
||||
template: '<div class="test-summary">Test Summary Content</div>',
|
||||
props: ['id'],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useDialogPluginComponent').returns({
|
||||
dialogRef: cy.stub(),
|
||||
onDialogHide: cy.stub().as('onDialogHideStub'),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly with required props', () => {
|
||||
cy.createWrapper(VnSummaryDialog, {
|
||||
props: {
|
||||
id: 1,
|
||||
summary: TestSummaryComponent,
|
||||
},
|
||||
});
|
||||
cy.get('.q-dialog').should('exist');
|
||||
});
|
||||
|
||||
it('renders dynamic summary component with correct props', () => {
|
||||
cy.createWrapper(VnSummaryDialog, {
|
||||
props: {
|
||||
id: 123,
|
||||
summary: TestSummaryComponent,
|
||||
},
|
||||
});
|
||||
cy.get('.test-summary').should('exist');
|
||||
cy.get('.test-summary').invoke('prop', 'id').should('equal', 123);
|
||||
});
|
||||
|
||||
it('handles dialog hide event', () => {
|
||||
cy.createWrapper(VnSummaryDialog, {
|
||||
props: {
|
||||
id: 1,
|
||||
summary: TestSummaryComponent,
|
||||
},
|
||||
});
|
||||
cy.get('.q-dialog').trigger('hide');
|
||||
cy.get('@onDialogHideStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('applies full-width class to dialog', () => {
|
||||
cy.createWrapper(VnSummaryDialog, {
|
||||
props: {
|
||||
id: 1,
|
||||
summary: TestSummaryComponent,
|
||||
},
|
||||
});
|
||||
cy.get('.q-dialog').should('have.class', 'full-width');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,94 @@
|
|||
// VnWeekdayPicker.spec.js
|
||||
import VnWeekdayPicker from 'src/components/common/VnWeekdayPicker.vue';
|
||||
|
||||
describe.skip('<VnWeekdayPicker />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnWeekdayPicker);
|
||||
describe.only('<VnWeekdayPicker />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock weekday store
|
||||
cy.stub(window, 'useWeekdayStore').returns({
|
||||
getLocalesMap: [
|
||||
{ index: 0, localeChar: 'M' },
|
||||
{ index: 1, localeChar: 'T' },
|
||||
{ index: 2, localeChar: 'W' },
|
||||
{ index: 3, localeChar: 'T' },
|
||||
{ index: 4, localeChar: 'F' },
|
||||
{ index: 5, localeChar: 'S' },
|
||||
{ index: 6, localeChar: 'S' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('renders all weekday buttons', () => {
|
||||
cy.createWrapper(VnWeekdayPicker, {
|
||||
props: {
|
||||
wdays: [false, false, false, false, false, false, false],
|
||||
},
|
||||
});
|
||||
cy.get('.q-btn').should('have.length', 7);
|
||||
});
|
||||
|
||||
it('displays correct weekday labels', () => {
|
||||
cy.createWrapper(VnWeekdayPicker, {
|
||||
props: {
|
||||
wdays: [false, false, false, false, false, false, false],
|
||||
},
|
||||
});
|
||||
cy.get('.q-btn').first().should('contain', 'M');
|
||||
cy.get('.q-btn').last().should('contain', 'S');
|
||||
});
|
||||
|
||||
it('toggles weekday selection on click', () => {
|
||||
const onUpdateWdays = cy.spy().as('updateSpy');
|
||||
cy.createWrapper(VnWeekdayPicker, {
|
||||
props: {
|
||||
wdays: [false, false, false, false, false, false, false],
|
||||
'onUpdate:wdays': onUpdateWdays,
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-btn').first().click();
|
||||
cy.get('@updateSpy').should('have.been.calledWith', [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
});
|
||||
|
||||
it('applies primary color to selected weekdays', () => {
|
||||
cy.createWrapper(VnWeekdayPicker, {
|
||||
props: {
|
||||
wdays: [true, false, true, false, false, false, false],
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-btn').eq(0).should('have.class', 'bg-primary');
|
||||
cy.get('.q-btn').eq(1).should('not.have.class', 'bg-primary');
|
||||
cy.get('.q-btn').eq(2).should('have.class', 'bg-primary');
|
||||
});
|
||||
|
||||
it('maintains selection state after multiple toggles', () => {
|
||||
const onUpdateWdays = cy.spy().as('updateSpy');
|
||||
cy.createWrapper(VnWeekdayPicker, {
|
||||
props: {
|
||||
wdays: [false, false, false, false, false, false, false],
|
||||
'onUpdate:wdays': onUpdateWdays,
|
||||
},
|
||||
});
|
||||
|
||||
cy.get('.q-btn').first().click();
|
||||
cy.get('.q-btn').first().click();
|
||||
|
||||
cy.get('@updateSpy').should('have.been.calledWith', [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import CardSummary from 'src/components/ui/CardSummary.vue';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
describe.skip('<CardSummary />', () => {
|
||||
describe.only('<CardSummary />', () => {
|
||||
let router, wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -1,8 +1,71 @@
|
|||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
|
||||
describe.skip('<VnConfirm />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnConfirm />', () => {
|
||||
it('renders with default props', () => {
|
||||
cy.createWrapper(VnConfirm);
|
||||
cy.get('.q-dialog').should('exist');
|
||||
});
|
||||
|
||||
it('renders with custom icon and title', () => {
|
||||
cy.createWrapper(VnConfirm, {
|
||||
props: {
|
||||
icon: 'warning',
|
||||
title: 'Test Title',
|
||||
},
|
||||
});
|
||||
cy.get('.q-icon').should('contain', 'warning');
|
||||
cy.get('.dialog-title').should('contain', 'Test Title');
|
||||
});
|
||||
|
||||
it('displays custom message', () => {
|
||||
cy.createWrapper(VnConfirm, {
|
||||
props: {
|
||||
message: 'Test Message',
|
||||
},
|
||||
});
|
||||
cy.get('.dialog-content').should('contain', 'Test Message');
|
||||
});
|
||||
|
||||
it('emits confirm event when confirmed', () => {
|
||||
const onConfirm = cy.spy().as('confirmSpy');
|
||||
cy.createWrapper(VnConfirm, {
|
||||
props: {
|
||||
onConfirm: onConfirm,
|
||||
},
|
||||
});
|
||||
cy.get('.confirm-button').click();
|
||||
cy.get('@confirmSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('handles promise execution', () => {
|
||||
const testPromise = cy.stub().resolves('success');
|
||||
cy.createWrapper(VnConfirm, {
|
||||
props: {
|
||||
promise: testPromise,
|
||||
data: { testKey: 'testValue' },
|
||||
},
|
||||
});
|
||||
cy.get('.confirm-button').click();
|
||||
cy.wrap(testPromise).should('have.been.calledWith', { testKey: 'testValue' });
|
||||
});
|
||||
|
||||
it('shows and hides dialog via exposed methods', () => {
|
||||
cy.createWrapper(VnConfirm).then((wrapper) => {
|
||||
wrapper.show();
|
||||
cy.get('.q-dialog').should('be.visible');
|
||||
wrapper.hide();
|
||||
cy.get('.q-dialog').should('not.be.visible');
|
||||
});
|
||||
});
|
||||
|
||||
it('handles dialog plugin events', () => {
|
||||
const onHide = cy.spy().as('hideSpy');
|
||||
cy.createWrapper(VnConfirm, {
|
||||
props: {
|
||||
onHide: onHide,
|
||||
},
|
||||
});
|
||||
cy.get('.cancel-button').click();
|
||||
cy.get('@hideSpy').should('have.been.called');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,90 @@
|
|||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
// VnFilterPanel.spec.js
|
||||
import VnFilterPanel from 'src/components/common/VnFilterPanel.vue';
|
||||
import { toDate } from 'src/filters';
|
||||
|
||||
describe.skip('<VnFilterPanel />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnFilterPanel);
|
||||
describe.only('<VnFilterPanel />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'useRoute').returns({
|
||||
query: {},
|
||||
});
|
||||
});
|
||||
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWrapper(VnFilterPanel, {
|
||||
props: {
|
||||
dataKey: 'test-key',
|
||||
...props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it('renders correctly with required props', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-filter-panel').should('exist');
|
||||
});
|
||||
|
||||
it('handles modelValue changes', () => {
|
||||
const modelValue = { search: 'test' };
|
||||
mountComponent({ modelValue });
|
||||
cy.get('.filter-chip').should('exist');
|
||||
cy.get('.filter-chip').should('contain', 'test');
|
||||
});
|
||||
|
||||
it('shows search button when searchButton prop is true', () => {
|
||||
mountComponent({ searchButton: true });
|
||||
cy.get('.search-button').should('exist');
|
||||
});
|
||||
|
||||
it('hides search button when searchButton prop is false', () => {
|
||||
mountComponent({ searchButton: false });
|
||||
cy.get('.search-button').should('not.exist');
|
||||
});
|
||||
|
||||
it('prevents removal of unremovable params', () => {
|
||||
const modelValue = { fixed: 'value', removable: 'test' };
|
||||
mountComponent({
|
||||
modelValue,
|
||||
unremovableParams: ['fixed'],
|
||||
});
|
||||
|
||||
cy.get('.filter-chip[data-param="fixed"] .remove-button').should('not.exist');
|
||||
cy.get('.filter-chip[data-param="removable"] .remove-button').should('exist');
|
||||
});
|
||||
|
||||
it('emits update:modelValue when filter is removed', () => {
|
||||
const modelValue = { param: 'value' };
|
||||
const onUpdateModelValue = cy.spy().as('updateSpy');
|
||||
|
||||
mountComponent({
|
||||
modelValue,
|
||||
'onUpdate:modelValue': onUpdateModelValue,
|
||||
});
|
||||
|
||||
cy.get('.filter-chip .remove-button').click();
|
||||
cy.get('@updateSpy').should('have.been.calledWith', {});
|
||||
});
|
||||
|
||||
it('shows all filters when showAll is true', () => {
|
||||
const modelValue = { param1: 'value1', param2: 'value2' };
|
||||
mountComponent({
|
||||
modelValue,
|
||||
showAll: true,
|
||||
});
|
||||
cy.get('.filter-chip').should('have.length', 2);
|
||||
});
|
||||
|
||||
it('formats date values correctly', () => {
|
||||
const modelValue = { date: '2024-03-20' };
|
||||
mountComponent({ modelValue });
|
||||
cy.get('.filter-chip').should('contain', toDate('2024-03-20'));
|
||||
});
|
||||
|
||||
it('syncs with route query params', () => {
|
||||
cy.stub(window, 'useRoute').returns({
|
||||
query: { search: 'queryTest' },
|
||||
});
|
||||
|
||||
mountComponent();
|
||||
cy.get('.filter-chip').should('contain', 'queryTest');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,49 @@
|
|||
import VnFilterPanelChip from 'src/components/ui/VnFilterPanelChip.vue';
|
||||
// VnFilterPanelChip.spec.js
|
||||
import VnFilterPanelChip from 'src/components/common/VnFilterPanelChip.vue';
|
||||
|
||||
describe.skip('<VnFilterPanelChip />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnFilterPanelChip);
|
||||
describe.only('<VnFilterPanelChip />', () => {
|
||||
const mountComponent = (props = {}, slots = {}) => {
|
||||
cy.createWrapper(VnFilterPanelChip, {
|
||||
props,
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders correctly with default props', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-chip').should('exist');
|
||||
});
|
||||
|
||||
it('applies default classes and attributes', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-chip')
|
||||
.should('have.class', 'text-dark')
|
||||
.and('have.class', 'bg-primary')
|
||||
.and('have.attr', 'size', 'sm');
|
||||
});
|
||||
|
||||
it('displays the label icon', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-chip .q-icon').should('contain', 'label');
|
||||
});
|
||||
|
||||
it('renders slot content correctly', () => {
|
||||
mountComponent(
|
||||
{},
|
||||
{
|
||||
default: 'Test Content',
|
||||
}
|
||||
);
|
||||
cy.get('.q-chip').should('contain', 'Test Content');
|
||||
});
|
||||
|
||||
it('forwards attributes via v-bind', () => {
|
||||
mountComponent({
|
||||
class: 'custom-class',
|
||||
'data-test': 'test-value',
|
||||
});
|
||||
cy.get('.q-chip')
|
||||
.should('have.class', 'custom-class')
|
||||
.and('have.attr', 'data-test', 'test-value');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,82 @@
|
|||
import VnImg from 'src/components/ui/VnImg.vue';
|
||||
|
||||
describe.skip('<VnImg />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnImg);
|
||||
describe.only('<VnImg />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock useSession composable
|
||||
cy.stub(window, 'useSession').returns({
|
||||
getTokenMultimedia: () => 'mock-token',
|
||||
});
|
||||
});
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWrapper(VnImg, {
|
||||
props,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders with default props', () => {
|
||||
mountComponent({ id: 1 });
|
||||
cy.get('img')
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'Images')
|
||||
.and('include', 'catalog')
|
||||
.and('include', '200x200');
|
||||
});
|
||||
|
||||
it('renders with custom storage and collection', () => {
|
||||
mountComponent({
|
||||
props: {
|
||||
id: 1,
|
||||
storage: 'CustomStorage',
|
||||
collection: 'custom-collection',
|
||||
resolution: '300x300',
|
||||
},
|
||||
});
|
||||
cy.get('img')
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'CustomStorage')
|
||||
.and('include', 'custom-collection')
|
||||
.and('include', '300x300');
|
||||
});
|
||||
|
||||
it('shows zoom functionality when enabled', () => {
|
||||
mountComponent({
|
||||
props: {
|
||||
id: 1,
|
||||
zoom: true,
|
||||
zoomResolution: '800x800',
|
||||
},
|
||||
});
|
||||
cy.get('img').click();
|
||||
cy.get('.zoomed-image').should('exist');
|
||||
});
|
||||
|
||||
it('disables zoom functionality when configured', () => {
|
||||
mountComponent({
|
||||
props: {
|
||||
id: 1,
|
||||
zoom: false,
|
||||
},
|
||||
});
|
||||
cy.get('img').click();
|
||||
cy.get('.zoomed-image').should('not.exist');
|
||||
});
|
||||
|
||||
it('includes authentication token in image URL', () => {
|
||||
mountComponent({
|
||||
props: {
|
||||
id: 1,
|
||||
},
|
||||
});
|
||||
cy.get('img').should('have.attr', 'src').and('include', 'mock-token');
|
||||
});
|
||||
|
||||
it('shows fallback image when loading fails', () => {
|
||||
mountComponent({
|
||||
props: {
|
||||
id: 1,
|
||||
},
|
||||
});
|
||||
cy.get('img').trigger('error');
|
||||
cy.get('img').should('have.attr', 'src', '/no-user.png');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,46 @@
|
|||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
||||
|
||||
describe.skip('<VnLinkPhone />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnLinkPhone);
|
||||
describe.only('<VnLinkPhone />', () => {
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWrapper(VnLinkPhone, {
|
||||
props,
|
||||
});
|
||||
};
|
||||
|
||||
it('should not render button when phone number is null', () => {
|
||||
mountComponent();
|
||||
cy.get('.q-btn').should('not.exist');
|
||||
});
|
||||
|
||||
it('should render button when phone number is provided', () => {
|
||||
mountComponent({ phoneNumber: '1234567890' });
|
||||
cy.get('.q-btn').should('exist');
|
||||
});
|
||||
|
||||
it('should generate correct SIP link from phone number', () => {
|
||||
mountComponent({ phoneNumber: '1234567890' });
|
||||
cy.get('.q-btn').should('have.attr', 'href', 'sip:1234567890');
|
||||
});
|
||||
|
||||
it('should have correct button attributes', () => {
|
||||
mountComponent({ phoneNumber: '1234567890' });
|
||||
cy.get('.q-btn')
|
||||
.should('have.class', 'q-btn--flat')
|
||||
.should('have.class', 'q-btn--round')
|
||||
.should('have.class', 'text-primary')
|
||||
.should('have.attr', 'padding', 'none');
|
||||
});
|
||||
|
||||
it('should display phone icon', () => {
|
||||
mountComponent({ phoneNumber: '1234567890' });
|
||||
cy.get('.q-btn .q-icon').should('contain', 'phone');
|
||||
});
|
||||
|
||||
it('should stop click event propagation', () => {
|
||||
const onClick = cy.spy().as('clickSpy');
|
||||
mountComponent({ phoneNumber: '1234567890' });
|
||||
cy.get('.q-btn').parent().on('click', onClick);
|
||||
cy.get('.q-btn').click();
|
||||
cy.get('@clickSpy').should('not.have.been.called');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,93 @@
|
|||
import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||
// VnNotes.spec.js
|
||||
import VnNotes from 'src/components/common/VnNotes.vue';
|
||||
|
||||
describe.skip('<VnNotes />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnNotes />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock axios to prevent real HTTP requests
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders without errors', () => {
|
||||
cy.createWrapper(VnNotes);
|
||||
cy.get('.vn-notes').should('exist');
|
||||
});
|
||||
|
||||
it('loads notes data correctly on mount', () => {
|
||||
cy.createWrapper(VnNotes);
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('displays the add note section when addNote prop is true', () => {
|
||||
cy.createWrapper(VnNotes, {
|
||||
props: {
|
||||
addNote: true,
|
||||
},
|
||||
});
|
||||
cy.get('.add-note-section').should('be.visible');
|
||||
});
|
||||
|
||||
it('hides the add note section when addNote prop is false', () => {
|
||||
cy.createWrapper(VnNotes, {
|
||||
props: {
|
||||
addNote: false,
|
||||
},
|
||||
});
|
||||
cy.get('.add-note-section').should('not.exist');
|
||||
});
|
||||
|
||||
it('allows the user to add a new note', () => {
|
||||
cy.createWrapper(VnNotes, {
|
||||
props: {
|
||||
addNote: true,
|
||||
},
|
||||
});
|
||||
cy.get('.note-input').type('Test note');
|
||||
cy.get('.submit-note-button').click();
|
||||
cy.get('@axiosStub').should('have.been.calledWithMatch', {
|
||||
method: 'post',
|
||||
url: '/api/notes',
|
||||
});
|
||||
});
|
||||
|
||||
it('displays an error message if adding a note fails', () => {
|
||||
cy.get('@axiosStub').throws(new Error('Network Error'));
|
||||
cy.createWrapper(VnNotes, {
|
||||
props: {
|
||||
addNote: true,
|
||||
},
|
||||
});
|
||||
cy.get('.note-input').type('Test note');
|
||||
cy.get('.submit-note-button').click();
|
||||
cy.get('.error-message').should('contain', 'Network Error');
|
||||
});
|
||||
|
||||
it('paginates notes correctly', () => {
|
||||
cy.createWrapper(VnNotes);
|
||||
cy.get('.pagination').should('exist');
|
||||
cy.get('.pagination .next-page').click();
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('displays observation types when selectType prop is true', () => {
|
||||
cy.createWrapper(VnNotes, {
|
||||
props: {
|
||||
selectType: true,
|
||||
},
|
||||
});
|
||||
cy.get('.observation-type-select').should('be.visible');
|
||||
});
|
||||
|
||||
it('handles before route leave with unsaved changes', () => {
|
||||
const onBeforeRouteLeave = cy.stub();
|
||||
cy.createWrapper(VnNotes, {
|
||||
listeners: {
|
||||
'before-route-leave': onBeforeRouteLeave,
|
||||
},
|
||||
});
|
||||
cy.get('.note-input').type('Unsaved note');
|
||||
cy.window().then((win) => {
|
||||
win.dispatchEvent(new Event('beforeunload'));
|
||||
expect(onBeforeRouteLeave).to.have.been.called;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,55 @@
|
|||
import VnOutForm from 'src/components/ui/VnOutForm.vue';
|
||||
// VnOutForm.spec.js
|
||||
import VnOutForm from 'src/components/common/VnOutForm.vue';
|
||||
|
||||
describe.skip('<VnOutForm />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnOutForm);
|
||||
describe.only('<VnOutForm />', () => {
|
||||
const mountComponent = (props = {}, slots = {}) => {
|
||||
cy.createWrapper(VnOutForm, {
|
||||
props,
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders without errors', () => {
|
||||
mountComponent({ title: 'Test Title' });
|
||||
cy.get('.formCard').should('exist');
|
||||
});
|
||||
|
||||
it('displays the title prop', () => {
|
||||
mountComponent({ title: 'Test Title' });
|
||||
cy.get('h5').should('contain', 'Test Title');
|
||||
});
|
||||
|
||||
it('renders the default icon when icon prop is not false', () => {
|
||||
mountComponent({ title: 'Test Title' });
|
||||
cy.get('.q-icon').should('exist');
|
||||
cy.get('.q-icon').should('have.attr', 'name', 'phonelink_lock');
|
||||
});
|
||||
|
||||
it('does not render the icon when icon prop is false', () => {
|
||||
mountComponent({ title: 'Test Title', icon: false });
|
||||
cy.get('.q-icon').should('not.exist');
|
||||
});
|
||||
|
||||
it('emits submit event when form is submitted', () => {
|
||||
const onSubmit = cy.spy().as('submitSpy');
|
||||
mountComponent({ title: 'Test Title', onSubmit });
|
||||
cy.get('form').submit();
|
||||
cy.get('@submitSpy').should('have.been.called');
|
||||
});
|
||||
|
||||
it('renders default slot content', () => {
|
||||
mountComponent(
|
||||
{ title: 'Test Title' },
|
||||
{ default: '<div class="slot-content">Default Slot Content</div>' }
|
||||
);
|
||||
cy.get('.slot-content').should('contain', 'Default Slot Content');
|
||||
});
|
||||
|
||||
it('renders buttons slot content', () => {
|
||||
mountComponent(
|
||||
{ title: 'Test Title' },
|
||||
{ buttons: '<button class="slot-buttons">Button Slot Content</button>' }
|
||||
);
|
||||
cy.get('.slot-buttons').should('contain', 'Button Slot Content');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,116 @@
|
|||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
// VnPaginate.spec.js
|
||||
import VnPaginate from 'src/components/common/VnPaginate.vue';
|
||||
|
||||
describe.skip('<VnPaginate />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnPaginate);
|
||||
describe.only('<VnPaginate />', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWrapper(VnPaginate, {
|
||||
props: {
|
||||
dataKey: 'test-key',
|
||||
...props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it('renders without errors', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-paginate').should('exist');
|
||||
});
|
||||
|
||||
it('loads data automatically when autoLoad is true', () => {
|
||||
const url = '/api/test';
|
||||
mountComponent({
|
||||
url,
|
||||
autoLoad: true,
|
||||
});
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('does not load data automatically when autoLoad is false', () => {
|
||||
mountComponent({
|
||||
url: '/api/test',
|
||||
autoLoad: false,
|
||||
});
|
||||
cy.get('@axiosStub').should('not.have.been.called');
|
||||
});
|
||||
|
||||
it('handles static data array', () => {
|
||||
const testData = [
|
||||
{ id: 1, name: 'Test 1' },
|
||||
{ id: 2, name: 'Test 2' },
|
||||
];
|
||||
mountComponent({
|
||||
data: testData,
|
||||
});
|
||||
cy.get('.vn-paginate').should('contain', 'Test 1');
|
||||
});
|
||||
|
||||
it('applies filters correctly', () => {
|
||||
const testFilter = { search: 'test' };
|
||||
mountComponent({
|
||||
url: '/api/test',
|
||||
filter: testFilter,
|
||||
});
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
params: Cypress.sinon.match(testFilter),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('handles pagination events', () => {
|
||||
mountComponent({
|
||||
url: '/api/test',
|
||||
});
|
||||
cy.get('.pagination-next').click();
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
params: Cypress.sinon.match({
|
||||
page: 2,
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('applies custom classes', () => {
|
||||
mountComponent({
|
||||
class: 'custom-class',
|
||||
});
|
||||
cy.get('.vn-paginate').should('have.class', 'custom-class');
|
||||
});
|
||||
|
||||
it('handles user filters', () => {
|
||||
const userFilter = { status: 'active' };
|
||||
mountComponent({
|
||||
url: '/api/test',
|
||||
userFilter,
|
||||
});
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
params: Cypress.sinon.match(userFilter),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('watches for filter changes and reloads data', () => {
|
||||
// eslint-disable-next-line cypress/no-assigning-return-values
|
||||
const wrapper = cy.createWrapper(VnPaginate, {
|
||||
props: {
|
||||
dataKey: 'test-key',
|
||||
url: '/api/test',
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.setProps({
|
||||
filter: { newFilter: 'value' },
|
||||
});
|
||||
|
||||
cy.get('@axiosStub').should('have.been.calledTwice');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,48 @@
|
|||
import VnRow from 'src/components/ui/VnRow.vue';
|
||||
// VnRow.spec.js
|
||||
import VnRow from 'src/components/common/VnRow.vue';
|
||||
|
||||
describe.skip('<VnRow />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnRow);
|
||||
describe.only('<VnRow />', () => {
|
||||
const mountComponent = (props = {}, slots = {}) => {
|
||||
cy.createWrapper(VnRow, {
|
||||
props,
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders without errors', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-row').should('exist');
|
||||
});
|
||||
|
||||
it('applies flex display style', () => {
|
||||
mountComponent();
|
||||
cy.get('.vn-row').should('have.css', 'display', 'flex');
|
||||
});
|
||||
|
||||
it('renders default slot content', () => {
|
||||
const slotContent = '<div class="slot-content">Test Content</div>';
|
||||
mountComponent({}, { default: slotContent });
|
||||
cy.get('.vn-row .slot-content').should('contain', 'Test Content');
|
||||
});
|
||||
|
||||
it('applies wrap class when wrap prop is true', () => {
|
||||
mountComponent({ wrap: true });
|
||||
cy.get('.vn-row').should('have.class', 'wrap');
|
||||
});
|
||||
|
||||
it('does not apply wrap class when wrap prop is false', () => {
|
||||
mountComponent({ wrap: false });
|
||||
cy.get('.vn-row').should('not.have.class', 'wrap');
|
||||
});
|
||||
|
||||
it('child elements have flex: 1 style', () => {
|
||||
const slotContent = `
|
||||
<div class="child-1">Child 1</div>
|
||||
<div class="child-2">Child 2</div>
|
||||
`;
|
||||
mountComponent({}, { default: slotContent });
|
||||
cy.get('.vn-row > *').each(($el) => {
|
||||
cy.wrap($el).should('have.css', 'flex', '1 1 0%');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,85 @@
|
|||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
// VnSearchbar.spec.js
|
||||
import VnSearchbar from 'src/components/common/VnSearchbar.vue';
|
||||
|
||||
describe.skip('<VnSearchbar />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnSearchbar);
|
||||
describe.only('<VnSearchbar />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock required composables and stores
|
||||
cy.stub(window, 'useQuasar').returns({});
|
||||
cy.stub(window, 'useI18n').returns({ t: (key) => key });
|
||||
cy.stub(window, 'useStateStore').returns({});
|
||||
cy.stub(window, 'useArrayData').returns({});
|
||||
});
|
||||
|
||||
const mountComponent = (props = {}) => {
|
||||
cy.createWrapper(VnSearchbar, {
|
||||
props: {
|
||||
dataKey: 'test-key',
|
||||
...props,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it('renders with default props', () => {
|
||||
mountComponent();
|
||||
cy.getComponent('VnInput').should('exist');
|
||||
cy.get('input').should('have.attr', 'placeholder', 'Search');
|
||||
});
|
||||
|
||||
it('displays custom label', () => {
|
||||
mountComponent({ label: 'Custom Search' });
|
||||
cy.get('input').should('have.attr', 'placeholder', 'Custom Search');
|
||||
});
|
||||
|
||||
it('shows info text when provided', () => {
|
||||
mountComponent({ info: 'Search Info' });
|
||||
cy.get('.info-text').should('contain', 'Search Info');
|
||||
});
|
||||
|
||||
it('handles search input', () => {
|
||||
mountComponent();
|
||||
cy.get('input').type('test search');
|
||||
cy.get('input').should('have.value', 'test search');
|
||||
});
|
||||
|
||||
it('triggers search with url when provided', () => {
|
||||
const searchUrl = '/api/search';
|
||||
mountComponent({ url: searchUrl });
|
||||
cy.get('input').type('test{enter}');
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
url: searchUrl,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('handles redirect prop', () => {
|
||||
const router = {
|
||||
push: cy.spy().as('routerPush'),
|
||||
};
|
||||
cy.stub(window, 'useRouter').returns(router);
|
||||
|
||||
mountComponent({ redirect: true });
|
||||
cy.get('input').type('test{enter}');
|
||||
cy.get('@routerPush').should('have.been.called');
|
||||
});
|
||||
|
||||
it('applies custom filter', () => {
|
||||
const customFilter = { category: 'test' };
|
||||
mountComponent({ filter: customFilter });
|
||||
cy.get('input').type('search{enter}');
|
||||
cy.get('@axiosStub').should(
|
||||
'have.been.calledWith',
|
||||
Cypress.sinon.match({
|
||||
params: Cypress.sinon.match(customFilter),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('clears search input', () => {
|
||||
mountComponent();
|
||||
cy.get('input').type('test');
|
||||
cy.get('.clear-button').click();
|
||||
cy.get('input').should('have.value', '');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,69 @@
|
|||
import VnSms from 'src/components/ui/VnSms.vue';
|
||||
// VnSms.spec.js
|
||||
import VnSms from 'src/components/common/VnSms.vue';
|
||||
|
||||
describe.skip('<VnSms />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnSms />', () => {
|
||||
beforeEach(() => {
|
||||
// Stub axios to prevent real HTTP requests
|
||||
cy.stub(window, 'axios').as('axiosStub');
|
||||
});
|
||||
|
||||
it('renders without errors', () => {
|
||||
cy.createWrapper(VnSms);
|
||||
cy.get('.vn-sms').should('exist');
|
||||
});
|
||||
|
||||
it('computes the correct filter based on props', () => {
|
||||
const whereProp = { status: 'delivered' };
|
||||
cy.createWrapper(VnSms, {
|
||||
props: {
|
||||
where: whereProp,
|
||||
},
|
||||
});
|
||||
cy.wrap(Cypress.vueWrapper.setupState.filter).then((filter) => {
|
||||
expect(filter.value.where).to.deep.equal(whereProp);
|
||||
expect(filter.value.fields).to.include('smsFk');
|
||||
expect(filter.value.include.relation).to.equal('sms');
|
||||
});
|
||||
});
|
||||
|
||||
it('displays SMS data correctly', () => {
|
||||
const smsData = [
|
||||
{
|
||||
smsFk: 1,
|
||||
sms: {
|
||||
senderFk: 1,
|
||||
sender: 'Jane Smith',
|
||||
destination: '+1234567890',
|
||||
message: 'Test message content',
|
||||
statusCode: 'sent',
|
||||
status: 'Sent',
|
||||
created: '2023-10-10T10:00:00Z',
|
||||
// sender: {
|
||||
// name: 'Jane Smith',
|
||||
// },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
cy.intercept('GET', '**/api/**', { body: smsData }).as('getSmsData');
|
||||
|
||||
cy.createWrapper(VnSms);
|
||||
cy.wait('@getSmsData');
|
||||
|
||||
cy.get('.sms-message').should('contain', 'Test message content');
|
||||
cy.get('.sms-destination').should('contain', '+1234567890');
|
||||
});
|
||||
|
||||
it('handles pagination through VnPaginate', () => {
|
||||
cy.createWrapper(VnSms);
|
||||
cy.get('.vn-paginate').should('exist');
|
||||
cy.get('.paginate-next').click();
|
||||
cy.get('@axiosStub').should('have.been.called');
|
||||
});
|
||||
|
||||
it('renders VnAvatar and VnUserLink components', () => {
|
||||
cy.createWrapper(VnSms);
|
||||
cy.getComponent('VnAvatar').should('exist');
|
||||
cy.getComponent('VnUserLink').should('exist');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,67 @@
|
|||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
// VnSubToolbar.spec.js
|
||||
import VnSubToolbar from 'src/components/common/VnSubToolbar.vue';
|
||||
|
||||
describe.skip('<VnSubToolbar />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
describe.only('<VnSubToolbar />', () => {
|
||||
beforeEach(() => {
|
||||
// Mock store
|
||||
cy.stub(window, 'useStateStore').returns({
|
||||
toggleSubToolbar: cy.stub().as('toggleSubToolbarStub'),
|
||||
});
|
||||
|
||||
// Mock DOM elements
|
||||
const actionDiv = document.createElement('div');
|
||||
actionDiv.id = 'st-actions';
|
||||
const dataDiv = document.createElement('div');
|
||||
dataDiv.id = 'st-data';
|
||||
document.body.appendChild(actionDiv);
|
||||
document.body.appendChild(dataDiv);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.querySelector('#st-actions')?.remove();
|
||||
document.querySelector('#st-data')?.remove();
|
||||
});
|
||||
|
||||
it('renders toolbar correctly', () => {
|
||||
cy.createWrapper(VnSubToolbar);
|
||||
cy.get('#subToolbar').should('exist');
|
||||
});
|
||||
|
||||
it('calls toggleSubToolbar on mount', () => {
|
||||
cy.createWrapper(VnSubToolbar);
|
||||
cy.get('@toggleSubToolbarStub').should('have.been.calledOnce');
|
||||
});
|
||||
|
||||
it('calls toggleSubToolbar on unmount', () => {
|
||||
// eslint-disable-next-line cypress/no-assigning-return-values
|
||||
const wrapper = cy.createWrapper(VnSubToolbar);
|
||||
wrapper.unmount();
|
||||
cy.get('@toggleSubToolbarStub').should('have.been.calledTwice');
|
||||
});
|
||||
|
||||
it('updates hasContent when actions content changes', () => {
|
||||
cy.createWrapper(VnSubToolbar);
|
||||
const actionsEl = document.querySelector('#st-actions');
|
||||
const newChild = document.createElement('div');
|
||||
actionsEl.appendChild(newChild);
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.hasContent).should('equal', 1);
|
||||
});
|
||||
|
||||
it('updates hasContent when data content changes', () => {
|
||||
cy.createWrapper(VnSubToolbar);
|
||||
const dataEl = document.querySelector('#st-data');
|
||||
const newChild = document.createElement('div');
|
||||
dataEl.appendChild(newChild);
|
||||
|
||||
cy.wrap(Cypress.vueWrapper.vm.hasContent).should('equal', 1);
|
||||
});
|
||||
|
||||
it('handles missing action and data elements', () => {
|
||||
document.querySelector('#st-actions')?.remove();
|
||||
document.querySelector('#st-data')?.remove();
|
||||
|
||||
cy.createWrapper(VnSubToolbar);
|
||||
cy.wrap(Cypress.vueWrapper.vm.hasContent).should('equal', false);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,50 @@
|
|||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||
|
||||
describe.skip('<VnUserLink />', () => {
|
||||
it('TODO: boilerplate', () => {
|
||||
// see: https://on.cypress.io/mounting-vue
|
||||
cy.createWrapper(VnUserLink);
|
||||
describe.only('<VnUserLink />', () => {
|
||||
const mountComponent = (props = {}, slots = {}) => {
|
||||
cy.createWrapper(VnUserLink, {
|
||||
props,
|
||||
slots,
|
||||
});
|
||||
};
|
||||
|
||||
it('renders with default props', () => {
|
||||
mountComponent();
|
||||
cy.get('span').should('exist');
|
||||
cy.get('span').should('not.have.class', 'link');
|
||||
cy.get('span').should('contain', '');
|
||||
});
|
||||
|
||||
it('displays name when provided and defaultName is false', () => {
|
||||
mountComponent({ name: 'John Doe' });
|
||||
cy.get('span').should('contain', 'John Doe');
|
||||
});
|
||||
|
||||
it('displays default name when defaultName is true', () => {
|
||||
mountComponent({ name: null, defaultName: true });
|
||||
cy.get('span').should('contain', 'globals.system');
|
||||
});
|
||||
|
||||
it('adds link class when workerId is provided', () => {
|
||||
mountComponent({ workerId: 123 });
|
||||
cy.get('span').should('have.class', 'link');
|
||||
});
|
||||
|
||||
it('renders WorkerDescriptorProxy when workerId is provided', () => {
|
||||
mountComponent({ workerId: 123 });
|
||||
cy.getComponent('WorkerDescriptorProxy').should('exist');
|
||||
cy.getComponent('WorkerDescriptorProxy')
|
||||
.invoke('props')
|
||||
.should('deep.include', { id: 123 });
|
||||
});
|
||||
|
||||
it('uses custom content from link slot', () => {
|
||||
mountComponent(
|
||||
{},
|
||||
{
|
||||
link: '<span class="custom-link">Custom Link Content</span>',
|
||||
}
|
||||
);
|
||||
cy.get('.custom-link').should('contain', 'Custom Link Content');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue