diff --git a/app/resources/js/components/deals/DealsTable.vue b/app/resources/js/components/deals/DealsTable.vue
index 1c3a9619..27afbf0d 100644
--- a/app/resources/js/components/deals/DealsTable.vue
+++ b/app/resources/js/components/deals/DealsTable.vue
@@ -122,6 +122,23 @@ function formatCost(cost: number): string {
{{ formatRelative(item.receivedMinutesAgo) }}
+
+
+
+
+
+
+ toggleSelect(internalItem)"
+ />
+
diff --git a/app/tests/Frontend/DealsTable.spec.ts b/app/tests/Frontend/DealsTable.spec.ts
new file mode 100644
index 00000000..cda6baff
--- /dev/null
+++ b/app/tests/Frontend/DealsTable.spec.ts
@@ -0,0 +1,59 @@
+import { describe, it, expect } from 'vitest';
+import { mount } from '@vue/test-utils';
+import { createVuetify } from 'vuetify';
+
+import DealsTable from '../../resources/js/components/deals/DealsTable.vue';
+import type { MockDeal } from '../../resources/js/composables/mockDeals';
+
+const vuetify = createVuetify();
+
+const sampleDeals: MockDeal[] = [
+ {
+ id: 1,
+ name: 'Иванов И.',
+ phone: '+7 (916) 100-00-01',
+ statusSlug: 'new',
+ project: 'B1 site',
+ manager: { initials: 'AD', name: 'Admin' },
+ cost: 1000,
+ receivedMinutesAgo: 5,
+ },
+ {
+ id: 2,
+ name: 'Петров П.',
+ phone: '+7 (916) 100-00-02',
+ statusSlug: 'new',
+ project: 'B1 call',
+ manager: { initials: 'AD', name: 'Admin' },
+ cost: 1500,
+ receivedMinutesAgo: 30,
+ },
+];
+
+describe('DealsTable a11y (Q.DEFER.004 sub-A)', () => {
+ it('select-all header checkbox has aria-label', () => {
+ const wrapper = mount(DealsTable, {
+ props: { deals: sampleDeals, selectedIds: [], statusBySlug: new Map() },
+ global: { plugins: [vuetify] },
+ });
+ const headerCheckbox = wrapper.find(
+ 'th .v-selection-control input[type="checkbox"][aria-label="Выбрать все сделки"]',
+ );
+ expect(headerCheckbox.exists()).toBe(true);
+ });
+
+ it('each row checkbox has aria-label referencing deal name', () => {
+ const wrapper = mount(DealsTable, {
+ props: { deals: sampleDeals, selectedIds: [], statusBySlug: new Map() },
+ global: { plugins: [vuetify] },
+ });
+ const rowCheckbox1 = wrapper.find(
+ 'tbody tr:nth-of-type(1) input[type="checkbox"][aria-label="Выбрать сделку «Иванов И.»"]',
+ );
+ const rowCheckbox2 = wrapper.find(
+ 'tbody tr:nth-of-type(2) input[type="checkbox"][aria-label="Выбрать сделку «Петров П.»"]',
+ );
+ expect(rowCheckbox1.exists()).toBe(true);
+ expect(rowCheckbox2.exists()).toBe(true);
+ });
+});