diff --git a/cypress.d.ts b/cypress.d.ts index 899dc07..5f674a7 100644 --- a/cypress.d.ts +++ b/cypress.d.ts @@ -40,6 +40,8 @@ declare global { component: React.ReactNode, options?: MountOptions, ): Cypress.Chainable; + + realHover(): Chainable; } } } diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index b149cec..41d2798 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,17 +1,17 @@ // put e2e + CT common commands here - +import 'cypress-real-events'; // @ts-expect-error // @see error 2306 https://github.com/microsoft/TypeScript/blob/3fcd1b51a1e6b16d007b368229af03455c7d5794/src/compiler/diagnosticMessages.json#L1635 -import registerCypressGrep from '@cypress/grep' -registerCypressGrep() +import registerCypressGrep from '@cypress/grep'; +registerCypressGrep(); Cypress.Commands.add('getByCy', (selector, ...args) => cy.get(`[data-cy="${selector}"]`, ...args), -) +); Cypress.Commands.add('getByCyLike', (selector, ...args) => cy.get(`[data-cy*=${selector}]`, ...args), -) +); Cypress.Commands.add('getByClassLike', (selector, ...args) => cy.get(`[class*=${selector}]`, ...args), -) +); diff --git a/cypress/support/plugins.ts b/cypress/support/plugins.ts index 811e9bf..94bb927 100644 --- a/cypress/support/plugins.ts +++ b/cypress/support/plugins.ts @@ -1,4 +1,4 @@ -const cyGrep = require('@cypress/grep/src/plugin') +const cyGrep = require('@cypress/grep/src/plugin'); /** * The collection of plugins to use with Cypress @@ -13,5 +13,5 @@ export default function plugins( // add plugins here // ...cyDataSession(on, config), // example ...cyGrep(config), - } + }; } diff --git a/package.json b/package.json index 3e358c8..3c46ca4 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@typescript-eslint/parser": "6.7.2", "@vitejs/plugin-react": "4.1.0", "cypress": "13.2.0", + "cypress-real-events": "^1.10.3", "eslint": "8.50.0", "eslint-config-prettier": "9.0.0", "eslint-config-react-app": "7.0.1", diff --git a/src/assets/db.icons.tsx b/src/assets/db.icons.tsx index c561133..1952d00 100644 --- a/src/assets/db.icons.tsx +++ b/src/assets/db.icons.tsx @@ -277,7 +277,7 @@ function Save({ fill, width, height }: IconProps) { ); } -function Arrow({ fill, width, height }: IconProps) { +function Arrow({ fill, width, height, onClick }: IconProps) { return ( { return ( - + {children} ); diff --git a/src/components/FilterCard/FilterCard.cy.tsx b/src/components/FilterCard/FilterCard.cy.tsx new file mode 100644 index 0000000..f4d80f6 --- /dev/null +++ b/src/components/FilterCard/FilterCard.cy.tsx @@ -0,0 +1,56 @@ +import FilterCard from './FilterCard'; +import GlobalStyle from '@styles/global'; + +describe('', () => { + beforeEach(() => { + const filterCardPropsMock = { + filter: 'JavaScript', + onClick: cy.stub().as('onClickMock'), + }; + + cy.mount( + <> + + + , + ); + }); + + it('should render base card with align-items: center', () => { + cy.getByCy('base-card').should('have.css', 'align-items', 'center'); + }); + + it('should render base card with justify-content: space-between', () => { + cy.getByCy('base-card').should( + 'have.css', + 'justify-content', + 'space-between', + ); + }); + + it('should arrow be cursor pointer when hover it', () => { + cy.getByCy('arrow').realHover(); + cy.getByCy('arrow').should('have.css', 'cursor', 'pointer'); + }); + + it('should text container has diplay: flex', () => { + cy.getByCy('text-container').should('have.css', 'display', 'flex'); + }); + + it('should text container has flex-direction: column', () => { + cy.getByCy('text-container').should('have.css', 'flex-direction', 'column'); + }); + + it('should text container has align-items: flex-start', () => { + cy.getByCy('text-container').should( + 'have.css', + 'align-items', + 'flex-start', + ); + }); + + it('should onClick be called when click on arrow', () => { + cy.getByCy('arrow').click(); + cy.get('@onClickMock').should('be.called'); + }); +}); diff --git a/src/components/FilterCard/FilterCard.test.tsx b/src/components/FilterCard/FilterCard.test.tsx new file mode 100644 index 0000000..f5323f9 --- /dev/null +++ b/src/components/FilterCard/FilterCard.test.tsx @@ -0,0 +1,39 @@ +import { render, screen } from '@testing-library/react'; +import { jest } from '@jest/globals'; + +import FilterCard from '@components/FilterCard'; + +const filterCardPropsMock = { + filter: 'JavaScript', + onClick: jest.fn(), +}; + +describe('', () => { + beforeEach(() => { + render(); + }); + + it('should be defined', () => { + screen.getByTestId('filter-card'); + }); + + it('should render base card', () => { + screen.getByTestId('base-card'); + }); + + it('should render text container', () => { + screen.getByTestId('text-container'); + }); + + it('should render text "Vagas"', () => { + screen.getByText('Vagas'); + }); + + it(`should render text "${filterCardPropsMock.filter}"`, () => { + screen.getByText(filterCardPropsMock.filter); + }); + + it('should render arrow icon', () => { + screen.getByTestId('arrow'); + }); +}); diff --git a/src/components/FilterCard/FilterCard.tsx b/src/components/FilterCard/FilterCard.tsx new file mode 100644 index 0000000..8f3a9c5 --- /dev/null +++ b/src/components/FilterCard/FilterCard.tsx @@ -0,0 +1,26 @@ +import BaseCard from '@components/BaseCard'; +import Text from '@components/Text'; +import { Arrow } from '@assets/db.icons'; + +import * as S from './styles'; + +type FilterCardProps = { + filter: string; + onClick: () => void; +}; + +const FilterCard = ({ filter, onClick }: FilterCardProps) => { + return ( + + +
+ + +
+ + + + ); +}; + +export default FilterCard; diff --git a/src/components/FilterCard/index.ts b/src/components/FilterCard/index.ts new file mode 100644 index 0000000..8744973 --- /dev/null +++ b/src/components/FilterCard/index.ts @@ -0,0 +1 @@ +export { default } from './FilterCard'; diff --git a/src/components/FilterCard/styles.ts b/src/components/FilterCard/styles.ts new file mode 100644 index 0000000..50500e3 --- /dev/null +++ b/src/components/FilterCard/styles.ts @@ -0,0 +1,18 @@ +import styled from 'styled-components'; + +export const FilterCard = styled.div` + .base-card { + align-items: center; + justify-content: space-between; + + .icon:hover { + cursor: pointer; + } + } + + .text-container { + display: flex; + flex-direction: column; + align-items: flex-start; + } +`; diff --git a/src/components/Text/index.tsx b/src/components/Text/index.tsx index e1fdac1..6e088a9 100644 --- a/src/components/Text/index.tsx +++ b/src/components/Text/index.tsx @@ -1,7 +1,11 @@ import * as S from './styles'; const Text = (props: TextProps) => { - return {props.label}; + return ( + + {props.label} + + ); }; export default Text; diff --git a/src/types/BaseCardProps.d.ts b/src/types/BaseCardProps.d.ts index be1e71f..8ed865b 100644 --- a/src/types/BaseCardProps.d.ts +++ b/src/types/BaseCardProps.d.ts @@ -1,6 +1,6 @@ type BaseCardProps = { padding?: 'large' | 'xmedium' | 'small'; - borderColor?: 'purple'; + borderColor?: 'purple' | 'white'; backgroundColor?: 'purple' | 'white'; children: React.ReactNode; }; diff --git a/yarn.lock b/yarn.lock index 76f09e2..91a2357 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4518,6 +4518,11 @@ csstype@^3.1.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +cypress-real-events@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.10.3.tgz#e2e949ea509cc4306df6c238de1a9982d67360e5" + integrity sha512-YN3fn+CJIAM638sE6uMvv2/n3PsWowdd0rOiN6ZoyezNAMyENfuQHvccLKZpN+apGfQZYetCml6QXLYgDid2fg== + cypress@13.2.0: version "13.2.0" resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.2.0.tgz#10f73d06a0764764ffbb903a31e96e2118dcfc1d"