Skip to content

Commit

Permalink
feat: Adds test id to flashbar dom selector
Browse files Browse the repository at this point in the history
  • Loading branch information
orangevolon committed Nov 8, 2024
1 parent 7a5e18d commit 2e88cbb
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exports[`test-utils selectors 1`] = `
],
"anchor-navigation": [
"awsui_anchor-item--active_17oho",
"awsui_anchor-item_17oho",
"awsui_anchor-link-info_17oho",
"awsui_anchor-link-text_17oho",
"awsui_anchor-link_17oho",
Expand Down
79 changes: 79 additions & 0 deletions src/flashbar/__tests__/collapsible.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,85 @@ describe('Collapsible Flashbar', () => {
});
});

test('assigns data-testid to flash items', () => {
const wrapper = renderFlashbar({
items: [
{
testId: 'flash-item-1',
content: 'first flash item',
},
{
testId: 'flash-item-2',
content: 'second flash item',
},
],
});
findNotificationBar(wrapper)!.click();
const flashbarItemsTestIds = wrapper
.findItems()
.map(flashbar => flashbar.getElement()!.getAttribute('data-testid'));

expect(flashbarItemsTestIds).toEqual(['flash-item-1', 'flash-item-2']);
});

test('findItemByTestId', () => {
const wrapper = renderFlashbar({
items: [
{
testId: 'flash-item-1',
content: 'first flash item',
},
{
testId: 'flash-item-2',
content: 'second flash item',
},
],
});
findNotificationBar(wrapper)!.click();
const secondFlashItemFromTestId = wrapper.findItemByTestId('flash-item-2')!.getElement();

expect(secondFlashItemFromTestId).toHaveTextContent('second flash item');
});

test('findItemByTestId returns the item even if the test ID contains double quotes', () => {
const wrapper = renderFlashbar({
items: [
{
testId: '"flash-item-1"',
content: 'first flash item',
},
{
testId: '"flash-item-2"',
content: 'second flash item',
},
],
});
findNotificationBar(wrapper)!.click();
const flashItem = wrapper.findItemByTestId('"flash-item-1"')!.getElement();

expect(flashItem).toHaveTextContent('first flash item');
});

test('findItemByTestId doesn not return the next items if the collapsible is not expanded', () => {
const wrapper = renderFlashbar({
items: [
{
testId: 'flash-item-1',
content: 'first flash item',
},
{
testId: 'flash-item-2',
content: 'second flash item',
},
],
});
const fistFlashItem = wrapper.findItemByTestId('flash-item-1');
const secondFlashItem = wrapper.findItemByTestId('flash-item-2');

expect(fistFlashItem).toBeTruthy();
expect(secondFlashItem).not.toBeTruthy();
});

test('findItemsByType', () => {
{
const wrapper = createFlashbarWrapper(
Expand Down
61 changes: 61 additions & 0 deletions src/flashbar/__tests__/flashbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,67 @@ describe('Flashbar component', () => {
}
});

test('assigns data-testid to flash items', () => {
const { container } = reactRender(
<Flashbar
items={[
{
testId: 'flash-item-1',
content: 'first flash item',
},
{
testId: 'flash-item-2',
content: 'second flash item',
},
]}
/>
);
const wrapper = createWrapper(container);
const flashbarItemsTestIds = wrapper
.findFlashbar()!
.findItems()
.map(flashbar => flashbar.getElement()!.getAttribute('data-testid'));

expect(flashbarItemsTestIds).toEqual(['flash-item-1', 'flash-item-2']);
});

test('findItemByTestId', () => {
const { container } = reactRender(
<Flashbar
items={[
{
testId: 'flash-item-1',
content: 'first flash item',
},
{
testId: 'flash-item-2',
content: 'second flash item',
},
]}
/>
);
const wrapper = createWrapper(container);
const secondFlashItemFromTestId = wrapper.findFlashbar()!.findItemByTestId('flash-item-2')!.getElement();
expect(secondFlashItemFromTestId).toHaveTextContent('second flash item');
});

test('findItemByTestId returns the item even if the test ID contains double quotes', () => {
const { container } = reactRender(
<Flashbar
items={[
{
testId: '"flash-item-test-id"',
content: 'flash item',
},
]}
/>
);
const wrapper = createWrapper(container);
const flashItem = wrapper.findFlashbar()?.findItemByTestId('"flash-item-test-id"')!.getElement();

expect(flashItem).toHaveTextContent('flash item');
});

test('findItemsByType', () => {
const wrapper = createFlashbarWrapper(
<Flashbar
Expand Down
1 change: 1 addition & 0 deletions src/flashbar/collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export default function CollapsibleFlashbar({ items, ...restProps }: FlashbarPro
{(state: string, transitionRootElement: React.Ref<HTMLDivElement> | undefined) => (
<li
aria-hidden={!showInnerContent(item)}
data-testid={item.testId}
className={
showInnerContent(item)
? clsx(
Expand Down
2 changes: 1 addition & 1 deletion src/flashbar/flash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const focusFlashById = throttle(
{ trailing: false }
);

export interface FlashProps extends FlashbarProps.MessageDefinition {
export interface FlashProps extends Omit<FlashbarProps.MessageDefinition, 'testId'> {
className: string;
transitionState?: string;
i18nStrings?: FlashbarProps.I18nStrings;
Expand Down
7 changes: 7 additions & 0 deletions src/flashbar/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ export namespace FlashbarProps {
buttonText?: ButtonProps['children'];
onButtonClick?: ButtonProps['onClick'];
onDismiss?: ButtonProps['onClick'];

/**
* Test ID of the flash list item.
* Assigns this value to the `data-testid` attribute of the flash list item.
* Flash component is the direct child of the flash list item.
*/
testId?: string;
}

export interface I18nStrings {
Expand Down
3 changes: 2 additions & 1 deletion src/flashbar/non-collapsible-flashbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProp
in={true}
>
{(state: string, transitionRootElement: React.Ref<HTMLDivElement> | undefined) => (
<li className={styles['flash-list-item']}>
<li className={styles['flash-list-item']} data-testid={item.testId}>
{renderItem(item, item.id ?? index, transitionRootElement, state)}
</li>
)}
Expand Down Expand Up @@ -91,6 +91,7 @@ export default function NonCollapsibleFlashbar({ items, i18nStrings, ...restProp
<li
key={item.id ?? index}
className={styles['flash-list-item']}
data-testid={item.testId}
{...getAnalyticsMetadataAttribute(getItemAnalyticsMetadata(index + 1, item.type || 'info', item.id))}
>
{renderItem(item, item.id ?? index)}
Expand Down
14 changes: 14 additions & 0 deletions src/test-utils/dom/flashbar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ export default class FlashbarWrapper extends ComponentWrapper {
);
}

/**
* Returns the wrapper of the first flash list item that matches the specified test ID.
* If the items are stacked, the hidden items will not be returned.
*
* Looks for the `data-testid` attribute that is assigned via `items` prop.
* If no matching flash list item is found, returns `null`.
*
* @param {string} testId
* @returns {FlashbarWrapper | null}
*/
findItemByTestId(testId: string): FlashWrapper | null {
return this.findComponent(`.${styles['flash-list-item']}[data-testid="${CSS.escape(testId)}"]`, FlashWrapper);
}

/**
* Returns the toggle button that expands and collapses stacked notifications.
*/
Expand Down

0 comments on commit 2e88cbb

Please sign in to comment.