Skip to content

Commit

Permalink
Merge branch 'feature/widget-recurrence' into feat/add-double-datalab…
Browse files Browse the repository at this point in the history
…el-plugin
  • Loading branch information
mateuseduardomedeiros committed Jan 8, 2025
2 parents 549ac40 + 50dfee6 commit c8ef9aa
Show file tree
Hide file tree
Showing 40 changed files with 3,205 additions and 307 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"dependencies": {
"@vueuse/core": "^10.11.0",
"@weni/unnnic-system": "^2.16.0",
"@weni/unnnic-system": "^2.19.0",
"axios": "^1.7.2",
"chart.js": "^4.4.2",
"chartjs-plugin-datalabels": "^2.2.0",
Expand Down
7 changes: 6 additions & 1 deletion src/components/insights/Layout/HeaderDashboardSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@
type="secondary"
size="large"
iconCenter="tune"
data-testid="options-dashboard-button"
/>
</template>
<UnnnicDropdownItem @click="showEditDashboard = true">
<UnnnicDropdownItem
data-testid="edit-dashboard-button"
@click="showEditDashboard = true"
>
{{ $t('edit_dashboard.title') }}
</UnnnicDropdownItem>
</UnnnicDropdown>
<DrawerDashboardConfig
v-if="showEditDashboard"
v-model="showEditDashboard"
:dashboard="currentDashboard"
data-testid="edit-dashboard-drawer"
@close="showEditDashboard = false"
/>
</template>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { mount } from '@vue/test-utils';
import { createStore } from 'vuex';
import HeaderDashboardSettings from '../HeaderDashboardSettings.vue';
import DrawerDashboardConfig from '../../dashboards/DrawerDashboardConfig.vue';

describe('HeaderDashboardSettings.vue', () => {
let store;
let wrapper;

beforeEach(() => {
store = createStore({
modules: {
dashboards: {
namespaced: true,
state: {
currentDashboard: {
uuid: '123',
name: 'Dashboard 1',
is_editable: true,
},
},
},
},
});
wrapper = mount(HeaderDashboardSettings, {
global: {
plugins: [store],
components: { DrawerDashboardConfig },
},
});
});

it('renders dropdown trigger when dashboard is editable', () => {
const dropdownTrigger = wrapper.findComponent({ name: 'UnnnicButton' });
expect(dropdownTrigger.exists()).toBe(true);
});

it('shows DrawerDashboardConfig when "showEditDashboard" is true', async () => {
expect(
wrapper.findComponent('[data-testid="edit-dashboard-drawer"]').exists(),
).toBe(false);

const optionMenuButton = wrapper.findComponent(
'[data-testid="options-dashboard-button"]',
);

await optionMenuButton.trigger('click');

const dropdownItem = wrapper.findComponent(
'[data-testid="edit-dashboard-button"]',
);

await dropdownItem.trigger('click');

expect(wrapper.vm.showEditDashboard).toBe(true);
});

it('closes DrawerDashboardConfig when close event is emitted', async () => {
const optionMenuButton = wrapper.findComponent(
'[data-testid="options-dashboard-button"]',
);

await optionMenuButton.trigger('click');

const dropdownItem = wrapper.findComponent(
'[data-testid="edit-dashboard-button"]',
);

await dropdownItem.trigger('click');

expect(wrapper.findComponent(DrawerDashboardConfig).exists()).toBe(true);

const drawerConfig = wrapper.findComponent(DrawerDashboardConfig);
await drawerConfig.vm.$emit('close');

expect(wrapper.findComponent(DrawerDashboardConfig).exists()).toBe(false);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { describe, it, expect } from 'vitest';

import { mount, config } from '@vue/test-utils';

import { createI18n } from 'vue-i18n';
import en from '@/locales/en.json';
import UnnnicSystem from '@/utils/plugins/UnnnicSystem';

const i18n = createI18n({
legacy: false,
locale: 'en',
messages: { en },
fallbackWarn: false,
missingWarn: false,
});

config.global.plugins = [i18n, UnnnicSystem];

import SkeletonHorizontalBarChart from '../SkeletonHorizontalBarChart.vue';

describe('SkeletonHorizontalBarChart', () => {
const BAR_HEIGHT = 48;

it('renders correctly when props are valid', () => {
const wrapper = mount(SkeletonHorizontalBarChart, {
props: { width: 300, height: 480 },
});

const totalBars = Math.floor(480 / BAR_HEIGHT);
expect(wrapper.findAll('.skeleton-h-bar-container__bar')).toHaveLength(
totalBars,
);
});

it('applies the correct styles and structure', () => {
const wrapper = mount(SkeletonHorizontalBarChart, {
props: { width: 300, height: 480 },
});

expect(wrapper.classes()).toContain('skeleton-h-bar-container');
expect(
wrapper.findAll('.skeleton-h-bar-container__bar').length,
).toBeGreaterThan(0);

expect(
wrapper.findComponent({ name: 'UnnnicSkeletonLoading' }).exists(),
).toBe(true);
});
});
7 changes: 6 additions & 1 deletion src/components/insights/dashboards/ModalDeleteDashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,21 @@
showActionsDivider
showCloseIcon
size="sm"
data-testid="modal-delete-dashboard"
@update:model-value="!$event ? close() : {}"
@primary-button-click="deleteDashboard"
>
<p class="delete-notice">
<p
class="delete-notice"
data-testid="delete-notice"
>
{{ $t('delete_dashboard.notice') }}
</p>
<UnnnicLabel :label="$t('confirmation')" />
<UnnnicInput
v-model="dashboardName"
:placeholder="dashboard.name"
data-testid="input-dashboard-name"
/>
</UnnnicModalDialog>
</template>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import Dashboards from '@/services/api/resources/dashboards';
import { createStore } from 'vuex';

import unnnic from '@weni/unnnic-system';

import ModalDeleteDashboard from '../ModalDeleteDashboard.vue';

vi.mock('@/services/api/resources/dashboards');

describe('ModalDeleteDashboard', () => {
let store;
let wrapper;
const mockDashboard = {
uuid: '123',
name: 'Test Dashboard',
};

beforeEach(() => {
store = createStore({
modules: {
dashboards: {
namespaced: true,
state: {
dashboards: [mockDashboard],
},
getters: {
dashboardDefault: () => mockDashboard,
},
mutations: {
SET_DASHBOARDS: vi.fn(),
},
},
},
});

Dashboards.deleteDashboard.mockResolvedValue();

wrapper = mount(ModalDeleteDashboard, {
props: { modelValue: true, dashboard: mockDashboard },
global: { plugins: [store] },
});
});

it('renders correctly with required props', () => {
expect(wrapper.find('[data-testid="delete-notice"]').text()).toContain(
wrapper.vm.$t('delete_dashboard.notice'),
);
expect(
wrapper.findComponent('[data-testid="modal-delete-dashboard"]').exists(),
).toBe(true);
});

it('enables primary button only if dashboard name matches', async () => {
const input = wrapper.findComponent('[data-testid="input-dashboard-name"]');

const deleteButton = wrapper.find('[data-testid="primary-button"]');

expect(deleteButton.attributes('disabled')).toBeDefined();

await input.setValue('Test Dashboard');

expect(deleteButton.attributes('disabled')).toBeUndefined();
});

it('calls deleteDashboard on primary button click', async () => {
const input = wrapper.findComponent('[data-testid="input-dashboard-name"]');
const deleteButton = wrapper.find('[data-testid="primary-button"]');

await input.setValue('Test Dashboard');
await deleteButton.trigger('click');

expect(Dashboards.deleteDashboard).toHaveBeenCalledWith(mockDashboard.uuid);
});

it('shows success alert and updates state on successful deletion', async () => {
const setDashboards = vi.spyOn(wrapper.vm, 'setDashboards');

const input = wrapper.findComponent('[data-testid="input-dashboard-name"]');
const deleteButton = wrapper.find('[data-testid="primary-button"]');

await input.setValue('Test Dashboard');
await deleteButton.trigger('click');

expect(setDashboards).toHaveBeenCalledWith([]);
});

it('shows error alert on failed deletion', async () => {
const callAlertSpy = vi.spyOn(unnnic, 'unnnicCallAlert');
Dashboards.deleteDashboard.mockRejectedValueOnce(new Error('Failed'));

const input = wrapper.findComponent('[data-testid="input-dashboard-name"]');
const deleteButton = wrapper.find('[data-testid="primary-button"]');

await input.setValue('Test Dashboard');
await deleteButton.trigger('click');

expect(Dashboards.deleteDashboard).toHaveBeenCalled();

expect(callAlertSpy).toHaveBeenCalledWith({
props: {
text: wrapper.vm.$t('delete_dashboard.alert.error'),
type: 'error',
},
seconds: 5,
});
});

it('closes modal and emits close event when secondary button is clicked', async () => {
const cancelButton = wrapper.find('[data-testid="secondary-button"]');

await cancelButton.trigger('click');

expect(wrapper.emitted('close')).toBeTruthy();
});
});
2 changes: 2 additions & 0 deletions src/components/insights/drawers/DrawerConfigContentCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

<component
:is="currentFormComponent"
:data-testid="`form-${type}`"
v-on="currentFormEvents"
/>

Expand All @@ -21,6 +22,7 @@
:text="$t('drawers.reset_widget')"
type="tertiary"
:disabled="disableResetWidgetButton"
data-testid="reset-widget-button"
@click="$emit('reset-widget')"
/>
</template>
Expand Down
2 changes: 2 additions & 0 deletions src/components/insights/drawers/DrawerConfigGallery/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ export default {
'e6c3ce0c-2bb5-45b6-b5ee-1d17ea88941b',
'd646822b-07b4-4386-a242-4c9ec6bb485f',
'661861a7-01ee-4986-8477-9195c7169858',
'9bdbad04-bcca-4bc7-a718-06fb7965e07f',
'a6c8fc78-495f-43bd-a2ee-d38dfa79aea6',
];
const enabledProjectsStg = ['95fa43d6-d91a-48d4-bbe8-256d93bf5254'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ export default {
},
},
'config.flow?.uuid'(_newFlow, oldFlow) {
if (typeof oldFlow === 'object') {
'config.flow.uuid'(newFlowUuid, oldFlowUuid) {
if (oldFlowUuid && newFlowUuid !== oldFlowUuid) {
this.config.flow.result = '';
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,7 @@ describe('FormFlowResult', () => {
it('resets flow result when flow uuid changes', async () => {
const initialConfig = {
flow: {
uuid: {
id: 'store-uuid',
},
uuid: 'flow-uuid',
result: 'test-result',
},
operation: 'sum',
Expand All @@ -218,6 +216,10 @@ describe('FormFlowResult', () => {
const storeWithConfig = createDefaultStore(initialConfig);
const wrapperWithStore = createWrapper(storeWithConfig);

wrapperWithStore.vm.config.flow.uuid = 'changed-id';

await wrapperWithStore.vm.$nextTick();

expect(wrapperWithStore.vm.config.flow.result).toBe('');
});
});
Expand Down
Loading

0 comments on commit c8ef9aa

Please sign in to comment.