Skip to content

Commit 9f29cfb

Browse files
committed
test(emojis): consolidate picker slot tests into integration coverage
The per-slot conversion left many heavily-mocked tests that only asserted a slot forwards an interaction to a mocked context setter β€” wiring, not behavior. Replace them with real end-to-end coverage: EmojiPickerPanel.test now mocks only react-virtuoso and drives the real nav / search / grid / preview / skin-tone slots against real context. - Delete the CategoryNav / EmojiButton / PreviewPane / SearchInput slot tests; their behavior (category activation, selection, hover preview, search, ArrowDown β†’ grid focus) is now asserted through the real component tree in EmojiPickerPanel.test. - Relocate the skin-tone resolution matrix to a resolveNative test in EmojiPickerContext, where that logic lives now (not in EmojiButton). - Merge duplicates (themeClassName, entry-exports, EmojiGrid a11y, SkinToneSelector keyboard) and drop a trivial aria-haspopup attribute check. Emoji suite: 104 β†’ 92 tests, 26 β†’ 22 files; behavior coverage preserved or improved.
1 parent 11f2c57 commit 9f29cfb

10 files changed

Lines changed: 162 additions & 375 deletions

β€Žsrc/plugins/Emojis/__tests__/StreamEmojiPicker.test.tsxβ€Ž

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,6 @@ describe('StreamEmojiPicker session state', () => {
122122
fireEvent.click(screen.getByText('select-rocket'));
123123
expect(screen.getByTestId('frequently-used').textContent).toBe('');
124124
});
125-
126-
it('marks the toggle button as opening a dialog popup', () => {
127-
render(<StreamEmojiPicker />);
128-
expect(screen.getByLabelText('aria/Emoji picker')).toHaveAttribute(
129-
'aria-haspopup',
130-
'dialog',
131-
);
132-
});
133125
});
134126

135127
describe('StreamEmojiPicker props', () => {

β€Žsrc/plugins/Emojis/__tests__/entry-exports.test.tsβ€Ž

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ import * as emojis from '../index';
22
import { StreamEmojiPicker } from '../StreamEmojiPicker';
33

44
describe('emojis entry exports', () => {
5-
it('exports both the deprecated EmojiPicker and the StreamEmojiPicker successor', () => {
5+
it('exports both pickers, the compound parts, and the context hook', () => {
6+
// Deprecated emoji-mart picker + its built-in successor.
67
expect(typeof emojis.EmojiPicker).toBe('function');
78
expect(typeof emojis.StreamEmojiPicker).toBe('function');
8-
});
9-
10-
it('exposes the compound API + context hook', () => {
9+
// Composition surface.
1110
expect(typeof emojis.useEmojiPickerContext).toBe('function');
1211
for (const part of [
1312
'Grid',

β€Žsrc/plugins/Emojis/components/__tests__/CategoryNav.test.tsxβ€Ž

Lines changed: 0 additions & 44 deletions
This file was deleted.

β€Žsrc/plugins/Emojis/components/__tests__/EmojiButton.test.tsxβ€Ž

Lines changed: 0 additions & 96 deletions
This file was deleted.

β€Žsrc/plugins/Emojis/components/__tests__/EmojiGrid.test.tsxβ€Ž

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from 'react';
2-
import { fireEvent, render, screen } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33

4-
// Capture the Virtuoso scroll callbacks so the scroll-spy behavior is testable, and
5-
// render every item synchronously so the non-search view's a11y tree is assertable.
4+
// Capture the Virtuoso scroll callbacks so scroll-spy is testable, and render items
5+
// synchronously so the browse view's a11y tree is assertable (jsdom has no layout).
66
const { virtuoso } = vi.hoisted(() => ({
77
virtuoso: {} as {
88
atBottomStateChange?: (atBottom: boolean) => void;
@@ -63,7 +63,7 @@ const base = () => ({
6363
isSearching: false,
6464
resolveNative: (e: { skins: { native: string }[] }) => e.skins[0]?.native ?? '',
6565
scrollTarget: null,
66-
searchResults: null as null | ReturnType<typeof emoji>[],
66+
searchResults: null,
6767
selectEmoji: vi.fn(),
6868
setActiveCategory: vi.fn(),
6969
});
@@ -72,36 +72,27 @@ beforeEach(() => {
7272
Object.assign(ctx, base());
7373
});
7474

75-
describe('EmojiGrid accessibility (non-search view)', () => {
76-
beforeEach(() => {
75+
describe('EmojiGrid browse view', () => {
76+
it('renders emojis as labeled buttons under labeled category regions, with no orphaned grid roles', () => {
7777
ctx.categories = [
7878
{
7979
emojis: [emoji('grinning', 'πŸ˜€', 'Grinning')],
8080
id: 'people',
8181
label: 'Smileys & People',
8282
},
8383
];
84-
});
85-
86-
it('renders emojis as accessible buttons with no orphaned grid/row/gridcell roles', () => {
8784
render(<EmojiGrid />);
8885

89-
// The review flagged row/gridcell elements with no owning grid in the virtualized
90-
// view. Native button semantics avoid the invalid ARIA entirely.
86+
// Native button semantics β€” no invalid ARIA grid/row/gridcell in the virtualized view.
9187
expect(screen.queryAllByRole('grid')).toHaveLength(0);
9288
expect(screen.queryAllByRole('row')).toHaveLength(0);
9389
expect(screen.queryAllByRole('gridcell')).toHaveLength(0);
94-
9590
expect(screen.getByRole('button', { name: 'Grinning' })).toBeInTheDocument();
96-
});
97-
98-
it('keeps emojis grouped under a labeled category region', () => {
99-
render(<EmojiGrid />);
10091
expect(screen.getByRole('region', { name: 'Smileys & People' })).toBeInTheDocument();
10192
});
10293
});
10394

104-
describe('EmojiGrid scroll-spy (active category tracking)', () => {
95+
describe('EmojiGrid scroll-spy', () => {
10596
beforeEach(() => {
10697
ctx.categories = [
10798
{ emojis: [emoji('grinning', 'πŸ˜€')], id: 'people', label: 'People' },
@@ -115,7 +106,7 @@ describe('EmojiGrid scroll-spy (active category tracking)', () => {
115106
expect(ctx.setActiveCategory).toHaveBeenLastCalledWith('flags');
116107
});
117108

118-
it('marks the last category active at the bottom, even when a short final category never reaches the top', () => {
109+
it('pins the last category active at the bottom, even when a short final category never reaches the top', () => {
119110
render(<EmojiGrid />);
120111
virtuoso.rangeChanged?.({ endIndex: 1, startIndex: 0 });
121112
virtuoso.atBottomStateChange?.(true);
@@ -125,14 +116,3 @@ describe('EmojiGrid scroll-spy (active category tracking)', () => {
125116
expect(ctx.setActiveCategory).toHaveBeenLastCalledWith('flags');
126117
});
127118
});
128-
129-
describe('EmojiGrid search view', () => {
130-
it('renders flat search results and selects through context', () => {
131-
const rocket = emoji('rocket', 'πŸš€', 'Rocket');
132-
ctx.isSearching = true;
133-
ctx.searchResults = [rocket];
134-
render(<EmojiGrid />);
135-
fireEvent.click(screen.getByRole('button', { name: 'Rocket' }));
136-
expect(ctx.selectEmoji).toHaveBeenCalledWith(rocket);
137-
});
138-
});

0 commit comments

Comments
Β (0)