From c55acee547f1adc0b5407be668874ec9ae7150cf Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Fri, 9 Jun 2023 15:40:42 -0400 Subject: [PATCH 1/3] chore(Card): added tests for new clickable/selectable --- .../__tests__/CardSelectableActions.test.tsx | 32 +++++ .../CardSelectableActions.test.tsx.snap | 11 ++ .../cypress/integration/card.spec.ts | 38 ++++- .../components/demos/CardDemo/CardDemo.tsx | 136 ++++++++++-------- 4 files changed, 156 insertions(+), 61 deletions(-) create mode 100644 packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx create mode 100644 packages/react-core/src/components/Card/__tests__/__snapshots__/CardSelectableActions.test.tsx.snap diff --git a/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx b/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx new file mode 100644 index 00000000000..f07d0e95c3e --- /dev/null +++ b/packages/react-core/src/components/Card/__tests__/CardSelectableActions.test.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { CardSelectableActions } from '../CardSelectableActions'; + +test('Matches the snapshot', () => { + const { asFragment } = render(Test); + expect(asFragment()).toMatchSnapshot(); +}); + +test('Renders without children', () => { + render(); + + expect(screen.getByTestId('card-selectable-actions')).toBeVisible(); +}); + +test('Renders children', () => { + render(Test); + + expect(screen.getByText('Test')).toBeVisible(); +}); + +test('Renders with class name pf-v5-c-card__selectable-actions', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('pf-v5-c-card__selectable-actions'); +}); + +test('Renders with custom class names provided via prop', () => { + render(Test); + + expect(screen.getByText('Test')).toHaveClass('test-class'); +}); diff --git a/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSelectableActions.test.tsx.snap b/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSelectableActions.test.tsx.snap new file mode 100644 index 00000000000..d3c07ec4969 --- /dev/null +++ b/packages/react-core/src/components/Card/__tests__/__snapshots__/CardSelectableActions.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches the snapshot 1`] = ` + +
+ Test +
+
+`; diff --git a/packages/react-integration/cypress/integration/card.spec.ts b/packages/react-integration/cypress/integration/card.spec.ts index b2fc5b76d8c..0d3f3ff6451 100644 --- a/packages/react-integration/cypress/integration/card.spec.ts +++ b/packages/react-integration/cypress/integration/card.spec.ts @@ -3,8 +3,8 @@ describe('Card Demo Test', () => { cy.visit('http://localhost:3000/card-demo-nav-link'); }); - it('Verify that selectable card can be selected and unselected with keyboard input', () => { - cy.get('#selectableCard').focus(); + it.skip('Verify that deprecated selectable card can be selected and unselected with keyboard input', () => { + cy.get('#selectableCardDeprecated').focus(); cy.focused().should('have.class', 'pf-m-selectable'); cy.focused().should('not.have.class', 'pf-m-selected'); cy.focused().type('{enter}'); @@ -13,7 +13,7 @@ describe('Card Demo Test', () => { cy.focused().should('not.have.class', 'pf-m-selected'); }); - it('Verify that selectableRaised card can be selected and unselected with keyboard input', () => { + it.skip('Verify that selectableRaised card can be selected and unselected with keyboard input', () => { cy.get('#selectableCardRaised').focus(); cy.focused().should('have.class', 'pf-m-selectable-raised'); cy.focused().should('not.have.class', 'pf-m-selected-raised'); @@ -23,10 +23,40 @@ describe('Card Demo Test', () => { cy.focused().should('not.have.class', 'pf-m-selected-raised'); }); - it('Verify card is expandable', () => { + it.skip('Verify card is expandable', () => { cy.get('#expand-card').should('not.have.class', 'pf-m-expanded'); cy.get('#expand-card .pf-v5-c-card__header').should('have.class', 'pf-m-toggle-right'); cy.get('.pf-v5-c-card__header-toggle .pf-v5-c-button').click(); cy.get('#expand-card').should('have.class', 'pf-m-expanded'); }); + + it.skip('Verify new selectable card can be selected', () => { + cy.get('#selectable-card-example-1 #selectable-card-input-1').should('not.be.checked'); + cy.get('#selectable-card-example-2 #selectable-card-input-2').should('not.be.checked'); + cy.get('#selectable-card-example-1').then(($card) => { + cy.wrap($card).click(); + cy.wrap($card).get('#selectable-card-input-1').should('be.checked'); + cy.get('#selectable-card-example-2 #selectable-card-input-2').should('not.be.checked'); + }); + cy.get('#selectable-card-example-2').then(($card) => { + cy.wrap($card).click(); + cy.wrap($card).get('#selectable-card-input-2').should('be.checked'); + cy.get('#selectable-card-example-1 #selectable-card-input-1').should('be.checked'); + }); + }); + + it.skip('Verify new single selectable card can be selected', () => { + cy.get('#single-selectable-card-example-1 #single-selectable-card-input-1').should('not.be.checked'); + cy.get('#single-selectable-card-example-2 #single-selectable-card-input-2').should('not.be.checked'); + cy.get('#single-selectable-card-example-1').then(($card) => { + cy.wrap($card).click(); + cy.wrap($card).get('#single-selectable-card-input-1').should('be.checked'); + cy.get('#single-selectable-card-example-2 #single-selectable-card-input-2').should('not.be.checked'); + }); + cy.get('#single-selectable-card-example-2').then(($card) => { + cy.wrap($card).click(); + cy.wrap($card).get('#single-selectable-card-input-2').should('be.checked'); + cy.get('#single-selectable-card-example-1 #single-selectable-card-input-1').should('not.be.checked'); + }); + }); }); diff --git a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx index ef3898d3f24..1b5cc11dfc2 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { + Brand, Card, CardTitle, CardHeader, @@ -7,7 +8,6 @@ import { CardFooter, CardExpandableContent, Checkbox, - Brand, Dropdown, DropdownItem, DropdownList, @@ -21,6 +21,8 @@ interface CardDemoState { isExpanded: boolean; isOpen: boolean; check1: boolean; + selectableChecked1: boolean; + selectableChecked2: boolean; } export class CardDemo extends React.Component { @@ -30,7 +32,9 @@ export class CardDemo extends React.Component { selected: null, isExpanded: false, isOpen: false, - check1: false + check1: false, + selectableChecked1: false, + selectableChecked2: false }; onKeyDown = (event: any) => { @@ -74,7 +78,21 @@ export class CardDemo extends React.Component { this.setState({ [name]: value }); }; + onSelectableChange = (event: React.FormEvent, checked: boolean) => { + const name = event.currentTarget.name; + + switch (name) { + case 'selectable-card-input-1': + this.setState({ selectableChecked1: checked }); + break; + case 'selectable-card-input-2': + this.setState({ selectableChecked2: checked }); + break; + } + }; + render() { + const { selectableChecked1, selectableChecked2 } = this.state; const dropdownItems = [ Link, Action, @@ -115,62 +133,19 @@ export class CardDemo extends React.Component { return ( - - Header - Body - Footer - -

- - Header - Body - Footer - -

- + + + + Header Body Footer

- - - Header - - Body - Footer - -

- - Header - Body - Footer - - - Header - Body - Footer - - - Header - Body - Footer - - - Header - Body - Footer - - - Header - Body - Footer - - @@ -202,13 +177,60 @@ export class CardDemo extends React.Component { )}

- - - + + + First card - Header - Body - Footer + This card is selectable. + + + + Second card + + This card is selectable. + +

+ + + First card + + This card is single selectable. + + + + Second card + + This card is single selectable.
); From c4c769c046b370ccdf28c4a777ac47e261d31bd7 Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Fri, 9 Jun 2023 16:17:30 -0400 Subject: [PATCH 2/3] Added tests for clickable cards --- .../cypress/integration/card.spec.ts | 42 +++++- .../components/demos/CardDemo/CardDemo.tsx | 125 +++++++++++++++++- 2 files changed, 156 insertions(+), 11 deletions(-) diff --git a/packages/react-integration/cypress/integration/card.spec.ts b/packages/react-integration/cypress/integration/card.spec.ts index 0d3f3ff6451..8c8b32c924d 100644 --- a/packages/react-integration/cypress/integration/card.spec.ts +++ b/packages/react-integration/cypress/integration/card.spec.ts @@ -3,7 +3,7 @@ describe('Card Demo Test', () => { cy.visit('http://localhost:3000/card-demo-nav-link'); }); - it.skip('Verify that deprecated selectable card can be selected and unselected with keyboard input', () => { + it('Verify that deprecated selectable card can be selected and unselected with keyboard input', () => { cy.get('#selectableCardDeprecated').focus(); cy.focused().should('have.class', 'pf-m-selectable'); cy.focused().should('not.have.class', 'pf-m-selected'); @@ -13,7 +13,7 @@ describe('Card Demo Test', () => { cy.focused().should('not.have.class', 'pf-m-selected'); }); - it.skip('Verify that selectableRaised card can be selected and unselected with keyboard input', () => { + it('Verify that selectableRaised card can be selected and unselected with keyboard input', () => { cy.get('#selectableCardRaised').focus(); cy.focused().should('have.class', 'pf-m-selectable-raised'); cy.focused().should('not.have.class', 'pf-m-selected-raised'); @@ -23,14 +23,14 @@ describe('Card Demo Test', () => { cy.focused().should('not.have.class', 'pf-m-selected-raised'); }); - it.skip('Verify card is expandable', () => { + it('Verify card is expandable', () => { cy.get('#expand-card').should('not.have.class', 'pf-m-expanded'); cy.get('#expand-card .pf-v5-c-card__header').should('have.class', 'pf-m-toggle-right'); cy.get('.pf-v5-c-card__header-toggle .pf-v5-c-button').click(); cy.get('#expand-card').should('have.class', 'pf-m-expanded'); }); - it.skip('Verify new selectable card can be selected', () => { + it('Verify new selectable card can be selected', () => { cy.get('#selectable-card-example-1 #selectable-card-input-1').should('not.be.checked'); cy.get('#selectable-card-example-2 #selectable-card-input-2').should('not.be.checked'); cy.get('#selectable-card-example-1').then(($card) => { @@ -45,7 +45,7 @@ describe('Card Demo Test', () => { }); }); - it.skip('Verify new single selectable card can be selected', () => { + it('Verify new single selectable card can be selected', () => { cy.get('#single-selectable-card-example-1 #single-selectable-card-input-1').should('not.be.checked'); cy.get('#single-selectable-card-example-2 #single-selectable-card-input-2').should('not.be.checked'); cy.get('#single-selectable-card-example-1').then(($card) => { @@ -59,4 +59,36 @@ describe('Card Demo Test', () => { cy.get('#single-selectable-card-example-1 #single-selectable-card-input-1').should('not.be.checked'); }); }); + + it('Verify clickable only card action is triggered', () => { + cy.get('#clickable-card-drawer').should('not.have.class', 'pf-m-expanded'); + cy.get('#clickable-card-example-1 #clickable-card-input-1').should('not.be.checked'); + cy.get('#clickable-card-example-1').click(); + cy.get('#clickable-card-drawer').should('have.class', 'pf-m-expanded'); + cy.get('#clickable-card-example-1 #clickable-card-input-1').should('be.checked'); + }); + + it('Verify clickable only card link is navigated to', () => { + cy.location('pathname').should('eq', '/card-demo-nav-link'); + cy.get('#clickable-card-example-2').click(); + cy.location('pathname').should('eq', '/button-demo-nav-link'); + cy.go('back'); + }); + + it('Verify clickable and selectable card', () => { + cy.get('#clickable-selectable-card-drawer').should('not.have.class', 'pf-m-expanded'); + cy.get('#clickable-selectable-card-example-1 #clickable-selectable-card-input-1').should('not.be.checked'); + // Clicking outside clickable areas should not change input or trigger action + cy.get('#clickable-selectable-card-example-1').click(); + cy.get('#clickable-selectable-card-drawer').should('not.have.class', 'pf-m-expanded'); + cy.get('#clickable-selectable-card-example-1 #clickable-selectable-card-input-1').should('not.be.checked'); + + // Ciicking input should not trigger action + cy.get('#clickable-selectable-card-example-1 #clickable-selectable-card-input-1').click(); + cy.get('#clickable-selectable-card-example-1 #clickable-selectable-card-input-1').should('be.checked'); + cy.get('#clickable-selectable-card-drawer').should('not.have.class', 'pf-m-expanded'); + + cy.get('#clickable-selectable-card-example-1 .pf-v5-c-button').click(); + cy.get('#clickable-selectable-card-drawer').should('have.class', 'pf-m-expanded'); + }); }); diff --git a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx index 1b5cc11dfc2..c5971c03abe 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Brand, + Button, Card, CardTitle, CardHeader, @@ -8,6 +9,10 @@ import { CardFooter, CardExpandableContent, Checkbox, + Drawer, + DrawerContent, + DrawerContentBody, + DrawerPanelContent, Dropdown, DropdownItem, DropdownList, @@ -23,6 +28,10 @@ interface CardDemoState { check1: boolean; selectableChecked1: boolean; selectableChecked2: boolean; + drawerIsExpanded: boolean; + selectableClickableChecked: boolean; + selectableClickableSelected: boolean; + selectaleClickableDrawerIsExpanded: boolean; } export class CardDemo extends React.Component { @@ -34,7 +43,11 @@ export class CardDemo extends React.Component { isOpen: false, check1: false, selectableChecked1: false, - selectableChecked2: false + selectableChecked2: false, + drawerIsExpanded: false, + selectableClickableChecked: false, + selectableClickableSelected: false, + selectaleClickableDrawerIsExpanded: false }; onKeyDown = (event: any) => { @@ -91,8 +104,26 @@ export class CardDemo extends React.Component { } }; + onSelectableClickableChange = (_event: React.FormEvent, checked: boolean) => { + this.setState({ selectableClickableChecked: checked }); + }; + + onSelectableClickableClick = () => { + this.setState({ + selectableClickableSelected: !this.state.selectableClickableSelected, + selectaleClickableDrawerIsExpanded: !this.state.selectaleClickableDrawerIsExpanded + }); + }; + render() { - const { selectableChecked1, selectableChecked2 } = this.state; + const { + selectableChecked1, + selectableChecked2, + drawerIsExpanded, + selectableClickableChecked, + selectableClickableSelected, + selectaleClickableDrawerIsExpanded + } = this.state; const dropdownItems = [ Link, Action, @@ -187,7 +218,7 @@ export class CardDemo extends React.Component { onChange: this.onSelectableChange }} > - First card + First selectable card This card is selectable. @@ -201,7 +232,7 @@ export class CardDemo extends React.Component { onChange: this.onSelectableChange }} > - Second card + Second selectable card This card is selectable. @@ -215,7 +246,7 @@ export class CardDemo extends React.Component { variant: 'single' }} > - First card + First single selectable card This card is single selectable. @@ -228,10 +259,92 @@ export class CardDemo extends React.Component { variant: 'single' }} > - Second card + Second single selectable card This card is single selectable. +

+
+ + + Clickable card drawer panel + + } + > + + + { + this.setState({ drawerIsExpanded: !drawerIsExpanded }); + }, + selectableActionId: 'clickable-card-input-1', + selectableActionAriaLabelledby: 'clickable-card-example-1', + name: 'clickable-card-example-1' + }} + > + Clickable card with action + + This card performs an action on click. + + + + +
+

+ + + Clickable card with link + + This card can navigate to a link on click. + +

+
+ + + Clickable and selectable card drawer panel + + } + > + + + + + + + + This card performs an action upon clicking the card title and is selectable. + + + + +
); } From 8d140b0994f8f06f20cbcc2335feec06a15dbee6 Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Mon, 12 Jun 2023 08:53:13 -0400 Subject: [PATCH 3/3] Updated card with actions test --- .../cypress/integration/card.spec.ts | 10 +++++++++ .../components/demos/CardDemo/CardDemo.tsx | 21 ++----------------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/react-integration/cypress/integration/card.spec.ts b/packages/react-integration/cypress/integration/card.spec.ts index 8c8b32c924d..3d7701566c7 100644 --- a/packages/react-integration/cypress/integration/card.spec.ts +++ b/packages/react-integration/cypress/integration/card.spec.ts @@ -3,6 +3,16 @@ describe('Card Demo Test', () => { cy.visit('http://localhost:3000/card-demo-nav-link'); }); + it('Verify card with actions', () => { + cy.get('#cardWithActions .pf-v5-c-menu-toggle').then(($menuToggle) => { + cy.wrap($menuToggle).should('not.have.class', 'pf-m-expanded'); + cy.wrap($menuToggle).click(); + cy.wrap($menuToggle).should('have.class', 'pf-m-expanded'); + }); + cy.get('#cardWithActions .pf-v5-c-menu .pf-v5-c-menu__item').first().click(); + cy.get('#cardWithActions .pf-v5-c-menu-toggle').should('not.have.class', 'pf-m-expanded'); + }); + it('Verify that deprecated selectable card can be selected and unselected with keyboard input', () => { cy.get('#selectableCardDeprecated').focus(); cy.focused().should('have.class', 'pf-m-selectable'); diff --git a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx index c5971c03abe..962f50e2f88 100644 --- a/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx +++ b/packages/react-integration/demo-app-ts/src/components/demos/CardDemo/CardDemo.tsx @@ -8,7 +8,6 @@ import { CardBody, CardFooter, CardExpandableContent, - Checkbox, Drawer, DrawerContent, DrawerContentBody, @@ -25,7 +24,6 @@ interface CardDemoState { selected: string; isExpanded: boolean; isOpen: boolean; - check1: boolean; selectableChecked1: boolean; selectableChecked2: boolean; drawerIsExpanded: boolean; @@ -41,7 +39,6 @@ export class CardDemo extends React.Component { selected: null, isExpanded: false, isOpen: false, - check1: false, selectableChecked1: false, selectableChecked2: false, drawerIsExpanded: false, @@ -84,13 +81,6 @@ export class CardDemo extends React.Component { }); }; - onClick = (event: any, _checked: boolean) => { - const target = event.target; - const value = target.type === 'checkbox' ? target.checked : target.value; - const name = target.name; - this.setState({ [name]: value }); - }; - onSelectableChange = (event: React.FormEvent, checked: boolean) => { const name = event.currentTarget.name; @@ -152,21 +142,14 @@ export class CardDemo extends React.Component { > {dropdownItems} - ); return ( - + - + Header Body