From 6b65be13e66b90a10c89971b67897668197dd88e Mon Sep 17 00:00:00 2001 From: Aleksandr Shumilov Date: Thu, 3 Aug 2023 13:00:40 +0300 Subject: [PATCH] test: notification, drawer, dropdown, and select (#3756) --- .changeset/nasty-meals-shout.md | 7 ++ cypress/component/Drawer.spec.tsx | 34 ++++++++++ cypress/component/Dropdown.spec.tsx | 37 +++++++++++ cypress/component/NotificationStream.spec.tsx | 44 +++++++++++++ cypress/component/Page.spec.tsx | 64 ++++++------------- cypress/component/Select.spec.tsx | 33 ++++++++++ package.json | 2 +- packages/picasso/src/Dropdown/styles.ts | 9 +-- packages/picasso/src/Popper/Popper.tsx | 2 +- packages/picasso/src/ScrollMenu/styles.ts | 10 +-- .../get-checkpoints.ts | 0 .../get-happo-targets/get-happo-targets.ts | 20 ++++++ .../src/test-utils/get-happo-targets/index.ts | 8 +++ packages/picasso/src/test-utils/index.tsx | 2 +- yarn.lock | 8 +-- 15 files changed, 217 insertions(+), 63 deletions(-) create mode 100644 .changeset/nasty-meals-shout.md rename packages/picasso/src/test-utils/{ => get-happo-targets}/get-checkpoints.ts (100%) create mode 100644 packages/picasso/src/test-utils/get-happo-targets/get-happo-targets.ts create mode 100644 packages/picasso/src/test-utils/get-happo-targets/index.ts diff --git a/.changeset/nasty-meals-shout.md b/.changeset/nasty-meals-shout.md new file mode 100644 index 0000000000..1a0f88ea67 --- /dev/null +++ b/.changeset/nasty-meals-shout.md @@ -0,0 +1,7 @@ +--- +'@toptal/picasso': patch +--- + +### Popper + +- use compact layout on extra-small screens diff --git a/cypress/component/Drawer.spec.tsx b/cypress/component/Drawer.spec.tsx index f8ab92d542..e49b99e17a 100644 --- a/cypress/component/Drawer.spec.tsx +++ b/cypress/component/Drawer.spec.tsx @@ -9,6 +9,7 @@ import { Typography, } from '@toptal/picasso' import { useModal, useNotifications } from '@toptal/picasso/utils' +import { HAPPO_TARGETS } from '@toptal/picasso/test-utils' const DrawerExample = ( props: Partial & { open: boolean; onOpen: () => void } @@ -148,4 +149,37 @@ describe('Drawer', () => { variant: 'ultra-wide/behind-modal', }) }) + + const testedDrawerVariants: DrawerProps['width'][] = [ + 'narrow', + 'regular', + 'ultra-wide', + ] + + Cypress._.each(HAPPO_TARGETS, happoTarget => { + const { width } = happoTarget + + describe(`when screen has ${width}px width`, () => { + Cypress._.each(testedDrawerVariants, variant => { + it(`renders ${variant} drawer`, () => { + cy.viewport(width, 1000) + cy.mount( + + + ${variant} drawer content + + + ) + + cy.getByTestId('trigger').click() + cy.getByRole('presentation').should('be.visible') + cy.get('body').happoScreenshot({ + component, + variant: `drawer-${variant}-width/${width}-default`, + targets: [happoTarget], + }) + }) + }) + }) + }) }) diff --git a/cypress/component/Dropdown.spec.tsx b/cypress/component/Dropdown.spec.tsx index 9e6279e639..1b0e298d4a 100644 --- a/cypress/component/Dropdown.spec.tsx +++ b/cypress/component/Dropdown.spec.tsx @@ -9,6 +9,7 @@ import { Form, Input, } from '@toptal/picasso' +import { HAPPO_TARGETS } from '@toptal/picasso/test-utils' const LongListExample = () => ( @@ -111,6 +112,42 @@ describe('Dropdown', () => { variant: 'custom-content-style/after-clicked', }) }) + + // Based on screen height, dropdown has different styling + // 250px was selected as a height that shrinks the dropdown enough, 586+px is a + // breakpoint that disables any extra styling + const heights = [250, 586] + + heights.forEach(height => { + Cypress._.each(HAPPO_TARGETS, happoTarget => { + const { width } = happoTarget + + describe(`when screen has ${width}px width and ${height}px height`, () => { + it(`renders dropdown`, () => { + cy.viewport(width, height) + + cy.mount( + + Open menu + + + ) + + cy.getByTestId('trigger').realClick() + cy.get('body').happoScreenshot({ + component, + variant: `dropdown/${width}x${height}-default`, + targets: [ + { + ...happoTarget, + viewport: `${happoTarget.width}x${height}`, + }, + ], + }) + }) + }) + }) + }) }) const menuItems = [ diff --git a/cypress/component/NotificationStream.spec.tsx b/cypress/component/NotificationStream.spec.tsx index 3d7ed21fbc..5de01dfa8d 100644 --- a/cypress/component/NotificationStream.spec.tsx +++ b/cypress/component/NotificationStream.spec.tsx @@ -7,6 +7,28 @@ import { Link, Pencil16, } from '@toptal/picasso' +import { HAPPO_TARGETS } from '@toptal/picasso/test-utils' +import { PicassoBreakpoints } from '@toptal/picasso-provider/index' + +const DefaultExample = () => { + const { showInfo } = useNotifications() + + return ( + + + + ) +} const VariantsExample = () => { const { showInfo, showSuccess, showError } = useNotifications() @@ -114,4 +136,26 @@ describe('NotificationStream', () => { variant: 'custom-icon', }) }) + + Cypress._.each(HAPPO_TARGETS, happoTarget => { + const { width } = happoTarget + const isNarrowScreenSize = width < PicassoBreakpoints.breakpoints.values.lg + + describe(`when screen has ${width}px width`, () => { + it(`notification uses ${ + isNarrowScreenSize ? 'compact' : 'regular' + } layout`, () => { + cy.viewport(width, 1000) + + cy.mount() + + cy.getByTestId('trigger-default').click() + cy.get('body').happoScreenshot({ + component, + variant: `notification/${width}-default`, + targets: [happoTarget], + }) + }) + }) + }) }) diff --git a/cypress/component/Page.spec.tsx b/cypress/component/Page.spec.tsx index 26eb8b559c..f06696f759 100644 --- a/cypress/component/Page.spec.tsx +++ b/cypress/component/Page.spec.tsx @@ -1,39 +1,11 @@ import React from 'react' import type { PageSidebarProps } from '@toptal/picasso' import { Container, Menu, Page, Typography } from '@toptal/picasso' -import { getCheckpoints } from '@toptal/picasso/test-utils' +import { HAPPO_TARGETS, getHappoTargets } from '@toptal/picasso/test-utils' const component = 'Page' const containerHeight = '30rem' -const checkpoints = getCheckpoints() - -// Sidebar menu has custom breakpoint at 1280px that changes its behavior, so 1280px -// acts as a divider for "small" and "wide" page checkpoints -const smallScreenCheckpoints = [ - ...checkpoints.filter(width => width < 1280), - 1279, -] -const wideScreenCheckpoints = [ - 1280, - ...checkpoints.filter(width => width >= 1280), -] - -const responsiveHappoTargets = [ - ...smallScreenCheckpoints, - ...wideScreenCheckpoints, -].reduce>((acc, width) => { - const name = `chrome-desktop-width-${width}` - - acc[name] = { - name, - browser: 'chrome', - viewport: `${width}x1024`, - } - - return acc -}, {}) - enum TestIds { WRAPPER = 'wrapper', SIDEBAR_SCROLLABLE_CONTAINER = 'sidebar-scrollable-container', @@ -203,9 +175,19 @@ describe('Page', () => { }) }) - describe('for screen sizes smaller than 1280px', () => { - Cypress._.each(smallScreenCheckpoints, width => { - describe(`when page is rendered on a ${width} screen width`, () => { + // Sidebar menu has custom breakpoint at 1280px that changes its behavior + const customBreakpoint = 1280 + const extendedHappoTargets = [ + ...HAPPO_TARGETS, + ...getHappoTargets([customBreakpoint - 1, customBreakpoint]), + ] + + Cypress._.each(extendedHappoTargets, happoTarget => { + const { width } = happoTarget + const isSmallScreenTarget = width < customBreakpoint + + if (isSmallScreenTarget) { + describe(`when screen has ${width}px width`, () => { it('renders hamburger menu and hides sidebar', () => { cy.viewport(width, 1000) cy.mount() @@ -213,7 +195,7 @@ describe('Page', () => { cy.get('body').happoScreenshot({ component, variant: `page-menu-screen-smaller-than-1280/${width}-initial`, - targets: [responsiveHappoTargets[`chrome-desktop-width-${width}`]], + targets: [happoTarget], }) cy.getByTestId('hamburger-button').should('be.visible') @@ -224,7 +206,7 @@ describe('Page', () => { cy.get('body').happoScreenshot({ component, variant: `page-menu-screen-smaller-than-1280/${width}-opened-menu`, - targets: [responsiveHappoTargets[`chrome-desktop-width-${width}`]], + targets: [happoTarget], }) cy.getByTestId('hamburger-button').realClick() @@ -234,16 +216,12 @@ describe('Page', () => { cy.get('body').happoScreenshot({ component, variant: `page-menu-screen-smaller-than-1280/${width}-closed-menu`, - targets: [responsiveHappoTargets[`chrome-desktop-width-${width}`]], + targets: [happoTarget], }) }) }) - }) - }) - - describe('for screen sizes equal or bigger than 1280px', () => { - Cypress._.each(wideScreenCheckpoints, width => { - describe(`when page is rendered on a ${width} screen width`, () => { + } else { + describe(`when screen has ${width}px width`, () => { it('does not show hamburger menu button and renders sidebar', () => { cy.viewport(width, 1000) cy.mount() @@ -253,10 +231,10 @@ describe('Page', () => { cy.get('body').happoScreenshot({ component, variant: `page-menu-screen-bigger-or-equal-than-1280/${width}-default`, - targets: [responsiveHappoTargets[`chrome-desktop-width-${width}`]], + targets: [happoTarget], }) }) }) - }) + } }) }) diff --git a/cypress/component/Select.spec.tsx b/cypress/component/Select.spec.tsx index 3efb202343..8145d77d5f 100644 --- a/cypress/component/Select.spec.tsx +++ b/cypress/component/Select.spec.tsx @@ -3,6 +3,7 @@ import React, { useState } from 'react' import type { SelectValueType, SelectProps } from '@toptal/picasso' import { Select, Form, Container, Drawer } from '@toptal/picasso' import { noop, palette } from '@toptal/picasso/utils' +import { HAPPO_TARGETS } from '@toptal/picasso/test-utils' const TestSelect = ({ onChange = noop, @@ -395,4 +396,36 @@ describe('Select', () => { cy.getByTestId('search-input').find('input').should('be.focused') }) }) + + // Based on screen height, select (scroll menu) has different styling + // 250px was selected as a height that shrinks the select enough, 586+px is a + // breakpoint that disables any extra styling + const heights = [250, 586] + + heights.forEach(height => { + Cypress._.each(HAPPO_TARGETS, happoTarget => { + const { width } = happoTarget + + describe(`when screen has ${width}px width and ${height}px height`, () => { + it(`renders select`, () => { + cy.viewport(width, height) + + cy.mount() + + openSelect() + + cy.get('body').happoScreenshot({ + component, + variant: `select/${width}x${height}-default`, + targets: [ + { + ...happoTarget, + viewport: `${happoTarget.width}x${height}`, + }, + ], + }) + }) + }) + }) + }) }) diff --git a/package.json b/package.json index c31ba726a0..287fa67b77 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "@toptal/davinci-syntax": "^20.2.1", "@types/debounce": "^1.2.1", "@types/esprima": "^4.0.3", - "@types/happo-cypress": "^4.1.0", + "@types/happo-cypress": "^4.1.1", "@types/jest-image-snapshot": "^3.1.0", "@types/react-truncate": "^2.3.4", "babel-loader": "^9.1.2", diff --git a/packages/picasso/src/Dropdown/styles.ts b/packages/picasso/src/Dropdown/styles.ts index 05d1899cd8..4c5eb88a74 100644 --- a/packages/picasso/src/Dropdown/styles.ts +++ b/packages/picasso/src/Dropdown/styles.ts @@ -28,17 +28,14 @@ export default ({ screens, shadows, palette }: Theme) => maxHeight: '14.75rem', // 6.5 lines of menu to show overflowY: 'auto', boxShadow: shadows[0], - [screens('xs', 'sm')]: { - maxHeight: '14.75rem', // 6.5 lines of menu to show - }, // height under which maxHeight menu starts to overflow // and needs to reduce height dynamically to avoid overflow '@media screen and (max-height: 585px)': { - maxHeight: 'calc(50vh - 3.5rem)', // half of screen minus header and anchor + maxHeight: 'calc(50vh - 3rem)', // half of viewport minus header and anchor - [screens('xs', 'sm')]: { - maxHeight: 'calc(50vh - 3rem)', // half of viewport minus header and anchor + [screens('md', 'lg', 'xl')]: { + maxHeight: 'calc(50vh - 3.5rem)', // half of screen minus header and anchor }, }, }, diff --git a/packages/picasso/src/Popper/Popper.tsx b/packages/picasso/src/Popper/Popper.tsx index cd4fa89ff4..cbca54bb43 100644 --- a/packages/picasso/src/Popper/Popper.tsx +++ b/packages/picasso/src/Popper/Popper.tsx @@ -139,7 +139,7 @@ export const Popper = forwardRef(function Popper(props, ref) { const isInsideModal = useContext(ModalContext) const classes = useStyles() - const isCompactLayoutResolution = useBreakpoint(['sm', 'md']) + const isCompactLayoutResolution = useBreakpoint(['xs', 'sm', 'md']) const isCompactLayout = enableCompactMode && isCompactLayoutResolution const widthStyle = useWidthStyle({ autoWidth, width, anchorEl }) const anchorElWidthStyle = !isCompactLayout && widthStyle diff --git a/packages/picasso/src/ScrollMenu/styles.ts b/packages/picasso/src/ScrollMenu/styles.ts index 0184241fe4..322bbcda82 100644 --- a/packages/picasso/src/ScrollMenu/styles.ts +++ b/packages/picasso/src/ScrollMenu/styles.ts @@ -10,17 +10,13 @@ export default ({ palette, screens }: Theme) => maxHeight: '26.875rem', // ~8.5 lines of menu to show overflowY: 'auto', - [screens('xs', 'sm')]: { - maxHeight: '26.875rem', // ~8.5 lines of menu to show - }, - // height under which maxHeight menu starts to overflow // and needs to reduce height dynamically to avoid overflow '@media screen and (max-height: 585px)': { - maxHeight: 'calc(50vh - 4.8125rem)', // half of viewport minus header and anchor + maxHeight: 'calc(50vh - 4.3125rem)', // half of viewport minus header and anchor - [screens('xs', 'sm')]: { - maxHeight: 'calc(50vh - 4.3125rem)', // half of viewport minus header and anchor + [screens('md', 'lg', 'xl')]: { + maxHeight: 'calc(50vh - 4.8125rem)', // half of viewport minus header and anchor }, }, }, diff --git a/packages/picasso/src/test-utils/get-checkpoints.ts b/packages/picasso/src/test-utils/get-happo-targets/get-checkpoints.ts similarity index 100% rename from packages/picasso/src/test-utils/get-checkpoints.ts rename to packages/picasso/src/test-utils/get-happo-targets/get-checkpoints.ts diff --git a/packages/picasso/src/test-utils/get-happo-targets/get-happo-targets.ts b/packages/picasso/src/test-utils/get-happo-targets/get-happo-targets.ts new file mode 100644 index 0000000000..660055b349 --- /dev/null +++ b/packages/picasso/src/test-utils/get-happo-targets/get-happo-targets.ts @@ -0,0 +1,20 @@ +type HappoTarget = { + name: string + browser: string + viewport: string + width: number +} + +/** + * Generates Happo targets for responsive visual tests + * + * @param screenWidths Screen widths to generate targets for + * @returns {Result} Object with Happo targets + */ +export const getHappoTargets = (checkpoints: number[]): HappoTarget[] => + checkpoints.map((width: number) => ({ + width, + name: `chrome-desktop-width-${width}`, + browser: 'chrome', + viewport: `${width}x1024`, + })) diff --git a/packages/picasso/src/test-utils/get-happo-targets/index.ts b/packages/picasso/src/test-utils/get-happo-targets/index.ts new file mode 100644 index 0000000000..1207b8dec6 --- /dev/null +++ b/packages/picasso/src/test-utils/get-happo-targets/index.ts @@ -0,0 +1,8 @@ +import { getCheckpoints } from './get-checkpoints' +import { getHappoTargets } from './get-happo-targets' + +const checkpoints = getCheckpoints() + +export { getHappoTargets } + +export const HAPPO_TARGETS = getHappoTargets(checkpoints) diff --git a/packages/picasso/src/test-utils/index.tsx b/packages/picasso/src/test-utils/index.tsx index 3fb4a0ed9b..76e43a47c5 100644 --- a/packages/picasso/src/test-utils/index.tsx +++ b/packages/picasso/src/test-utils/index.tsx @@ -31,4 +31,4 @@ const customRender = ( export * from '@testing-library/react' export { customRender as render, TestingPicasso } -export { getCheckpoints } from './get-checkpoints' +export { HAPPO_TARGETS, getHappoTargets } from './get-happo-targets' diff --git a/yarn.lock b/yarn.lock index 42f13b445e..508b77b217 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5927,10 +5927,10 @@ dependencies: "@types/node" "*" -"@types/happo-cypress@^4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@types/happo-cypress/-/happo-cypress-4.1.0.tgz#bd2d76fd0453c4d980d9be85328d77122e506e45" - integrity sha512-RwY+ExkWtiItcCH10DIaTGQXwSt/z6r1Yh0XTd4/jtoFRT8ZKMt/Mgaxyoc3LooAIpm7mV1Dq2bpS0NtqsY+EQ== +"@types/happo-cypress@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@types/happo-cypress/-/happo-cypress-4.1.1.tgz#1f0192abf129d98ec0adc6bf48816596144e1f1b" + integrity sha512-eIRD12nyF8aA3L6Mlvar0RMu9M4FAB34SmTQO8Q/7NjY4r19IQcjgEk1UN5LuVxXj4CrUdBCixzHUYnrkD6rjw== dependencies: cypress ">=6.4.0"