-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test(ProductiveCard): add avt test coverage #6518
Merged
anamikaanu96
merged 9 commits into
carbon-design-system:main
from
devadula-nandan:6472-productive-card-avt
Dec 11, 2024
Merged
Changes from 5 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a02b81c
test(ProductiveCard): add avt test coverage
devadula-nandan 3b0675e
chore: docs update
devadula-nandan ef5ad03
test: add tests for all clickable zones and test focus
devadula-nandan f4ff126
fix: prefix
devadula-nandan f1cfe3c
Merge branch 'main' into 6472-productive-card-avt
devadula-nandan 7641402
fix: pr comment changes
devadula-nandan 2f97f63
chore: add deprecation notice for iconDescription
devadula-nandan 53e00c5
test: add mouse hover states
devadula-nandan 3354055
Merge branch 'main' into 6472-productive-card-avt
devadula-nandan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
|
||
import { expect, test } from '@playwright/test'; | ||
import { visitStory } from '../../test-utils/storybook'; | ||
import { carbon, pkg } from '../../../packages/ibm-products/src/settings'; | ||
|
||
test.describe('ProductiveCard @avt', () => { | ||
test('@avt-default-state', async ({ page }) => { | ||
|
@@ -23,4 +24,226 @@ test.describe('ProductiveCard @avt', () => { | |
'ProductiveCard @avt-default-state' | ||
); | ||
}); | ||
|
||
test('@avt-with-caption', async ({ page }) => { | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--with-caption', | ||
globals: { | ||
carbonTheme: 'white', | ||
}, | ||
}); | ||
await expect(page).toHaveNoACViolations('ProductiveCard @avt-with-caption'); | ||
}); | ||
|
||
// Disabled state test | ||
test('@avt-disabled: validates disabled button state', async ({ page }) => { | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--with-action-ghost-button', | ||
}); | ||
|
||
await expect(page).toHaveNoACViolations('ProductiveCard @avt-disabled'); | ||
|
||
const buttons = page.locator(`button.${carbon.prefix}--btn`); | ||
const disabledButton = buttons.nth(2); | ||
expect(await disabledButton.getAttribute('disabled')).not.toBeNull(); | ||
|
||
await page.keyboard.press('Tab'); | ||
expect( | ||
await buttons.nth(0).evaluate((btn) => document.activeElement === btn) | ||
).toBe(true); | ||
|
||
await page.keyboard.press('Tab'); | ||
expect( | ||
await buttons.nth(1).evaluate((btn) => document.activeElement === btn) | ||
).toBe(true); | ||
// disabled button | ||
await page.keyboard.press('Tab'); | ||
expect( | ||
await buttons.nth(2).evaluate((btn) => document.activeElement === btn) | ||
).toBe(false); | ||
}); | ||
|
||
// Overflow menu open/close states test | ||
test('@avt-overflow-menu: validates overflow menu interactions', async ({ | ||
page, | ||
}) => { | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--with-overflow', | ||
}); | ||
|
||
const menuButton = page.locator('button[aria-haspopup="true"]'); | ||
const menu = page.locator('ul[role="menu"]'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can probably use the roles here as well. :) |
||
|
||
// Check initial state | ||
expect(await menuButton.getAttribute('aria-expanded')).toBe('false'); | ||
|
||
// Open the menu | ||
await menuButton.click(); | ||
|
||
// Wait for menu to be visible | ||
await expect(menu).toBeVisible(); | ||
|
||
expect(await menuButton.getAttribute('aria-expanded')).toBe('true'); | ||
await expect(page).toHaveNoACViolations('ProductiveCard @menu-open'); | ||
|
||
// Close the menu with Escape | ||
await page.keyboard.press('Escape'); | ||
await expect(menu).not.toBeVisible(); | ||
|
||
expect(await menuButton.getAttribute('aria-expanded')).toBe('false'); | ||
await expect(page).toHaveNoACViolations('ProductiveCard @menu-closed'); | ||
|
||
// Reopen the menu via keyboard | ||
await page.keyboard.press('Tab'); | ||
expect( | ||
await menuButton.evaluate((btn) => document.activeElement === btn) | ||
).toBe(true); | ||
|
||
await page.keyboard.press('Enter'); | ||
await expect(menu).toBeVisible(); | ||
|
||
// Check menu item count and focus | ||
const menuItems = page.locator(`li.${carbon.prefix}--menu-item`); | ||
expect(await menuItems.count()).toBeGreaterThan(0); | ||
expect( | ||
await menuItems.first().evaluate((btn) => document.activeElement === btn) | ||
).toBe(true); | ||
expect(await menuButton.getAttribute('aria-expanded')).toBe('true'); | ||
|
||
// Ensure the menu is closed when pressing Escape | ||
await page.keyboard.press('Escape'); | ||
// Focus returns to menu button | ||
expect( | ||
await menuButton.evaluate((btn) => document.activeElement === btn) | ||
).toBe(true); | ||
|
||
// Check final state | ||
await expect(menu).not.toBeVisible(); | ||
}); | ||
|
||
test('@avt-keyboard: validates keyboard navigation for all interactive elements', async ({ | ||
page, | ||
}) => { | ||
// Navigate to the "Supplemental Bottom Bar" story for ProductiveCard, that has all interactive elements | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--supplemental-bottom-bar', | ||
}); | ||
|
||
// Ensure no accessibility violations for the story | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - Supplemental Bottom Bar' | ||
); | ||
|
||
// Move focus to the Edit button and validate | ||
await page.keyboard.press('Tab'); | ||
const editButton = page.getByLabel('Edit'); | ||
await expect(editButton).toBeVisible(); | ||
await expect(editButton).toBeFocused(); | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - Edit Button' | ||
); | ||
|
||
// Move focus to the Delete button and validate | ||
await page.keyboard.press('Tab'); | ||
const deleteButton = page.getByLabel('Delete'); | ||
await expect(deleteButton).toBeVisible(); | ||
await expect(deleteButton).toBeFocused(); | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - Delete Button' | ||
); | ||
|
||
// Move focus to the Read more button and validate | ||
await page.keyboard.press('Tab'); | ||
const readMoreButton1 = page.getByText('Read more'); | ||
await expect(readMoreButton1).toBeVisible(); | ||
await expect(readMoreButton1).toBeFocused(); | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - Read more Button' | ||
); | ||
|
||
// Tab Navigation in "Clickable Card" story for ProductiveCard, (zone one is default, whole card recieves focus) | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--clickable', | ||
}); | ||
|
||
// Ensure no accessibility violations for the story | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - Clickable Card' | ||
); | ||
|
||
// Move focus to the card element and validate | ||
await page.keyboard.press('Tab'); | ||
const zone1 = page.locator( | ||
`[${pkg.devtoolsAttribute}="${pkg.prefix}--ProductiveCard"]` | ||
); | ||
await expect(zone1).toBeFocused(); | ||
await expect(zone1).toHaveAttribute('role', 'button'); | ||
|
||
// Move focus to the Read more button and validate | ||
await page.keyboard.press('Tab'); | ||
const readMoreButton2 = page.getByText('Read more'); | ||
await expect(readMoreButton2).toBeVisible(); | ||
await expect(readMoreButton2).toBeFocused(); | ||
|
||
// Validate zone two focus | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--clickable&args=clickZone:two', | ||
}); | ||
await page.keyboard.press('Tab'); | ||
|
||
const zone2 = page.locator(`.${pkg.prefix}--card__header-body-container`); | ||
await expect(zone2).toBeFocused(); | ||
await expect(zone2).toHaveAttribute('role', 'button'); | ||
|
||
// Move focus to the Read more button and validate | ||
await page.keyboard.press('Tab'); | ||
const readMoreButton3 = page.getByText('Read more'); | ||
await expect(readMoreButton3).toBeVisible(); | ||
await expect(readMoreButton3).toBeFocused(); | ||
|
||
// Validate zone three focus | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--clickable&args=clickZone:three', | ||
}); | ||
await page.keyboard.press('Tab'); | ||
const zone3 = page.locator(`.${pkg.prefix}--card__body`); | ||
await expect(zone3).toBeFocused(); | ||
await expect(zone3).toHaveAttribute('role', 'button'); | ||
|
||
// Move focus to the Read more button and validate | ||
await page.keyboard.press('Tab'); | ||
const readMoreButton4 = page.getByText('Read more'); | ||
await expect(readMoreButton4).toBeVisible(); | ||
await expect(readMoreButton4).toBeFocused(); | ||
|
||
// Navigate to the "button with href" story for ProductiveCard | ||
await visitStory(page, { | ||
component: 'ProductiveCard', | ||
id: 'ibm-products-components-cards-productivecard--with-button-href', | ||
}); | ||
|
||
// Ensure no accessibility violations for the story | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - button with href' | ||
); | ||
|
||
// Move focus to the href button and validate | ||
await page.keyboard.press('Tab'); | ||
await page.keyboard.press('Tab'); | ||
await page.keyboard.press('Tab'); | ||
const hrefButton = page.getByText('Read more'); | ||
await expect(hrefButton).toHaveAttribute('href', '#'); | ||
await expect(hrefButton).toBeVisible(); | ||
await expect(hrefButton).toBeFocused(); | ||
await expect(page).toHaveNoACViolations( | ||
'ProductiveCard @keyboard-navigation - href Button' | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we typically try to query by role or text over a specific query selector.
In this case, we could probably do
Or some similar variation of that.