From df92ac02ffdd77074285055acafd312ade83c61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 12 May 2026 15:23:29 +0300 Subject: [PATCH] feat(projects-bulk): wire 3 new dialogs into BulkActionsBar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add RegionsBulkDialog / DaysBulkDialog / LimitBulkDialog to BulkActionsBar with open-state refs (regionsOpen/daysOpen/limitOpen), runBulk helper via store.bulkUpdate, and flex-wrap layout. Update spec: fix existing tests (bulkAction → bulkUpdate), add 3 new dialog-wiring tests (7/7 pass; full suite 614+3skipped/0failed). Co-Authored-By: Claude Sonnet 4.6 --- .../js/components/projects/BulkActionsBar.vue | 58 +++++++++++- app/tests/Frontend/BulkActionsBar.spec.ts | 91 +++++++++++++++++-- 2 files changed, 138 insertions(+), 11 deletions(-) diff --git a/app/resources/js/components/projects/BulkActionsBar.vue b/app/resources/js/components/projects/BulkActionsBar.vue index 4f55bd6c..1ddead55 100644 --- a/app/resources/js/components/projects/BulkActionsBar.vue +++ b/app/resources/js/components/projects/BulkActionsBar.vue @@ -1,40 +1,91 @@ diff --git a/app/tests/Frontend/BulkActionsBar.spec.ts b/app/tests/Frontend/BulkActionsBar.spec.ts index 63f0ae4e..3e96c454 100644 --- a/app/tests/Frontend/BulkActionsBar.spec.ts +++ b/app/tests/Frontend/BulkActionsBar.spec.ts @@ -2,14 +2,31 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { mount } from '@vue/test-utils'; import { createPinia, setActivePinia } from 'pinia'; import { createVuetify } from 'vuetify'; +import axios from 'axios'; import BulkActionsBar from '../../resources/js/components/projects/BulkActionsBar.vue'; import { useProjectsStore } from '../../resources/js/stores/projectsStore'; -const factory = () => - mount(BulkActionsBar, { - global: { plugins: [createVuetify()] }, +vi.mock('axios'); + +const defaultStubs = { + VDialog: { template: '
' }, + DevIndexBadge: true, + RegionsBulkDialog: true, + DaysBulkDialog: true, + LimitBulkDialog: true, +}; + +const factory = () => { + vi.mocked(axios.post).mockResolvedValue({ data: { updated: 0, skipped: [], warnings: [] } }); + vi.mocked(axios.get).mockResolvedValue({ data: { data: [], meta: { total: 0 } } }); + return mount(BulkActionsBar, { + global: { + plugins: [createVuetify()], + stubs: defaultStubs, + }, }); +}; beforeEach(() => { setActivePinia(createPinia()); @@ -25,20 +42,20 @@ describe('BulkActionsBar', () => { expect(wrapper.text()).toContain('2'); }); - it('clicking Pause triggers store.bulkAction("pause") after confirm', async () => { + it('clicking Pause triggers store.bulkUpdate("pause") after confirm', async () => { const store = useProjectsStore(); store.selectedIds.add(1); - const spy = vi.spyOn(store, 'bulkAction').mockResolvedValue(); + const spy = vi.spyOn(store, 'bulkUpdate').mockResolvedValue({ updated: 1, skipped: [], warnings: [] }); window.confirm = vi.fn(() => true); const wrapper = factory(); await wrapper.find('[data-testid="bulk-pause"]').trigger('click'); - expect(spy).toHaveBeenCalledWith('pause'); + expect(spy).toHaveBeenCalledWith({ action: 'pause' }); }); - it('cancel confirm — bulkAction NOT called', async () => { + it('cancel confirm — bulkUpdate NOT called', async () => { const store = useProjectsStore(); store.selectedIds.add(1); - const spy = vi.spyOn(store, 'bulkAction').mockResolvedValue(); + const spy = vi.spyOn(store, 'bulkUpdate').mockResolvedValue({ updated: 0, skipped: [], warnings: [] }); window.confirm = vi.fn(() => false); const wrapper = factory(); await wrapper.find('[data-testid="bulk-pause"]').trigger('click'); @@ -53,3 +70,61 @@ describe('BulkActionsBar', () => { expect(store.selectedIds.size).toBe(0); }); }); + +describe('BulkActionsBar — extended', () => { + it('renders 3 new dialog-open buttons (Regions/Days/Limit)', async () => { + const { wrapper } = await (async () => { + setActivePinia(createPinia()); + vi.mocked(axios.post).mockResolvedValue({ data: { updated: 1, skipped: [], warnings: [] } }); + vi.mocked(axios.get).mockResolvedValue({ data: { data: [], meta: { total: 0 } } }); + const store = useProjectsStore(); + store.selectedIds.add(1); + store.selectedIds.add(2); + const wrapper = mount(BulkActionsBar, { + global: { + plugins: [createVuetify()], + stubs: defaultStubs, + }, + }); + return { wrapper, store }; + })(); + expect(wrapper.find('[data-testid="bulk-regions"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="bulk-days"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="bulk-limit"]').exists()).toBe(true); + }); + + it('opens RegionsBulkDialog on regions button click', async () => { + setActivePinia(createPinia()); + vi.mocked(axios.post).mockResolvedValue({ data: { updated: 1, skipped: [], warnings: [] } }); + vi.mocked(axios.get).mockResolvedValue({ data: { data: [], meta: { total: 0 } } }); + const store = useProjectsStore(); + store.selectedIds.add(1); + store.selectedIds.add(2); + const wrapper = mount(BulkActionsBar, { + global: { + plugins: [createVuetify()], + stubs: defaultStubs, + }, + }); + await wrapper.find('[data-testid="bulk-regions"]').trigger('click'); + expect((wrapper.vm as any).regionsOpen).toBe(true); + }); + + it('keeps existing pause/resume/archive buttons', async () => { + setActivePinia(createPinia()); + vi.mocked(axios.post).mockResolvedValue({ data: { updated: 1, skipped: [], warnings: [] } }); + vi.mocked(axios.get).mockResolvedValue({ data: { data: [], meta: { total: 0 } } }); + const store = useProjectsStore(); + store.selectedIds.add(1); + store.selectedIds.add(2); + const wrapper = mount(BulkActionsBar, { + global: { + plugins: [createVuetify()], + stubs: defaultStubs, + }, + }); + expect(wrapper.find('[data-testid="bulk-pause"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="bulk-resume"]').exists()).toBe(true); + expect(wrapper.find('[data-testid="bulk-archive"]').exists()).toBe(true); + }); +});